relionhq 2.0.0 → 2.0.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/index.js +81 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ var path = __toESM(require("path"));
|
|
|
32
32
|
var os = __toESM(require("os"));
|
|
33
33
|
var GLOBAL_CONFIG_DIR = path.join(os.homedir(), ".relion");
|
|
34
34
|
var GLOBAL_CONFIG_PATH = path.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
35
|
-
var DEFAULT_API_URL = "https://
|
|
35
|
+
var DEFAULT_API_URL = "https://relionapi.com";
|
|
36
36
|
function readGlobalConfig() {
|
|
37
37
|
try {
|
|
38
38
|
const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf8");
|
|
@@ -600,35 +600,85 @@ async function verifyToken(token, apiUrl) {
|
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
// src/commands/login.ts
|
|
603
|
+
var http = __toESM(require("http"));
|
|
604
|
+
var net = __toESM(require("net"));
|
|
605
|
+
var import_child_process2 = require("child_process");
|
|
606
|
+
var DEFAULT_API_URL2 = "https://relionapi.com";
|
|
603
607
|
async function loginCommand(flags) {
|
|
604
|
-
const apiUrl = flags.url ?? process.env.RELION_API_URL ??
|
|
608
|
+
const apiUrl = (flags.url ?? process.env.RELION_API_URL ?? DEFAULT_API_URL2).replace(/\/$/, "");
|
|
605
609
|
if (flags.token) {
|
|
606
|
-
await
|
|
610
|
+
await saveAndVerifyToken(flags.token, apiUrl);
|
|
607
611
|
return;
|
|
608
612
|
}
|
|
609
|
-
|
|
613
|
+
await browserLogin(apiUrl);
|
|
614
|
+
}
|
|
615
|
+
async function browserLogin(apiUrl) {
|
|
616
|
+
const port = await getFreePort();
|
|
617
|
+
const callbackUrl = `http://localhost:${port}`;
|
|
618
|
+
const authUrl = `${apiUrl}/cli-auth?callback=${encodeURIComponent(callbackUrl)}`;
|
|
610
619
|
console.log(`
|
|
611
620
|
${color.bold("Relion Login")}
|
|
612
621
|
`);
|
|
613
|
-
|
|
614
|
-
${color.cyan(loginUrl)}
|
|
615
|
-
`);
|
|
616
|
-
console.log(`Then run:
|
|
617
|
-
${color.dim("relion login --token <your-token>")}
|
|
618
|
-
`);
|
|
619
|
-
}
|
|
620
|
-
async function saveToken(token, apiUrl) {
|
|
622
|
+
printInfo("Opening browser for authentication\u2026");
|
|
621
623
|
console.log(`
|
|
622
|
-
${color.
|
|
624
|
+
${color.dim("If it doesn't open automatically, visit:")}`);
|
|
625
|
+
console.log(` ${color.cyan(authUrl)}
|
|
623
626
|
`);
|
|
624
|
-
|
|
627
|
+
openBrowser(authUrl);
|
|
628
|
+
const token = await waitForCallback(port);
|
|
629
|
+
if (!token) {
|
|
630
|
+
printError("Login timed out or was cancelled.", "Run relion login again.");
|
|
631
|
+
process.exit(1);
|
|
632
|
+
}
|
|
633
|
+
await saveAndVerifyToken(token, apiUrl);
|
|
634
|
+
}
|
|
635
|
+
function getFreePort() {
|
|
636
|
+
return new Promise((resolve3, reject) => {
|
|
637
|
+
const server = net.createServer();
|
|
638
|
+
server.unref();
|
|
639
|
+
server.listen(0, "127.0.0.1", () => {
|
|
640
|
+
const addr = server.address();
|
|
641
|
+
server.close(() => resolve3(addr.port));
|
|
642
|
+
});
|
|
643
|
+
server.on("error", reject);
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
function openBrowser(url) {
|
|
647
|
+
const cmd = process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
|
|
648
|
+
(0, import_child_process2.exec)(cmd, () => {
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
function waitForCallback(port, timeoutMs = 5 * 60 * 1e3) {
|
|
652
|
+
return new Promise((resolve3) => {
|
|
653
|
+
const timer = setTimeout(() => {
|
|
654
|
+
server.close();
|
|
655
|
+
resolve3(null);
|
|
656
|
+
}, timeoutMs);
|
|
657
|
+
const server = http.createServer((req, res) => {
|
|
658
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
659
|
+
const token = url.searchParams.get("token");
|
|
660
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
661
|
+
res.end(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
|
662
|
+
<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#070a12;color:#e2e8f0}
|
|
663
|
+
.box{text-align:center;padding:2rem;max-width:320px}h1{font-size:1.1rem;margin-bottom:.5rem;color:#4fd1c5}p{font-size:.85rem;color:#94a3b8}</style>
|
|
664
|
+
</head><body><div class="box"><h1>${token ? "\u2713 Authenticated" : "\u2717 No token received"}</h1>
|
|
665
|
+
<p>${token ? "You can close this tab and return to your terminal." : "Something went wrong. Run relion login again."}</p></div></body></html>`);
|
|
666
|
+
clearTimeout(timer);
|
|
667
|
+
server.close();
|
|
668
|
+
resolve3(token ?? null);
|
|
669
|
+
});
|
|
670
|
+
server.listen(port, "127.0.0.1");
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
async function saveAndVerifyToken(token, apiUrl) {
|
|
674
|
+
printInfo("Verifying token\u2026");
|
|
625
675
|
let email;
|
|
626
676
|
try {
|
|
627
|
-
const res = await fetch(`${apiUrl
|
|
677
|
+
const res = await fetch(`${apiUrl}/api/cli/whoami`, {
|
|
628
678
|
headers: { Authorization: `Bearer ${token}` }
|
|
629
679
|
});
|
|
630
680
|
if (res.status === 401 || res.status === 403) {
|
|
631
|
-
printError("Token is invalid or revoked.",
|
|
681
|
+
printError("Token is invalid or revoked.", `Create a new token at ${apiUrl}/settings/tokens`);
|
|
632
682
|
process.exit(1);
|
|
633
683
|
}
|
|
634
684
|
if (res.ok) {
|
|
@@ -639,12 +689,15 @@ ${color.bold("Relion Login")}
|
|
|
639
689
|
console.warn(color.yellow(" Could not verify token (network issue). Saving anyway."));
|
|
640
690
|
}
|
|
641
691
|
const existing = readGlobalConfig();
|
|
642
|
-
writeGlobalConfig({
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
692
|
+
writeGlobalConfig({
|
|
693
|
+
...existing,
|
|
694
|
+
token,
|
|
695
|
+
apiUrl: apiUrl !== DEFAULT_API_URL2 ? apiUrl : void 0,
|
|
696
|
+
email
|
|
697
|
+
});
|
|
698
|
+
console.log(`
|
|
699
|
+
${color.green("\u2713")} ${color.bold("Authenticated")}${email ? ` as ${color.cyan(email)}` : ""}`);
|
|
700
|
+
console.log(color.dim(" Token saved to ~/.relion/config.json\n"));
|
|
648
701
|
}
|
|
649
702
|
async function logoutCommand() {
|
|
650
703
|
writeGlobalConfig({});
|
|
@@ -654,13 +707,13 @@ async function logoutCommand() {
|
|
|
654
707
|
async function whoamiCommand(flags) {
|
|
655
708
|
const config = readGlobalConfig();
|
|
656
709
|
const token = process.env.RELION_TOKEN ?? config.token;
|
|
657
|
-
const apiUrl = flags.url ?? config.apiUrl ??
|
|
710
|
+
const apiUrl = (flags.url ?? config.apiUrl ?? DEFAULT_API_URL2).replace(/\/$/, "");
|
|
658
711
|
if (!token) {
|
|
659
712
|
printError("Not logged in.", "Run: relion login");
|
|
660
713
|
process.exit(1);
|
|
661
714
|
}
|
|
662
715
|
try {
|
|
663
|
-
const res = await fetch(`${apiUrl
|
|
716
|
+
const res = await fetch(`${apiUrl}/api/cli/whoami`, {
|
|
664
717
|
headers: { Authorization: `Bearer ${token}` }
|
|
665
718
|
});
|
|
666
719
|
if (!res.ok) {
|
|
@@ -670,9 +723,9 @@ async function whoamiCommand(flags) {
|
|
|
670
723
|
const data = await res.json();
|
|
671
724
|
console.log(`
|
|
672
725
|
${color.bold("Relion identity")}`);
|
|
673
|
-
if (data.
|
|
674
|
-
if (data.
|
|
675
|
-
console.log(` API:
|
|
726
|
+
if (data.name) console.log(` Name: ${data.name}`);
|
|
727
|
+
if (data.email) console.log(` Email: ${data.email}`);
|
|
728
|
+
console.log(` API: ${apiUrl}
|
|
676
729
|
`);
|
|
677
730
|
} catch {
|
|
678
731
|
printError("Could not reach Relion API.", `URL: ${apiUrl}`);
|
|
@@ -984,7 +1037,7 @@ ${color.bold("Environment variables:")}
|
|
|
984
1037
|
RELION_COMMIT Git commit SHA
|
|
985
1038
|
RELION_BRANCH Branch name
|
|
986
1039
|
|
|
987
|
-
${color.dim("https://
|
|
1040
|
+
${color.dim("https://relionapi.com/predeploy-review/guide")}
|
|
988
1041
|
`);
|
|
989
1042
|
}
|
|
990
1043
|
async function main() {
|