@secondlayer/cli 19.3.0 → 19.4.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/dist/cli.js CHANGED
@@ -2550,6 +2550,118 @@ var init_output = __esm(() => {
2550
2550
  ANSI_ESCAPE_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
2551
2551
  });
2552
2552
 
2553
+ // src/lib/api-client.ts
2554
+ import { ApiError, SecondLayer } from "@secondlayer/sdk";
2555
+ function nextStepHint(status) {
2556
+ if (status === undefined)
2557
+ return;
2558
+ if (status === 403)
2559
+ return "You may not have access — check your active project with `secondlayer whoami`.";
2560
+ if (status === 404)
2561
+ return "Check the name/slug — run the matching `list` command to see what exists.";
2562
+ if (status === 400 || status === 422)
2563
+ return "Check the command arguments and flags — see `--help` for the expected format.";
2564
+ if (status === 429)
2565
+ return "Rate limited — wait a moment and retry.";
2566
+ if (status >= 500)
2567
+ return "Server error — retry shortly, or check `secondlayer status`.";
2568
+ return;
2569
+ }
2570
+ function handleApiError(err, action) {
2571
+ const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
2572
+ if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
2573
+ printError("Authentication required.", {
2574
+ hint: isOssMode() ? "Set INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
2575
+ });
2576
+ process.exit(1);
2577
+ }
2578
+ const detail = err instanceof Error ? err.message : String(err);
2579
+ printError(`Failed to ${action}: ${detail}`, { hint: nextStepHint(status) });
2580
+ process.exit(1);
2581
+ }
2582
+ function withErrorHandling(fn, options) {
2583
+ return async (...args) => {
2584
+ try {
2585
+ await fn(...args);
2586
+ } catch (err) {
2587
+ if (options?.onError) {
2588
+ options.onError(err);
2589
+ } else {
2590
+ handleApiError(err, options?.action ?? "execute command");
2591
+ }
2592
+ }
2593
+ };
2594
+ }
2595
+ async function getPlatformClient() {
2596
+ const { apiUrl, ephemeralKey } = await resolveHostedAuth();
2597
+ return new SecondLayer({ baseUrl: apiUrl, apiKey: ephemeralKey });
2598
+ }
2599
+ async function listSubgraphsApi() {
2600
+ return (await getPlatformClient()).subgraphs.list();
2601
+ }
2602
+ async function getSubgraphApi(name) {
2603
+ return (await getPlatformClient()).subgraphs.status(name);
2604
+ }
2605
+ async function getSubgraphOpenApi(name, options) {
2606
+ return (await getPlatformClient()).subgraphs.openapi(name, options);
2607
+ }
2608
+ async function getSubgraphAgentSchema(name, options) {
2609
+ return (await getPlatformClient()).subgraphs.schema(name, options);
2610
+ }
2611
+ async function getSubgraphMarkdown(name, options) {
2612
+ return (await getPlatformClient()).subgraphs.markdown(name, options);
2613
+ }
2614
+ async function reindexSubgraphApi(name) {
2615
+ return (await getPlatformClient()).subgraphs.reindex(name);
2616
+ }
2617
+ async function backfillSubgraphApi(name, options) {
2618
+ return (await getPlatformClient()).subgraphs.backfill(name, options);
2619
+ }
2620
+ async function stopSubgraphApi(name) {
2621
+ return (await getPlatformClient()).subgraphs.stop(name);
2622
+ }
2623
+ async function deleteSubgraphApi(name, options) {
2624
+ return (await getPlatformClient()).subgraphs.delete(name, options);
2625
+ }
2626
+ async function deploySubgraphApi(data) {
2627
+ return (await getPlatformClient()).subgraphs.deploy(data);
2628
+ }
2629
+ async function querySubgraphTableRows(name, table, params = {}) {
2630
+ return (await getPlatformClient()).subgraphs.rows(name, table, params);
2631
+ }
2632
+ async function querySubgraphTableCount(name, table, params = {}) {
2633
+ return (await getPlatformClient()).subgraphs.count(name, table, params);
2634
+ }
2635
+ async function getSubgraphGaps(name, opts) {
2636
+ return (await getPlatformClient()).subgraphs.gaps(name, opts);
2637
+ }
2638
+ async function listSubgraphOperationsApi(name) {
2639
+ return (await getPlatformClient()).subgraphs.operations(name);
2640
+ }
2641
+ async function getSubgraphOperationApi(name, operationId) {
2642
+ return (await getPlatformClient()).subgraphs.getOperation(name, operationId);
2643
+ }
2644
+ async function getSubgraphSourceApi(name) {
2645
+ return (await getPlatformClient()).subgraphs.getSource(name);
2646
+ }
2647
+ async function getSubgraphRowsApi(name, table, opts = {}) {
2648
+ return (await getPlatformClient()).subgraphs.rows(name, table, opts);
2649
+ }
2650
+ async function getContractPrintSchema(contractId) {
2651
+ let client;
2652
+ try {
2653
+ client = await getPlatformClient();
2654
+ } catch {
2655
+ client = new SecondLayer({ baseUrl: resolveApiUrl() });
2656
+ }
2657
+ return client.index.printSchema(contractId);
2658
+ }
2659
+ var init_api_client = __esm(() => {
2660
+ init_http();
2661
+ init_output();
2662
+ init_resolve_auth();
2663
+ });
2664
+
2553
2665
  // ../../node_modules/fast-glob/out/utils/array.js
2554
2666
  var require_array = __commonJS(function(exports) {
2555
2667
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -16630,7 +16742,7 @@ var init_dist3 = __esm(() => {
16630
16742
  // ../../node_modules/tinyexec/dist/main.js
16631
16743
  import { createRequire as e } from "module";
16632
16744
  import { spawn as t } from "node:child_process";
16633
- import { delimiter as n2, dirname as r, normalize as i, resolve as a2 } from "node:path";
16745
+ import { delimiter as n3, dirname as r, normalize as i, resolve as a2 } from "node:path";
16634
16746
  import { cwd as o } from "node:process";
16635
16747
  import { PassThrough as s } from "node:stream";
16636
16748
  import c from "node:readline";
@@ -16649,7 +16761,7 @@ function x(e) {
16649
16761
  return b;
16650
16762
  }
16651
16763
  function S(e, t) {
16652
- const i = t.value.split(n2);
16764
+ const i = t.value.split(n3);
16653
16765
  let o = e;
16654
16766
  let s;
16655
16767
  do {
@@ -16659,7 +16771,7 @@ function S(e, t) {
16659
16771
  } while (o !== s);
16660
16772
  return {
16661
16773
  key: t.key,
16662
- value: i.join(n2)
16774
+ value: i.join(n3)
16663
16775
  };
16664
16776
  }
16665
16777
  function C(e, t) {
@@ -23945,19 +24057,19 @@ class c2 {
23945
24057
  }
23946
24058
  }
23947
24059
  function i2() {
23948
- return this[n3].next();
24060
+ return this[n4].next();
23949
24061
  }
23950
24062
  function o2(r) {
23951
- return this[n3].return(r);
24063
+ return this[n4].return(r);
23952
24064
  }
23953
24065
  function h2({ preventCancel: r = false } = {}) {
23954
24066
  const e = this.getReader(), t = new c2(e, r), s = Object.create(u2);
23955
- return s[n3] = t, s;
24067
+ return s[n4] = t, s;
23956
24068
  }
23957
- var a3, n3, u2;
24069
+ var a3, n4, u2;
23958
24070
  var init_asyncIterator = __esm(() => {
23959
24071
  a3 = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype);
23960
- n3 = Symbol();
24072
+ n4 = Symbol();
23961
24073
  Object.defineProperty(i2, "name", { value: "next" });
23962
24074
  Object.defineProperty(o2, "name", { value: "return" });
23963
24075
  u2 = Object.create(a3, {
@@ -28890,115 +29002,6 @@ var init_subgraphs = __esm(() => {
28890
29002
  init_format();
28891
29003
  });
28892
29004
 
28893
- // src/lib/api-client.ts
28894
- import { ApiError, SecondLayer as SecondLayer2 } from "@secondlayer/sdk";
28895
- function nextStepHint(status) {
28896
- if (status === undefined)
28897
- return;
28898
- if (status === 403)
28899
- return "You may not have access — check your active project with `secondlayer whoami`.";
28900
- if (status === 404)
28901
- return "Check the name/slug — run the matching `list` command to see what exists.";
28902
- if (status === 400 || status === 422)
28903
- return "Check the command arguments and flags — see `--help` for the expected format.";
28904
- if (status === 429)
28905
- return "Rate limited — wait a moment and retry.";
28906
- if (status >= 500)
28907
- return "Server error — retry shortly, or check `secondlayer status`.";
28908
- return;
28909
- }
28910
- function handleApiError(err, action) {
28911
- const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
28912
- if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
28913
- printError("Authentication required.", {
28914
- hint: isOssMode() ? "Set INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
28915
- });
28916
- process.exit(1);
28917
- }
28918
- const detail = err instanceof Error ? err.message : String(err);
28919
- printError(`Failed to ${action}: ${detail}`, { hint: nextStepHint(status) });
28920
- process.exit(1);
28921
- }
28922
- function withErrorHandling(fn, options) {
28923
- return async (...args) => {
28924
- try {
28925
- await fn(...args);
28926
- } catch (err) {
28927
- if (options?.onError) {
28928
- options.onError(err);
28929
- } else {
28930
- handleApiError(err, options?.action ?? "execute command");
28931
- }
28932
- }
28933
- };
28934
- }
28935
- async function getPlatformClient() {
28936
- const { apiUrl, ephemeralKey } = await resolveHostedAuth();
28937
- return new SecondLayer2({ baseUrl: apiUrl, apiKey: ephemeralKey });
28938
- }
28939
- async function listSubgraphsApi() {
28940
- return (await getPlatformClient()).subgraphs.list();
28941
- }
28942
- async function getSubgraphApi(name) {
28943
- return (await getPlatformClient()).subgraphs.status(name);
28944
- }
28945
- async function getSubgraphOpenApi(name, options) {
28946
- return (await getPlatformClient()).subgraphs.openapi(name, options);
28947
- }
28948
- async function getSubgraphAgentSchema(name, options) {
28949
- return (await getPlatformClient()).subgraphs.schema(name, options);
28950
- }
28951
- async function getSubgraphMarkdown(name, options) {
28952
- return (await getPlatformClient()).subgraphs.markdown(name, options);
28953
- }
28954
- async function reindexSubgraphApi(name) {
28955
- return (await getPlatformClient()).subgraphs.reindex(name);
28956
- }
28957
- async function backfillSubgraphApi(name, options) {
28958
- return (await getPlatformClient()).subgraphs.backfill(name, options);
28959
- }
28960
- async function stopSubgraphApi(name) {
28961
- return (await getPlatformClient()).subgraphs.stop(name);
28962
- }
28963
- async function deleteSubgraphApi(name, options) {
28964
- return (await getPlatformClient()).subgraphs.delete(name, options);
28965
- }
28966
- async function deploySubgraphApi(data) {
28967
- return (await getPlatformClient()).subgraphs.deploy(data);
28968
- }
28969
- async function querySubgraphTableRows(name, table, params = {}) {
28970
- return (await getPlatformClient()).subgraphs.rows(name, table, params);
28971
- }
28972
- async function querySubgraphTableCount(name, table, params = {}) {
28973
- return (await getPlatformClient()).subgraphs.count(name, table, params);
28974
- }
28975
- async function getSubgraphGaps(name, opts) {
28976
- return (await getPlatformClient()).subgraphs.gaps(name, opts);
28977
- }
28978
- async function listSubgraphOperationsApi(name) {
28979
- return (await getPlatformClient()).subgraphs.operations(name);
28980
- }
28981
- async function getSubgraphOperationApi(name, operationId) {
28982
- return (await getPlatformClient()).subgraphs.getOperation(name, operationId);
28983
- }
28984
- async function getSubgraphSourceApi(name) {
28985
- return (await getPlatformClient()).subgraphs.getSource(name);
28986
- }
28987
- async function getContractPrintSchema(contractId) {
28988
- let client;
28989
- try {
28990
- client = await getPlatformClient();
28991
- } catch {
28992
- client = new SecondLayer2({ baseUrl: resolveApiUrl() });
28993
- }
28994
- return client.index.printSchema(contractId);
28995
- }
28996
- var init_api_client = __esm(() => {
28997
- init_http();
28998
- init_output();
28999
- init_resolve_auth();
29000
- });
29001
-
29002
29005
  // src/lib/derive-abi.ts
29003
29006
  import {
29004
29007
  extractSubgraphDefinition,
@@ -29440,7 +29443,7 @@ var init_git_status = () => {};
29440
29443
 
29441
29444
  // ../../node_modules/typescript/lib/typescript.js
29442
29445
  var require_typescript = __commonJS(function(exports, module) {
29443
- var __dirname = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a5aea7deee5fef330/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a5aea7deee5fef330/node_modules/typescript/lib/typescript.js";
29446
+ var __dirname = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a9a35af4d4343442c/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a9a35af4d4343442c/node_modules/typescript/lib/typescript.js";
29444
29447
  /*! *****************************************************************************
29445
29448
  Copyright (c) Microsoft Corporation. All rights reserved.
29446
29449
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -198803,7 +198806,7 @@ import {
198803
198806
  } from "@secondlayer/shared/schemas";
198804
198807
  import { TRAIT_STANDARDS } from "@secondlayer/stacks/clarity";
198805
198808
  import {
198806
- deriveVerification,
198809
+ deriveVerification as deriveVerification2,
198807
198810
  isDeterminismViolation
198808
198811
  } from "@secondlayer/subgraphs/verification";
198809
198812
  function webhookHint(apiUrl, name, firstTable) {
@@ -199145,7 +199148,7 @@ function formatVerificationStatus(verification) {
199145
199148
  return verification.unproven.length > 0 ? `${head} (unproven: ${verification.unproven.join("; ")})` : head;
199146
199149
  }
199147
199150
  function checkDeterminism(def, findings) {
199148
- const verification = deriveVerification(def, findings);
199151
+ const verification = deriveVerification2(def, findings);
199149
199152
  if (isDeterminismViolation(verification)) {
199150
199153
  error("Nondeterministic handler. This subgraph's sources are provable, so its handlers must give the same rows on every run:");
199151
199154
  for (const r of verification.reasons)
@@ -202595,7 +202598,7 @@ var {
202595
202598
  // package.json
202596
202599
  var package_default = {
202597
202600
  name: "@secondlayer/cli",
202598
- version: "19.3.0",
202601
+ version: "19.4.0",
202599
202602
  description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
202600
202603
  repository: {
202601
202604
  type: "git",
@@ -202634,11 +202637,11 @@ var package_default = {
202634
202637
  "@inquirer/prompts": "^8.2.0",
202635
202638
  "@secondlayer/bundler": "^0.7.0",
202636
202639
  "@secondlayer/scaffold": "^1.6.1",
202637
- "@secondlayer/sdk": "^14.3.0",
202638
- "@secondlayer/shared": "^11.22.0",
202639
- "@secondlayer/stacks": "^6.1.1",
202640
- "@secondlayer/subgraphs": "^6.4.0",
202641
- "@secondlayer/verify": "^0.2.0",
202640
+ "@secondlayer/sdk": "^14.5.0",
202641
+ "@secondlayer/shared": "^11.23.0",
202642
+ "@secondlayer/stacks": "^6.2.0",
202643
+ "@secondlayer/subgraphs": "^6.5.0",
202644
+ "@secondlayer/verify": "^0.3.0",
202642
202645
  esbuild: "^0.28.2",
202643
202646
  "smol-toml": "^1.8.0",
202644
202647
  zod: "^4.3.6"
@@ -202665,7 +202668,7 @@ var package_default = {
202665
202668
 
202666
202669
  // src/commands/archive.ts
202667
202670
  import {
202668
- SecondLayer,
202671
+ SecondLayer as SecondLayer2,
202669
202672
  resolveAccountKey as resolveAccountKey3
202670
202673
  } from "@secondlayer/sdk";
202671
202674
 
@@ -204090,6 +204093,7 @@ var LINKS = [
204090
204093
  { step: "burn", label: "burn" },
204091
204094
  { step: "signer-set", label: "cycle" },
204092
204095
  { step: "signatures", label: "signatures" },
204096
+ { step: "txs", label: "txs" },
204093
204097
  { step: "witness", label: "state root" },
204094
204098
  { step: "names", label: "diff" },
204095
204099
  { step: "rows", label: "rows" }
@@ -204147,7 +204151,7 @@ function prepareSource(src) {
204147
204151
  };
204148
204152
  return out;
204149
204153
  }
204150
- function linkDetail(step, r, cp, rows) {
204154
+ function linkDetail(step, r, cp) {
204151
204155
  switch (step) {
204152
204156
  case "ancestry": {
204153
204157
  const a = r.ancestry;
@@ -204167,6 +204171,8 @@ function linkDetail(step, r, cp, rows) {
204167
204171
  return r.cycle === cp.stacks.cycle ? `${r.cycle}, the checkpoint's own signer set` : `${r.cycle}, signer set proven forward from checkpoint cycle ${cp.stacks.cycle}`;
204168
204172
  case "signatures":
204169
204173
  return `${n(r.signerWeight ?? 0n)} / ${n(r.totalWeight ?? 0n)} weight signed, threshold ${n(r.threshold ?? 0n)}`;
204174
+ case "txs":
204175
+ return `${n(r.transactions?.length ?? 0)} transactions match the tx merkle root`;
204170
204176
  case "witness":
204171
204177
  return `${r.stateRoot} matches the witness`;
204172
204178
  case "names": {
@@ -204174,7 +204180,7 @@ function linkDetail(step, r, cp, rows) {
204174
204180
  if (!d)
204175
204181
  return "";
204176
204182
  const named = d.writes.filter((w) => w.named).length;
204177
- const written = named ? `${d.writes.length} written (${named} named, ${d.writes.length - named} unnamed)` : `${d.writes.length} written (unnamed${rows ? "" : "; --rows names them"})`;
204183
+ const written = named ? `${d.writes.length} written (${named} named, ${d.writes.length - named} unnamed)` : `${d.writes.length} written (unnamed)`;
204178
204184
  return `${written}, ${d.carried.length} carried, ${d.internal.length} internal`;
204179
204185
  }
204180
204186
  case "rows":
@@ -204206,12 +204212,13 @@ function report(r, cp, rows) {
204206
204212
  writeData(dim(`· ${label} not needed: the block is hash-chained to the checkpoint`));
204207
204213
  else if (link.step === "rows" && r.rowsChecked === undefined)
204208
204214
  writeData(dim(`· ${label} not checked: the source serves no indexed rows`));
204215
+ else if (link.step === "txs" && r.transactions === undefined)
204216
+ writeData(dim(`· ${label} not checked: no transaction bytes (epoch 2.x, or the source served the header only)`));
204209
204217
  else
204210
- writeData(`${green("✓")} ${label} ${linkDetail(link.step, r, cp, rows)}`);
204218
+ writeData(`${green("✓")} ${label} ${linkDetail(link.step, r, cp)}`);
204211
204219
  }
204212
204220
  for (const line of r.notes)
204213
- if (rows || !line.includes("state_writes"))
204214
- note(` note: ${line}`);
204221
+ note(` note: ${line}`);
204215
204222
  if (!first) {
204216
204223
  const from = n(parseNakamotoHeader(unhex(cp.stacks.header)).chainLength);
204217
204224
  writeData(green(`✓ Block ${n(r.height ?? 0)} is proven. Trusted: only the checkpoint (Stacks ${from}, Bitcoin ${n(cp.bitcoin.height)}).`));
@@ -204221,7 +204228,8 @@ function report(r, cp, rows) {
204221
204228
  writeData(red(first.code === "unavailable" ? `✗ Could not check the ${label} link: the source could not serve it.` : `✗ Not proven: the ${label} link is broken.`));
204222
204229
  }
204223
204230
  function verificationJson(r) {
204224
- return JSON.stringify(r, (_k, v) => typeof v === "bigint" ? v.toString() : v, 2);
204231
+ const { transactions, ...rest } = r;
204232
+ return JSON.stringify(transactions ? { ...rest, transactions: transactions.map((t) => t.txid) } : rest, (_k, v) => typeof v === "bigint" ? v.toString() : v, 2);
204225
204233
  }
204226
204234
  function exitCodeOf(r) {
204227
204235
  if (r.ok)
@@ -204250,7 +204258,7 @@ async function runVerifyBlock(ref, opts, deps = {}) {
204250
204258
  return exitCodeOf(result);
204251
204259
  }
204252
204260
  function attachVerifyBlockCommand(verify) {
204253
- return verify.command("block").description("Prove one Stacks block from the checkpoint built into this release, trusting nothing else").argument("<ref>", "block height or index block hash").option("--node <url>", "read blocks and MARF proofs from this Stacks node RPC instead of the API").option("--checkpoint <file>", "trust this checkpoint JSON instead of the one built into this release").option("--rows", "also prove the indexer's rows for the block (state_writes, vm_events) against its state diff").addHelpText("after", `
204261
+ return verify.command("block").description("Prove one Stacks block from the checkpoint built into this release, trusting nothing else").argument("<ref>", "block height or index block hash").option("--node <url>", "read blocks and MARF proofs from this Stacks node RPC instead of the API").option("--checkpoint <file>", "trust this checkpoint JSON instead of the one built into this release").option("--rows", "also prove the Index API's vm_events rows for the block against its state diff (billed as Index rows)").addHelpText("after", `
204254
204262
  What is proven, link by link:
204255
204263
  ancestry below the checkpoint only: the block's id, from the checkpoint by
204256
204264
  parent links or one MARF proof (signer links are then not needed)
@@ -204258,9 +204266,13 @@ What is proven, link by link:
204258
204266
  burn the block's consensus hash commits to that Bitcoin block
204259
204267
  cycle the reward cycle's signer set, proven forward from the checkpoint's set
204260
204268
  signatures signers holding at least 70% of the weight signed the block header
204269
+ txs the block's transactions hash to the tx merkle root in its header
204261
204270
  state root the state witness hashes to the root in the signed header
204262
- diff every leaf the block wrote, carried, or kept as bookkeeping
204263
- rows with --rows: the Index API's rows match that diff
204271
+ diff every leaf the block wrote, carried, or kept as bookkeeping; writes
204272
+ are named from the block's state_writes (free, /v1/proofs/writes)
204273
+ when the source has them, else listed as unnamed with a note
204274
+ rows with --rows: the Index API's vm_events rows match that diff
204275
+ (billed as Index rows; everything else is free)
204264
204276
 
204265
204277
  Nothing is trusted except the checkpoint. Proofs come from the API
204266
204278
  (SECONDLAYER_API_URL, or --api-url) with your account key, or from a node
@@ -204284,13 +204296,242 @@ Exit codes:
204284
204296
  });
204285
204297
  }
204286
204298
 
204299
+ // src/commands/verify-subgraph.ts
204300
+ init_api_client();
204301
+ init_output();
204302
+ import { deriveVerification } from "@secondlayer/subgraphs/verification";
204303
+ import {
204304
+ checkPin,
204305
+ compareRows,
204306
+ loadDeterministicDefinition,
204307
+ replayContracts,
204308
+ replaySubgraph
204309
+ } from "@secondlayer/subgraphs/verify";
204310
+ import {
204311
+ MAINNET_CHECKPOINT as MAINNET_CHECKPOINT2,
204312
+ parseNakamotoHeader as parseNakamotoHeader2,
204313
+ unhex as unhex2
204314
+ } from "@secondlayer/verify";
204315
+ var LINKS2 = [
204316
+ { step: "pin", label: "pin" },
204317
+ { step: "blocks", label: "blocks" },
204318
+ { step: "txs", label: "txs" },
204319
+ { step: "inputs", label: "inputs" },
204320
+ { step: "handlers", label: "handlers" },
204321
+ { step: "rows", label: "rows" }
204322
+ ];
204323
+ var LABEL_WIDTH2 = Math.max(...LINKS2.map((l) => l.label.length));
204324
+ var PROGRESS_EVERY = 100;
204325
+ var PAGE = 1000;
204326
+ var n2 = (v) => v.toLocaleString("en-US");
204327
+ var short = (h) => `${h.slice(0, 4)}…${h.slice(-4)}`;
204328
+
204329
+ class InputError extends Error {
204330
+ }
204331
+ function parseHeight2(raw, flag) {
204332
+ if (raw === undefined)
204333
+ return;
204334
+ if (!/^\d+$/.test(raw) || !Number.isSafeInteger(Number(raw)))
204335
+ throw new InputError(`${flag} must be a block height, got "${raw}"`);
204336
+ return Number(raw);
204337
+ }
204338
+ async function readTable(fetchRows, name, table) {
204339
+ const out = [];
204340
+ let cursor;
204341
+ for (;; ) {
204342
+ const page = await fetchRows(name, table, cursor);
204343
+ out.push(...page.rows);
204344
+ if (!page.next_cursor || page.rows.length === 0)
204345
+ return out;
204346
+ cursor = page.next_cursor;
204347
+ }
204348
+ }
204349
+ function linkLine(step, r) {
204350
+ const res = r.result;
204351
+ switch (step) {
204352
+ case "pin":
204353
+ return `${short(r.pinValue ?? "")} handler, schema and startBlock match the deploy`;
204354
+ case "blocks":
204355
+ return `${n2(res.blocks)} proven from the checkpoint${res.marfProofs ? ` (${n2(res.marfProofs)} MARF proof${res.marfProofs === 1 ? "" : "s"}, then parent links)` : ""}`;
204356
+ case "txs":
204357
+ return `${n2(res.txs)} transactions match their blocks' tx merkle roots`;
204358
+ case "inputs":
204359
+ return `${n2(res.blocks)} diffs fully named; ${n2(res.writes)} writes to ${r.contracts.map((c) => c.split(".")[1] ?? c).join(", ")}`;
204360
+ case "handlers":
204361
+ return `${n2(res.events)} events, ${n2(res.handlerErrors)} handler errors, deterministic realm`;
204362
+ case "rows":
204363
+ return (r.comparison?.tables ?? []).map((t) => `${t.table}: ${n2(t.equal)} equal${t.superseded ? `, ${n2(t.superseded)} superseded after ${n2(res.to)}` : ""} digest ${short(t.digest)}`).join(`
204364
+ ${" ".repeat(LABEL_WIDTH2 + 4)}`);
204365
+ }
204366
+ }
204367
+ function firstFailure(r) {
204368
+ if (r.pin.status === "failed")
204369
+ return r.pin.failure;
204370
+ return r.result?.failures[0] ?? r.comparison?.failures[0];
204371
+ }
204372
+ function report2(r, from, to) {
204373
+ const first = firstFailure(r);
204374
+ const broken = first ? LINKS2.findIndex((l) => l.step === first.step) : LINKS2.length;
204375
+ const inconclusive = !first ? r.result?.inconclusive : undefined;
204376
+ for (const [i, link] of LINKS2.entries()) {
204377
+ const label = link.label.padEnd(LABEL_WIDTH2);
204378
+ if (first && i === broken)
204379
+ writeData(`${red("✗")} ${label} ${first.message}`);
204380
+ else if (i > broken)
204381
+ writeData(dim(`· ${label} not checked: an earlier link is broken`));
204382
+ else if (link.step === "pin" && r.pin.status === "unchecked")
204383
+ writeData(dim(`· ${label} not checked: deployed before pin inputs were stored (redeploy)`));
204384
+ else if (link.step === "rows" && inconclusive)
204385
+ writeData(dim(`· ${label} not checked: ${inconclusive}`));
204386
+ else
204387
+ writeData(`${green("✓")} ${label} ${linkLine(link.step, r)}`);
204388
+ }
204389
+ for (const line of [...r.pin.notes, ...r.result?.notes ?? []])
204390
+ note(` note: ${line}`);
204391
+ if (first) {
204392
+ const label = LINKS2[broken]?.label ?? first.step;
204393
+ writeData(red(first.unavailable ? `✗ Could not check the ${label} link: the source could not serve it.` : `✗ Not proven: the ${label} link is broken.`));
204394
+ return first.unavailable ? VERIFY_EXIT.UNANCHORED : VERIFY_EXIT.DIVERGED;
204395
+ }
204396
+ if (inconclusive) {
204397
+ writeData(dim(`· Inconclusive: ${inconclusive}. Rows were not compared.`));
204398
+ return VERIFY_EXIT.UNANCHORED;
204399
+ }
204400
+ const cp = MAINNET_CHECKPOINT2;
204401
+ const stacks = n2(Number(parseNakamotoHeader2(unhex2(cp.stacks.header)).chainLength));
204402
+ writeData(green(`✓ ${r.name} ${n2(from)}..${n2(to)} recomputed from proven inputs. Trusted: only the checkpoint (Stacks ${stacks}, Bitcoin ${n2(cp.bitcoin.height)}).`));
204403
+ writeData(dim(` unproven, so not compared: ${[...r.unproven, "rows compare declared columns and _block_height only"].join("; ")}`));
204404
+ return VERIFY_EXIT.CLEAN;
204405
+ }
204406
+ function reportJson(r) {
204407
+ const { tables, ...result } = r.result ?? {};
204408
+ return JSON.stringify({
204409
+ pin: r.pin,
204410
+ replay: r.result ? {
204411
+ ...result,
204412
+ tables: Object.fromEntries([...tables ?? new Map].map(([t, rows]) => [t, rows.length]))
204413
+ } : null,
204414
+ comparison: r.comparison ?? null
204415
+ }, (_k, v) => typeof v === "bigint" ? v.toString() : v, 2);
204416
+ }
204417
+ async function runVerifySubgraph(name, opts, deps = {}) {
204418
+ const fetchSubgraph = deps.fetchSubgraph ?? getSubgraphApi;
204419
+ const fetchSource = deps.fetchSource ?? getSubgraphSourceApi;
204420
+ const fetchRows = deps.fetchRows ?? ((n, t, cursor) => getSubgraphRowsApi(n, t, { cursor, limit: PAGE }));
204421
+ try {
204422
+ if (!opts.replay)
204423
+ throw new InputError("pass --replay: the only check today re-runs the handlers over proven blocks");
204424
+ const fromFlag = parseHeight2(opts.from, "--from");
204425
+ const toFlag = parseHeight2(opts.to, "--to");
204426
+ const detail = await fetchSubgraph(name);
204427
+ const level = detail.verification;
204428
+ if (level?.level !== "state")
204429
+ throw new InputError(level ? `${name} is level ${level.level}, not state: ${level.reasons.join("; ")}` : `${name} has no verification level: deployed before levels were derived (redeploy)`);
204430
+ const served = await fetchSource(name);
204431
+ if (!served.handlerCode)
204432
+ throw new InputError(`${name} has no stored handler bundle to replay (a local deploy)`);
204433
+ const def = await loadDeterministicDefinition(served.handlerCode);
204434
+ const pin = checkPin({
204435
+ pin: served.pin ?? null,
204436
+ pinPreimage: served.pinPreimage ?? null,
204437
+ handlerCode: served.handlerCode
204438
+ }, def);
204439
+ const startBlock = typeof detail.definition?.startBlock === "number" ? detail.definition.startBlock : def.startBlock ?? 0;
204440
+ const contracts = replayContracts(def);
204441
+ const tables = Object.keys(def.schema);
204442
+ const first = tables[0] ? await fetchRows(name, tables[0]) : { tip: { subgraph_height: startBlock } };
204443
+ const tip = first.tip.subgraph_height;
204444
+ const from = fromFlag ?? startBlock;
204445
+ const to = toFlag ?? tip;
204446
+ if (to > tip)
204447
+ throw new InputError(`--to ${n2(to)} is past the served subgraph: it is at ${n2(tip)}`);
204448
+ if (from > to)
204449
+ throw new InputError(`--from ${n2(from)} is after --to ${n2(to)}`);
204450
+ const r = {
204451
+ name,
204452
+ pin,
204453
+ pinValue: served.pin ?? null,
204454
+ contracts: Array.isArray(contracts) ? contracts : [],
204455
+ unproven: deriveVerification(def).unproven
204456
+ };
204457
+ if (pin.status !== "failed") {
204458
+ const servedRows = new Map;
204459
+ for (const table of tables)
204460
+ servedRows.set(table, await readTable(fetchRows, name, table));
204461
+ note(`Replaying ${name} ${n2(from)}..${n2(to)} (${n2(to - from + 1)} blocks)`);
204462
+ r.result = await (deps.replay ?? replaySubgraph)({
204463
+ source: deps.source ?? defaultSource(opts.node),
204464
+ handlerCode: served.handlerCode,
204465
+ from,
204466
+ to,
204467
+ startBlock,
204468
+ onProgress: (h) => {
204469
+ const done = h - from + 1;
204470
+ if (done % PROGRESS_EVERY === 0)
204471
+ note(` replayed ${n2(done)} / ${n2(to - from + 1)} blocks`);
204472
+ }
204473
+ });
204474
+ if (r.result.failures.length === 0 && !r.result.inconclusive)
204475
+ r.comparison = compareRows(def.schema, r.result, servedRows);
204476
+ }
204477
+ if (opts.json) {
204478
+ writeData(reportJson(r));
204479
+ const f = firstFailure(r);
204480
+ if (f)
204481
+ return f.unavailable ? VERIFY_EXIT.UNANCHORED : VERIFY_EXIT.DIVERGED;
204482
+ return r.result?.inconclusive ? VERIFY_EXIT.UNANCHORED : VERIFY_EXIT.CLEAN;
204483
+ }
204484
+ return report2(r, from, to);
204485
+ } catch (err) {
204486
+ printError(err instanceof Error ? err.message : String(err));
204487
+ return VERIFY_EXIT.UNANCHORED;
204488
+ }
204489
+ }
204490
+ function attachVerifySubgraphCommand(verify) {
204491
+ return verify.command("subgraph").description("Recompute a state-level subgraph from proven blocks and check its served rows").argument("<name>", "deployed subgraph name").option("--replay", "re-run the handlers over blocks proven from the checkpoint").option("--from <height>", "first block to replay (default: the subgraph's startBlock)").option("--to <height>", "last block to replay (default: the served subgraph's height)").option("--node <url>", "read blocks and MARF proofs from this Stacks node RPC instead of the API").addHelpText("after", `
204492
+ What is proven, link by link:
204493
+ pin the served pin is the sha256 of its preimage, which names the served
204494
+ handler bundle, its schema and startBlock
204495
+ blocks every block in the range, from the checkpoint (signatures above it,
204496
+ parent links and MARF proofs below it)
204497
+ txs each block's transactions hash to its header's tx merkle root
204498
+ inputs each block's writes are named, nothing hidden (state_writes vs witness)
204499
+ handlers the bundle runs in the deterministic realm over those writes
204500
+ rows the served rows equal the recomputed ones (keyed by the first
204501
+ unique key, else as a multiset), with a digest per table
204502
+
204503
+ Starting after startBlock (--from) is inconclusive once a handler reads or
204504
+ merges rows written before the range (findOne, increment, a partial upsert).
204505
+ Not proven, so not compared: which transaction made a write (event.tx,
204506
+ _tx_id) and writes overwritten within one block. Rows compare on their
204507
+ declared columns and _block_height.
204508
+
204509
+ Reads are free: proofs and each block's state writes from /v1/proofs (rate
204510
+ limited; witnesses 2 per second, so 1,000 blocks take 8 minutes or more) and
204511
+ the subgraph's rows from /v1/subgraphs. Nothing bills as Index rows.
204512
+
204513
+ Examples:
204514
+ $ secondlayer verify subgraph pool-reserves --replay
204515
+ $ secondlayer verify subgraph pool-reserves --replay --from 1230000 --to 1231000
204516
+ $ secondlayer verify subgraph pool-reserves --replay --json
204517
+
204518
+ Exit codes:
204519
+ 0 every link holds
204520
+ 1 a link is broken (the first is named)
204521
+ 2 could not check: the source could not serve a link, the replay is
204522
+ inconclusive, the subgraph is not state-level, or bad input`).action(async (name, opts, cmd) => {
204523
+ const json = cmd.optsWithGlobals().json === true;
204524
+ process.exit(await runVerifySubgraph(name, { ...opts, json }));
204525
+ });
204526
+ }
204527
+
204287
204528
  // src/commands/verify.ts
204288
204529
  var VERIFY_EXIT = {
204289
204530
  CLEAN: 0,
204290
204531
  DIVERGED: 1,
204291
204532
  UNANCHORED: 2
204292
204533
  };
204293
- function parseHeight2(value, flag) {
204534
+ function parseHeight3(value, flag) {
204294
204535
  const parsed = Number(value);
204295
204536
  if (!Number.isSafeInteger(parsed) || parsed < 0) {
204296
204537
  throw new Error(`${flag} must be a non-negative integer, got "${value}"`);
@@ -204326,8 +204567,8 @@ Exit codes:
204326
204567
  try {
204327
204568
  const target = parseVerifyTarget(targetArg);
204328
204569
  const mode = opts.deep ? "deep" : opts.anchor ? "anchor" : "quick";
204329
- const fromBlock = opts.fromBlock === undefined ? undefined : parseHeight2(opts.fromBlock, "--from-block");
204330
- const toBlock = opts.toBlock === undefined ? undefined : parseHeight2(opts.toBlock, "--to-block");
204570
+ const fromBlock = opts.fromBlock === undefined ? undefined : parseHeight3(opts.fromBlock, "--from-block");
204571
+ const toBlock = opts.toBlock === undefined ? undefined : parseHeight3(opts.toBlock, "--to-block");
204331
204572
  if (fromBlock !== undefined && toBlock !== undefined && toBlock < fromBlock) {
204332
204573
  throw new Error("--to-block must be >= --from-block");
204333
204574
  }
@@ -204501,13 +204742,14 @@ Exit codes:
204501
204742
  });
204502
204743
  }
204503
204744
  function registerVerifyCommand(program) {
204504
- const verify = attachVerifyCommand(program.command("verify").description("Compare local chain data against a signed archive, or prove one block with `verify block` (read-only)"));
204745
+ const verify = attachVerifyCommand(program.command("verify").description("Compare local chain data against a signed archive, prove one block with `verify block`, or recompute a subgraph with `verify subgraph --replay` (read-only)"));
204505
204746
  attachVerifyBlockCommand(verify);
204747
+ attachVerifySubgraphCommand(verify);
204506
204748
  }
204507
204749
 
204508
204750
  // src/commands/archive.ts
204509
204751
  var ARCHIVE_KEY_HINT = "set SECONDLAYER_API_KEY (sk-sl_*) for archive latest/quote; INSTANCE_TOKEN is the instance";
204510
- function parseHeight3(value, flag) {
204752
+ function parseHeight4(value, flag) {
204511
204753
  const parsed = Number(value);
204512
204754
  if (!Number.isSafeInteger(parsed) || parsed < 0) {
204513
204755
  throw new Error(`${flag} must be a non-negative integer, got "${value}"`);
@@ -204528,7 +204770,7 @@ function requireAccountKey(resolve = resolveAccountKey3) {
204528
204770
  return accountKey;
204529
204771
  }
204530
204772
  function defaultArchive(accountKey) {
204531
- return new SecondLayer({
204773
+ return new SecondLayer2({
204532
204774
  accountKey,
204533
204775
  archiveOpsUrl: resolveArchiveOpsUrl()
204534
204776
  }).archive;
@@ -204569,8 +204811,8 @@ async function runLatest(opts, deps = {}) {
204569
204811
  async function runQuote(opts, deps = {}) {
204570
204812
  const accountKey = requireAccountKey(deps.resolveAccountKey);
204571
204813
  const flow = parseFlow(opts.flow);
204572
- const fromBlock = opts.fromBlock === undefined ? undefined : parseHeight3(opts.fromBlock, "--from-block");
204573
- const toBlock = opts.toBlock === undefined ? undefined : parseHeight3(opts.toBlock, "--to-block");
204814
+ const fromBlock = opts.fromBlock === undefined ? undefined : parseHeight4(opts.fromBlock, "--from-block");
204815
+ const toBlock = opts.toBlock === undefined ? undefined : parseHeight4(opts.toBlock, "--to-block");
204574
204816
  if (fromBlock !== undefined && toBlock !== undefined && toBlock < fromBlock) {
204575
204817
  printError("--to-block must be >= --from-block");
204576
204818
  process.exit(1);
@@ -207047,7 +207289,7 @@ function consumeHandlers(io) {
207047
207289
  }
207048
207290
  };
207049
207291
  }
207050
- function parseHeight4(value, name) {
207292
+ function parseHeight5(value, name) {
207051
207293
  if (value === undefined)
207052
207294
  return;
207053
207295
  const n = Number.parseInt(value, 10);
@@ -207081,8 +207323,8 @@ Examples:
207081
207323
  sender: parseList(options.sender),
207082
207324
  recipient: parseList(options.recipient),
207083
207325
  cursor: options.cursor,
207084
- fromHeight: parseHeight4(options.fromBlock, "--from-block"),
207085
- toHeight: parseHeight4(options.toBlock, "--to-block"),
207326
+ fromHeight: parseHeight5(options.fromBlock, "--from-block"),
207327
+ toHeight: parseHeight5(options.toBlock, "--to-block"),
207086
207328
  limit: parseLimit(options.limit)
207087
207329
  });
207088
207330
  writeData(JSON.stringify(envelope, null, 2));
@@ -207146,8 +207388,8 @@ Examples:
207146
207388
  });
207147
207389
  const runDumps = async (options) => {
207148
207390
  try {
207149
- const fromBlock = parseHeight4(options.fromBlock, "--from-block");
207150
- const toBlock = parseHeight4(options.toBlock, "--to-block");
207391
+ const fromBlock = parseHeight5(options.fromBlock, "--from-block");
207392
+ const toBlock = parseHeight5(options.toBlock, "--to-block");
207151
207393
  const dumps = dumpsClient(options.dumpsUrl).dumps;
207152
207394
  const manifest = await dumps.list();
207153
207395
  const files = manifest.files.filter((f) => (fromBlock === undefined || f.to_block >= fromBlock) && (toBlock === undefined || f.from_block <= toBlock));
@@ -207178,7 +207420,7 @@ Examples:
207178
207420
  $ secondlayer streams dumps --to ./dump --from-block 150000 --to-block 200000`).action(runDumps);
207179
207421
  streams.command("canonical <height>").description("Canonical block metadata at a given height").option("--json", "Output as JSON (streams always emits JSON)").action(async (heightArg) => {
207180
207422
  try {
207181
- const height = parseHeight4(heightArg, "<height>");
207423
+ const height = parseHeight5(heightArg, "<height>");
207182
207424
  if (height === undefined)
207183
207425
  throw new Error("<height> is required");
207184
207426
  const block = await client2().canonical(height);
@@ -209598,5 +209840,5 @@ registerCreditsCommand(program);
209598
209840
  registerArchiveCommand(program);
209599
209841
  program.parse();
209600
209842
 
209601
- //# debugId=ECF90476FCFF9CB564756E2164756E21
209843
+ //# debugId=F270856631D97EA764756E2164756E21
209602
209844
  //# sourceMappingURL=cli.js.map