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.
Files changed (2) hide show
  1. package/dist/index.js +81 -28
  2. 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://relion.dev";
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 ?? "https://relion.dev";
608
+ const apiUrl = (flags.url ?? process.env.RELION_API_URL ?? DEFAULT_API_URL2).replace(/\/$/, "");
605
609
  if (flags.token) {
606
- await saveToken(flags.token, apiUrl);
610
+ await saveAndVerifyToken(flags.token, apiUrl);
607
611
  return;
608
612
  }
609
- const loginUrl = `${apiUrl}/settings/tokens`;
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
- console.log(`Create an API token at:
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.bold("Relion Login")}
624
+ ${color.dim("If it doesn't open automatically, visit:")}`);
625
+ console.log(` ${color.cyan(authUrl)}
623
626
  `);
624
- printInfo("Verifying token...");
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.replace(/\/$/, "")}/api/cli/whoami`, {
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.", "Create a new token at " + apiUrl + "/settings/tokens");
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({ ...existing, token, apiUrl: apiUrl !== "https://relion.dev" ? apiUrl : void 0, email });
643
- console.log(`${color.green("\u2713")} ${color.bold("Authenticated")}${email ? ` as ${email}` : ""}`);
644
- console.log(`${color.dim(" Token saved to ~/.relion/config.json")}
645
- `);
646
- console.log(`Run: ${color.cyan("relion scan .")}
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 ?? "https://relion.dev";
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.replace(/\/$/, "")}/api/cli/whoami`, {
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.email) console.log(` Email: ${data.email}`);
674
- if (data.workspace) console.log(` Workspace: ${data.workspace}`);
675
- console.log(` API: ${apiUrl}
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://relion.dev/docs/cli")}
1040
+ ${color.dim("https://relionapi.com/predeploy-review/guide")}
988
1041
  `);
989
1042
  }
990
1043
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relionhq",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Relion CLI — pre-deploy API risk detection and monitoring client.",
5
5
  "license": "MIT",
6
6
  "bin": {