@reporting-bi/cli 0.1.14 → 0.1.16

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 +116 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9315,6 +9315,7 @@ var require_dist = __commonJS({
9315
9315
  // src/commands/login.ts
9316
9316
  var http = __toESM(require("node:http"));
9317
9317
  var import_node_child_process2 = require("node:child_process");
9318
+ var readline = __toESM(require("node:readline"));
9318
9319
 
9319
9320
  // src/config.ts
9320
9321
  var fs2 = __toESM(require("node:fs"));
@@ -10397,23 +10398,67 @@ var callback_default = `<!DOCTYPE html>
10397
10398
  function renderCallback(status6, title, message) {
10398
10399
  return callback_default.replace("{{status}}", status6).replace("{{title}}", title).replace("{{message}}", message);
10399
10400
  }
10400
- function openBrowser(url2) {
10401
+ function canOpenBrowser() {
10402
+ const env = process.env;
10403
+ if (process.platform === "linux" || process.platform === "freebsd" || process.platform === "openbsd") {
10404
+ return !!(env.DISPLAY || env.WAYLAND_DISPLAY);
10405
+ }
10406
+ return !(env.SSH_CONNECTION || env.SSH_TTY);
10407
+ }
10408
+ function openBrowser(url2, onError) {
10401
10409
  const platform = process.platform;
10402
10410
  const cmd = platform === "darwin" ? "open" : platform === "win32" ? 'start ""' : "xdg-open";
10403
- (0, import_node_child_process2.exec)(`${cmd} ${JSON.stringify(url2)}`);
10411
+ (0, import_node_child_process2.exec)(`${cmd} ${JSON.stringify(url2)}`, (err) => {
10412
+ if (err) onError();
10413
+ });
10414
+ }
10415
+ function parsePastedCode(input) {
10416
+ const text2 = input.trim();
10417
+ if (!text2) return {};
10418
+ if (/[?&](code|error)=/.test(text2)) {
10419
+ const params3 = new URL(text2, "http://localhost").searchParams;
10420
+ return { code: params3.get("code") || void 0, error: params3.get("error") || void 0 };
10421
+ }
10422
+ return { code: text2 };
10423
+ }
10424
+ async function resolveDomain(domain2) {
10425
+ let origin = new URL(domain2).origin;
10426
+ for (let i = 0; i < 5; i++) {
10427
+ let res;
10428
+ try {
10429
+ res = await fetch(`${origin}/auth/info`, { method: "HEAD", redirect: "manual" });
10430
+ } catch {
10431
+ return origin;
10432
+ }
10433
+ const location = res.headers.get("location");
10434
+ if (res.status < 300 || res.status >= 400 || !location) return origin;
10435
+ const next = new URL(location, origin).origin;
10436
+ if (next === origin) return origin;
10437
+ origin = next;
10438
+ }
10439
+ return origin;
10404
10440
  }
10405
10441
  async function login(args) {
10406
10442
  const { positional, flags } = parseArgs(args);
10407
- const domain2 = positional[0] || "https://reporting.bi";
10443
+ const requested = positional[0] || "https://bi.reporting.eu";
10444
+ const domain2 = await resolveDomain(requested);
10408
10445
  const accounting2 = flags.accounting ? parseInt(flags.accounting) : void 0;
10409
- console.log(`Logging in to ${domain2}...`);
10410
- const code = await getAuthorizationCode(domain2);
10446
+ const port = flags.port ? parseInt(flags.port) : 0;
10447
+ const browser = flags["no-browser"] !== "true" && canOpenBrowser();
10448
+ console.log(`Logging in to ${domain2}${domain2 !== requested.replace(/\/+$/, "") ? ` (redirected from ${requested})` : ""}...`);
10449
+ const code = await getAuthorizationCode(domain2, port, browser);
10411
10450
  if (!code) {
10412
10451
  console.error("Login cancelled or timed out.");
10413
10452
  process.exit(1);
10414
10453
  }
10415
10454
  const client = createAuthClient(domain2);
10416
- await client.authorize(code);
10455
+ try {
10456
+ await client.authorize(code);
10457
+ } catch (e) {
10458
+ const data = e.data;
10459
+ console.error(`Login failed: ${data?.error_description || data?.error || e.message}${data?.status ? ` (HTTP ${data.status})` : ""}`);
10460
+ process.exit(1);
10461
+ }
10417
10462
  const credentials = await client.readCredentials();
10418
10463
  if (!credentials?.access_token) {
10419
10464
  console.error("Failed to obtain tokens.");
@@ -10440,12 +10485,17 @@ async function login(args) {
10440
10485
  console.log('No accounting set. Use "rpbi use <domain> --accounting <id>" to set one.');
10441
10486
  }
10442
10487
  }
10443
- function getAuthorizationCode(domain2) {
10488
+ function getAuthorizationCode(domain2, port, browser) {
10444
10489
  return new Promise((resolve8) => {
10445
10490
  let timeout;
10491
+ let rl;
10492
+ let finished = false;
10446
10493
  const done = (result) => {
10494
+ if (finished) return;
10495
+ finished = true;
10447
10496
  clearTimeout(timeout);
10448
10497
  server.close();
10498
+ rl?.close();
10449
10499
  resolve8(result);
10450
10500
  };
10451
10501
  const server = http.createServer((req, res) => {
@@ -10463,17 +10513,57 @@ function getAuthorizationCode(domain2) {
10463
10513
  res.end("Waiting for authentication...");
10464
10514
  }
10465
10515
  });
10466
- server.listen(0, "localhost", () => {
10516
+ server.on("error", (err) => {
10517
+ console.error(`Cannot listen for the login callback: ${err.message}`);
10518
+ done(null);
10519
+ });
10520
+ server.listen(port, "localhost", () => {
10467
10521
  const address = server.address();
10468
10522
  if (!address || typeof address === "string") {
10469
10523
  done(null);
10470
10524
  return;
10471
10525
  }
10472
- const port = address.port;
10473
- const redirectUri = `http://localhost:${port}`;
10526
+ const redirectUri = `http://localhost:${address.port}`;
10474
10527
  const authUrl = `${domain2}/auth?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(redirectUri)}`;
10475
- console.log(`Opening browser for authentication...`);
10476
- openBrowser(authUrl);
10528
+ const printManual = () => {
10529
+ console.log("Open this URL in a browser and sign in:");
10530
+ console.log("");
10531
+ console.log(` ${authUrl}`);
10532
+ console.log("");
10533
+ if (process.stdin.isTTY) {
10534
+ console.log(`The browser then goes to ${redirectUri}/?code=... - if that page does not load`);
10535
+ console.log("(the browser runs on another machine), copy its whole address from the address bar");
10536
+ console.log("and paste it here.");
10537
+ }
10538
+ };
10539
+ if (browser) {
10540
+ console.log("Opening browser for authentication...");
10541
+ console.log(`If it does not open, visit: ${authUrl}`);
10542
+ openBrowser(authUrl, () => {
10543
+ console.log("Could not open a browser.");
10544
+ printManual();
10545
+ });
10546
+ } else {
10547
+ printManual();
10548
+ }
10549
+ if (process.stdin.isTTY) {
10550
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false });
10551
+ rl.on("line", (line) => {
10552
+ let pasted;
10553
+ try {
10554
+ pasted = parsePastedCode(line);
10555
+ } catch {
10556
+ console.error("Not a valid address, paste the whole URL from the address bar.");
10557
+ return;
10558
+ }
10559
+ if (pasted.error) {
10560
+ console.error(`Login failed: ${pasted.error}`);
10561
+ done(null);
10562
+ } else if (pasted.code) {
10563
+ done(pasted.code);
10564
+ }
10565
+ });
10566
+ }
10477
10567
  });
10478
10568
  timeout = setTimeout(() => done(null), 5 * 60 * 1e3);
10479
10569
  });
@@ -36588,7 +36678,7 @@ async function mcp() {
36588
36678
  setMcpMode();
36589
36679
  const server = new McpServer({
36590
36680
  name: "reporting-bi",
36591
- version: "0.1.14"
36681
+ version: "0.1.16"
36592
36682
  });
36593
36683
  server.tool(
36594
36684
  "status",
@@ -37129,8 +37219,8 @@ async function checkForUpdate() {
37129
37219
  saveUpdateCheck({ lastCheck: now });
37130
37220
  const latest = await fetchLatestVersion();
37131
37221
  if (!latest) return;
37132
- if (!isNewer(latest, "0.1.14")) return;
37133
- console.error(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.1.14"} \u2192 ${latest}...\x1B[0m`);
37222
+ if (!isNewer(latest, "0.1.16")) return;
37223
+ console.error(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.1.16"} \u2192 ${latest}...\x1B[0m`);
37134
37224
  (0, import_node_child_process3.execSync)(npmInstallCmd(latest), { stdio: ["ignore", 2, 2] });
37135
37225
  console.error(`\x1B[32mUpdated to ${latest}.\x1B[0m`);
37136
37226
  } catch {
@@ -37142,11 +37232,11 @@ async function forceUpdate() {
37142
37232
  console.error("Could not fetch latest version from npm.");
37143
37233
  process.exit(1);
37144
37234
  }
37145
- if (!isNewer(latest, "0.1.14")) {
37146
- console.log(`Already up to date (${"0.1.14"}).`);
37235
+ if (!isNewer(latest, "0.1.16")) {
37236
+ console.log(`Already up to date (${"0.1.16"}).`);
37147
37237
  return;
37148
37238
  }
37149
- console.log(`Updating ${PACKAGE_NAME} ${"0.1.14"} \u2192 ${latest}...`);
37239
+ console.log(`Updating ${PACKAGE_NAME} ${"0.1.16"} \u2192 ${latest}...`);
37150
37240
  (0, import_node_child_process3.execSync)(npmInstallCmd(latest), { stdio: "inherit" });
37151
37241
  console.log(`\x1B[32mUpdated to ${latest}.\x1B[0m`);
37152
37242
  saveUpdateCheck({ lastCheck: Date.now() });
@@ -37167,7 +37257,10 @@ pull removes local files deleted on the server (a locally modified file is kept)
37167
37257
  deletes on the server what was deleted locally \u2014 single files or whole folders.
37168
37258
 
37169
37259
  Commands:
37170
- login [domain] [--accounting <id>] Login to a Reporting.bi instance (opens browser)
37260
+ login [domain] [--accounting <id>] [--no-browser] [--port <n>]
37261
+ Login to a Reporting.bi instance (opens browser; without a
37262
+ display prints the URL - paste back the address the browser
37263
+ ends at, or forward --port over SSH)
37171
37264
  logout [domain] Logout and revoke tokens (default: active connection)
37172
37265
  use <domain> [--accounting <id>] Switch active connection and/or set accounting
37173
37266
  status [--json] Show all connections, token and session expiry
@@ -37284,12 +37377,12 @@ Global options:
37284
37377
  --filter <expression> Filter results (server-side where clause)
37285
37378
  --verbose Show API request URLs for debugging
37286
37379
 
37287
- Default domain: https://reporting.bi
37380
+ Default domain: https://bi.reporting.eu
37288
37381
  Default language: cs
37289
37382
 
37290
37383
  Examples:
37291
- rpbi login https://reporting.bi --accounting 100000
37292
- rpbi use https://reporting.bi --accounting 100000
37384
+ rpbi login https://bi.reporting.eu --accounting 100000
37385
+ rpbi use https://bi.reporting.eu --accounting 100000
37293
37386
  rpbi status
37294
37387
 
37295
37388
  rpbi etl list
@@ -37337,7 +37430,7 @@ Examples:
37337
37430
  (async () => {
37338
37431
  const [command, ...args] = process.argv.slice(2);
37339
37432
  if (command === "--version" || command === "-v") {
37340
- console.log("0.1.14");
37433
+ console.log("0.1.16");
37341
37434
  return;
37342
37435
  }
37343
37436
  await checkForUpdate();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reporting-bi/cli",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Reporting.bi CLI — command-line interface for the Reporting.bi platform",
6
6
  "main": "./dist/index.js",