clawfire 0.4.0 → 0.4.1
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-MMWHTL5T.js → dev-server-DRZ52WIA.js} +195 -34
- package/dist/dev.cjs +193 -32
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +195 -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-DRZ52WIA.js");
|
|
213
213
|
await startDevServer({
|
|
214
214
|
projectDir,
|
|
215
215
|
port,
|
|
@@ -1189,10 +1189,10 @@ function generateDashboardHtml(options) {
|
|
|
1189
1189
|
</div>
|
|
1190
1190
|
</div>
|
|
1191
1191
|
<div id="step2-action" style="display:none;">
|
|
1192
|
-
<button id="login-btn" onclick="startFirebaseLogin()" style="padding:8px 20px;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">
|
|
1192
|
+
<button id="login-btn" onclick="startFirebaseLogin(false)" style="padding:8px 20px;background:#3b82f6;color:#fff;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">
|
|
1193
1193
|
Login to Firebase
|
|
1194
1194
|
</button>
|
|
1195
|
-
<button id="reauth-btn" onclick="startFirebaseLogin()" style="display:none;padding:8px 20px;background:#eab308;color:#000;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">
|
|
1195
|
+
<button id="reauth-btn" onclick="startFirebaseLogin(true)" style="display:none;padding:8px 20px;background:#eab308;color:#000;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">
|
|
1196
1196
|
Re-authenticate
|
|
1197
1197
|
</button>
|
|
1198
1198
|
<button id="cancel-login-btn" onclick="cancelFirebaseLogin()" style="display:none;padding:8px 20px;background:transparent;border:1px solid #2a2a2a;border-radius:6px;color:#a3a3a3;font-size:13px;cursor:pointer;margin-left:8px;">
|
|
@@ -1202,14 +1202,27 @@ function generateDashboardHtml(options) {
|
|
|
1202
1202
|
<!-- Login progress / auth URL -->
|
|
1203
1203
|
<div id="login-progress" style="display:none;margin-top:12px;padding:16px;border-radius:8px;background:#0a0a1a;border:1px solid #3b82f6;">
|
|
1204
1204
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
|
|
1205
|
-
<span id="login-spinner" style="display:inline-block;width:14px;height:14px;border:2px solid #3b82f6;border-top-color:transparent;border-radius:50
|
|
1206
|
-
<span style="color:#e5e5e5;font-size:13px;font-weight:600;">
|
|
1205
|
+
<span id="login-spinner" style="display:inline-block;width:14px;height:14px;border:2px solid #3b82f6;border-top-color:transparent;border-radius:50%;animation:spin 1s linear infinite;"></span>
|
|
1206
|
+
<span id="login-spinner-text" style="color:#e5e5e5;font-size:13px;font-weight:600;">Starting login...</span>
|
|
1207
1207
|
</div>
|
|
1208
|
-
<div id="login-url-box" style="display:none;margin-top:
|
|
1209
|
-
<div style="font-size:
|
|
1210
|
-
<a id="login-url-link" href="#" target="_blank" rel="noopener" style="
|
|
1208
|
+
<div id="login-url-box" style="display:none;margin-top:12px;">
|
|
1209
|
+
<div style="font-size:13px;color:#e5e5e5;margin-bottom:6px;font-weight:600;">Step 1: Open this link to authenticate</div>
|
|
1210
|
+
<a id="login-url-link" href="#" target="_blank" rel="noopener" style="display:inline-block;padding:8px 16px;background:#3b82f6;color:#fff;border-radius:6px;font-size:13px;text-decoration:none;margin-bottom:8px;">Open Google Login</a>
|
|
1211
|
+
<div style="font-size:11px;color:#666;margin-top:4px;word-break:break-all;font-family:monospace;" id="login-url-raw"></div>
|
|
1211
1212
|
</div>
|
|
1212
|
-
<div id="
|
|
1213
|
+
<div id="auth-code-box" style="display:none;margin-top:12px;">
|
|
1214
|
+
<div style="font-size:13px;color:#e5e5e5;margin-bottom:6px;font-weight:600;">Step 2: Paste the authorization code</div>
|
|
1215
|
+
<div style="font-size:12px;color:#a3a3a3;margin-bottom:8px;">After signing in, Google will show an authorization code. Copy it and paste below.</div>
|
|
1216
|
+
<div style="display:flex;gap:8px;">
|
|
1217
|
+
<input id="auth-code-input" type="text" placeholder="Paste authorization code here"
|
|
1218
|
+
style="flex:1;padding:8px 12px;background:#0a0a0a;border:1px solid #2a2a2a;border-radius:6px;color:#e5e5e5;font-family:monospace;font-size:14px;outline:none;" />
|
|
1219
|
+
<button id="auth-code-submit" onclick="submitAuthCode()" style="padding:8px 16px;background:#22c55e;color:#000;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;">
|
|
1220
|
+
Submit Code
|
|
1221
|
+
</button>
|
|
1222
|
+
</div>
|
|
1223
|
+
<div id="auth-code-error" style="display:none;margin-top:6px;font-size:12px;color:#ef4444;"></div>
|
|
1224
|
+
</div>
|
|
1225
|
+
<div id="login-output" style="display:none;margin-top:8px;max-height:80px;overflow-y:auto;padding:8px;background:#000;border-radius:4px;font-family:monospace;font-size:11px;color:#666;white-space:pre-wrap;"></div>
|
|
1213
1226
|
</div>
|
|
1214
1227
|
<div id="login-result" style="display:none;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;"></div>
|
|
1215
1228
|
</div>
|
|
@@ -1260,7 +1273,7 @@ function generateDashboardHtml(options) {
|
|
|
1260
1273
|
<div id="setup-done" style="display:none;padding:16px;border-radius:8px;background:#0a1a0a;border:1px solid #22c55e;text-align:center;">
|
|
1261
1274
|
<div style="font-size:16px;color:#22c55e;font-weight:700;margin-bottom:4px;">Setup Complete</div>
|
|
1262
1275
|
<div id="setup-done-detail" style="font-size:13px;color:#a3a3a3;"></div>
|
|
1263
|
-
<button onclick="startFirebaseLogin()" style="margin-top:8px;padding:6px 14px;background:transparent;border:1px solid #2a2a2a;border-radius:6px;color:#a3a3a3;font-size:12px;cursor:pointer;">Re-authenticate</button>
|
|
1276
|
+
<button onclick="startFirebaseLogin(true)" style="margin-top:8px;padding:6px 14px;background:transparent;border:1px solid #2a2a2a;border-radius:6px;color:#a3a3a3;font-size:12px;cursor:pointer;">Re-authenticate</button>
|
|
1264
1277
|
</div>
|
|
1265
1278
|
</div>
|
|
1266
1279
|
</div>
|
|
@@ -1533,7 +1546,7 @@ function generateDashboardHtml(options) {
|
|
|
1533
1546
|
};
|
|
1534
1547
|
|
|
1535
1548
|
// \u2500\u2500\u2500 Step 2: Login \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1536
|
-
window.startFirebaseLogin = function() {
|
|
1549
|
+
window.startFirebaseLogin = function(reauth) {
|
|
1537
1550
|
var loginBtn = document.getElementById('login-btn');
|
|
1538
1551
|
var reauthBtn = document.getElementById('reauth-btn');
|
|
1539
1552
|
var cancelBtn = document.getElementById('cancel-login-btn');
|
|
@@ -1546,8 +1559,14 @@ function generateDashboardHtml(options) {
|
|
|
1546
1559
|
progress.style.display = 'block';
|
|
1547
1560
|
result.style.display = 'none';
|
|
1548
1561
|
document.getElementById('login-url-box').style.display = 'none';
|
|
1562
|
+
document.getElementById('auth-code-box').style.display = 'none';
|
|
1563
|
+
document.getElementById('login-spinner-text').textContent = 'Starting login...';
|
|
1549
1564
|
|
|
1550
|
-
fetch(API + '/__dev/setup/login', {
|
|
1565
|
+
fetch(API + '/__dev/setup/login', {
|
|
1566
|
+
method: 'POST',
|
|
1567
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1568
|
+
body: JSON.stringify({ reauth: !!reauth })
|
|
1569
|
+
})
|
|
1551
1570
|
.then(function(r) { return r.json(); })
|
|
1552
1571
|
.then(function() {
|
|
1553
1572
|
// Start polling login state
|
|
@@ -1572,9 +1591,17 @@ function generateDashboardHtml(options) {
|
|
|
1572
1591
|
if (state.authUrl) {
|
|
1573
1592
|
var urlBox = document.getElementById('login-url-box');
|
|
1574
1593
|
var urlLink = document.getElementById('login-url-link');
|
|
1594
|
+
var urlRaw = document.getElementById('login-url-raw');
|
|
1575
1595
|
urlBox.style.display = 'block';
|
|
1576
1596
|
urlLink.href = state.authUrl;
|
|
1577
|
-
urlLink.textContent =
|
|
1597
|
+
urlLink.textContent = 'Open Google Login';
|
|
1598
|
+
if (urlRaw) urlRaw.textContent = state.authUrl;
|
|
1599
|
+
document.getElementById('login-spinner-text').textContent = 'Waiting for authentication...';
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
// Show auth code input when waiting for code
|
|
1603
|
+
if (state.waitingForCode) {
|
|
1604
|
+
document.getElementById('auth-code-box').style.display = 'block';
|
|
1578
1605
|
}
|
|
1579
1606
|
|
|
1580
1607
|
// Show output log
|
|
@@ -1617,6 +1644,45 @@ function generateDashboardHtml(options) {
|
|
|
1617
1644
|
}, 1500);
|
|
1618
1645
|
}
|
|
1619
1646
|
|
|
1647
|
+
window.submitAuthCode = function() {
|
|
1648
|
+
var input = document.getElementById('auth-code-input');
|
|
1649
|
+
var errEl = document.getElementById('auth-code-error');
|
|
1650
|
+
var btn = document.getElementById('auth-code-submit');
|
|
1651
|
+
var code = input ? input.value.trim() : '';
|
|
1652
|
+
if (!code) {
|
|
1653
|
+
errEl.textContent = 'Please paste the authorization code.';
|
|
1654
|
+
errEl.style.display = 'block';
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
errEl.style.display = 'none';
|
|
1658
|
+
btn.disabled = true;
|
|
1659
|
+
btn.textContent = 'Submitting...';
|
|
1660
|
+
|
|
1661
|
+
fetch(API + '/__dev/setup/submit-auth-code', {
|
|
1662
|
+
method: 'POST',
|
|
1663
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1664
|
+
body: JSON.stringify({ code: code })
|
|
1665
|
+
})
|
|
1666
|
+
.then(function(r) { return r.json(); })
|
|
1667
|
+
.then(function(data) {
|
|
1668
|
+
if (data.success) {
|
|
1669
|
+
document.getElementById('login-spinner-text').textContent = 'Verifying authorization...';
|
|
1670
|
+
document.getElementById('auth-code-box').style.display = 'none';
|
|
1671
|
+
} else {
|
|
1672
|
+
errEl.textContent = data.message || 'Failed to submit code.';
|
|
1673
|
+
errEl.style.display = 'block';
|
|
1674
|
+
}
|
|
1675
|
+
btn.disabled = false;
|
|
1676
|
+
btn.textContent = 'Submit Code';
|
|
1677
|
+
})
|
|
1678
|
+
.catch(function(err) {
|
|
1679
|
+
errEl.textContent = 'Error: ' + err.message;
|
|
1680
|
+
errEl.style.display = 'block';
|
|
1681
|
+
btn.disabled = false;
|
|
1682
|
+
btn.textContent = 'Submit Code';
|
|
1683
|
+
});
|
|
1684
|
+
};
|
|
1685
|
+
|
|
1620
1686
|
window.cancelFirebaseLogin = function() {
|
|
1621
1687
|
if (loginPollTimer) { clearInterval(loginPollTimer); loginPollTimer = null; }
|
|
1622
1688
|
fetch(API + '/__dev/setup/cancel-login', { method: 'POST' }).catch(function() {});
|
|
@@ -2089,14 +2155,16 @@ function generateDashboardHtml(options) {
|
|
|
2089
2155
|
|
|
2090
2156
|
// src/dev/firebase-setup.ts
|
|
2091
2157
|
import { execFile as execFile2, spawn } from "child_process";
|
|
2092
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
2093
|
-
import { resolve as resolve4 } from "path";
|
|
2158
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync } from "fs";
|
|
2159
|
+
import { resolve as resolve4, join as join3, dirname as dirname2 } from "path";
|
|
2160
|
+
import { homedir } from "os";
|
|
2094
2161
|
var FirebaseSetup = class {
|
|
2095
2162
|
projectDir;
|
|
2096
2163
|
loginProcess = null;
|
|
2097
2164
|
loginSession = {
|
|
2098
2165
|
active: false,
|
|
2099
2166
|
authUrl: null,
|
|
2167
|
+
waitingForCode: false,
|
|
2100
2168
|
completed: false,
|
|
2101
2169
|
error: null,
|
|
2102
2170
|
output: ""
|
|
@@ -2164,7 +2232,7 @@ var FirebaseSetup = class {
|
|
|
2164
2232
|
return { success: true, message: "Firebase CLI is already installed." };
|
|
2165
2233
|
} catch {
|
|
2166
2234
|
}
|
|
2167
|
-
|
|
2235
|
+
await this.execTimeout(
|
|
2168
2236
|
"npm",
|
|
2169
2237
|
["install", "-g", "firebase-tools"],
|
|
2170
2238
|
12e4
|
|
@@ -2181,21 +2249,56 @@ var FirebaseSetup = class {
|
|
|
2181
2249
|
return { success: false, message: `Failed to install Firebase CLI: ${msg}` };
|
|
2182
2250
|
}
|
|
2183
2251
|
}
|
|
2252
|
+
// ─── Analytics Pre-config ──────────────────────────────────────────
|
|
2253
|
+
/**
|
|
2254
|
+
* Pre-configure Firebase analytics preference to avoid the interactive
|
|
2255
|
+
* "Allow Firebase to collect..." prompt that breaks non-TTY spawns.
|
|
2256
|
+
*/
|
|
2257
|
+
ensureAnalyticsConfigured() {
|
|
2258
|
+
try {
|
|
2259
|
+
const home = homedir();
|
|
2260
|
+
const configPath = join3(home, ".config", "configstore", "firebase-tools.json");
|
|
2261
|
+
if (existsSync5(configPath)) {
|
|
2262
|
+
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
2263
|
+
if (config.usage === void 0) {
|
|
2264
|
+
config.usage = false;
|
|
2265
|
+
writeFileSync2(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
2266
|
+
}
|
|
2267
|
+
} else {
|
|
2268
|
+
const dir = dirname2(configPath);
|
|
2269
|
+
mkdirSync(dir, { recursive: true });
|
|
2270
|
+
writeFileSync2(configPath, JSON.stringify({ usage: false }, null, 2), "utf-8");
|
|
2271
|
+
}
|
|
2272
|
+
} catch {
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2184
2275
|
// ─── Login Flow ────────────────────────────────────────────────────
|
|
2185
|
-
|
|
2276
|
+
/**
|
|
2277
|
+
* Start login using `firebase login --no-localhost`.
|
|
2278
|
+
*
|
|
2279
|
+
* This mode is designed for non-TTY environments:
|
|
2280
|
+
* 1. Prints a Google OAuth URL
|
|
2281
|
+
* 2. User opens URL in browser and authenticates
|
|
2282
|
+
* 3. Google shows an authorization code on screen
|
|
2283
|
+
* 4. User pastes code back → call submitAuthCode()
|
|
2284
|
+
*/
|
|
2285
|
+
startLogin(reauth = false) {
|
|
2186
2286
|
this.cleanupLogin();
|
|
2287
|
+
this.ensureAnalyticsConfigured();
|
|
2187
2288
|
this.loginSession = {
|
|
2188
2289
|
active: true,
|
|
2189
2290
|
authUrl: null,
|
|
2291
|
+
waitingForCode: false,
|
|
2190
2292
|
completed: false,
|
|
2191
2293
|
error: null,
|
|
2192
2294
|
output: ""
|
|
2193
2295
|
};
|
|
2194
2296
|
try {
|
|
2195
|
-
const
|
|
2297
|
+
const args = reauth ? ["login", "--reauth", "--no-localhost"] : ["login", "--no-localhost"];
|
|
2298
|
+
const proc = spawn("firebase", args, {
|
|
2196
2299
|
cwd: this.projectDir,
|
|
2197
2300
|
stdio: ["pipe", "pipe", "pipe"],
|
|
2198
|
-
env: { ...process.env }
|
|
2301
|
+
env: { ...process.env, TERM: "dumb" }
|
|
2199
2302
|
});
|
|
2200
2303
|
this.loginProcess = proc;
|
|
2201
2304
|
const appendOutput = (data) => {
|
|
@@ -2204,16 +2307,14 @@ var FirebaseSetup = class {
|
|
|
2204
2307
|
const urlMatch = text.match(/(https:\/\/accounts\.google\.com\S+)/);
|
|
2205
2308
|
if (urlMatch) {
|
|
2206
2309
|
this.loginSession.authUrl = urlMatch[1];
|
|
2310
|
+
this.loginSession.waitingForCode = true;
|
|
2207
2311
|
}
|
|
2208
|
-
|
|
2209
|
-
if (localhostMatch && !this.loginSession.authUrl) {
|
|
2210
|
-
this.loginSession.authUrl = localhostMatch[1];
|
|
2211
|
-
}
|
|
2212
|
-
if (text.includes("Success") || text.includes("Logged in as") || text.includes("\u2714")) {
|
|
2312
|
+
if (text.includes("Success") || text.includes("Logged in as")) {
|
|
2213
2313
|
this.loginSession.completed = true;
|
|
2214
2314
|
this.loginSession.active = false;
|
|
2315
|
+
this.loginSession.waitingForCode = false;
|
|
2215
2316
|
}
|
|
2216
|
-
if (text.includes("Allow Firebase to collect") || text.includes("
|
|
2317
|
+
if (text.includes("Allow Firebase to collect") || text.includes("(Y/n)")) {
|
|
2217
2318
|
try {
|
|
2218
2319
|
proc.stdin?.write("n\n");
|
|
2219
2320
|
} catch {
|
|
@@ -2224,10 +2325,13 @@ var FirebaseSetup = class {
|
|
|
2224
2325
|
proc.stderr?.on("data", appendOutput);
|
|
2225
2326
|
proc.on("close", (code) => {
|
|
2226
2327
|
this.loginSession.active = false;
|
|
2328
|
+
this.loginSession.waitingForCode = false;
|
|
2227
2329
|
if (code === 0) {
|
|
2228
2330
|
this.loginSession.completed = true;
|
|
2229
2331
|
} else if (!this.loginSession.completed) {
|
|
2230
|
-
this.loginSession.
|
|
2332
|
+
const lines = this.loginSession.output.trim().split("\n").filter((l) => l.trim());
|
|
2333
|
+
const lastLines = lines.slice(-3).join(" | ");
|
|
2334
|
+
this.loginSession.error = `Login failed (exit code ${code}).` + (lastLines ? ` Details: ${lastLines}` : "") + ` Try running "firebase login" in your terminal.`;
|
|
2231
2335
|
}
|
|
2232
2336
|
this.loginProcess = null;
|
|
2233
2337
|
});
|
|
@@ -2251,6 +2355,25 @@ var FirebaseSetup = class {
|
|
|
2251
2355
|
getLoginState() {
|
|
2252
2356
|
return { ...this.loginSession };
|
|
2253
2357
|
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Submit the authorization code that the user copied from the browser.
|
|
2360
|
+
* This writes the code to the Firebase CLI process stdin.
|
|
2361
|
+
*/
|
|
2362
|
+
submitAuthCode(code) {
|
|
2363
|
+
if (!this.loginProcess || !this.loginProcess.stdin) {
|
|
2364
|
+
return { success: false, message: "No active login process. Please start login again." };
|
|
2365
|
+
}
|
|
2366
|
+
if (!code || !code.trim()) {
|
|
2367
|
+
return { success: false, message: "Authorization code is required." };
|
|
2368
|
+
}
|
|
2369
|
+
try {
|
|
2370
|
+
this.loginProcess.stdin.write(code.trim() + "\n");
|
|
2371
|
+
this.loginSession.waitingForCode = false;
|
|
2372
|
+
return { success: true, message: "Authorization code submitted. Waiting for verification..." };
|
|
2373
|
+
} catch (err) {
|
|
2374
|
+
return { success: false, message: "Failed to submit code: " + (err instanceof Error ? err.message : "unknown error") };
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2254
2377
|
cancelLogin() {
|
|
2255
2378
|
this.cleanupLogin();
|
|
2256
2379
|
this.loginSession.error = "Login cancelled by user.";
|
|
@@ -2268,6 +2391,7 @@ var FirebaseSetup = class {
|
|
|
2268
2391
|
this.loginTimeout = null;
|
|
2269
2392
|
}
|
|
2270
2393
|
this.loginSession.active = false;
|
|
2394
|
+
this.loginSession.waitingForCode = false;
|
|
2271
2395
|
}
|
|
2272
2396
|
// ─── Project Listing ───────────────────────────────────────────────
|
|
2273
2397
|
async listProjects() {
|
|
@@ -2275,7 +2399,8 @@ var FirebaseSetup = class {
|
|
|
2275
2399
|
const output = await this.execTimeout(
|
|
2276
2400
|
"firebase",
|
|
2277
2401
|
["projects:list", "--json"],
|
|
2278
|
-
|
|
2402
|
+
3e4
|
|
2403
|
+
// 30s — can be slow on first call
|
|
2279
2404
|
);
|
|
2280
2405
|
const data = JSON.parse(output);
|
|
2281
2406
|
if (data?.result && Array.isArray(data.result)) {
|
|
@@ -2290,8 +2415,11 @@ var FirebaseSetup = class {
|
|
|
2290
2415
|
return { projects: [], error: "Unexpected response format" };
|
|
2291
2416
|
} catch (err) {
|
|
2292
2417
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
2293
|
-
if (msg.includes("authenticate") || msg.includes("login")) {
|
|
2294
|
-
return { projects: [], error: "
|
|
2418
|
+
if (msg.includes("authenticate") || msg.includes("login") || msg.includes("credential")) {
|
|
2419
|
+
return { projects: [], error: "Session expired. Please re-authenticate first." };
|
|
2420
|
+
}
|
|
2421
|
+
if (msg.includes("Timeout")) {
|
|
2422
|
+
return { projects: [], error: "Request timed out. Please try again." };
|
|
2295
2423
|
}
|
|
2296
2424
|
return { projects: [], error: msg };
|
|
2297
2425
|
}
|
|
@@ -2322,7 +2450,7 @@ var FirebaseSetup = class {
|
|
|
2322
2450
|
rc.projects.default = projectId;
|
|
2323
2451
|
writeFileSync2(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
2324
2452
|
return { success: true, message: `Active project set to "${projectId}".` };
|
|
2325
|
-
} catch
|
|
2453
|
+
} catch {
|
|
2326
2454
|
try {
|
|
2327
2455
|
const firebasercPath = resolve4(this.projectDir, ".firebaserc");
|
|
2328
2456
|
const rc = {
|
|
@@ -2331,7 +2459,7 @@ var FirebaseSetup = class {
|
|
|
2331
2459
|
writeFileSync2(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
2332
2460
|
return { success: true, message: `Active project set to "${projectId}" (via .firebaserc).` };
|
|
2333
2461
|
} catch (writeErr) {
|
|
2334
|
-
const msg =
|
|
2462
|
+
const msg = writeErr instanceof Error ? writeErr.message : "Unknown error";
|
|
2335
2463
|
return { success: false, message: `Failed to set project: ${msg}` };
|
|
2336
2464
|
}
|
|
2337
2465
|
}
|
|
@@ -2339,9 +2467,11 @@ var FirebaseSetup = class {
|
|
|
2339
2467
|
// ─── Helpers ───────────────────────────────────────────────────────
|
|
2340
2468
|
execTimeout(command, args, timeoutMs) {
|
|
2341
2469
|
return new Promise((resolve6, reject) => {
|
|
2342
|
-
const proc = execFile2(command, args, { cwd: this.projectDir, timeout: timeoutMs }, (err, stdout) => {
|
|
2470
|
+
const proc = execFile2(command, args, { cwd: this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
2343
2471
|
if (err) {
|
|
2344
|
-
|
|
2472
|
+
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
2473
|
+
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
2474
|
+
reject(enriched);
|
|
2345
2475
|
} else {
|
|
2346
2476
|
resolve6(stdout);
|
|
2347
2477
|
}
|
|
@@ -3267,8 +3397,20 @@ ${liveReloadScript}
|
|
|
3267
3397
|
return;
|
|
3268
3398
|
}
|
|
3269
3399
|
if (url.pathname === "/__dev/setup/login" && req.method === "POST") {
|
|
3270
|
-
|
|
3271
|
-
|
|
3400
|
+
let body = "";
|
|
3401
|
+
req.on("data", (chunk) => {
|
|
3402
|
+
body += chunk;
|
|
3403
|
+
});
|
|
3404
|
+
req.on("end", () => {
|
|
3405
|
+
let reauth = false;
|
|
3406
|
+
try {
|
|
3407
|
+
const data = JSON.parse(body);
|
|
3408
|
+
reauth = !!data.reauth;
|
|
3409
|
+
} catch {
|
|
3410
|
+
}
|
|
3411
|
+
const session = this.firebaseSetup.startLogin(reauth);
|
|
3412
|
+
sendJson(session);
|
|
3413
|
+
});
|
|
3272
3414
|
return;
|
|
3273
3415
|
}
|
|
3274
3416
|
if (url.pathname === "/__dev/setup/login-state" && req.method === "GET") {
|
|
@@ -3280,6 +3422,25 @@ ${liveReloadScript}
|
|
|
3280
3422
|
sendJson({ ok: true });
|
|
3281
3423
|
return;
|
|
3282
3424
|
}
|
|
3425
|
+
if (url.pathname === "/__dev/setup/submit-auth-code" && req.method === "POST") {
|
|
3426
|
+
let body = "";
|
|
3427
|
+
req.on("data", (chunk) => {
|
|
3428
|
+
body += chunk;
|
|
3429
|
+
});
|
|
3430
|
+
req.on("end", () => {
|
|
3431
|
+
try {
|
|
3432
|
+
const data = JSON.parse(body);
|
|
3433
|
+
if (!data.code) {
|
|
3434
|
+
sendJson({ success: false, message: "code is required" }, 400);
|
|
3435
|
+
return;
|
|
3436
|
+
}
|
|
3437
|
+
sendJson(this.firebaseSetup.submitAuthCode(data.code));
|
|
3438
|
+
} catch {
|
|
3439
|
+
sendJson({ success: false, message: "Invalid JSON body" }, 400);
|
|
3440
|
+
}
|
|
3441
|
+
});
|
|
3442
|
+
return;
|
|
3443
|
+
}
|
|
3283
3444
|
if (url.pathname === "/__dev/setup/projects" && req.method === "GET") {
|
|
3284
3445
|
this.firebaseSetup.listProjects().then((result) => sendJson(result)).catch((err) => sendJson({ projects: [], error: err instanceof Error ? err.message : "Failed" }, 500));
|
|
3285
3446
|
return;
|