@synapseone/cli 0.7.0 → 0.7.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/README.md CHANGED
@@ -24,7 +24,7 @@ npm link ./tools/cli # then call `synapseone ...` anywhere
24
24
  ## Quick start
25
25
 
26
26
  ```bash
27
- export SYNAPSEONE_BASE_URL=http://localhost:8080
27
+ # Defaults to https://synapseone.space (or pass --base http://localhost:8080 for local dev)
28
28
  synapseone login --email demo@acme.local
29
29
  synapseone orgs
30
30
  synapseone accounts create prod Production
@@ -33,9 +33,7 @@ synapseone workflows create --template webhook-to-log --name demo
33
33
  synapseone audit --limit 20
34
34
  ```
35
35
 
36
- Against the live demo: add `--base https://api.synapseone.space` (or
37
- `export SYNAPSEONE_BASE_URL=https://api.synapseone.space`) and sign in with an API key
38
- (`synapseone use-key <key>`).
36
+ For local container development: add `--base http://localhost:8080` (or `export SYNAPSEONE_BASE_URL=http://localhost:8080`).
39
37
 
40
38
  ## Full documentation
41
39
 
package/bin/synapseone.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2026 VKU.VIC
2
4
  /*
3
5
  * Copyright 2026 SynapseOne Contributors
4
6
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,7 +43,7 @@ function saveConfig(cfg) {
41
43
  try { fs.chmodSync(CONF_FILE, 0o600); } catch { /* non-POSIX (win) */ }
42
44
  }
43
45
  function baseUrl(opts) {
44
- return (opts.base || process.env.SYNAPSEONE_BASE_URL || process.env.SYNAPSEDX_BASE_URL || loadConfig().baseUrl || 'http://localhost:8080').replace(/\/$/, '');
46
+ return (opts.base || process.env.SYNAPSEONE_BASE_URL || process.env.SYNAPSEDX_BASE_URL || loadConfig().baseUrl || 'https://api.synapseone.space').replace(/\/$/, '');
45
47
  }
46
48
  function authHeaders(opts) {
47
49
  const cfg = loadConfig();
@@ -73,6 +75,16 @@ async function req(method, p, body, opts) {
73
75
  data = text;
74
76
  }
75
77
  if (!r.ok) throw httpError(r.status, p, data);
78
+ // A 200 HTML page means the base URL is the console/marketing host, not the
79
+ // gateway. Surface it instead of printing the SPA as if it were data.
80
+ const ctype = String(r.headers.get('content-type') || '').toLowerCase();
81
+ const looksHtml = ctype.includes('text/html') || /^\s*(<!doctype html|<html)/i.test(String(data || ''));
82
+ if (looksHtml) {
83
+ throw new Error(
84
+ `non-JSON response from ${baseUrl(opts)}${p}: received HTML (status ${r.status}). ` +
85
+ 'The base URL looks like the console host; use https://api.synapseone.space or pass --base.',
86
+ );
87
+ }
76
88
  return data;
77
89
  }
78
90
  function httpError(status, p, data) {
@@ -156,6 +168,7 @@ function parse(argv) {
156
168
  for (let i = 0; i < argv.length; i++) {
157
169
  const a = argv[i];
158
170
  if (a === '--json') opts.json = true;
171
+ else if (a === '--ready') opts.ready = true;
159
172
  else if (a === '--base' || a === '--token' || a === '--apikey') opts[a.slice(2)] = argv[++i];
160
173
  else if (a.startsWith('--base=')) opts.base = a.slice(7);
161
174
  else if (a.startsWith('--token=')) opts.token = a.slice(8);
@@ -305,6 +318,30 @@ async function cmdUseKey(o) {
305
318
  async function cmdMe(o) {
306
319
  out(await GET('/v1/auth/me', o), o);
307
320
  }
321
+ async function cmdHealth(o) {
322
+ const path = o.ready ? '/ready' : '/health';
323
+ const r = await fetch(baseUrl(o) + path, { headers: authHeaders(o) });
324
+ const text = await r.text();
325
+ let data;
326
+ try {
327
+ data = text ? JSON.parse(text) : null;
328
+ } catch {
329
+ throw new Error(`non-JSON response from ${baseUrl(o)}${path}: use https://api.synapseone.space`);
330
+ }
331
+ if (r.status >= 500 && r.status !== 503) throw httpError(r.status, path, data);
332
+ if (o.json) {
333
+ console.log(JSON.stringify(data, null, 2));
334
+ } else if (o.ready && data && Array.isArray(data.upstreams)) {
335
+ console.log(`status: ${data.status} (${data.service || 'gateway'} v${data.version || '?'})`);
336
+ for (const u of data.upstreams) {
337
+ console.log(` ${u.ok ? 'ok ' : 'FAIL'} ${u.name}${u.status ? ` status=${u.status}` : ''}${typeof u.ms === 'number' ? ` ${u.ms}ms` : ''}`);
338
+ }
339
+ } else {
340
+ for (const [k, v] of Object.entries(data || {})) console.log(`${k}: ${fmt(v)}`);
341
+ }
342
+ // Degraded readiness is a non-zero exit so probes/scripts can gate on it.
343
+ if (o.ready && data && data.status !== 'ready') process.exitCode = 3;
344
+ }
308
345
  async function cmdOrgs(o) {
309
346
  const [sub, ...rest] = o._;
310
347
  if (!sub || sub === 'list') return out(await GET('/v1/orgs', o), o, ['slug', 'display_name', 'id']);
@@ -913,6 +950,7 @@ const COMMANDS = {
913
950
  logout: { fn: async () => { saveConfig({ baseUrl: loadConfig().baseUrl }); console.log('logged out'); }, use: 'logout', doc: 'Clear saved credentials' },
914
951
  config: { fn: cmdConfig, use: 'config', doc: 'Show saved config (secrets redacted)' },
915
952
  whoami: { fn: cmdMe, use: 'whoami', doc: 'Current user (/v1/auth/me)' },
953
+ health: { fn: cmdHealth, use: 'health [--ready] [--json]', doc: 'Gateway /health or aggregate /ready (exit 3 when degraded)' },
916
954
  orgs: { fn: cmdOrgs, use: 'orgs [list|create <slug> [name]]', doc: 'Organizations' },
917
955
  accounts: { fn: cmdAccounts, use: 'accounts [org] [list] | accounts create [org] <slug> [name]', doc: 'Accounts' },
918
956
  users: { fn: cmdUsers, use: 'users [org] | users create <org> <email> [name] | users policies <user-id>', doc: 'Users + effective policies' },
@@ -942,7 +980,7 @@ function help() {
942
980
 
943
981
  Usage: synapseone [--base URL] [--token T | --apikey K] [--json] <command> [args]
944
982
 
945
- Auth defaults: --base > $SYNAPSEONE_BASE_URL > ~/.synapseone/config.json > http://localhost:8080
983
+ Auth defaults: --base > $SYNAPSEONE_BASE_URL > ~/.synapseone/config.json > https://api.synapseone.space
946
984
  `);
947
985
  const names = Object.keys(COMMANDS);
948
986
  const w = Math.max(...names.map((n) => n.length));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapseone/cli",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "license": "Apache-2.0",
5
5
  "description": "synapseone CLI - zero-dependency command line for Tier-1 PaaS (Node 18+)",
6
6
  "homepage": "https://synapseone.space",