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
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
// src/dev/dev-server.ts
|
|
10
10
|
import http from "http";
|
|
11
11
|
import { resolve as resolve5, relative as relative2, extname as extname3 } from "path";
|
|
12
|
-
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as
|
|
12
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
13
13
|
import { pathToFileURL } from "url";
|
|
14
14
|
|
|
15
15
|
// src/core/schema.ts
|
|
@@ -645,8 +645,8 @@ var FileWatcher = class extends EventEmitter {
|
|
|
645
645
|
};
|
|
646
646
|
|
|
647
647
|
// src/dev/page-compiler.ts
|
|
648
|
-
import { resolve, join as join2, dirname, basename } from "path";
|
|
649
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
648
|
+
import { resolve, join as join2, relative, dirname, basename } from "path";
|
|
649
|
+
import { existsSync as existsSync2, readFileSync, readdirSync as readdirSync2, statSync as statSync2, writeFileSync, mkdirSync } from "fs";
|
|
650
650
|
var MAX_COMPONENT_DEPTH = 10;
|
|
651
651
|
var META_REGEX = /<!--\s*@(\w+):\s*(.+?)\s*-->/g;
|
|
652
652
|
var COMPONENT_REGEX = /<c-([a-z][a-z0-9-]*)\s*\/>/g;
|
|
@@ -741,6 +741,62 @@ var PageCompiler = class {
|
|
|
741
741
|
path: pathname
|
|
742
742
|
};
|
|
743
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Build all pages into static HTML for production deployment.
|
|
746
|
+
* Walks app/pages/ recursively, compiles each page, and writes to outputDir.
|
|
747
|
+
*
|
|
748
|
+
* - Skips _layout.html (wrapper-only, not standalone)
|
|
749
|
+
* - _404.html → 404.html (Firebase auto-serves for 404s)
|
|
750
|
+
* - Injects optional script (e.g. production router) before </body>
|
|
751
|
+
*/
|
|
752
|
+
buildForProduction(outputDir, scriptToInject) {
|
|
753
|
+
const pages = [];
|
|
754
|
+
const errors = [];
|
|
755
|
+
if (!this.isActive()) {
|
|
756
|
+
return { pages, errors };
|
|
757
|
+
}
|
|
758
|
+
const walk = (dir) => {
|
|
759
|
+
const entries = readdirSync2(dir);
|
|
760
|
+
for (const entry of entries) {
|
|
761
|
+
const fullPath = join2(dir, entry);
|
|
762
|
+
const stat = statSync2(fullPath);
|
|
763
|
+
if (stat.isDirectory()) {
|
|
764
|
+
walk(fullPath);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (!entry.endsWith(".html")) continue;
|
|
768
|
+
if (entry === "_layout.html") continue;
|
|
769
|
+
try {
|
|
770
|
+
const compiled = this.compile(fullPath);
|
|
771
|
+
let html = compiled.html;
|
|
772
|
+
if (scriptToInject) {
|
|
773
|
+
if (html.includes("</body>")) {
|
|
774
|
+
html = html.replace("</body>", scriptToInject + "\n</body>");
|
|
775
|
+
} else {
|
|
776
|
+
html += scriptToInject;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
const relPath = relative(this.pagesDir, fullPath);
|
|
780
|
+
let outputPath;
|
|
781
|
+
if (entry === "_404.html") {
|
|
782
|
+
const parentRel = relative(this.pagesDir, dir);
|
|
783
|
+
outputPath = parentRel ? join2(outputDir, parentRel, "404.html") : join2(outputDir, "404.html");
|
|
784
|
+
} else {
|
|
785
|
+
outputPath = join2(outputDir, relPath);
|
|
786
|
+
}
|
|
787
|
+
const outputDirPath = dirname(outputPath);
|
|
788
|
+
mkdirSync(outputDirPath, { recursive: true });
|
|
789
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
790
|
+
pages.push(relPath);
|
|
791
|
+
} catch (err) {
|
|
792
|
+
const relPath = relative(this.pagesDir, fullPath);
|
|
793
|
+
errors.push(`${relPath}: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
walk(this.pagesDir);
|
|
798
|
+
return { pages, errors };
|
|
799
|
+
}
|
|
744
800
|
// ─── Internal Methods ────────────────────────────────────────────
|
|
745
801
|
/**
|
|
746
802
|
* Extract <!-- @key: value --> metadata from HTML.
|
|
@@ -819,7 +875,7 @@ ${html}
|
|
|
819
875
|
};
|
|
820
876
|
|
|
821
877
|
// src/dev/env-manager.ts
|
|
822
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
878
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
|
|
823
879
|
import { resolve as resolve2 } from "path";
|
|
824
880
|
var KEY_PATTERN = /^[A-Z_][A-Z0-9_]*$/i;
|
|
825
881
|
var PLACEHOLDER_PATTERNS = [
|
|
@@ -893,7 +949,7 @@ var EnvManager = class {
|
|
|
893
949
|
lines.push(`${key}=${value}`);
|
|
894
950
|
}
|
|
895
951
|
}
|
|
896
|
-
|
|
952
|
+
writeFileSync2(this.envPath, lines.join("\n"), "utf-8");
|
|
897
953
|
if (description !== void 0) {
|
|
898
954
|
const descriptions = this.readDescriptions();
|
|
899
955
|
descriptions[key] = description;
|
|
@@ -911,7 +967,7 @@ var EnvManager = class {
|
|
|
911
967
|
if (eqIdx === -1) return true;
|
|
912
968
|
return trimmed.slice(0, eqIdx).trim() !== key;
|
|
913
969
|
});
|
|
914
|
-
|
|
970
|
+
writeFileSync2(this.envPath, filtered.join("\n"), "utf-8");
|
|
915
971
|
const descriptions = this.readDescriptions();
|
|
916
972
|
if (key in descriptions) {
|
|
917
973
|
delete descriptions[key];
|
|
@@ -928,7 +984,7 @@ var EnvManager = class {
|
|
|
928
984
|
}
|
|
929
985
|
}
|
|
930
986
|
writeDescriptions(descriptions) {
|
|
931
|
-
|
|
987
|
+
writeFileSync2(
|
|
932
988
|
this.descriptionsPath,
|
|
933
989
|
JSON.stringify(descriptions, null, 2) + "\n",
|
|
934
990
|
"utf-8"
|
|
@@ -1856,8 +1912,9 @@ function generateDashboardHtml(options) {
|
|
|
1856
1912
|
}
|
|
1857
1913
|
|
|
1858
1914
|
btn.disabled = true;
|
|
1859
|
-
btn.textContent = 'Setting...';
|
|
1860
|
-
status.
|
|
1915
|
+
btn.textContent = 'Setting up...';
|
|
1916
|
+
status.textContent = 'Selecting project, detecting web app, auto-filling config...';
|
|
1917
|
+
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;';
|
|
1861
1918
|
|
|
1862
1919
|
fetch(API + '/__dev/setup/select-project', {
|
|
1863
1920
|
method: 'POST',
|
|
@@ -1867,8 +1924,11 @@ function generateDashboardHtml(options) {
|
|
|
1867
1924
|
.then(function(r) { return r.json(); })
|
|
1868
1925
|
.then(function(data) {
|
|
1869
1926
|
if (data.success) {
|
|
1870
|
-
|
|
1871
|
-
status.
|
|
1927
|
+
var msg = data.steps ? data.steps.join('\\n') : data.message;
|
|
1928
|
+
status.textContent = msg;
|
|
1929
|
+
status.style.whiteSpace = 'pre-line';
|
|
1930
|
+
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;';
|
|
1931
|
+
btn.textContent = 'Done';
|
|
1872
1932
|
setTimeout(refreshSetupStatus, 1000);
|
|
1873
1933
|
} else {
|
|
1874
1934
|
status.textContent = data.message;
|
|
@@ -2577,7 +2637,7 @@ function generateDashboardHtml(options) {
|
|
|
2577
2637
|
|
|
2578
2638
|
// src/dev/firebase-setup.ts
|
|
2579
2639
|
import { execFile as execFile2, spawn } from "child_process";
|
|
2580
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as
|
|
2640
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2581
2641
|
import { resolve as resolve4, join as join3 } from "path";
|
|
2582
2642
|
import { tmpdir, platform, homedir } from "os";
|
|
2583
2643
|
var FirebaseSetup = class {
|
|
@@ -2600,7 +2660,7 @@ var FirebaseSetup = class {
|
|
|
2600
2660
|
saveState(partial) {
|
|
2601
2661
|
const current = this.loadState();
|
|
2602
2662
|
const merged = { ...current, ...partial, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2603
|
-
|
|
2663
|
+
writeFileSync3(this.stateFilePath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
2604
2664
|
}
|
|
2605
2665
|
// ─── Status Check ──────────────────────────────────────────────────
|
|
2606
2666
|
async getStatus() {
|
|
@@ -2702,7 +2762,7 @@ var FirebaseSetup = class {
|
|
|
2702
2762
|
try {
|
|
2703
2763
|
if (os === "darwin") {
|
|
2704
2764
|
const scriptPath = join3(tmpdir(), "clawfire-firebase-login.command");
|
|
2705
|
-
|
|
2765
|
+
writeFileSync3(scriptPath, [
|
|
2706
2766
|
"#!/bin/bash",
|
|
2707
2767
|
`cd "${this.projectDir}"`,
|
|
2708
2768
|
cmd,
|
|
@@ -2724,7 +2784,7 @@ var FirebaseSetup = class {
|
|
|
2724
2784
|
child.unref();
|
|
2725
2785
|
} else {
|
|
2726
2786
|
const scriptPath = join3(tmpdir(), "clawfire-firebase-login.sh");
|
|
2727
|
-
|
|
2787
|
+
writeFileSync3(scriptPath, [
|
|
2728
2788
|
"#!/bin/bash",
|
|
2729
2789
|
`cd "${this.projectDir}"`,
|
|
2730
2790
|
cmd,
|
|
@@ -2833,7 +2893,7 @@ var FirebaseSetup = class {
|
|
|
2833
2893
|
rc.projects = {};
|
|
2834
2894
|
}
|
|
2835
2895
|
rc.projects.default = projectId;
|
|
2836
|
-
|
|
2896
|
+
writeFileSync3(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
2837
2897
|
return { success: true, message: `Active project set to "${projectId}".` };
|
|
2838
2898
|
} catch {
|
|
2839
2899
|
try {
|
|
@@ -2841,7 +2901,7 @@ var FirebaseSetup = class {
|
|
|
2841
2901
|
const rc = {
|
|
2842
2902
|
projects: { default: projectId }
|
|
2843
2903
|
};
|
|
2844
|
-
|
|
2904
|
+
writeFileSync3(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
2845
2905
|
return { success: true, message: `Active project set to "${projectId}" (via .firebaserc).` };
|
|
2846
2906
|
} catch (writeErr) {
|
|
2847
2907
|
const msg = writeErr instanceof Error ? writeErr.message : "Unknown error";
|
|
@@ -2960,7 +3020,11 @@ var FirebaseSetup = class {
|
|
|
2960
3020
|
config.hosting = {
|
|
2961
3021
|
public: "public",
|
|
2962
3022
|
ignore: ["firebase.json", "**/.*", "**/node_modules/**"],
|
|
2963
|
-
|
|
3023
|
+
cleanUrls: true,
|
|
3024
|
+
rewrites: [
|
|
3025
|
+
{ source: "/api/**", function: "api" },
|
|
3026
|
+
{ source: "**", destination: "/index.html" }
|
|
3027
|
+
]
|
|
2964
3028
|
};
|
|
2965
3029
|
}
|
|
2966
3030
|
break;
|
|
@@ -2974,14 +3038,14 @@ var FirebaseSetup = class {
|
|
|
2974
3038
|
}
|
|
2975
3039
|
const rulesPath = resolve4(this.projectDir, "firestore.rules");
|
|
2976
3040
|
if (!existsSync5(rulesPath)) {
|
|
2977
|
-
|
|
3041
|
+
writeFileSync3(
|
|
2978
3042
|
rulesPath,
|
|
2979
3043
|
"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"
|
|
2980
3044
|
);
|
|
2981
3045
|
}
|
|
2982
3046
|
const indexesPath = resolve4(this.projectDir, "firestore.indexes.json");
|
|
2983
3047
|
if (!existsSync5(indexesPath)) {
|
|
2984
|
-
|
|
3048
|
+
writeFileSync3(indexesPath, JSON.stringify({ indexes: [], fieldOverrides: [] }, null, 2) + "\n");
|
|
2985
3049
|
}
|
|
2986
3050
|
break;
|
|
2987
3051
|
}
|
|
@@ -2991,7 +3055,7 @@ var FirebaseSetup = class {
|
|
|
2991
3055
|
}
|
|
2992
3056
|
const storageRulesPath = resolve4(this.projectDir, "storage.rules");
|
|
2993
3057
|
if (!existsSync5(storageRulesPath)) {
|
|
2994
|
-
|
|
3058
|
+
writeFileSync3(
|
|
2995
3059
|
storageRulesPath,
|
|
2996
3060
|
"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"
|
|
2997
3061
|
);
|
|
@@ -2999,7 +3063,7 @@ var FirebaseSetup = class {
|
|
|
2999
3063
|
break;
|
|
3000
3064
|
}
|
|
3001
3065
|
}
|
|
3002
|
-
|
|
3066
|
+
writeFileSync3(firebaseJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3003
3067
|
return { success: true, message: `${service} enabled in firebase.json.` };
|
|
3004
3068
|
}
|
|
3005
3069
|
// ─── Firestore Database Automation ──────────────────────────────────
|
|
@@ -3119,41 +3183,48 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3119
3183
|
* Handles "ALREADY_EXISTS" gracefully — returns success.
|
|
3120
3184
|
*/
|
|
3121
3185
|
async createFirestoreDatabase(location = "nam5") {
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
)
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3132
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3133
|
-
}
|
|
3134
|
-
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3135
|
-
const enableResult = await this.enableFirestoreApi();
|
|
3136
|
-
if (!enableResult.success) {
|
|
3137
|
-
return enableResult;
|
|
3186
|
+
const dbArgs = ["firestore:databases:create", "(default)", "--location", location, "--json"];
|
|
3187
|
+
const tryCreate = async () => {
|
|
3188
|
+
try {
|
|
3189
|
+
await this.execTimeout("firebase", dbArgs, 6e4);
|
|
3190
|
+
return { ok: true, alreadyExists: false, needsApi: false, msg: "" };
|
|
3191
|
+
} catch (err) {
|
|
3192
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3193
|
+
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3194
|
+
return { ok: true, alreadyExists: true, needsApi: false, msg };
|
|
3138
3195
|
}
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
await this.execTimeout(
|
|
3142
|
-
"firebase",
|
|
3143
|
-
["firestore:databases:create", "(default)", "--location", location, "--json"],
|
|
3144
|
-
6e4
|
|
3145
|
-
);
|
|
3146
|
-
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3147
|
-
} catch (retryErr) {
|
|
3148
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : "Unknown error";
|
|
3149
|
-
if (retryMsg.includes("ALREADY_EXISTS") || retryMsg.includes("already exists")) {
|
|
3150
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3151
|
-
}
|
|
3152
|
-
return { success: false, message: `Failed to create Firestore database after enabling API: ${retryMsg}` };
|
|
3196
|
+
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3197
|
+
return { ok: false, alreadyExists: false, needsApi: true, msg };
|
|
3153
3198
|
}
|
|
3199
|
+
return { ok: false, alreadyExists: false, needsApi: false, msg };
|
|
3200
|
+
}
|
|
3201
|
+
};
|
|
3202
|
+
const first = await tryCreate();
|
|
3203
|
+
if (first.ok) {
|
|
3204
|
+
return { success: true, message: first.alreadyExists ? "Firestore database already exists." : `Firestore database created (location: ${location}).` };
|
|
3205
|
+
}
|
|
3206
|
+
if (!first.needsApi) {
|
|
3207
|
+
return { success: false, message: `Failed to create Firestore database: ${first.msg}` };
|
|
3208
|
+
}
|
|
3209
|
+
const enableResult = await this.enableFirestoreApi();
|
|
3210
|
+
if (!enableResult.success) {
|
|
3211
|
+
return enableResult;
|
|
3212
|
+
}
|
|
3213
|
+
const waits = [5e3, 5e3, 1e4, 1e4, 15e3];
|
|
3214
|
+
for (let i = 0; i < waits.length; i++) {
|
|
3215
|
+
await new Promise((r) => setTimeout(r, waits[i]));
|
|
3216
|
+
const retry = await tryCreate();
|
|
3217
|
+
if (retry.ok) {
|
|
3218
|
+
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3219
|
+
}
|
|
3220
|
+
if (!retry.needsApi) {
|
|
3221
|
+
return { success: false, message: `Failed to create Firestore database: ${retry.msg}` };
|
|
3154
3222
|
}
|
|
3155
|
-
return { success: false, message: `Failed to create Firestore database: ${msg}` };
|
|
3156
3223
|
}
|
|
3224
|
+
return {
|
|
3225
|
+
success: false,
|
|
3226
|
+
message: "Firestore API was enabled but database creation timed out waiting for propagation. Please wait a minute and try again."
|
|
3227
|
+
};
|
|
3157
3228
|
}
|
|
3158
3229
|
/**
|
|
3159
3230
|
* Deploy open Firestore security rules for dev testing.
|
|
@@ -3163,7 +3234,7 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3163
3234
|
const rulesPath = resolve4(this.projectDir, "firestore.rules");
|
|
3164
3235
|
try {
|
|
3165
3236
|
if (openForDev) {
|
|
3166
|
-
|
|
3237
|
+
writeFileSync3(
|
|
3167
3238
|
rulesPath,
|
|
3168
3239
|
"rules_version = '2';\nservice cloud.firestore {\n match /databases/{database}/documents {\n match /{document=**} {\n allow read, write: if true;\n }\n }\n}\n"
|
|
3169
3240
|
);
|
|
@@ -3429,6 +3500,92 @@ function generateRouterScript() {
|
|
|
3429
3500
|
})();
|
|
3430
3501
|
</script>`;
|
|
3431
3502
|
}
|
|
3503
|
+
function generateProductionRouterScript() {
|
|
3504
|
+
return `
|
|
3505
|
+
<script data-clawfire-router>
|
|
3506
|
+
(function() {
|
|
3507
|
+
function updateActiveNav() {
|
|
3508
|
+
var path = location.pathname;
|
|
3509
|
+
var links = document.querySelectorAll('#nav-links a[href]');
|
|
3510
|
+
for (var i = 0; i < links.length; i++) {
|
|
3511
|
+
var href = links[i].getAttribute('href');
|
|
3512
|
+
if (!href || href.startsWith('http')) continue;
|
|
3513
|
+
var isActive = (path === '/' && href === '/') || (href !== '/' && path.startsWith(href));
|
|
3514
|
+
links[i].setAttribute('data-active', isActive ? 'true' : 'false');
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
function navigate(url) {
|
|
3519
|
+
var target = new URL(url, location.href);
|
|
3520
|
+
if (target.origin !== location.origin) return false;
|
|
3521
|
+
if (target.pathname === location.pathname && target.hash) return false;
|
|
3522
|
+
|
|
3523
|
+
fetch(target.pathname)
|
|
3524
|
+
.then(function(res) {
|
|
3525
|
+
if (!res.ok) throw new Error('Page not found');
|
|
3526
|
+
return res.text();
|
|
3527
|
+
})
|
|
3528
|
+
.then(function(html) {
|
|
3529
|
+
// Parse the fetched full HTML and extract #clawfire-page content
|
|
3530
|
+
var parser = new DOMParser();
|
|
3531
|
+
var doc = parser.parseFromString(html, 'text/html');
|
|
3532
|
+
var newPage = doc.getElementById('clawfire-page');
|
|
3533
|
+
if (!newPage) throw new Error('No #clawfire-page found');
|
|
3534
|
+
|
|
3535
|
+
var container = document.getElementById('clawfire-page');
|
|
3536
|
+
if (container) {
|
|
3537
|
+
container.innerHTML = newPage.innerHTML;
|
|
3538
|
+
// Execute scripts in new content
|
|
3539
|
+
var scripts = container.querySelectorAll('script');
|
|
3540
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
3541
|
+
var newScript = document.createElement('script');
|
|
3542
|
+
if (scripts[i].src) {
|
|
3543
|
+
newScript.src = scripts[i].src;
|
|
3544
|
+
} else {
|
|
3545
|
+
newScript.textContent = scripts[i].textContent;
|
|
3546
|
+
}
|
|
3547
|
+
scripts[i].parentNode.replaceChild(newScript, scripts[i]);
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
// Update title from fetched document
|
|
3551
|
+
var newTitle = doc.querySelector('title');
|
|
3552
|
+
if (newTitle) document.title = newTitle.textContent || '';
|
|
3553
|
+
// Update URL
|
|
3554
|
+
history.pushState(null, '', target.pathname);
|
|
3555
|
+
updateActiveNav();
|
|
3556
|
+
document.dispatchEvent(new CustomEvent('clawfire:navigate', { detail: { path: target.pathname } }));
|
|
3557
|
+
window.scrollTo(0, 0);
|
|
3558
|
+
})
|
|
3559
|
+
.catch(function() {
|
|
3560
|
+
// Fallback: full page navigation
|
|
3561
|
+
location.href = url;
|
|
3562
|
+
});
|
|
3563
|
+
|
|
3564
|
+
return true;
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
document.addEventListener('click', function(e) {
|
|
3568
|
+
var anchor = e.target.closest ? e.target.closest('a[href]') : null;
|
|
3569
|
+
if (!anchor) return;
|
|
3570
|
+
var href = anchor.getAttribute('href');
|
|
3571
|
+
if (!href) return;
|
|
3572
|
+
if (href.startsWith('http') || href.startsWith('//')) return;
|
|
3573
|
+
if (anchor.target === '_blank') return;
|
|
3574
|
+
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
|
|
3575
|
+
if (anchor.hasAttribute('download')) return;
|
|
3576
|
+
|
|
3577
|
+
e.preventDefault();
|
|
3578
|
+
navigate(href);
|
|
3579
|
+
});
|
|
3580
|
+
|
|
3581
|
+
window.addEventListener('popstate', function() {
|
|
3582
|
+
navigate(location.pathname);
|
|
3583
|
+
});
|
|
3584
|
+
|
|
3585
|
+
updateActiveNav();
|
|
3586
|
+
})();
|
|
3587
|
+
</script>`;
|
|
3588
|
+
}
|
|
3432
3589
|
var DevServer = class {
|
|
3433
3590
|
frontendServer = null;
|
|
3434
3591
|
apiServer = null;
|
|
@@ -4173,10 +4330,57 @@ ${liveReloadScript}
|
|
|
4173
4330
|
sendJson({ success: false, message: "projectId is required" }, 400);
|
|
4174
4331
|
return;
|
|
4175
4332
|
}
|
|
4176
|
-
|
|
4333
|
+
(async () => {
|
|
4334
|
+
const selectResult = await this.firebaseSetup.selectProject(data.projectId);
|
|
4335
|
+
if (!selectResult.success) {
|
|
4336
|
+
sendJson(selectResult);
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
const steps = [selectResult.message];
|
|
4340
|
+
try {
|
|
4341
|
+
const { apps } = await this.firebaseSetup.listWebApps();
|
|
4342
|
+
let webAppId = "";
|
|
4343
|
+
if (apps.length > 0) {
|
|
4344
|
+
webAppId = apps[0].appId;
|
|
4345
|
+
this.firebaseSetup.selectWebApp(apps[0].appId, apps[0].displayName);
|
|
4346
|
+
steps.push(`Web app "${apps[0].displayName}" selected.`);
|
|
4347
|
+
} else {
|
|
4348
|
+
const createResult = await this.firebaseSetup.createWebApp(data.projectId);
|
|
4349
|
+
if (createResult.success && createResult.appId) {
|
|
4350
|
+
webAppId = createResult.appId;
|
|
4351
|
+
steps.push(`Web app "${data.projectId}" created.`);
|
|
4352
|
+
} else {
|
|
4353
|
+
steps.push(`Web app creation skipped: ${createResult.message}`);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
if (webAppId) {
|
|
4357
|
+
try {
|
|
4358
|
+
const sdkConfig = await fetchFirebaseSdkConfig(this.options.projectDir, webAppId);
|
|
4359
|
+
const fields = {};
|
|
4360
|
+
for (const [key, value] of Object.entries(sdkConfig)) {
|
|
4361
|
+
if (value && typeof value === "string") {
|
|
4362
|
+
fields[key] = value;
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
if (Object.keys(fields).length > 0) {
|
|
4366
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
4367
|
+
try {
|
|
4368
|
+
this.updateProjectConfig(key, value);
|
|
4369
|
+
} catch {
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
steps.push("Config auto-filled in clawfire.config.ts.");
|
|
4373
|
+
}
|
|
4374
|
+
} catch (configErr) {
|
|
4375
|
+
steps.push(`Config auto-fill skipped: ${configErr instanceof Error ? configErr.message : "unknown error"}`);
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
} catch (autoFillErr) {
|
|
4379
|
+
steps.push(`Auto-setup partial: ${autoFillErr instanceof Error ? autoFillErr.message : "unknown error"}`);
|
|
4380
|
+
}
|
|
4177
4381
|
clearFirebaseStatusCache();
|
|
4178
|
-
sendJson(
|
|
4179
|
-
}).catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4382
|
+
sendJson({ success: true, message: steps.join(" "), steps });
|
|
4383
|
+
})().catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4180
4384
|
} catch {
|
|
4181
4385
|
sendJson({ success: false, message: "Invalid JSON body" }, 400);
|
|
4182
4386
|
}
|
|
@@ -4210,10 +4414,25 @@ ${liveReloadScript}
|
|
|
4210
4414
|
return;
|
|
4211
4415
|
}
|
|
4212
4416
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4417
|
+
(async () => {
|
|
4418
|
+
try {
|
|
4419
|
+
if (this.pageCompiler.isActive()) {
|
|
4420
|
+
const routerScript = generateProductionRouterScript();
|
|
4421
|
+
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, routerScript);
|
|
4422
|
+
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4423
|
+
if (buildResult.errors.length > 0) {
|
|
4424
|
+
for (const err of buildResult.errors) {
|
|
4425
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${err}`);
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
const result = await this.firebaseSetup.deployHosting();
|
|
4430
|
+
clearFirebaseStatusCache();
|
|
4431
|
+
sendJson(result);
|
|
4432
|
+
} catch (err) {
|
|
4433
|
+
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4434
|
+
}
|
|
4435
|
+
})();
|
|
4217
4436
|
return;
|
|
4218
4437
|
}
|
|
4219
4438
|
if (url.pathname === "/__dev/enable-service" && req.method === "POST") {
|
|
@@ -4360,7 +4579,7 @@ ${liveReloadScript}
|
|
|
4360
4579
|
throw new Error(`Key "${key}" not found in config`);
|
|
4361
4580
|
}
|
|
4362
4581
|
content = content.replace(pattern, `$1"${value.replace(/"/g, '\\"')}"`);
|
|
4363
|
-
|
|
4582
|
+
writeFileSync4(configPath, content, "utf-8");
|
|
4364
4583
|
}
|
|
4365
4584
|
escapeRegex(s) {
|
|
4366
4585
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|