@secondlayer/cli 10.2.0 → 10.3.0

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
@@ -10,51 +10,27 @@ sl --version
10
10
 
11
11
  ## Auth
12
12
 
13
- Two ways to authenticate:
13
+ Default API is `http://127.0.0.1:3800`. Override with `SL_API_URL`.
14
14
 
15
- - **Interactive (`sl login`)** — magic-link email → 6-digit code → session
16
- written to `~/.secondlayer/session.json`. Used for day-to-day CLI work.
17
- - **Machine / CI** — set `SL_API_KEY` to an API key created in the platform
18
- console at https://secondlayer.tools/platform/api-keys. Keys are prefixed
19
- `sk-sl_`. For a persisted headless login: `echo "$SL_API_KEY" | sl login --with-token`.
15
+ Writes against a published bind use `INSTANCE_TOKEN` from `sl init` as
16
+ `SL_API_KEY`. Loopback reads need no token.
20
17
 
21
18
  ```bash
22
- # interactive
23
- sl login
24
-
25
- # machine / CI
26
- export SL_API_KEY=sk-sl_xxxxxxxx
19
+ export SL_API_URL=http://127.0.0.1:3800
20
+ export SL_API_KEY=<INSTANCE_TOKEN>
27
21
  ```
28
22
 
29
- `sl whoami` shows the active account, the effective API URL, and the credential
30
- source (and exits non-zero when not logged in). The global `--api-key` /
31
- `--api-url` flags (and `SL_API_KEY` / `SL_API_URL`) apply to every command.
32
-
33
- During open beta, reads are public (no key needed) — for subgraphs that means
34
- **public** subgraphs only (managed deploys default public; BYO deploys and all
35
- pre-existing subgraphs are private, readable with your key). Writes — deploying,
36
- publishing, or managing subgraphs and subscriptions — require a session or an
37
- `sk-sl_` key.
38
-
39
23
  ## Quickstart
40
24
 
41
25
  ```bash
42
26
  bun add -g @secondlayer/cli
43
- sl login
44
- sl projects create my-app
45
- sl projects use my-app
27
+ sl init --network mainnet
28
+ sl start --print
29
+ # docker compose -f docker/oss/docker-compose.yml up -d
46
30
 
47
- # scaffold + deploy a subgraph from a deployed contract
48
31
  sl subgraphs scaffold SP1234ABCD.my-contract -o subgraphs/my-contract.ts
49
32
  sl subgraphs deploy subgraphs/my-contract.ts --start-block <recent-block>
50
33
  sl subgraphs query my-contract <table> --sort _block_height --order desc
51
-
52
- # wire a webhook receiver
53
- sl subscriptions create my-hook \
54
- --runtime node \
55
- --subgraph my-contract \
56
- --table <table> \
57
- --url https://<receiver-host>/webhook
58
34
  ```
59
35
 
60
36
  `sl subgraphs scaffold` writes the definition file, creates/updates
@@ -75,27 +51,6 @@ No account. Writes `.env.local`, restores history, prints the Stacks observer st
75
51
  | `sl verify [all\|raw\|decode:<name>\|subgraph:<name>] --against <manifest> [--quick\|--deep\|--anchor]` | Compare local data to a signed archive. Default target `raw`. Exit `0` clean, `1` diverged, `2` unanchored |
76
52
  | `sl repair --against <archive> [--apply]` | Plan (default) or apply an archive repair |
77
53
 
78
- ### Auth & project
79
-
80
- | Command | What it does |
81
- |---|---|
82
- | `sl login` / `sl logout` | Start or revoke a session |
83
- | `sl whoami` | Print account, credential source, and active project |
84
- | `sl keys create --product streams [--name <name>]` | Mint a scoped `streams`/`index` read key; prints the `sk-sl_` key **once**. Needs an account key in `SL_API_KEY` |
85
- | `sl projects create [name]` | Create a project |
86
- | `sl projects list` | List projects |
87
- | `sl projects use <slug>` | Bind cwd to a project (writes `./.secondlayer/project`) |
88
- | `sl projects get` | Show resolved project + source file |
89
- | `sl projects delete <slug>` (alias `rm`) | Delete a project (`-y` to skip confirm) |
90
-
91
- Project binding is per-directory: `.secondlayer/project` in cwd takes
92
- precedence over `~/.secondlayer/config.json:defaultProject`. The walk-up stops
93
- at `.git`.
94
-
95
- **Key products:** an `account` key (dashboard default) grants both `streams:read`
96
- and `index:read` and is the only key that can mint; `streams`/`index` keys are
97
- scoped reads and cannot mint (403). Minted keys inherit your plan's tier.
98
-
99
54
  ### Subgraphs
100
55
 
101
56
  | Command | What it does |
@@ -153,19 +108,17 @@ deliveries/...) operates on both kinds.
153
108
  | Command | What it does |
154
109
  |---|---|
155
110
  | `sl contracts generate [files...]` (alias `gen`) | Generate TS interfaces from Clarity contracts |
156
- | `sl context` | Print a headless orientation snapshot — account, Streams + Index tips, your subgraphs, subscriptions, and in-flight reindex operations. CLI counterpart to the MCP `secondlayer://context` resource |
111
+ | `sl context` | Instance snapshot — Streams + Index tips, subgraphs, subscriptions |
157
112
  | `sl doctor` / `sl status` | Reachability + health checks |
158
- | `sl account get` / `sl account update` | Show or update display name / bio / slug |
159
- | `sl account billing` | Show plan, subscription, trial, discounts |
160
113
  | `sl config get/set/reset/delete` | Inspect or reset local config |
161
114
 
162
115
  ## Environment variables
163
116
 
164
117
  | Var | Purpose |
165
118
  |---|---|
166
- | `SL_API_KEY` | An `sk-sl_` API key (or session token) for machine/CI use; bypasses platform resolution |
167
- | `SL_API_URL` | Point at an OSS or internal API directly, bypassing the platform |
168
- | `SL_PLATFORM_API_URL` | Override the platform API base (default `https://api.secondlayer.tools`) |
119
+ | `SL_API_KEY` | `INSTANCE_TOKEN` from `sl init` for writes. Loopback reads need no token |
120
+ | `SL_API_URL` | Instance API. Default `http://127.0.0.1:3800` |
121
+ | `SL_PLATFORM_API_URL` | Alias of `SL_API_URL` |
169
122
  | `STACKS_NETWORK` | Default network (also via `--network <local\|testnet\|mainnet>`) |
170
123
  | `HIRO_API_KEY` | Used by `sl contracts generate` for remote contract fetches |
171
124
 
package/dist/cli.js CHANGED
@@ -2580,7 +2580,7 @@ function isOssMode() {
2580
2580
  return true;
2581
2581
  }
2582
2582
  }
2583
- var LOCAL_API_URL = "http://127.0.0.1:3800";
2583
+ var LOCAL_API_URL = "http://127.0.0.1:3800", ARCHIVE_OPS_API_URL = "https://api.secondlayer.tools";
2584
2584
  var init_resolve_auth = __esm(() => {
2585
2585
  init_session();
2586
2586
  });
@@ -2629,9 +2629,28 @@ async function httpPlatform(path2, opts = {}) {
2629
2629
  async function httpPlatformAnon(path2, opts = {}) {
2630
2630
  return request(`${resolveApiUrl()}${path2}`, opts);
2631
2631
  }
2632
+ function resolveArchiveOpsUrl() {
2633
+ return (process.env.SL_CREDITS_API_URL ?? ARCHIVE_OPS_API_URL).replace(/\/+$/, "");
2634
+ }
2635
+ async function httpArchiveOpsAnon(path2, opts = {}) {
2636
+ return request(`${resolveArchiveOpsUrl()}${path2}`, opts);
2637
+ }
2638
+ async function httpArchiveOps(path2, opts = {}) {
2639
+ const envKey = resolveEnvKey();
2640
+ const session = envKey ? null : await readSession();
2641
+ const bearer = envKey ?? session?.token;
2642
+ if (!bearer) {
2643
+ throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, "Not logged in — run `SL_API_URL=https://api.secondlayer.tools sl login`");
2644
+ }
2645
+ return request(`${resolveArchiveOpsUrl()}${path2}`, {
2646
+ ...opts,
2647
+ bearer
2648
+ });
2649
+ }
2632
2650
  var CliHttpError, REQUEST_TIMEOUT_MS = 30000;
2633
2651
  var init_http = __esm(() => {
2634
2652
  init_resolve_auth();
2653
+ init_session();
2635
2654
  CliHttpError = class CliHttpError extends Error {
2636
2655
  status;
2637
2656
  code;
@@ -34787,7 +34806,7 @@ init_esm();
34787
34806
  // package.json
34788
34807
  var package_default = {
34789
34808
  name: "@secondlayer/cli",
34790
- version: "10.2.0",
34809
+ version: "10.3.0",
34791
34810
  repository: {
34792
34811
  type: "git",
34793
34812
  url: "git+https://github.com/ryanwaits/secondlayer.git",
@@ -34831,7 +34850,7 @@ var package_default = {
34831
34850
  "@secondlayer/bundler": "^0.5.0",
34832
34851
  "@secondlayer/scaffold": "^1.5.1",
34833
34852
  "@secondlayer/sdk": "^6.54.0",
34834
- "@secondlayer/shared": "^7.11.0",
34853
+ "@secondlayer/shared": "^7.11.1",
34835
34854
  "@secondlayer/stacks": "^3.3.1",
34836
34855
  "@secondlayer/subgraphs": "^3.26.4",
34837
34856
  esbuild: "^0.27.4",
@@ -34874,15 +34893,13 @@ async function runBillingStatus(json) {
34874
34893
  output({ json, data: res, human: () => renderBillingStatus(res) });
34875
34894
  }
34876
34895
  function addBillingCommand(parent) {
34877
- parent.command("billing").description("Show your plan, Stripe subscription, trial, and discounts").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
34896
+ parent.command("billing").description("Show archive credit balance (hidden; use sl credits)").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
34878
34897
  }
34879
34898
  function renderBillingStatus(res) {
34880
34899
  if (!res.subscription) {
34881
34900
  console.log(formatKeyValue([
34882
- ["Plan", "Free"],
34883
- ["Reads", dim("10 req/s · last ~24h window")],
34884
- ["Subgraphs", dim("upgrade to deploy / go private")],
34885
- ["Upgrade", dim("https://secondlayer.tools/platform/billing")]
34901
+ ["Credits", dim("sl credits balance")],
34902
+ ["Buy", dim("sl credits buy --email you@example.com --pack 25")]
34886
34903
  ]));
34887
34904
  return;
34888
34905
  }
@@ -34980,6 +34997,115 @@ function registerAccountCommand(program2) {
34980
34997
  action: "update profile"
34981
34998
  }));
34982
34999
  }
35000
+ // src/commands/credits.ts
35001
+ init_http();
35002
+ init_output();
35003
+ var PACKS = [10, 25, 50, 100];
35004
+ function parsePack(raw) {
35005
+ const n = Number(raw);
35006
+ if (!PACKS.includes(n)) {
35007
+ error(`--pack must be one of ${PACKS.join(", ")}`);
35008
+ process.exit(1);
35009
+ }
35010
+ return n;
35011
+ }
35012
+ async function runBuy(opts) {
35013
+ const email = opts.email.trim().toLowerCase();
35014
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
35015
+ error("--email must be a valid address");
35016
+ process.exit(1);
35017
+ }
35018
+ const amount = parsePack(opts.pack);
35019
+ let res;
35020
+ try {
35021
+ res = await httpArchiveOpsAnon("/api/public/credits/checkout", { method: "POST", body: { email, amount } });
35022
+ } catch (err) {
35023
+ if (err instanceof CliHttpError) {
35024
+ error(err.message);
35025
+ process.exit(1);
35026
+ }
35027
+ throw err;
35028
+ }
35029
+ output({
35030
+ json: opts.json,
35031
+ data: res,
35032
+ human: () => {
35033
+ success(`Checkout for $${amount} → ${email}`);
35034
+ console.log(res.url);
35035
+ console.log(dim("After payment: SL_API_URL=https://api.secondlayer.tools sl login && sl credits balance"));
35036
+ }
35037
+ });
35038
+ }
35039
+ async function runBalance(opts) {
35040
+ let res;
35041
+ try {
35042
+ res = await httpArchiveOps("/api/billing/status");
35043
+ } catch (err) {
35044
+ if (err instanceof CliHttpError) {
35045
+ error(err.message);
35046
+ process.exit(1);
35047
+ }
35048
+ throw err;
35049
+ }
35050
+ const micros = BigInt(res.creditsUsdMicros ?? "0");
35051
+ const usd = Number(micros) / 1e6;
35052
+ output({
35053
+ json: opts.json,
35054
+ data: { creditsUsd: usd, creditsUsdMicros: micros.toString() },
35055
+ human: () => {
35056
+ const refill = res.refill;
35057
+ console.log(formatKeyValue([
35058
+ ["Balance", `$${usd.toFixed(2)}`],
35059
+ [
35060
+ "Refill",
35061
+ refill?.belowUsd != null ? `on — below $${refill.belowUsd} buy $${refill.packUsd}` : dim("off")
35062
+ ],
35063
+ ["Buy", dim("sl credits buy --email you@example.com --pack 25")]
35064
+ ]));
35065
+ }
35066
+ });
35067
+ }
35068
+ function registerCreditsCommand(program2) {
35069
+ const credits = program2.command("credits").description("Buy and check archive credits");
35070
+ credits.command("buy").description("Open a one-time Stripe checkout for archive credits").requiredOption("--email <email>", "Receipt email; becomes the account").option("--pack <usd>", `One of ${PACKS.join(", ")}`, "25").option("--json", "Output as JSON").action((opts) => runBuy(opts));
35071
+ credits.command("balance").description("Show prepaid archive credit balance").option("--json", "Output as JSON").action((opts) => runBalance(opts));
35072
+ credits.command("refill").description("Opt-in auto-refill when the balance drops under a threshold").option("--below <usd>", "Trigger when balance is under this USD amount").option("--pack <usd>", `Pack to buy (${PACKS.join(", ")})`, "25").option("--off", "Turn auto-refill off").option("--json", "Output as JSON").action((opts) => runRefill(opts));
35073
+ }
35074
+ async function runRefill(opts) {
35075
+ if (!opts.off && opts.below === undefined) {
35076
+ await runBalance(opts);
35077
+ return;
35078
+ }
35079
+ const body = opts.off ? { belowUsd: null } : { belowUsd: Number(opts.below), packUsd: parsePack(opts.pack) };
35080
+ if (!opts.off && (!Number.isFinite(body.belowUsd) || (body.belowUsd ?? 0) < 1)) {
35081
+ error("--below must be at least 1");
35082
+ process.exit(1);
35083
+ }
35084
+ let res;
35085
+ try {
35086
+ res = await httpArchiveOps("/api/billing/refill", {
35087
+ method: "POST",
35088
+ body
35089
+ });
35090
+ } catch (err) {
35091
+ if (err instanceof CliHttpError) {
35092
+ error(err.message);
35093
+ process.exit(1);
35094
+ }
35095
+ throw err;
35096
+ }
35097
+ output({
35098
+ json: opts.json,
35099
+ data: res,
35100
+ human: () => {
35101
+ if (res.belowUsd == null) {
35102
+ success("Auto-refill off");
35103
+ return;
35104
+ }
35105
+ success(`Auto-refill on — below $${res.belowUsd} buy $${res.packUsd}`);
35106
+ }
35107
+ });
35108
+ }
34983
35109
 
34984
35110
  // src/commands/index.ts
34985
35111
  init_codegen();
@@ -35406,94 +35532,71 @@ function registerContextCommand(program2) {
35406
35532
  });
35407
35533
  }
35408
35534
  // src/commands/status.ts
35409
- init_config2();
35410
35535
  init_http();
35411
35536
  init_output();
35537
+ init_resolve_auth();
35412
35538
  function registerStatusCommand(program2) {
35413
- program2.command("status").description("Show system status").option("--json", "Output as JSON").action(async (options3) => {
35414
- const config = await loadConfig2();
35539
+ program2.command("status").description("Show local instance status").option("--json", "Output as JSON").action(async (options3) => {
35415
35540
  try {
35416
- const local = process.env.INSTANCE_MODE === "oss" || (process.env.SL_API_URL ?? "").includes("127.0.0.1") || (process.env.SL_API_URL ?? "").includes("localhost");
35417
- const status = local ? await httpPlatform("/public/status") : await httpPlatform("/status");
35541
+ const status = await httpPlatformAnon("/public/status");
35418
35542
  output({
35419
35543
  json: options3.json,
35420
35544
  data: status,
35421
- human: () => printStatus(status)
35545
+ human: () => printPublicStatus(status)
35422
35546
  });
35423
- } catch (err) {
35424
- if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED") {
35425
- console.error("Not logged in. Run: sl login");
35426
- process.exit(1);
35427
- }
35547
+ } catch {
35428
35548
  console.log("");
35429
35549
  console.log(blue("System Status"));
35430
35550
  console.log(` ${red("NOT RUNNING")}`);
35431
35551
  console.log("");
35432
- if (config.network === "local") {
35433
- console.log(dim(" API service is not running."));
35434
- console.log(dim(" Start with: sl local start"));
35435
- } else {
35436
- console.log(dim(" Can't reach the platform API."));
35437
- console.log(dim(" Check your connection or try again."));
35438
- }
35552
+ console.log(dim(` Can't reach ${resolveApiUrl()}/public/status.`));
35553
+ console.log(dim(" Start with: docker compose up -d"));
35439
35554
  console.log("");
35440
35555
  process.exit(1);
35441
35556
  }
35442
35557
  });
35443
35558
  }
35444
- function printStatus(status) {
35559
+ function printPublicStatus(status) {
35560
+ const overall = String(status.status ?? "unknown");
35561
+ const color = overall === "healthy" ? green : red;
35445
35562
  console.log("");
35446
- const statusColor = status.status === "healthy" ? green : red;
35447
35563
  console.log(blue("System Status"));
35448
- console.log(` ${statusColor(status.status.toUpperCase())}${status.network ? dim(` (${status.network})`) : ""}`);
35564
+ console.log(` ${color(overall.toUpperCase())}`);
35449
35565
  console.log("");
35450
- console.log(blue("Database"));
35451
- const dbColor = status.database.status === "ok" ? green : red;
35452
- console.log(` Status: ${dbColor(status.database.status)}`);
35453
- console.log("");
35454
- console.log(blue("Index Progress"));
35455
- if (status.indexProgress.length === 0) {
35456
- console.log(dim(" No data indexed yet"));
35457
- } else {
35458
- for (const p2 of status.indexProgress) {
35459
- const behind = p2.highestSeenBlock - p2.lastIndexedBlock;
35460
- const behindStr = behind > 0 ? yellow(` (${behind} behind)`) : green(" (synced)");
35461
- console.log(` ${p2.network}: block ${p2.lastIndexedBlock}${behindStr}`);
35462
- if (status.chainTip && status.chainTip > 0) {
35463
- const pct = Math.min(p2.lastIndexedBlock / status.chainTip * 100, 100);
35464
- const barWidth = 30;
35465
- const filled = Math.round(pct / 100 * barWidth);
35466
- const empty = barWidth - filled;
35467
- const bar = `${"█".repeat(filled)}${"░".repeat(empty)}`;
35468
- const pctStr = `${pct.toFixed(1)}%`;
35469
- const color = pct >= 99.9 ? green : pct >= 50 ? yellow : red;
35470
- console.log(` ${dim("chain:")} ${color(bar)} ${color(pctStr)} ${dim(`(tip: ${status.chainTip.toLocaleString()})`)}`);
35471
- }
35472
- const contiguous = p2.lastContiguousBlock ?? 0;
35473
- if (status.integrity === "complete") {
35474
- console.log(` ${dim("contiguous:")} ${contiguous} ${green("(complete)")}`);
35475
- } else {
35476
- const gapCount = status.gaps?.length ?? 0;
35477
- const missing = status.totalMissingBlocks ?? 0;
35478
- console.log(` ${dim("contiguous:")} ${contiguous} ${yellow(`(${gapCount} gaps, ${missing} missing blocks)`)}`);
35479
- if (status.gaps) {
35480
- for (const gap of status.gaps.slice(0, 5)) {
35481
- const range = gap.gapStart === gap.gapEnd ? `${gap.gapStart}` : `${gap.gapStart}-${gap.gapEnd}`;
35482
- console.log(` ${dim("gap:")} ${range} ${dim(`(${gap.size} block${gap.size > 1 ? "s" : ""})`)}`);
35483
- }
35484
- }
35485
- }
35566
+ const tip = status.chainTip;
35567
+ if (typeof tip === "number") {
35568
+ console.log(blue("Chain"));
35569
+ console.log(` tip: ${tip.toLocaleString()}`);
35570
+ const integrity = status.chainIntegrity;
35571
+ if (integrity) {
35572
+ console.log(` integrity: ${integrity.ok ? green("ok") : yellow("check")}`);
35486
35573
  }
35574
+ console.log("");
35487
35575
  }
35488
- console.log("");
35489
- if (status.activeSubgraphs !== undefined) {
35490
- console.log(blue("Activity"));
35491
- console.log(formatKeyValue([
35492
- [" Active Subgraphs", status.activeSubgraphs.toString()]
35493
- ]));
35576
+ const streams = status.streams;
35577
+ if (streams) {
35578
+ console.log(blue("Streams"));
35579
+ console.log(` ${streams.status ?? "unknown"}`);
35580
+ if (typeof streams.tip?.lag_seconds === "number") {
35581
+ console.log(` lag: ${streams.tip.lag_seconds}s`);
35582
+ }
35494
35583
  console.log("");
35495
35584
  }
35496
- console.log(dim(`Last updated: ${status.timestamp}`));
35585
+ const index = status.index;
35586
+ if (index) {
35587
+ console.log(blue("Index"));
35588
+ console.log(` ${index.status ?? "unknown"}`);
35589
+ const bad = (index.decoders ?? []).filter((d2) => d2.status !== "ok");
35590
+ if (bad.length > 0) {
35591
+ for (const d2 of bad.slice(0, 8)) {
35592
+ console.log(` ${yellow(d2.decoder)} ${d2.status}`);
35593
+ }
35594
+ }
35595
+ console.log("");
35596
+ }
35597
+ if (typeof status.timestamp === "string") {
35598
+ console.log(dim(`Last updated: ${status.timestamp}`));
35599
+ }
35497
35600
  }
35498
35601
  // src/commands/subscriptions.ts
35499
35602
  init_api_client();
@@ -37316,7 +37419,6 @@ function registerKeysCommand(program2) {
37316
37419
  });
37317
37420
  }
37318
37421
  // src/commands/doctor.ts
37319
- init_api_client();
37320
37422
  init_config2();
37321
37423
 
37322
37424
  // src/lib/health.ts
@@ -37462,50 +37564,31 @@ async function checkHealth() {
37462
37564
  init_http();
37463
37565
  init_network();
37464
37566
  init_output();
37567
+ init_resolve_auth();
37465
37568
  function registerDoctorCommand(program2) {
37466
37569
  program2.command("doctor").description("Run diagnostics on the full stack").option("--json", "Output as JSON").action(async (options3) => {
37467
37570
  const config = await loadConfig2();
37468
37571
  if (config.network === "local") {
37469
37572
  await runLocalDoctor(options3.json);
37470
- } else {
37471
- await runHostedDoctor(options3.json);
37573
+ return;
37472
37574
  }
37575
+ await runInstanceDoctor(options3.json);
37473
37576
  });
37474
37577
  }
37475
- async function runHostedDoctor(jsonOutput) {
37578
+ async function runInstanceDoctor(jsonOutput) {
37476
37579
  const config = await loadConfig2();
37477
- const apiUrl = process.env.SL_PLATFORM_API_URL ?? process.env.SL_API_URL ?? "http://127.0.0.1:3800";
37580
+ const apiUrl = resolveApiUrl();
37478
37581
  const issues = [];
37479
37582
  const results = { network: config.network, apiUrl };
37480
37583
  let apiHealthy = false;
37481
37584
  let statusData = null;
37482
37585
  try {
37483
- statusData = await httpPlatform("/status");
37586
+ statusData = await httpPlatformAnon("/public/status");
37484
37587
  apiHealthy = true;
37485
- } catch (err) {
37486
- if (err instanceof CliHttpError) {
37487
- if (err.code === "SESSION_EXPIRED") {
37488
- issues.push("Not authenticated. Run: sl login");
37489
- } else {
37490
- issues.push(`API error: ${err.code}`);
37491
- }
37492
- } else {
37493
- issues.push(`Cannot reach API at ${apiUrl}`);
37494
- }
37588
+ } catch {
37589
+ issues.push(`Cannot reach ${apiUrl}/public/status`);
37495
37590
  }
37496
37591
  results.apiHealthy = apiHealthy;
37497
- let authOk = false;
37498
- let account = null;
37499
- try {
37500
- account = await getAccountProfile();
37501
- authOk = true;
37502
- } catch (err) {
37503
- if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED") {
37504
- issues.push("Not authenticated. Run: sl login");
37505
- }
37506
- }
37507
- results.authOk = authOk;
37508
- results.account = account;
37509
37592
  if (jsonOutput) {
37510
37593
  console.log(JSON.stringify({ ...results, status: statusData, issues }, null, 2));
37511
37594
  return;
@@ -37517,28 +37600,18 @@ async function runHostedDoctor(jsonOutput) {
37517
37600
  console.log(blue("API"));
37518
37601
  console.log(` ${apiHealthy ? green("✓") : red("✗")} ${apiHealthy ? green("reachable") : red("unreachable")}`);
37519
37602
  console.log("");
37520
- console.log(blue("Auth"));
37521
- if (authOk && account) {
37522
- console.log(` ${green("✓")} Authenticated`);
37523
- console.log(formatKeyValue([
37524
- [" Email", account.email ?? dim("unknown")],
37525
- [" Plan", account.plan ?? dim("unknown")]
37526
- ]));
37527
- } else {
37528
- console.log(` ${red("✗")} Not authenticated`);
37529
- }
37530
- console.log("");
37531
37603
  if (statusData) {
37532
- const progress = statusData.indexProgress;
37533
- if (progress?.length) {
37534
- console.log(blue("Index Progress"));
37535
- for (const p2 of progress) {
37536
- const behind = p2.highestSeenBlock - p2.lastIndexedBlock;
37537
- const behindStr = behind > 0 ? yellow(` (${behind} behind)`) : green(" (synced)");
37538
- console.log(` ${p2.network}: block ${p2.lastIndexedBlock}${behindStr}`);
37539
- }
37540
- console.log("");
37541
- }
37604
+ const tip = statusData.chainTip;
37605
+ const streams = statusData.streams;
37606
+ const index = statusData.index;
37607
+ console.log(blue("Instance"));
37608
+ if (typeof tip === "number")
37609
+ console.log(` tip: ${tip.toLocaleString()}`);
37610
+ if (streams?.status)
37611
+ console.log(` streams: ${streams.status}`);
37612
+ if (index?.status)
37613
+ console.log(` index: ${index.status}`);
37614
+ console.log("");
37542
37615
  }
37543
37616
  console.log(blue("Issues"));
37544
37617
  if (issues.length === 0) {
@@ -39886,9 +39959,10 @@ registerContextCommand(program);
39886
39959
  registerVerifyCommand(program);
39887
39960
  registerRepairCommand(program);
39888
39961
  program.commandsGroup("Account:");
39962
+ registerCreditsCommand(program);
39889
39963
  registerAccountCommand(program);
39890
39964
  registerKeysCommand(program);
39891
39965
  program.parse();
39892
39966
 
39893
- //# debugId=E414197C37677A7F64756E2164756E21
39967
+ //# debugId=F9D9C4C9412258E564756E2164756E21
39894
39968
  //# sourceMappingURL=cli.js.map