@synkro-sh/cli 1.0.3 → 1.0.5
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/bootstrap.js +104 -108
- package/dist/bootstrap.js.map +1 -1
- package/package.json +4 -2
package/dist/bootstrap.js
CHANGED
|
@@ -1595,22 +1595,26 @@ import { createServer } from "http";
|
|
|
1595
1595
|
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
1596
1596
|
import { homedir as homedir3, platform } from "os";
|
|
1597
1597
|
import { join as join3, dirname as dirname3 } from "path";
|
|
1598
|
-
import {
|
|
1598
|
+
import { execFile } from "child_process";
|
|
1599
1599
|
import jwt from "jsonwebtoken";
|
|
1600
1600
|
function openBrowser(url) {
|
|
1601
1601
|
const os = platform();
|
|
1602
|
-
let
|
|
1602
|
+
let bin;
|
|
1603
|
+
let args2;
|
|
1603
1604
|
switch (os) {
|
|
1604
1605
|
case "darwin":
|
|
1605
|
-
|
|
1606
|
+
bin = "open";
|
|
1607
|
+
args2 = [url];
|
|
1606
1608
|
break;
|
|
1607
1609
|
case "win32":
|
|
1608
|
-
|
|
1610
|
+
bin = "cmd";
|
|
1611
|
+
args2 = ["/c", "start", "", url];
|
|
1609
1612
|
break;
|
|
1610
1613
|
default:
|
|
1611
|
-
|
|
1614
|
+
bin = "xdg-open";
|
|
1615
|
+
args2 = [url];
|
|
1612
1616
|
}
|
|
1613
|
-
|
|
1617
|
+
execFile(bin, args2, (error) => {
|
|
1614
1618
|
if (error) {
|
|
1615
1619
|
console.error("Failed to open browser automatically.");
|
|
1616
1620
|
console.log(`Please open this URL manually: ${url}`);
|
|
@@ -1637,14 +1641,30 @@ function loadCredentials() {
|
|
|
1637
1641
|
}
|
|
1638
1642
|
function createCallbackServer() {
|
|
1639
1643
|
const CORS_HEADERS = {
|
|
1640
|
-
"Access-Control-Allow-Origin":
|
|
1641
|
-
"Access-Control-Allow-Methods": "
|
|
1642
|
-
"Access-Control-Allow-Headers": "
|
|
1644
|
+
"Access-Control-Allow-Origin": SYNKRO_WEB_AUTH_URL,
|
|
1645
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
1646
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
1647
|
+
"Vary": "Origin"
|
|
1643
1648
|
};
|
|
1644
1649
|
return new Promise((resolve2, reject) => {
|
|
1645
1650
|
const server = createServer((req, res) => {
|
|
1646
1651
|
if (req.method === "OPTIONS") {
|
|
1647
|
-
|
|
1652
|
+
const origin = req.headers.origin;
|
|
1653
|
+
if (origin === SYNKRO_WEB_AUTH_URL) {
|
|
1654
|
+
res.writeHead(204, CORS_HEADERS);
|
|
1655
|
+
} else {
|
|
1656
|
+
res.writeHead(204, {
|
|
1657
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
1658
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
1659
|
+
"Vary": "Origin"
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
res.end();
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
const reqOrigin = req.headers.origin;
|
|
1666
|
+
if (reqOrigin && reqOrigin !== SYNKRO_WEB_AUTH_URL) {
|
|
1667
|
+
res.writeHead(403, { "Vary": "Origin" });
|
|
1648
1668
|
res.end();
|
|
1649
1669
|
return;
|
|
1650
1670
|
}
|
|
@@ -1659,35 +1679,78 @@ function createCallbackServer() {
|
|
|
1659
1679
|
res.end();
|
|
1660
1680
|
return;
|
|
1661
1681
|
}
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
const userId = url.searchParams.get("user_id") || "";
|
|
1665
|
-
const email = url.searchParams.get("email") || "";
|
|
1666
|
-
const orgId = url.searchParams.get("org_id") || "";
|
|
1667
|
-
const state = url.searchParams.get("state") || "";
|
|
1668
|
-
if (!token) {
|
|
1669
|
-
res.writeHead(400, { ...CORS_HEADERS, "Content-Type": "text/html" });
|
|
1682
|
+
if (req.method !== "POST") {
|
|
1683
|
+
res.writeHead(405, { ...CORS_HEADERS, "Allow": "POST, OPTIONS", "Content-Type": "text/html" });
|
|
1670
1684
|
res.end(ERROR_HTML);
|
|
1671
|
-
setTimeout(() => {
|
|
1672
|
-
server.close();
|
|
1673
|
-
reject(new Error("Authentication failed: missing token in callback"));
|
|
1674
|
-
}, 500);
|
|
1675
1685
|
return;
|
|
1676
1686
|
}
|
|
1677
|
-
const
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1687
|
+
const MAX_BODY = 16 * 1024;
|
|
1688
|
+
const chunks = [];
|
|
1689
|
+
let total = 0;
|
|
1690
|
+
let aborted = false;
|
|
1691
|
+
req.on("data", (chunk) => {
|
|
1692
|
+
if (aborted) return;
|
|
1693
|
+
total += chunk.length;
|
|
1694
|
+
if (total > MAX_BODY) {
|
|
1695
|
+
aborted = true;
|
|
1696
|
+
res.writeHead(413, CORS_HEADERS);
|
|
1697
|
+
res.end();
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
chunks.push(chunk);
|
|
1701
|
+
});
|
|
1702
|
+
req.on("end", () => {
|
|
1703
|
+
if (aborted) return;
|
|
1704
|
+
let parsed;
|
|
1705
|
+
try {
|
|
1706
|
+
parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
1707
|
+
} catch {
|
|
1708
|
+
res.writeHead(400, { ...CORS_HEADERS, "Content-Type": "application/json" });
|
|
1709
|
+
res.end(JSON.stringify({ error: "invalid_json" }));
|
|
1710
|
+
setTimeout(() => {
|
|
1711
|
+
server.close();
|
|
1712
|
+
reject(new Error("Authentication failed: invalid JSON body"));
|
|
1713
|
+
}, 200);
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const token = parsed?.token;
|
|
1717
|
+
if (!token || typeof token !== "string") {
|
|
1718
|
+
res.writeHead(400, { ...CORS_HEADERS, "Content-Type": "application/json" });
|
|
1719
|
+
res.end(JSON.stringify({ error: "missing_token" }));
|
|
1720
|
+
setTimeout(() => {
|
|
1721
|
+
server.close();
|
|
1722
|
+
reject(new Error("Authentication failed: missing token"));
|
|
1723
|
+
}, 200);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
const authData = {
|
|
1727
|
+
access_token: token,
|
|
1728
|
+
refresh_token: typeof parsed.refresh_token === "string" ? parsed.refresh_token : "",
|
|
1729
|
+
user_id: typeof parsed.user_id === "string" ? parsed.user_id : void 0,
|
|
1730
|
+
email: typeof parsed.email === "string" ? parsed.email : void 0,
|
|
1731
|
+
org_id: typeof parsed.org_id === "string" ? parsed.org_id : void 0,
|
|
1732
|
+
state: typeof parsed.state === "string" ? parsed.state : void 0
|
|
1733
|
+
};
|
|
1734
|
+
res.writeHead(200, { ...CORS_HEADERS, "Content-Type": "application/json" });
|
|
1735
|
+
res.end(JSON.stringify({ ok: true }));
|
|
1736
|
+
setTimeout(() => {
|
|
1737
|
+
server.close();
|
|
1738
|
+
resolve2(authData);
|
|
1739
|
+
}, 200);
|
|
1740
|
+
});
|
|
1741
|
+
req.on("error", (e) => {
|
|
1742
|
+
if (aborted) return;
|
|
1743
|
+
aborted = true;
|
|
1744
|
+
try {
|
|
1745
|
+
res.writeHead(500, CORS_HEADERS);
|
|
1746
|
+
res.end();
|
|
1747
|
+
} catch {
|
|
1748
|
+
}
|
|
1749
|
+
setTimeout(() => {
|
|
1750
|
+
server.close();
|
|
1751
|
+
reject(e);
|
|
1752
|
+
}, 200);
|
|
1753
|
+
});
|
|
1691
1754
|
});
|
|
1692
1755
|
server.listen(PORT);
|
|
1693
1756
|
server.on("error", (error) => {
|
|
@@ -1765,80 +1828,13 @@ function clearCredentials() {
|
|
|
1765
1828
|
unlinkSync2(AUTH_FILE);
|
|
1766
1829
|
}
|
|
1767
1830
|
}
|
|
1768
|
-
var PORT, SYNKRO_WEB_AUTH_URL, AUTH_FILE,
|
|
1831
|
+
var PORT, SYNKRO_WEB_AUTH_URL, AUTH_FILE, ERROR_HTML;
|
|
1769
1832
|
var init_stub = __esm({
|
|
1770
1833
|
"cli/auth/stub.ts"() {
|
|
1771
1834
|
"use strict";
|
|
1772
1835
|
PORT = 8100;
|
|
1773
|
-
SYNKRO_WEB_AUTH_URL = process.env.SYNKRO_WEB_AUTH_URL || "
|
|
1836
|
+
SYNKRO_WEB_AUTH_URL = process.env.SYNKRO_WEB_AUTH_URL || "https://app.synkro.sh";
|
|
1774
1837
|
AUTH_FILE = process.env.SYNKRO_AUTH_FILE || join3(homedir3(), ".synkro", "credentials.json");
|
|
1775
|
-
SUCCESS_HTML = `
|
|
1776
|
-
<!DOCTYPE html>
|
|
1777
|
-
<html>
|
|
1778
|
-
<head>
|
|
1779
|
-
<title>Authentication Successful - Synkro CLI</title>
|
|
1780
|
-
<style>
|
|
1781
|
-
body {
|
|
1782
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
1783
|
-
display: flex;
|
|
1784
|
-
justify-content: center;
|
|
1785
|
-
align-items: center;
|
|
1786
|
-
height: 100vh;
|
|
1787
|
-
margin: 0;
|
|
1788
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
1789
|
-
}
|
|
1790
|
-
.container {
|
|
1791
|
-
background: white;
|
|
1792
|
-
padding: 3rem;
|
|
1793
|
-
border-radius: 1rem;
|
|
1794
|
-
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
1795
|
-
text-align: center;
|
|
1796
|
-
max-width: 400px;
|
|
1797
|
-
}
|
|
1798
|
-
.checkmark {
|
|
1799
|
-
width: 80px;
|
|
1800
|
-
height: 80px;
|
|
1801
|
-
border-radius: 50%;
|
|
1802
|
-
background: #10b981;
|
|
1803
|
-
margin: 0 auto 1.5rem;
|
|
1804
|
-
display: flex;
|
|
1805
|
-
align-items: center;
|
|
1806
|
-
justify-content: center;
|
|
1807
|
-
}
|
|
1808
|
-
.checkmark svg {
|
|
1809
|
-
width: 50px;
|
|
1810
|
-
height: 50px;
|
|
1811
|
-
stroke: white;
|
|
1812
|
-
}
|
|
1813
|
-
h1 {
|
|
1814
|
-
color: #1f2937;
|
|
1815
|
-
margin: 0 0 0.5rem;
|
|
1816
|
-
}
|
|
1817
|
-
p {
|
|
1818
|
-
color: #6b7280;
|
|
1819
|
-
margin: 0;
|
|
1820
|
-
}
|
|
1821
|
-
.close-note {
|
|
1822
|
-
margin-top: 1.5rem;
|
|
1823
|
-
font-size: 0.875rem;
|
|
1824
|
-
color: #9ca3af;
|
|
1825
|
-
}
|
|
1826
|
-
</style>
|
|
1827
|
-
</head>
|
|
1828
|
-
<body>
|
|
1829
|
-
<div class="container">
|
|
1830
|
-
<div class="checkmark">
|
|
1831
|
-
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1832
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path>
|
|
1833
|
-
</svg>
|
|
1834
|
-
</div>
|
|
1835
|
-
<h1>Authentication Successful!</h1>
|
|
1836
|
-
<p>Your Synkro CLI has been authenticated.</p>
|
|
1837
|
-
<p class="close-note">You can close this window and return to your terminal.</p>
|
|
1838
|
-
</div>
|
|
1839
|
-
</body>
|
|
1840
|
-
</html>
|
|
1841
|
-
`;
|
|
1842
1838
|
ERROR_HTML = `
|
|
1843
1839
|
<!DOCTYPE html>
|
|
1844
1840
|
<html>
|
|
@@ -1966,7 +1962,7 @@ function writeConfigEnv(opts) {
|
|
|
1966
1962
|
`SYNKRO_GATEWAY_URL=${shellQuoteSingle(safeGateway)}`,
|
|
1967
1963
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
1968
1964
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
1969
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.0.
|
|
1965
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.0.5")}`
|
|
1970
1966
|
];
|
|
1971
1967
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
1972
1968
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|
|
@@ -1998,7 +1994,7 @@ function assertGatewayAllowed(gatewayUrl) {
|
|
|
1998
1994
|
}
|
|
1999
1995
|
}
|
|
2000
1996
|
async function installCommand(opts = {}) {
|
|
2001
|
-
const gatewayUrl = opts.gatewayUrl || process.env.SYNKRO_GATEWAY_URL || "
|
|
1997
|
+
const gatewayUrl = opts.gatewayUrl || process.env.SYNKRO_GATEWAY_URL || "https://api.synkro.sh";
|
|
2002
1998
|
try {
|
|
2003
1999
|
assertGatewayAllowed(gatewayUrl);
|
|
2004
2000
|
} catch (err) {
|
|
@@ -2028,7 +2024,7 @@ async function installCommand(opts = {}) {
|
|
|
2028
2024
|
}
|
|
2029
2025
|
});
|
|
2030
2026
|
if (!result) {
|
|
2031
|
-
console.error("Authentication failed.
|
|
2027
|
+
console.error("Authentication failed. If you are running a self-hosted dashboard, set SYNKRO_WEB_AUTH_URL to its origin.");
|
|
2032
2028
|
process.exit(1);
|
|
2033
2029
|
}
|
|
2034
2030
|
}
|