clawfire 0.4.2 → 0.4.4
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-65H4AQFS.js → dev-server-XLMLGSQP.js} +119 -34
- package/dist/dev.cjs +119 -34
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +119 -34
- package/dist/dev.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -209,7 +209,7 @@ async function runDevServer() {
|
|
|
209
209
|
const port = portArg ? parseInt(portArg.split("=")[1], 10) : 3e3;
|
|
210
210
|
const apiPort = apiPortArg ? parseInt(apiPortArg.split("=")[1], 10) : 3456;
|
|
211
211
|
const noHotReload = args.includes("--no-hot-reload");
|
|
212
|
-
const { startDevServer } = await import("./dev-server-
|
|
212
|
+
const { startDevServer } = await import("./dev-server-XLMLGSQP.js");
|
|
213
213
|
await startDevServer({
|
|
214
214
|
projectDir,
|
|
215
215
|
port,
|
|
@@ -1083,38 +1083,89 @@ async function checkCli(projectDir) {
|
|
|
1083
1083
|
return result;
|
|
1084
1084
|
}
|
|
1085
1085
|
async function fetchFirebaseSdkConfig(projectDir) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
return
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1086
|
+
try {
|
|
1087
|
+
const output = await execWithTimeout(
|
|
1088
|
+
"firebase",
|
|
1089
|
+
["apps:sdkconfig", "web", "--json"],
|
|
1090
|
+
projectDir,
|
|
1091
|
+
15e3
|
|
1092
|
+
);
|
|
1093
|
+
const config = parseSdkConfigOutput(output);
|
|
1094
|
+
if (config) return config;
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
1097
|
+
let webApps = [];
|
|
1098
|
+
try {
|
|
1099
|
+
const appsOutput = await execWithTimeout(
|
|
1100
|
+
"firebase",
|
|
1101
|
+
["apps:list", "--json"],
|
|
1102
|
+
projectDir,
|
|
1103
|
+
15e3
|
|
1104
|
+
);
|
|
1105
|
+
const appsData = JSON.parse(appsOutput);
|
|
1106
|
+
const allApps = appsData?.result || [];
|
|
1107
|
+
webApps = allApps.filter((a) => a.platform === "WEB").map((a) => ({
|
|
1108
|
+
appId: String(a.appId || ""),
|
|
1109
|
+
displayName: String(a.displayName || "")
|
|
1110
|
+
})).filter((a) => a.appId);
|
|
1111
|
+
} catch {
|
|
1112
|
+
throw new Error(
|
|
1113
|
+
"Failed to fetch Firebase SDK config. Make sure you are logged in and have an active project selected."
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
if (webApps.length === 0) {
|
|
1117
|
+
throw new Error(
|
|
1118
|
+
"No web app registered in this Firebase project. Go to Firebase Console > Project Settings > General > Your apps > Add app (Web) to create one, then click Auto-fill again."
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
const appId = webApps[0].appId;
|
|
1122
|
+
try {
|
|
1123
|
+
const output = await execWithTimeout(
|
|
1124
|
+
"firebase",
|
|
1125
|
+
["apps:sdkconfig", "web", appId, "--json"],
|
|
1126
|
+
projectDir,
|
|
1127
|
+
15e3
|
|
1128
|
+
);
|
|
1129
|
+
const config = parseSdkConfigOutput(output);
|
|
1130
|
+
if (config) return config;
|
|
1131
|
+
} catch (err) {
|
|
1132
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
1133
|
+
throw new Error(`Failed to fetch config for web app ${appId}: ${msg}`);
|
|
1110
1134
|
}
|
|
1111
1135
|
throw new Error("Could not parse Firebase SDK config from CLI output");
|
|
1112
1136
|
}
|
|
1137
|
+
function parseSdkConfigOutput(output) {
|
|
1138
|
+
try {
|
|
1139
|
+
const data = JSON.parse(output);
|
|
1140
|
+
if (data?.result?.sdkConfig) {
|
|
1141
|
+
return data.result.sdkConfig;
|
|
1142
|
+
}
|
|
1143
|
+
if (data?.result?.fileContents) {
|
|
1144
|
+
const contents = data.result.fileContents;
|
|
1145
|
+
const config = {};
|
|
1146
|
+
const extract = (key) => {
|
|
1147
|
+
const match = contents.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
|
|
1148
|
+
return match ? match[1] : void 0;
|
|
1149
|
+
};
|
|
1150
|
+
config.apiKey = extract("apiKey");
|
|
1151
|
+
config.authDomain = extract("authDomain");
|
|
1152
|
+
config.projectId = extract("projectId");
|
|
1153
|
+
config.storageBucket = extract("storageBucket");
|
|
1154
|
+
config.messagingSenderId = extract("messagingSenderId");
|
|
1155
|
+
config.appId = extract("appId");
|
|
1156
|
+
if (config.apiKey || config.projectId) return config;
|
|
1157
|
+
}
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1113
1162
|
function execWithTimeout(command, args, cwd, timeoutMs) {
|
|
1114
1163
|
return new Promise((resolve6, reject) => {
|
|
1115
|
-
const proc = execFile(command, args, { cwd, timeout: timeoutMs }, (err, stdout) => {
|
|
1164
|
+
const proc = execFile(command, args, { cwd, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
1116
1165
|
if (err) {
|
|
1117
|
-
|
|
1166
|
+
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
1167
|
+
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
1168
|
+
reject(enriched);
|
|
1118
1169
|
} else {
|
|
1119
1170
|
resolve6(stdout);
|
|
1120
1171
|
}
|
|
@@ -1413,6 +1464,9 @@ function generateDashboardHtml(options) {
|
|
|
1413
1464
|
document.getElementById('step-' + i).style.display = 'none';
|
|
1414
1465
|
}
|
|
1415
1466
|
document.getElementById('setup-done').style.display = 'none';
|
|
1467
|
+
// Reset login UI state from previous interactions
|
|
1468
|
+
document.getElementById('login-waiting').style.display = 'none';
|
|
1469
|
+
document.getElementById('login-result').style.display = 'none';
|
|
1416
1470
|
|
|
1417
1471
|
if (status.nextStep === 'done') {
|
|
1418
1472
|
// All done!
|
|
@@ -1576,7 +1630,12 @@ function generateDashboardHtml(options) {
|
|
|
1576
1630
|
var result = document.getElementById('login-result');
|
|
1577
1631
|
result.textContent = 'Login successful! Logged in as ' + status.auth.user;
|
|
1578
1632
|
result.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#0a1a0a;border:1px solid #22c55e;color:#22c55e;';
|
|
1579
|
-
|
|
1633
|
+
// Wait for token to fully settle, then refresh wizard + force-load projects
|
|
1634
|
+
setTimeout(function() {
|
|
1635
|
+
refreshSetupStatus();
|
|
1636
|
+
// Extra delay for project list \u2014 Firebase CLI needs time after fresh login
|
|
1637
|
+
setTimeout(function() { loadProjectList(''); }, 2500);
|
|
1638
|
+
}, 2000);
|
|
1580
1639
|
}
|
|
1581
1640
|
})
|
|
1582
1641
|
.catch(function() {});
|
|
@@ -1584,7 +1643,8 @@ function generateDashboardHtml(options) {
|
|
|
1584
1643
|
}
|
|
1585
1644
|
|
|
1586
1645
|
// \u2500\u2500\u2500 Step 3: Project Selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1587
|
-
function loadProjectList(currentProjectId) {
|
|
1646
|
+
function loadProjectList(currentProjectId, retryCount) {
|
|
1647
|
+
retryCount = retryCount || 0;
|
|
1588
1648
|
var select = document.getElementById('project-select');
|
|
1589
1649
|
select.innerHTML = '<option value="">Loading projects...</option>';
|
|
1590
1650
|
select.disabled = true;
|
|
@@ -1594,10 +1654,21 @@ function generateDashboardHtml(options) {
|
|
|
1594
1654
|
.then(function(data) {
|
|
1595
1655
|
select.innerHTML = '';
|
|
1596
1656
|
if (data.error) {
|
|
1657
|
+
// Auto-retry up to 2 times on error (token might not be ready yet after fresh login)
|
|
1658
|
+
if (retryCount < 2) {
|
|
1659
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
1660
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1597
1663
|
select.innerHTML = '<option value="">Error: ' + escHtml(data.error) + '</option>';
|
|
1598
1664
|
return;
|
|
1599
1665
|
}
|
|
1600
1666
|
if (!data.projects || data.projects.length === 0) {
|
|
1667
|
+
if (retryCount < 2) {
|
|
1668
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
1669
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1601
1672
|
select.innerHTML = '<option value="">No projects found</option>';
|
|
1602
1673
|
return;
|
|
1603
1674
|
}
|
|
@@ -1613,6 +1684,11 @@ function generateDashboardHtml(options) {
|
|
|
1613
1684
|
select.disabled = false;
|
|
1614
1685
|
})
|
|
1615
1686
|
.catch(function(err) {
|
|
1687
|
+
if (retryCount < 2) {
|
|
1688
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
1689
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1616
1692
|
select.innerHTML = '<option value="">Failed to load</option>';
|
|
1617
1693
|
});
|
|
1618
1694
|
}
|
|
@@ -1838,7 +1914,12 @@ function generateDashboardHtml(options) {
|
|
|
1838
1914
|
if (wizStatus) wizStatus.style.display = 'none';
|
|
1839
1915
|
|
|
1840
1916
|
fetch(API + '/__dev/firebase-sdk-config')
|
|
1841
|
-
.then(function(r) {
|
|
1917
|
+
.then(function(r) {
|
|
1918
|
+
if (!r.ok) {
|
|
1919
|
+
return r.json().catch(function() { return { error: 'Server error (' + r.status + ')' }; });
|
|
1920
|
+
}
|
|
1921
|
+
return r.json();
|
|
1922
|
+
})
|
|
1842
1923
|
.then(function(data) {
|
|
1843
1924
|
if (data.error) {
|
|
1844
1925
|
showAutoFillResult(false, data.error);
|
|
@@ -2154,13 +2235,16 @@ var FirebaseSetup = class {
|
|
|
2154
2235
|
`cd "${this.projectDir}"`,
|
|
2155
2236
|
cmd,
|
|
2156
2237
|
'echo ""',
|
|
2157
|
-
'echo "Login complete!
|
|
2158
|
-
|
|
2238
|
+
'echo "Login complete! Closing in 3 seconds..."',
|
|
2239
|
+
"sleep 3",
|
|
2240
|
+
// Spawn osascript in background to close this specific terminal window, then exit
|
|
2241
|
+
`(sleep 1 && osascript -e 'tell application "Terminal" to close (every window whose name contains "clawfire-firebase-login")' 2>/dev/null) &`,
|
|
2242
|
+
"exit 0"
|
|
2159
2243
|
].join("\n"), { mode: 493 });
|
|
2160
2244
|
const child = spawn("open", [scriptPath], { detached: true, stdio: "ignore" });
|
|
2161
2245
|
child.unref();
|
|
2162
2246
|
} else if (os === "win32") {
|
|
2163
|
-
const child = spawn("cmd", ["/c", "start", "cmd", "/
|
|
2247
|
+
const child = spawn("cmd", ["/c", "start", "cmd", "/c", `${cmd} && timeout /t 3 >nul`], {
|
|
2164
2248
|
cwd: this.projectDir,
|
|
2165
2249
|
detached: true,
|
|
2166
2250
|
stdio: "ignore"
|
|
@@ -2173,8 +2257,9 @@ var FirebaseSetup = class {
|
|
|
2173
2257
|
`cd "${this.projectDir}"`,
|
|
2174
2258
|
cmd,
|
|
2175
2259
|
'echo ""',
|
|
2176
|
-
'echo "Login complete!
|
|
2177
|
-
|
|
2260
|
+
'echo "Login complete! Closing in 3 seconds..."',
|
|
2261
|
+
"sleep 3",
|
|
2262
|
+
"exit 0"
|
|
2178
2263
|
].join("\n"), { mode: 493 });
|
|
2179
2264
|
const terminals = [
|
|
2180
2265
|
{ cmd: "x-terminal-emulator", args: ["-e", scriptPath] },
|
package/dist/dev.cjs
CHANGED
|
@@ -1495,38 +1495,89 @@ async function checkCli(projectDir) {
|
|
|
1495
1495
|
return result;
|
|
1496
1496
|
}
|
|
1497
1497
|
async function fetchFirebaseSdkConfig(projectDir) {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
return
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1498
|
+
try {
|
|
1499
|
+
const output = await execWithTimeout(
|
|
1500
|
+
"firebase",
|
|
1501
|
+
["apps:sdkconfig", "web", "--json"],
|
|
1502
|
+
projectDir,
|
|
1503
|
+
15e3
|
|
1504
|
+
);
|
|
1505
|
+
const config = parseSdkConfigOutput(output);
|
|
1506
|
+
if (config) return config;
|
|
1507
|
+
} catch {
|
|
1508
|
+
}
|
|
1509
|
+
let webApps = [];
|
|
1510
|
+
try {
|
|
1511
|
+
const appsOutput = await execWithTimeout(
|
|
1512
|
+
"firebase",
|
|
1513
|
+
["apps:list", "--json"],
|
|
1514
|
+
projectDir,
|
|
1515
|
+
15e3
|
|
1516
|
+
);
|
|
1517
|
+
const appsData = JSON.parse(appsOutput);
|
|
1518
|
+
const allApps = appsData?.result || [];
|
|
1519
|
+
webApps = allApps.filter((a) => a.platform === "WEB").map((a) => ({
|
|
1520
|
+
appId: String(a.appId || ""),
|
|
1521
|
+
displayName: String(a.displayName || "")
|
|
1522
|
+
})).filter((a) => a.appId);
|
|
1523
|
+
} catch {
|
|
1524
|
+
throw new Error(
|
|
1525
|
+
"Failed to fetch Firebase SDK config. Make sure you are logged in and have an active project selected."
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
if (webApps.length === 0) {
|
|
1529
|
+
throw new Error(
|
|
1530
|
+
"No web app registered in this Firebase project. Go to Firebase Console > Project Settings > General > Your apps > Add app (Web) to create one, then click Auto-fill again."
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
const appId = webApps[0].appId;
|
|
1534
|
+
try {
|
|
1535
|
+
const output = await execWithTimeout(
|
|
1536
|
+
"firebase",
|
|
1537
|
+
["apps:sdkconfig", "web", appId, "--json"],
|
|
1538
|
+
projectDir,
|
|
1539
|
+
15e3
|
|
1540
|
+
);
|
|
1541
|
+
const config = parseSdkConfigOutput(output);
|
|
1542
|
+
if (config) return config;
|
|
1543
|
+
} catch (err) {
|
|
1544
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
1545
|
+
throw new Error(`Failed to fetch config for web app ${appId}: ${msg}`);
|
|
1522
1546
|
}
|
|
1523
1547
|
throw new Error("Could not parse Firebase SDK config from CLI output");
|
|
1524
1548
|
}
|
|
1549
|
+
function parseSdkConfigOutput(output) {
|
|
1550
|
+
try {
|
|
1551
|
+
const data = JSON.parse(output);
|
|
1552
|
+
if (data?.result?.sdkConfig) {
|
|
1553
|
+
return data.result.sdkConfig;
|
|
1554
|
+
}
|
|
1555
|
+
if (data?.result?.fileContents) {
|
|
1556
|
+
const contents = data.result.fileContents;
|
|
1557
|
+
const config = {};
|
|
1558
|
+
const extract = (key) => {
|
|
1559
|
+
const match = contents.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
|
|
1560
|
+
return match ? match[1] : void 0;
|
|
1561
|
+
};
|
|
1562
|
+
config.apiKey = extract("apiKey");
|
|
1563
|
+
config.authDomain = extract("authDomain");
|
|
1564
|
+
config.projectId = extract("projectId");
|
|
1565
|
+
config.storageBucket = extract("storageBucket");
|
|
1566
|
+
config.messagingSenderId = extract("messagingSenderId");
|
|
1567
|
+
config.appId = extract("appId");
|
|
1568
|
+
if (config.apiKey || config.projectId) return config;
|
|
1569
|
+
}
|
|
1570
|
+
} catch {
|
|
1571
|
+
}
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1525
1574
|
function execWithTimeout(command, args, cwd, timeoutMs) {
|
|
1526
1575
|
return new Promise((resolve7, reject) => {
|
|
1527
|
-
const proc = (0, import_node_child_process.execFile)(command, args, { cwd, timeout: timeoutMs }, (err, stdout) => {
|
|
1576
|
+
const proc = (0, import_node_child_process.execFile)(command, args, { cwd, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
1528
1577
|
if (err) {
|
|
1529
|
-
|
|
1578
|
+
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
1579
|
+
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
1580
|
+
reject(enriched);
|
|
1530
1581
|
} else {
|
|
1531
1582
|
resolve7(stdout);
|
|
1532
1583
|
}
|
|
@@ -1825,6 +1876,9 @@ function generateDashboardHtml(options) {
|
|
|
1825
1876
|
document.getElementById('step-' + i).style.display = 'none';
|
|
1826
1877
|
}
|
|
1827
1878
|
document.getElementById('setup-done').style.display = 'none';
|
|
1879
|
+
// Reset login UI state from previous interactions
|
|
1880
|
+
document.getElementById('login-waiting').style.display = 'none';
|
|
1881
|
+
document.getElementById('login-result').style.display = 'none';
|
|
1828
1882
|
|
|
1829
1883
|
if (status.nextStep === 'done') {
|
|
1830
1884
|
// All done!
|
|
@@ -1988,7 +2042,12 @@ function generateDashboardHtml(options) {
|
|
|
1988
2042
|
var result = document.getElementById('login-result');
|
|
1989
2043
|
result.textContent = 'Login successful! Logged in as ' + status.auth.user;
|
|
1990
2044
|
result.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#0a1a0a;border:1px solid #22c55e;color:#22c55e;';
|
|
1991
|
-
|
|
2045
|
+
// Wait for token to fully settle, then refresh wizard + force-load projects
|
|
2046
|
+
setTimeout(function() {
|
|
2047
|
+
refreshSetupStatus();
|
|
2048
|
+
// Extra delay for project list \u2014 Firebase CLI needs time after fresh login
|
|
2049
|
+
setTimeout(function() { loadProjectList(''); }, 2500);
|
|
2050
|
+
}, 2000);
|
|
1992
2051
|
}
|
|
1993
2052
|
})
|
|
1994
2053
|
.catch(function() {});
|
|
@@ -1996,7 +2055,8 @@ function generateDashboardHtml(options) {
|
|
|
1996
2055
|
}
|
|
1997
2056
|
|
|
1998
2057
|
// \u2500\u2500\u2500 Step 3: Project Selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1999
|
-
function loadProjectList(currentProjectId) {
|
|
2058
|
+
function loadProjectList(currentProjectId, retryCount) {
|
|
2059
|
+
retryCount = retryCount || 0;
|
|
2000
2060
|
var select = document.getElementById('project-select');
|
|
2001
2061
|
select.innerHTML = '<option value="">Loading projects...</option>';
|
|
2002
2062
|
select.disabled = true;
|
|
@@ -2006,10 +2066,21 @@ function generateDashboardHtml(options) {
|
|
|
2006
2066
|
.then(function(data) {
|
|
2007
2067
|
select.innerHTML = '';
|
|
2008
2068
|
if (data.error) {
|
|
2069
|
+
// Auto-retry up to 2 times on error (token might not be ready yet after fresh login)
|
|
2070
|
+
if (retryCount < 2) {
|
|
2071
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
2072
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2009
2075
|
select.innerHTML = '<option value="">Error: ' + escHtml(data.error) + '</option>';
|
|
2010
2076
|
return;
|
|
2011
2077
|
}
|
|
2012
2078
|
if (!data.projects || data.projects.length === 0) {
|
|
2079
|
+
if (retryCount < 2) {
|
|
2080
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
2081
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2013
2084
|
select.innerHTML = '<option value="">No projects found</option>';
|
|
2014
2085
|
return;
|
|
2015
2086
|
}
|
|
@@ -2025,6 +2096,11 @@ function generateDashboardHtml(options) {
|
|
|
2025
2096
|
select.disabled = false;
|
|
2026
2097
|
})
|
|
2027
2098
|
.catch(function(err) {
|
|
2099
|
+
if (retryCount < 2) {
|
|
2100
|
+
select.innerHTML = '<option value="">Loading projects... (retry)</option>';
|
|
2101
|
+
setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2028
2104
|
select.innerHTML = '<option value="">Failed to load</option>';
|
|
2029
2105
|
});
|
|
2030
2106
|
}
|
|
@@ -2250,7 +2326,12 @@ function generateDashboardHtml(options) {
|
|
|
2250
2326
|
if (wizStatus) wizStatus.style.display = 'none';
|
|
2251
2327
|
|
|
2252
2328
|
fetch(API + '/__dev/firebase-sdk-config')
|
|
2253
|
-
.then(function(r) {
|
|
2329
|
+
.then(function(r) {
|
|
2330
|
+
if (!r.ok) {
|
|
2331
|
+
return r.json().catch(function() { return { error: 'Server error (' + r.status + ')' }; });
|
|
2332
|
+
}
|
|
2333
|
+
return r.json();
|
|
2334
|
+
})
|
|
2254
2335
|
.then(function(data) {
|
|
2255
2336
|
if (data.error) {
|
|
2256
2337
|
showAutoFillResult(false, data.error);
|
|
@@ -2566,13 +2647,16 @@ var FirebaseSetup = class {
|
|
|
2566
2647
|
`cd "${this.projectDir}"`,
|
|
2567
2648
|
cmd,
|
|
2568
2649
|
'echo ""',
|
|
2569
|
-
'echo "Login complete!
|
|
2570
|
-
|
|
2650
|
+
'echo "Login complete! Closing in 3 seconds..."',
|
|
2651
|
+
"sleep 3",
|
|
2652
|
+
// Spawn osascript in background to close this specific terminal window, then exit
|
|
2653
|
+
`(sleep 1 && osascript -e 'tell application "Terminal" to close (every window whose name contains "clawfire-firebase-login")' 2>/dev/null) &`,
|
|
2654
|
+
"exit 0"
|
|
2571
2655
|
].join("\n"), { mode: 493 });
|
|
2572
2656
|
const child = (0, import_node_child_process2.spawn)("open", [scriptPath], { detached: true, stdio: "ignore" });
|
|
2573
2657
|
child.unref();
|
|
2574
2658
|
} else if (os === "win32") {
|
|
2575
|
-
const child = (0, import_node_child_process2.spawn)("cmd", ["/c", "start", "cmd", "/
|
|
2659
|
+
const child = (0, import_node_child_process2.spawn)("cmd", ["/c", "start", "cmd", "/c", `${cmd} && timeout /t 3 >nul`], {
|
|
2576
2660
|
cwd: this.projectDir,
|
|
2577
2661
|
detached: true,
|
|
2578
2662
|
stdio: "ignore"
|
|
@@ -2585,8 +2669,9 @@ var FirebaseSetup = class {
|
|
|
2585
2669
|
`cd "${this.projectDir}"`,
|
|
2586
2670
|
cmd,
|
|
2587
2671
|
'echo ""',
|
|
2588
|
-
'echo "Login complete!
|
|
2589
|
-
|
|
2672
|
+
'echo "Login complete! Closing in 3 seconds..."',
|
|
2673
|
+
"sleep 3",
|
|
2674
|
+
"exit 0"
|
|
2590
2675
|
].join("\n"), { mode: 493 });
|
|
2591
2676
|
const terminals = [
|
|
2592
2677
|
{ cmd: "x-terminal-emulator", args: ["-e", scriptPath] },
|