clawfire 0.4.1 → 0.4.2
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-DRZ52WIA.js → dev-server-65H4AQFS.js} +105 -312
- package/dist/dev.cjs +102 -309
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +105 -312
- package/dist/dev.js.map +1 -1
- package/package.json +1 -1
package/dist/dev.cjs
CHANGED
|
@@ -1607,34 +1607,15 @@ function generateDashboardHtml(options) {
|
|
|
1607
1607
|
<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;">
|
|
1608
1608
|
Re-authenticate
|
|
1609
1609
|
</button>
|
|
1610
|
-
<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;">
|
|
1611
|
-
Cancel
|
|
1612
|
-
</button>
|
|
1613
1610
|
</div>
|
|
1614
|
-
<!-- Login
|
|
1615
|
-
<div id="login-
|
|
1611
|
+
<!-- Login waiting message -->
|
|
1612
|
+
<div id="login-waiting" style="display:none;margin-top:12px;padding:16px;border-radius:8px;background:#0a0a1a;border:1px solid #3b82f6;">
|
|
1616
1613
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
|
|
1617
|
-
<span
|
|
1618
|
-
<span
|
|
1619
|
-
</div>
|
|
1620
|
-
<div id="login-url-box" style="display:none;margin-top:12px;">
|
|
1621
|
-
<div style="font-size:13px;color:#e5e5e5;margin-bottom:6px;font-weight:600;">Step 1: Open this link to authenticate</div>
|
|
1622
|
-
<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>
|
|
1623
|
-
<div style="font-size:11px;color:#666;margin-top:4px;word-break:break-all;font-family:monospace;" id="login-url-raw"></div>
|
|
1614
|
+
<span 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>
|
|
1615
|
+
<span style="color:#e5e5e5;font-size:13px;font-weight:600;">Waiting for login...</span>
|
|
1624
1616
|
</div>
|
|
1625
|
-
<div
|
|
1626
|
-
|
|
1627
|
-
<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>
|
|
1628
|
-
<div style="display:flex;gap:8px;">
|
|
1629
|
-
<input id="auth-code-input" type="text" placeholder="Paste authorization code here"
|
|
1630
|
-
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;" />
|
|
1631
|
-
<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;">
|
|
1632
|
-
Submit Code
|
|
1633
|
-
</button>
|
|
1634
|
-
</div>
|
|
1635
|
-
<div id="auth-code-error" style="display:none;margin-top:6px;font-size:12px;color:#ef4444;"></div>
|
|
1636
|
-
</div>
|
|
1637
|
-
<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>
|
|
1617
|
+
<div style="font-size:13px;color:#a3a3a3;">A terminal window has been opened. Please complete the Firebase login there.</div>
|
|
1618
|
+
<div style="font-size:12px;color:#666;margin-top:6px;">This page will update automatically when login is detected.</div>
|
|
1638
1619
|
</div>
|
|
1639
1620
|
<div id="login-result" style="display:none;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;"></div>
|
|
1640
1621
|
</div>
|
|
@@ -1881,14 +1862,14 @@ function generateDashboardHtml(options) {
|
|
|
1881
1862
|
document.getElementById('step2-action').style.display = 'block';
|
|
1882
1863
|
document.getElementById('login-btn').style.display = 'none';
|
|
1883
1864
|
document.getElementById('reauth-btn').style.display = 'inline-block';
|
|
1884
|
-
document.getElementById('
|
|
1865
|
+
document.getElementById('login-waiting').style.display = 'none';
|
|
1885
1866
|
} else {
|
|
1886
1867
|
document.getElementById('step2-icon').textContent = RED;
|
|
1887
1868
|
document.getElementById('step2-detail').textContent = 'Not logged in to Firebase';
|
|
1888
1869
|
document.getElementById('step2-action').style.display = 'block';
|
|
1889
1870
|
document.getElementById('login-btn').style.display = 'inline-block';
|
|
1890
1871
|
document.getElementById('reauth-btn').style.display = 'none';
|
|
1891
|
-
document.getElementById('
|
|
1872
|
+
document.getElementById('login-waiting').style.display = 'none';
|
|
1892
1873
|
}
|
|
1893
1874
|
|
|
1894
1875
|
if (status.nextStep === 'login') {
|
|
@@ -1957,22 +1938,17 @@ function generateDashboardHtml(options) {
|
|
|
1957
1938
|
});
|
|
1958
1939
|
};
|
|
1959
1940
|
|
|
1960
|
-
// \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
|
|
1941
|
+
// \u2500\u2500\u2500 Step 2: Login (opens terminal window) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1961
1942
|
window.startFirebaseLogin = function(reauth) {
|
|
1962
1943
|
var loginBtn = document.getElementById('login-btn');
|
|
1963
1944
|
var reauthBtn = document.getElementById('reauth-btn');
|
|
1964
|
-
var
|
|
1965
|
-
var progress = document.getElementById('login-progress');
|
|
1945
|
+
var waiting = document.getElementById('login-waiting');
|
|
1966
1946
|
var result = document.getElementById('login-result');
|
|
1967
1947
|
|
|
1968
1948
|
loginBtn.style.display = 'none';
|
|
1969
1949
|
reauthBtn.style.display = 'none';
|
|
1970
|
-
|
|
1971
|
-
progress.style.display = 'block';
|
|
1950
|
+
waiting.style.display = 'block';
|
|
1972
1951
|
result.style.display = 'none';
|
|
1973
|
-
document.getElementById('login-url-box').style.display = 'none';
|
|
1974
|
-
document.getElementById('auth-code-box').style.display = 'none';
|
|
1975
|
-
document.getElementById('login-spinner-text').textContent = 'Starting login...';
|
|
1976
1952
|
|
|
1977
1953
|
fetch(API + '/__dev/setup/login', {
|
|
1978
1954
|
method: 'POST',
|
|
@@ -1980,129 +1956,45 @@ function generateDashboardHtml(options) {
|
|
|
1980
1956
|
body: JSON.stringify({ reauth: !!reauth })
|
|
1981
1957
|
})
|
|
1982
1958
|
.then(function(r) { return r.json(); })
|
|
1983
|
-
.then(function() {
|
|
1984
|
-
|
|
1959
|
+
.then(function(data) {
|
|
1960
|
+
if (!data.success) {
|
|
1961
|
+
waiting.style.display = 'none';
|
|
1962
|
+
result.textContent = data.message;
|
|
1963
|
+
result.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#1c0808;border:1px solid #ef4444;color:#ef4444;';
|
|
1964
|
+
loginBtn.style.display = 'inline-block';
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
// Poll setup status until login is detected
|
|
1985
1968
|
startLoginPoll();
|
|
1986
1969
|
})
|
|
1987
1970
|
.catch(function(err) {
|
|
1988
|
-
|
|
1989
|
-
result.textContent = 'Failed
|
|
1971
|
+
waiting.style.display = 'none';
|
|
1972
|
+
result.textContent = 'Failed: ' + err.message;
|
|
1990
1973
|
result.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#1c0808;border:1px solid #ef4444;color:#ef4444;';
|
|
1991
1974
|
loginBtn.style.display = 'inline-block';
|
|
1992
|
-
cancelBtn.style.display = 'none';
|
|
1993
1975
|
});
|
|
1994
1976
|
};
|
|
1995
1977
|
|
|
1996
1978
|
function startLoginPoll() {
|
|
1997
1979
|
if (loginPollTimer) clearInterval(loginPollTimer);
|
|
1998
1980
|
loginPollTimer = setInterval(function() {
|
|
1999
|
-
fetch(API + '/__dev/setup/
|
|
1981
|
+
fetch(API + '/__dev/setup/status')
|
|
2000
1982
|
.then(function(r) { return r.json(); })
|
|
2001
|
-
.then(function(
|
|
2002
|
-
|
|
2003
|
-
if (state.authUrl) {
|
|
2004
|
-
var urlBox = document.getElementById('login-url-box');
|
|
2005
|
-
var urlLink = document.getElementById('login-url-link');
|
|
2006
|
-
var urlRaw = document.getElementById('login-url-raw');
|
|
2007
|
-
urlBox.style.display = 'block';
|
|
2008
|
-
urlLink.href = state.authUrl;
|
|
2009
|
-
urlLink.textContent = 'Open Google Login';
|
|
2010
|
-
if (urlRaw) urlRaw.textContent = state.authUrl;
|
|
2011
|
-
document.getElementById('login-spinner-text').textContent = 'Waiting for authentication...';
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
// Show auth code input when waiting for code
|
|
2015
|
-
if (state.waitingForCode) {
|
|
2016
|
-
document.getElementById('auth-code-box').style.display = 'block';
|
|
2017
|
-
}
|
|
2018
|
-
|
|
2019
|
-
// Show output log
|
|
2020
|
-
if (state.output) {
|
|
2021
|
-
var outputEl = document.getElementById('login-output');
|
|
2022
|
-
outputEl.style.display = 'block';
|
|
2023
|
-
outputEl.textContent = state.output.slice(-500);
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
|
-
// Check if done
|
|
2027
|
-
if (state.completed) {
|
|
1983
|
+
.then(function(status) {
|
|
1984
|
+
if (status.auth.authenticated) {
|
|
2028
1985
|
clearInterval(loginPollTimer);
|
|
2029
1986
|
loginPollTimer = null;
|
|
2030
|
-
document.getElementById('login-
|
|
2031
|
-
document.getElementById('cancel-login-btn').style.display = 'none';
|
|
1987
|
+
document.getElementById('login-waiting').style.display = 'none';
|
|
2032
1988
|
var result = document.getElementById('login-result');
|
|
2033
|
-
result.textContent = 'Login successful!';
|
|
1989
|
+
result.textContent = 'Login successful! Logged in as ' + status.auth.user;
|
|
2034
1990
|
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;';
|
|
2035
|
-
// Refresh wizard after short delay
|
|
2036
1991
|
setTimeout(refreshSetupStatus, 1500);
|
|
2037
1992
|
}
|
|
2038
|
-
|
|
2039
|
-
if (state.error) {
|
|
2040
|
-
clearInterval(loginPollTimer);
|
|
2041
|
-
loginPollTimer = null;
|
|
2042
|
-
document.getElementById('login-progress').style.display = 'none';
|
|
2043
|
-
document.getElementById('cancel-login-btn').style.display = 'none';
|
|
2044
|
-
var result2 = document.getElementById('login-result');
|
|
2045
|
-
result2.textContent = state.error;
|
|
2046
|
-
result2.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#1c0808;border:1px solid #ef4444;color:#ef4444;';
|
|
2047
|
-
document.getElementById('login-btn').style.display = 'inline-block';
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
if (!state.active && !state.completed && !state.error) {
|
|
2051
|
-
clearInterval(loginPollTimer);
|
|
2052
|
-
loginPollTimer = null;
|
|
2053
|
-
}
|
|
2054
1993
|
})
|
|
2055
1994
|
.catch(function() {});
|
|
2056
|
-
},
|
|
1995
|
+
}, 3000);
|
|
2057
1996
|
}
|
|
2058
1997
|
|
|
2059
|
-
window.submitAuthCode = function() {
|
|
2060
|
-
var input = document.getElementById('auth-code-input');
|
|
2061
|
-
var errEl = document.getElementById('auth-code-error');
|
|
2062
|
-
var btn = document.getElementById('auth-code-submit');
|
|
2063
|
-
var code = input ? input.value.trim() : '';
|
|
2064
|
-
if (!code) {
|
|
2065
|
-
errEl.textContent = 'Please paste the authorization code.';
|
|
2066
|
-
errEl.style.display = 'block';
|
|
2067
|
-
return;
|
|
2068
|
-
}
|
|
2069
|
-
errEl.style.display = 'none';
|
|
2070
|
-
btn.disabled = true;
|
|
2071
|
-
btn.textContent = 'Submitting...';
|
|
2072
|
-
|
|
2073
|
-
fetch(API + '/__dev/setup/submit-auth-code', {
|
|
2074
|
-
method: 'POST',
|
|
2075
|
-
headers: { 'Content-Type': 'application/json' },
|
|
2076
|
-
body: JSON.stringify({ code: code })
|
|
2077
|
-
})
|
|
2078
|
-
.then(function(r) { return r.json(); })
|
|
2079
|
-
.then(function(data) {
|
|
2080
|
-
if (data.success) {
|
|
2081
|
-
document.getElementById('login-spinner-text').textContent = 'Verifying authorization...';
|
|
2082
|
-
document.getElementById('auth-code-box').style.display = 'none';
|
|
2083
|
-
} else {
|
|
2084
|
-
errEl.textContent = data.message || 'Failed to submit code.';
|
|
2085
|
-
errEl.style.display = 'block';
|
|
2086
|
-
}
|
|
2087
|
-
btn.disabled = false;
|
|
2088
|
-
btn.textContent = 'Submit Code';
|
|
2089
|
-
})
|
|
2090
|
-
.catch(function(err) {
|
|
2091
|
-
errEl.textContent = 'Error: ' + err.message;
|
|
2092
|
-
errEl.style.display = 'block';
|
|
2093
|
-
btn.disabled = false;
|
|
2094
|
-
btn.textContent = 'Submit Code';
|
|
2095
|
-
});
|
|
2096
|
-
};
|
|
2097
|
-
|
|
2098
|
-
window.cancelFirebaseLogin = function() {
|
|
2099
|
-
if (loginPollTimer) { clearInterval(loginPollTimer); loginPollTimer = null; }
|
|
2100
|
-
fetch(API + '/__dev/setup/cancel-login', { method: 'POST' }).catch(function() {});
|
|
2101
|
-
document.getElementById('login-progress').style.display = 'none';
|
|
2102
|
-
document.getElementById('cancel-login-btn').style.display = 'none';
|
|
2103
|
-
document.getElementById('login-btn').style.display = 'inline-block';
|
|
2104
|
-
};
|
|
2105
|
-
|
|
2106
1998
|
// \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
|
|
2107
1999
|
function loadProjectList(currentProjectId) {
|
|
2108
2000
|
var select = document.getElementById('project-select');
|
|
@@ -2572,16 +2464,6 @@ var import_node_path4 = require("path");
|
|
|
2572
2464
|
var import_node_os = require("os");
|
|
2573
2465
|
var FirebaseSetup = class {
|
|
2574
2466
|
projectDir;
|
|
2575
|
-
loginProcess = null;
|
|
2576
|
-
loginSession = {
|
|
2577
|
-
active: false,
|
|
2578
|
-
authUrl: null,
|
|
2579
|
-
waitingForCode: false,
|
|
2580
|
-
completed: false,
|
|
2581
|
-
error: null,
|
|
2582
|
-
output: ""
|
|
2583
|
-
};
|
|
2584
|
-
loginTimeout = null;
|
|
2585
2467
|
constructor(projectDir) {
|
|
2586
2468
|
this.projectDir = projectDir;
|
|
2587
2469
|
}
|
|
@@ -2661,149 +2543,89 @@ var FirebaseSetup = class {
|
|
|
2661
2543
|
return { success: false, message: `Failed to install Firebase CLI: ${msg}` };
|
|
2662
2544
|
}
|
|
2663
2545
|
}
|
|
2664
|
-
// ───
|
|
2665
|
-
/**
|
|
2666
|
-
* Pre-configure Firebase analytics preference to avoid the interactive
|
|
2667
|
-
* "Allow Firebase to collect..." prompt that breaks non-TTY spawns.
|
|
2668
|
-
*/
|
|
2669
|
-
ensureAnalyticsConfigured() {
|
|
2670
|
-
try {
|
|
2671
|
-
const home = (0, import_node_os.homedir)();
|
|
2672
|
-
const configPath = (0, import_node_path4.join)(home, ".config", "configstore", "firebase-tools.json");
|
|
2673
|
-
if ((0, import_node_fs4.existsSync)(configPath)) {
|
|
2674
|
-
const config = JSON.parse((0, import_node_fs4.readFileSync)(configPath, "utf-8"));
|
|
2675
|
-
if (config.usage === void 0) {
|
|
2676
|
-
config.usage = false;
|
|
2677
|
-
(0, import_node_fs4.writeFileSync)(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
2678
|
-
}
|
|
2679
|
-
} else {
|
|
2680
|
-
const dir = (0, import_node_path4.dirname)(configPath);
|
|
2681
|
-
(0, import_node_fs4.mkdirSync)(dir, { recursive: true });
|
|
2682
|
-
(0, import_node_fs4.writeFileSync)(configPath, JSON.stringify({ usage: false }, null, 2), "utf-8");
|
|
2683
|
-
}
|
|
2684
|
-
} catch {
|
|
2685
|
-
}
|
|
2686
|
-
}
|
|
2687
|
-
// ─── Login Flow ────────────────────────────────────────────────────
|
|
2546
|
+
// ─── Login via Terminal ───────────────────────────────────────────
|
|
2688
2547
|
/**
|
|
2689
|
-
*
|
|
2548
|
+
* Opens a new terminal window and runs `firebase login`.
|
|
2690
2549
|
*
|
|
2691
|
-
*
|
|
2692
|
-
*
|
|
2693
|
-
*
|
|
2694
|
-
*
|
|
2695
|
-
*
|
|
2550
|
+
* Firebase CLI requires a real TTY for interactive login.
|
|
2551
|
+
* Instead of trying to fake a TTY, we open an actual terminal.
|
|
2552
|
+
* The dashboard polls getStatus() to detect when login completes.
|
|
2553
|
+
*
|
|
2554
|
+
* macOS: Creates a .command file and opens it (Terminal.app)
|
|
2555
|
+
* Linux: Tries common terminal emulators
|
|
2556
|
+
* Windows: Opens a new cmd window
|
|
2696
2557
|
*/
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
this.loginSession = {
|
|
2701
|
-
active: true,
|
|
2702
|
-
authUrl: null,
|
|
2703
|
-
waitingForCode: false,
|
|
2704
|
-
completed: false,
|
|
2705
|
-
error: null,
|
|
2706
|
-
output: ""
|
|
2707
|
-
};
|
|
2558
|
+
openLoginTerminal(reauth = false) {
|
|
2559
|
+
const cmd = reauth ? "firebase login --reauth" : "firebase login";
|
|
2560
|
+
const os = (0, import_node_os.platform)();
|
|
2708
2561
|
try {
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
const
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2562
|
+
if (os === "darwin") {
|
|
2563
|
+
const scriptPath = (0, import_node_path4.join)((0, import_node_os.tmpdir)(), "clawfire-firebase-login.command");
|
|
2564
|
+
(0, import_node_fs4.writeFileSync)(scriptPath, [
|
|
2565
|
+
"#!/bin/bash",
|
|
2566
|
+
`cd "${this.projectDir}"`,
|
|
2567
|
+
cmd,
|
|
2568
|
+
'echo ""',
|
|
2569
|
+
'echo "Login complete! You can close this window."',
|
|
2570
|
+
'read -p "Press Enter to close..."'
|
|
2571
|
+
].join("\n"), { mode: 493 });
|
|
2572
|
+
const child = (0, import_node_child_process2.spawn)("open", [scriptPath], { detached: true, stdio: "ignore" });
|
|
2573
|
+
child.unref();
|
|
2574
|
+
} else if (os === "win32") {
|
|
2575
|
+
const child = (0, import_node_child_process2.spawn)("cmd", ["/c", "start", "cmd", "/k", cmd], {
|
|
2576
|
+
cwd: this.projectDir,
|
|
2577
|
+
detached: true,
|
|
2578
|
+
stdio: "ignore"
|
|
2579
|
+
});
|
|
2580
|
+
child.unref();
|
|
2581
|
+
} else {
|
|
2582
|
+
const scriptPath = (0, import_node_path4.join)((0, import_node_os.tmpdir)(), "clawfire-firebase-login.sh");
|
|
2583
|
+
(0, import_node_fs4.writeFileSync)(scriptPath, [
|
|
2584
|
+
"#!/bin/bash",
|
|
2585
|
+
`cd "${this.projectDir}"`,
|
|
2586
|
+
cmd,
|
|
2587
|
+
'echo ""',
|
|
2588
|
+
'echo "Login complete! You can close this window."',
|
|
2589
|
+
'read -p "Press Enter to close..."'
|
|
2590
|
+
].join("\n"), { mode: 493 });
|
|
2591
|
+
const terminals = [
|
|
2592
|
+
{ cmd: "x-terminal-emulator", args: ["-e", scriptPath] },
|
|
2593
|
+
{ cmd: "gnome-terminal", args: ["--", "bash", scriptPath] },
|
|
2594
|
+
{ cmd: "konsole", args: ["-e", "bash", scriptPath] },
|
|
2595
|
+
{ cmd: "xfce4-terminal", args: ["-e", scriptPath] },
|
|
2596
|
+
{ cmd: "xterm", args: ["-e", scriptPath] }
|
|
2597
|
+
];
|
|
2598
|
+
let opened = false;
|
|
2599
|
+
for (const t of terminals) {
|
|
2730
2600
|
try {
|
|
2731
|
-
|
|
2601
|
+
const child = (0, import_node_child_process2.spawn)(t.cmd, t.args, { detached: true, stdio: "ignore" });
|
|
2602
|
+
child.unref();
|
|
2603
|
+
child.on("error", () => {
|
|
2604
|
+
});
|
|
2605
|
+
opened = true;
|
|
2606
|
+
break;
|
|
2732
2607
|
} catch {
|
|
2608
|
+
continue;
|
|
2733
2609
|
}
|
|
2734
2610
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
this.loginSession.waitingForCode = false;
|
|
2741
|
-
if (code === 0) {
|
|
2742
|
-
this.loginSession.completed = true;
|
|
2743
|
-
} else if (!this.loginSession.completed) {
|
|
2744
|
-
const lines = this.loginSession.output.trim().split("\n").filter((l) => l.trim());
|
|
2745
|
-
const lastLines = lines.slice(-3).join(" | ");
|
|
2746
|
-
this.loginSession.error = `Login failed (exit code ${code}).` + (lastLines ? ` Details: ${lastLines}` : "") + ` Try running "firebase login" in your terminal.`;
|
|
2747
|
-
}
|
|
2748
|
-
this.loginProcess = null;
|
|
2749
|
-
});
|
|
2750
|
-
proc.on("error", (err) => {
|
|
2751
|
-
this.loginSession.active = false;
|
|
2752
|
-
this.loginSession.error = err.message;
|
|
2753
|
-
this.loginProcess = null;
|
|
2754
|
-
});
|
|
2755
|
-
this.loginTimeout = setTimeout(() => {
|
|
2756
|
-
if (this.loginSession.active) {
|
|
2757
|
-
this.loginSession.error = "Login timed out (5 minutes). Please try again.";
|
|
2758
|
-
this.cleanupLogin();
|
|
2611
|
+
if (!opened) {
|
|
2612
|
+
return {
|
|
2613
|
+
success: false,
|
|
2614
|
+
message: `Could not find a terminal emulator. Please run "${cmd}" manually in your terminal.`
|
|
2615
|
+
};
|
|
2759
2616
|
}
|
|
2760
|
-
}, 5 * 60 * 1e3);
|
|
2761
|
-
} catch (err) {
|
|
2762
|
-
this.loginSession.active = false;
|
|
2763
|
-
this.loginSession.error = err instanceof Error ? err.message : "Failed to start login";
|
|
2764
|
-
}
|
|
2765
|
-
return this.loginSession;
|
|
2766
|
-
}
|
|
2767
|
-
getLoginState() {
|
|
2768
|
-
return { ...this.loginSession };
|
|
2769
|
-
}
|
|
2770
|
-
/**
|
|
2771
|
-
* Submit the authorization code that the user copied from the browser.
|
|
2772
|
-
* This writes the code to the Firebase CLI process stdin.
|
|
2773
|
-
*/
|
|
2774
|
-
submitAuthCode(code) {
|
|
2775
|
-
if (!this.loginProcess || !this.loginProcess.stdin) {
|
|
2776
|
-
return { success: false, message: "No active login process. Please start login again." };
|
|
2777
|
-
}
|
|
2778
|
-
if (!code || !code.trim()) {
|
|
2779
|
-
return { success: false, message: "Authorization code is required." };
|
|
2780
|
-
}
|
|
2781
|
-
try {
|
|
2782
|
-
this.loginProcess.stdin.write(code.trim() + "\n");
|
|
2783
|
-
this.loginSession.waitingForCode = false;
|
|
2784
|
-
return { success: true, message: "Authorization code submitted. Waiting for verification..." };
|
|
2785
|
-
} catch (err) {
|
|
2786
|
-
return { success: false, message: "Failed to submit code: " + (err instanceof Error ? err.message : "unknown error") };
|
|
2787
|
-
}
|
|
2788
|
-
}
|
|
2789
|
-
cancelLogin() {
|
|
2790
|
-
this.cleanupLogin();
|
|
2791
|
-
this.loginSession.error = "Login cancelled by user.";
|
|
2792
|
-
}
|
|
2793
|
-
cleanupLogin() {
|
|
2794
|
-
if (this.loginProcess) {
|
|
2795
|
-
try {
|
|
2796
|
-
this.loginProcess.kill("SIGTERM");
|
|
2797
|
-
} catch {
|
|
2798
2617
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2618
|
+
return {
|
|
2619
|
+
success: true,
|
|
2620
|
+
message: "Terminal window opened. Please complete the login in the new terminal."
|
|
2621
|
+
};
|
|
2622
|
+
} catch (err) {
|
|
2623
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
2624
|
+
return {
|
|
2625
|
+
success: false,
|
|
2626
|
+
message: `Failed to open terminal: ${msg}. Please run "${cmd}" manually in your terminal.`
|
|
2627
|
+
};
|
|
2804
2628
|
}
|
|
2805
|
-
this.loginSession.active = false;
|
|
2806
|
-
this.loginSession.waitingForCode = false;
|
|
2807
2629
|
}
|
|
2808
2630
|
// ─── Project Listing ───────────────────────────────────────────────
|
|
2809
2631
|
async listProjects() {
|
|
@@ -2897,7 +2719,6 @@ var FirebaseSetup = class {
|
|
|
2897
2719
|
}
|
|
2898
2720
|
/** Cleanup resources */
|
|
2899
2721
|
destroy() {
|
|
2900
|
-
this.cleanupLogin();
|
|
2901
2722
|
}
|
|
2902
2723
|
};
|
|
2903
2724
|
|
|
@@ -3820,36 +3641,8 @@ ${liveReloadScript}
|
|
|
3820
3641
|
reauth = !!data.reauth;
|
|
3821
3642
|
} catch {
|
|
3822
3643
|
}
|
|
3823
|
-
const
|
|
3824
|
-
sendJson(
|
|
3825
|
-
});
|
|
3826
|
-
return;
|
|
3827
|
-
}
|
|
3828
|
-
if (url.pathname === "/__dev/setup/login-state" && req.method === "GET") {
|
|
3829
|
-
sendJson(this.firebaseSetup.getLoginState());
|
|
3830
|
-
return;
|
|
3831
|
-
}
|
|
3832
|
-
if (url.pathname === "/__dev/setup/cancel-login" && req.method === "POST") {
|
|
3833
|
-
this.firebaseSetup.cancelLogin();
|
|
3834
|
-
sendJson({ ok: true });
|
|
3835
|
-
return;
|
|
3836
|
-
}
|
|
3837
|
-
if (url.pathname === "/__dev/setup/submit-auth-code" && req.method === "POST") {
|
|
3838
|
-
let body = "";
|
|
3839
|
-
req.on("data", (chunk) => {
|
|
3840
|
-
body += chunk;
|
|
3841
|
-
});
|
|
3842
|
-
req.on("end", () => {
|
|
3843
|
-
try {
|
|
3844
|
-
const data = JSON.parse(body);
|
|
3845
|
-
if (!data.code) {
|
|
3846
|
-
sendJson({ success: false, message: "code is required" }, 400);
|
|
3847
|
-
return;
|
|
3848
|
-
}
|
|
3849
|
-
sendJson(this.firebaseSetup.submitAuthCode(data.code));
|
|
3850
|
-
} catch {
|
|
3851
|
-
sendJson({ success: false, message: "Invalid JSON body" }, 400);
|
|
3852
|
-
}
|
|
3644
|
+
const result = this.firebaseSetup.openLoginTerminal(reauth);
|
|
3645
|
+
sendJson(result);
|
|
3853
3646
|
});
|
|
3854
3647
|
return;
|
|
3855
3648
|
}
|