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.cjs
CHANGED
|
@@ -1153,6 +1153,62 @@ var PageCompiler = class {
|
|
|
1153
1153
|
path: pathname
|
|
1154
1154
|
};
|
|
1155
1155
|
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Build all pages into static HTML for production deployment.
|
|
1158
|
+
* Walks app/pages/ recursively, compiles each page, and writes to outputDir.
|
|
1159
|
+
*
|
|
1160
|
+
* - Skips _layout.html (wrapper-only, not standalone)
|
|
1161
|
+
* - _404.html → 404.html (Firebase auto-serves for 404s)
|
|
1162
|
+
* - Injects optional script (e.g. production router) before </body>
|
|
1163
|
+
*/
|
|
1164
|
+
buildForProduction(outputDir, scriptToInject) {
|
|
1165
|
+
const pages = [];
|
|
1166
|
+
const errors = [];
|
|
1167
|
+
if (!this.isActive()) {
|
|
1168
|
+
return { pages, errors };
|
|
1169
|
+
}
|
|
1170
|
+
const walk = (dir) => {
|
|
1171
|
+
const entries = (0, import_node_fs.readdirSync)(dir);
|
|
1172
|
+
for (const entry of entries) {
|
|
1173
|
+
const fullPath = (0, import_node_path.join)(dir, entry);
|
|
1174
|
+
const stat = (0, import_node_fs.statSync)(fullPath);
|
|
1175
|
+
if (stat.isDirectory()) {
|
|
1176
|
+
walk(fullPath);
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
if (!entry.endsWith(".html")) continue;
|
|
1180
|
+
if (entry === "_layout.html") continue;
|
|
1181
|
+
try {
|
|
1182
|
+
const compiled = this.compile(fullPath);
|
|
1183
|
+
let html = compiled.html;
|
|
1184
|
+
if (scriptToInject) {
|
|
1185
|
+
if (html.includes("</body>")) {
|
|
1186
|
+
html = html.replace("</body>", scriptToInject + "\n</body>");
|
|
1187
|
+
} else {
|
|
1188
|
+
html += scriptToInject;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
const relPath = (0, import_node_path.relative)(this.pagesDir, fullPath);
|
|
1192
|
+
let outputPath;
|
|
1193
|
+
if (entry === "_404.html") {
|
|
1194
|
+
const parentRel = (0, import_node_path.relative)(this.pagesDir, dir);
|
|
1195
|
+
outputPath = parentRel ? (0, import_node_path.join)(outputDir, parentRel, "404.html") : (0, import_node_path.join)(outputDir, "404.html");
|
|
1196
|
+
} else {
|
|
1197
|
+
outputPath = (0, import_node_path.join)(outputDir, relPath);
|
|
1198
|
+
}
|
|
1199
|
+
const outputDirPath = (0, import_node_path.dirname)(outputPath);
|
|
1200
|
+
(0, import_node_fs.mkdirSync)(outputDirPath, { recursive: true });
|
|
1201
|
+
(0, import_node_fs.writeFileSync)(outputPath, html, "utf-8");
|
|
1202
|
+
pages.push(relPath);
|
|
1203
|
+
} catch (err) {
|
|
1204
|
+
const relPath = (0, import_node_path.relative)(this.pagesDir, fullPath);
|
|
1205
|
+
errors.push(`${relPath}: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
walk(this.pagesDir);
|
|
1210
|
+
return { pages, errors };
|
|
1211
|
+
}
|
|
1156
1212
|
// ─── Internal Methods ────────────────────────────────────────────
|
|
1157
1213
|
/**
|
|
1158
1214
|
* Extract <!-- @key: value --> metadata from HTML.
|
|
@@ -2268,8 +2324,9 @@ function generateDashboardHtml(options) {
|
|
|
2268
2324
|
}
|
|
2269
2325
|
|
|
2270
2326
|
btn.disabled = true;
|
|
2271
|
-
btn.textContent = 'Setting...';
|
|
2272
|
-
status.
|
|
2327
|
+
btn.textContent = 'Setting up...';
|
|
2328
|
+
status.textContent = 'Selecting project, detecting web app, auto-filling config...';
|
|
2329
|
+
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;';
|
|
2273
2330
|
|
|
2274
2331
|
fetch(API + '/__dev/setup/select-project', {
|
|
2275
2332
|
method: 'POST',
|
|
@@ -2279,8 +2336,11 @@ function generateDashboardHtml(options) {
|
|
|
2279
2336
|
.then(function(r) { return r.json(); })
|
|
2280
2337
|
.then(function(data) {
|
|
2281
2338
|
if (data.success) {
|
|
2282
|
-
|
|
2283
|
-
status.
|
|
2339
|
+
var msg = data.steps ? data.steps.join('\\n') : data.message;
|
|
2340
|
+
status.textContent = msg;
|
|
2341
|
+
status.style.whiteSpace = 'pre-line';
|
|
2342
|
+
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;';
|
|
2343
|
+
btn.textContent = 'Done';
|
|
2284
2344
|
setTimeout(refreshSetupStatus, 1000);
|
|
2285
2345
|
} else {
|
|
2286
2346
|
status.textContent = data.message;
|
|
@@ -3372,7 +3432,11 @@ var FirebaseSetup = class {
|
|
|
3372
3432
|
config.hosting = {
|
|
3373
3433
|
public: "public",
|
|
3374
3434
|
ignore: ["firebase.json", "**/.*", "**/node_modules/**"],
|
|
3375
|
-
|
|
3435
|
+
cleanUrls: true,
|
|
3436
|
+
rewrites: [
|
|
3437
|
+
{ source: "/api/**", function: "api" },
|
|
3438
|
+
{ source: "**", destination: "/index.html" }
|
|
3439
|
+
]
|
|
3376
3440
|
};
|
|
3377
3441
|
}
|
|
3378
3442
|
break;
|
|
@@ -3531,41 +3595,48 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3531
3595
|
* Handles "ALREADY_EXISTS" gracefully — returns success.
|
|
3532
3596
|
*/
|
|
3533
3597
|
async createFirestoreDatabase(location = "nam5") {
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
)
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3544
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3545
|
-
}
|
|
3546
|
-
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3547
|
-
const enableResult = await this.enableFirestoreApi();
|
|
3548
|
-
if (!enableResult.success) {
|
|
3549
|
-
return enableResult;
|
|
3598
|
+
const dbArgs = ["firestore:databases:create", "(default)", "--location", location, "--json"];
|
|
3599
|
+
const tryCreate = async () => {
|
|
3600
|
+
try {
|
|
3601
|
+
await this.execTimeout("firebase", dbArgs, 6e4);
|
|
3602
|
+
return { ok: true, alreadyExists: false, needsApi: false, msg: "" };
|
|
3603
|
+
} catch (err) {
|
|
3604
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3605
|
+
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3606
|
+
return { ok: true, alreadyExists: true, needsApi: false, msg };
|
|
3550
3607
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
await this.execTimeout(
|
|
3554
|
-
"firebase",
|
|
3555
|
-
["firestore:databases:create", "(default)", "--location", location, "--json"],
|
|
3556
|
-
6e4
|
|
3557
|
-
);
|
|
3558
|
-
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3559
|
-
} catch (retryErr) {
|
|
3560
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : "Unknown error";
|
|
3561
|
-
if (retryMsg.includes("ALREADY_EXISTS") || retryMsg.includes("already exists")) {
|
|
3562
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3563
|
-
}
|
|
3564
|
-
return { success: false, message: `Failed to create Firestore database after enabling API: ${retryMsg}` };
|
|
3608
|
+
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3609
|
+
return { ok: false, alreadyExists: false, needsApi: true, msg };
|
|
3565
3610
|
}
|
|
3611
|
+
return { ok: false, alreadyExists: false, needsApi: false, msg };
|
|
3612
|
+
}
|
|
3613
|
+
};
|
|
3614
|
+
const first = await tryCreate();
|
|
3615
|
+
if (first.ok) {
|
|
3616
|
+
return { success: true, message: first.alreadyExists ? "Firestore database already exists." : `Firestore database created (location: ${location}).` };
|
|
3617
|
+
}
|
|
3618
|
+
if (!first.needsApi) {
|
|
3619
|
+
return { success: false, message: `Failed to create Firestore database: ${first.msg}` };
|
|
3620
|
+
}
|
|
3621
|
+
const enableResult = await this.enableFirestoreApi();
|
|
3622
|
+
if (!enableResult.success) {
|
|
3623
|
+
return enableResult;
|
|
3624
|
+
}
|
|
3625
|
+
const waits = [5e3, 5e3, 1e4, 1e4, 15e3];
|
|
3626
|
+
for (let i = 0; i < waits.length; i++) {
|
|
3627
|
+
await new Promise((r) => setTimeout(r, waits[i]));
|
|
3628
|
+
const retry = await tryCreate();
|
|
3629
|
+
if (retry.ok) {
|
|
3630
|
+
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3631
|
+
}
|
|
3632
|
+
if (!retry.needsApi) {
|
|
3633
|
+
return { success: false, message: `Failed to create Firestore database: ${retry.msg}` };
|
|
3566
3634
|
}
|
|
3567
|
-
return { success: false, message: `Failed to create Firestore database: ${msg}` };
|
|
3568
3635
|
}
|
|
3636
|
+
return {
|
|
3637
|
+
success: false,
|
|
3638
|
+
message: "Firestore API was enabled but database creation timed out waiting for propagation. Please wait a minute and try again."
|
|
3639
|
+
};
|
|
3569
3640
|
}
|
|
3570
3641
|
/**
|
|
3571
3642
|
* Deploy open Firestore security rules for dev testing.
|
|
@@ -3841,6 +3912,92 @@ function generateRouterScript() {
|
|
|
3841
3912
|
})();
|
|
3842
3913
|
</script>`;
|
|
3843
3914
|
}
|
|
3915
|
+
function generateProductionRouterScript() {
|
|
3916
|
+
return `
|
|
3917
|
+
<script data-clawfire-router>
|
|
3918
|
+
(function() {
|
|
3919
|
+
function updateActiveNav() {
|
|
3920
|
+
var path = location.pathname;
|
|
3921
|
+
var links = document.querySelectorAll('#nav-links a[href]');
|
|
3922
|
+
for (var i = 0; i < links.length; i++) {
|
|
3923
|
+
var href = links[i].getAttribute('href');
|
|
3924
|
+
if (!href || href.startsWith('http')) continue;
|
|
3925
|
+
var isActive = (path === '/' && href === '/') || (href !== '/' && path.startsWith(href));
|
|
3926
|
+
links[i].setAttribute('data-active', isActive ? 'true' : 'false');
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
function navigate(url) {
|
|
3931
|
+
var target = new URL(url, location.href);
|
|
3932
|
+
if (target.origin !== location.origin) return false;
|
|
3933
|
+
if (target.pathname === location.pathname && target.hash) return false;
|
|
3934
|
+
|
|
3935
|
+
fetch(target.pathname)
|
|
3936
|
+
.then(function(res) {
|
|
3937
|
+
if (!res.ok) throw new Error('Page not found');
|
|
3938
|
+
return res.text();
|
|
3939
|
+
})
|
|
3940
|
+
.then(function(html) {
|
|
3941
|
+
// Parse the fetched full HTML and extract #clawfire-page content
|
|
3942
|
+
var parser = new DOMParser();
|
|
3943
|
+
var doc = parser.parseFromString(html, 'text/html');
|
|
3944
|
+
var newPage = doc.getElementById('clawfire-page');
|
|
3945
|
+
if (!newPage) throw new Error('No #clawfire-page found');
|
|
3946
|
+
|
|
3947
|
+
var container = document.getElementById('clawfire-page');
|
|
3948
|
+
if (container) {
|
|
3949
|
+
container.innerHTML = newPage.innerHTML;
|
|
3950
|
+
// Execute scripts in new content
|
|
3951
|
+
var scripts = container.querySelectorAll('script');
|
|
3952
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
3953
|
+
var newScript = document.createElement('script');
|
|
3954
|
+
if (scripts[i].src) {
|
|
3955
|
+
newScript.src = scripts[i].src;
|
|
3956
|
+
} else {
|
|
3957
|
+
newScript.textContent = scripts[i].textContent;
|
|
3958
|
+
}
|
|
3959
|
+
scripts[i].parentNode.replaceChild(newScript, scripts[i]);
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
// Update title from fetched document
|
|
3963
|
+
var newTitle = doc.querySelector('title');
|
|
3964
|
+
if (newTitle) document.title = newTitle.textContent || '';
|
|
3965
|
+
// Update URL
|
|
3966
|
+
history.pushState(null, '', target.pathname);
|
|
3967
|
+
updateActiveNav();
|
|
3968
|
+
document.dispatchEvent(new CustomEvent('clawfire:navigate', { detail: { path: target.pathname } }));
|
|
3969
|
+
window.scrollTo(0, 0);
|
|
3970
|
+
})
|
|
3971
|
+
.catch(function() {
|
|
3972
|
+
// Fallback: full page navigation
|
|
3973
|
+
location.href = url;
|
|
3974
|
+
});
|
|
3975
|
+
|
|
3976
|
+
return true;
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
document.addEventListener('click', function(e) {
|
|
3980
|
+
var anchor = e.target.closest ? e.target.closest('a[href]') : null;
|
|
3981
|
+
if (!anchor) return;
|
|
3982
|
+
var href = anchor.getAttribute('href');
|
|
3983
|
+
if (!href) return;
|
|
3984
|
+
if (href.startsWith('http') || href.startsWith('//')) return;
|
|
3985
|
+
if (anchor.target === '_blank') return;
|
|
3986
|
+
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
|
|
3987
|
+
if (anchor.hasAttribute('download')) return;
|
|
3988
|
+
|
|
3989
|
+
e.preventDefault();
|
|
3990
|
+
navigate(href);
|
|
3991
|
+
});
|
|
3992
|
+
|
|
3993
|
+
window.addEventListener('popstate', function() {
|
|
3994
|
+
navigate(location.pathname);
|
|
3995
|
+
});
|
|
3996
|
+
|
|
3997
|
+
updateActiveNav();
|
|
3998
|
+
})();
|
|
3999
|
+
</script>`;
|
|
4000
|
+
}
|
|
3844
4001
|
var DevServer = class {
|
|
3845
4002
|
frontendServer = null;
|
|
3846
4003
|
apiServer = null;
|
|
@@ -4585,10 +4742,57 @@ ${liveReloadScript}
|
|
|
4585
4742
|
sendJson({ success: false, message: "projectId is required" }, 400);
|
|
4586
4743
|
return;
|
|
4587
4744
|
}
|
|
4588
|
-
|
|
4745
|
+
(async () => {
|
|
4746
|
+
const selectResult = await this.firebaseSetup.selectProject(data.projectId);
|
|
4747
|
+
if (!selectResult.success) {
|
|
4748
|
+
sendJson(selectResult);
|
|
4749
|
+
return;
|
|
4750
|
+
}
|
|
4751
|
+
const steps = [selectResult.message];
|
|
4752
|
+
try {
|
|
4753
|
+
const { apps } = await this.firebaseSetup.listWebApps();
|
|
4754
|
+
let webAppId = "";
|
|
4755
|
+
if (apps.length > 0) {
|
|
4756
|
+
webAppId = apps[0].appId;
|
|
4757
|
+
this.firebaseSetup.selectWebApp(apps[0].appId, apps[0].displayName);
|
|
4758
|
+
steps.push(`Web app "${apps[0].displayName}" selected.`);
|
|
4759
|
+
} else {
|
|
4760
|
+
const createResult = await this.firebaseSetup.createWebApp(data.projectId);
|
|
4761
|
+
if (createResult.success && createResult.appId) {
|
|
4762
|
+
webAppId = createResult.appId;
|
|
4763
|
+
steps.push(`Web app "${data.projectId}" created.`);
|
|
4764
|
+
} else {
|
|
4765
|
+
steps.push(`Web app creation skipped: ${createResult.message}`);
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
if (webAppId) {
|
|
4769
|
+
try {
|
|
4770
|
+
const sdkConfig = await fetchFirebaseSdkConfig(this.options.projectDir, webAppId);
|
|
4771
|
+
const fields = {};
|
|
4772
|
+
for (const [key, value] of Object.entries(sdkConfig)) {
|
|
4773
|
+
if (value && typeof value === "string") {
|
|
4774
|
+
fields[key] = value;
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
if (Object.keys(fields).length > 0) {
|
|
4778
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
4779
|
+
try {
|
|
4780
|
+
this.updateProjectConfig(key, value);
|
|
4781
|
+
} catch {
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
steps.push("Config auto-filled in clawfire.config.ts.");
|
|
4785
|
+
}
|
|
4786
|
+
} catch (configErr) {
|
|
4787
|
+
steps.push(`Config auto-fill skipped: ${configErr instanceof Error ? configErr.message : "unknown error"}`);
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
} catch (autoFillErr) {
|
|
4791
|
+
steps.push(`Auto-setup partial: ${autoFillErr instanceof Error ? autoFillErr.message : "unknown error"}`);
|
|
4792
|
+
}
|
|
4589
4793
|
clearFirebaseStatusCache();
|
|
4590
|
-
sendJson(
|
|
4591
|
-
}).catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4794
|
+
sendJson({ success: true, message: steps.join(" "), steps });
|
|
4795
|
+
})().catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4592
4796
|
} catch {
|
|
4593
4797
|
sendJson({ success: false, message: "Invalid JSON body" }, 400);
|
|
4594
4798
|
}
|
|
@@ -4622,10 +4826,25 @@ ${liveReloadScript}
|
|
|
4622
4826
|
return;
|
|
4623
4827
|
}
|
|
4624
4828
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4829
|
+
(async () => {
|
|
4830
|
+
try {
|
|
4831
|
+
if (this.pageCompiler.isActive()) {
|
|
4832
|
+
const routerScript = generateProductionRouterScript();
|
|
4833
|
+
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, routerScript);
|
|
4834
|
+
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4835
|
+
if (buildResult.errors.length > 0) {
|
|
4836
|
+
for (const err of buildResult.errors) {
|
|
4837
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${err}`);
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
const result = await this.firebaseSetup.deployHosting();
|
|
4842
|
+
clearFirebaseStatusCache();
|
|
4843
|
+
sendJson(result);
|
|
4844
|
+
} catch (err) {
|
|
4845
|
+
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4846
|
+
}
|
|
4847
|
+
})();
|
|
4629
4848
|
return;
|
|
4630
4849
|
}
|
|
4631
4850
|
if (url.pathname === "/__dev/enable-service" && req.method === "POST") {
|