@secondlayer/cli 21.0.0 → 21.1.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
@@ -82,7 +82,7 @@ No account. Writes `.env.local`, restores history, prints the Stacks observer st
82
82
  | `secondlayer init [--network mainnet\|testnet\|devnet] [--api-url <url>] [--force]` | Write `.env.local` (token, secrets key, webhook signing key). `--network` and `--api-url` are the global flags. Idempotent |
83
83
  | `secondlayer bootstrap --against <manifest> [--from-block <n>] [--to-block <n>] [--verify all\|blocks] [--public-key <pem>] [-y] [--json]` | Restore chain history from a verified archive into an empty database. A run that died mid-way resumes per dataset on re-run. After the load, digests for blocks, transactions, and events are checked over the restored range (`--verify blocks` skips the child datasets and the minutes they cost). Partition fetches retry three times with backoff on resets, timeouts, 429 (honoring `Retry-After`) and 5xx; a link that stays down exits `1` with a re-run hint, and the re-run resumes. Exit `0` restored, `1` diverged or interrupted, `2` refused |
84
84
  | `secondlayer observer [--mode indexer\|signer-shared] [--endpoint host:port] [--network …]` | Print the `[[events_observer]]` stanza. Signer-shared skips retries; a missed block stays a gap until `repair` |
85
- | `secondlayer 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 |
85
+ | `secondlayer verify [all\|raw] --against <manifest> [--quick\|--deep\|--anchor]` | Compare local data to a signed archive. Default target `raw`. Exit `0` clean, `1` diverged, `2` unanchored |
86
86
  | `secondlayer verify block <height\|index_block_hash> [--node <url>] [--checkpoint <file>] [--rows] [--json]` | Prove one Stacks block from the checkpoint built into this release: Bitcoin headers, burn block, signer set, signatures, state root, state diff, and with `--rows` the indexed rows. Blocks below the checkpoint are tied to it by hash (parent links or one MARF proof) instead of signatures. Nothing else is trusted; proofs come from the API, or a node with `--node`. Exit `0` proven, `1` a link is broken, `2` could not check |
87
87
  | `secondlayer repair --against <archive> [--apply] [-y]` | Plan (default) or apply an archive repair. A fixed block is rewritten with its transactions and events from the archive; when the reference has no child partition for a height, the block is rewritten alone, the height is named with a `bootstrap --from-block H --to-block H` remedy, and the exit is `1`. Partition fetches retry like `bootstrap`; a link that stays down exits `1` with a re-run hint, and heights already repaired are kept |
88
88
 
package/dist/cli.js CHANGED
@@ -29020,6 +29020,33 @@ function sourcesNeedingAbi(sources) {
29020
29020
  }
29021
29021
  return out;
29022
29022
  }
29023
+ function sourcesNamingState(sources) {
29024
+ if (!sources || typeof sources !== "object")
29025
+ return [];
29026
+ const out = [];
29027
+ for (const [name, raw] of Object.entries(sources)) {
29028
+ const src = raw;
29029
+ if (typeof src?.contractId !== "string" || src.contractId.includes("*") || src.trait !== undefined) {
29030
+ continue;
29031
+ }
29032
+ if ((src.type === "map_set" || src.type === "map_insert" || src.type === "map_delete") && typeof src.map === "string") {
29033
+ out.push({
29034
+ name,
29035
+ contractId: src.contractId,
29036
+ kind: "map",
29037
+ stateName: src.map
29038
+ });
29039
+ } else if (src.type === "var_set" && typeof src.varName === "string") {
29040
+ out.push({
29041
+ name,
29042
+ contractId: src.contractId,
29043
+ kind: "var",
29044
+ stateName: src.varName
29045
+ });
29046
+ }
29047
+ }
29048
+ return out;
29049
+ }
29023
29050
  async function withDerivedAbis(source, client = new StacksApiClient) {
29024
29051
  let sources;
29025
29052
  try {
@@ -29028,16 +29055,22 @@ async function withDerivedAbis(source, client = new StacksApiClient) {
29028
29055
  return { source, abis: {} };
29029
29056
  }
29030
29057
  const needed = sourcesNeedingAbi(sources);
29031
- if (needed.length === 0)
29058
+ const stateSources = sourcesNamingState(sources);
29059
+ if (needed.length === 0 && stateSources.length === 0) {
29032
29060
  return { source, abis: {} };
29061
+ }
29033
29062
  const byContract = new Map;
29034
29063
  const abis = {};
29035
- for (const { name, contractId } of needed) {
29064
+ const interfaceOf = (contractId) => {
29036
29065
  let pending = byContract.get(contractId);
29037
29066
  if (!pending) {
29038
29067
  pending = client.getContractInfo(contractId).then(normalizeAbi3);
29039
29068
  byContract.set(contractId, pending);
29040
29069
  }
29070
+ return pending;
29071
+ };
29072
+ for (const { name, contractId } of needed) {
29073
+ const pending = interfaceOf(contractId);
29041
29074
  try {
29042
29075
  abis[name] = await pending;
29043
29076
  } catch (err) {
@@ -29045,6 +29078,19 @@ async function withDerivedAbis(source, client = new StacksApiClient) {
29045
29078
  throw new Error(`Could not fetch the abi for source "${name}" (${contractId}): ${reason}. Pass abi on the source instead (normalizeAbi() from @secondlayer/stacks/clarity).`);
29046
29079
  }
29047
29080
  }
29081
+ for (const { name, contractId, kind, stateName } of stateSources) {
29082
+ let contract;
29083
+ try {
29084
+ contract = await interfaceOf(contractId);
29085
+ } catch {
29086
+ continue;
29087
+ }
29088
+ const defined = ((kind === "map" ? contract.maps : contract.variables) ?? []).map((entry) => entry.name);
29089
+ if (!defined.includes(stateName)) {
29090
+ const noun = kind === "map" ? "map" : "variable";
29091
+ throw new Error(`Source "${name}" reads ${noun} "${stateName}", which ${contractId} does not define. Its ${noun}s: ${defined.join(", ") || "none"}.`);
29092
+ }
29093
+ }
29048
29094
  return { source: injectSourceAbis(source, abis), abis };
29049
29095
  }
29050
29096
  var init_derive_abi = __esm(() => {
@@ -29423,7 +29469,7 @@ var init_git_status = () => {};
29423
29469
 
29424
29470
  // ../../node_modules/typescript/lib/typescript.js
29425
29471
  var require_typescript = __commonJS(function(exports, module) {
29426
- var __dirname = "/Users/ryan/projects/secondlayer-release/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer-release/node_modules/typescript/lib/typescript.js";
29472
+ var __dirname = "/private/tmp/claude-501/-Users-ryan-projects-secondlayer/f3803aac-4d84-4ad1-b9ab-de61be6a7179/scratchpad/rel/node_modules/typescript/lib", __filename = "/private/tmp/claude-501/-Users-ryan-projects-secondlayer/f3803aac-4d84-4ad1-b9ab-de61be6a7179/scratchpad/rel/node_modules/typescript/lib/typescript.js";
29427
29473
  /*! *****************************************************************************
29428
29474
  Copyright (c) Microsoft Corporation. All rights reserved.
29429
29475
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -202646,7 +202692,7 @@ var {
202646
202692
  // package.json
202647
202693
  var package_default = {
202648
202694
  name: "@secondlayer/cli",
202649
- version: "21.0.0",
202695
+ version: "21.1.0",
202650
202696
  description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
202651
202697
  repository: {
202652
202698
  type: "git",
@@ -202687,9 +202733,9 @@ var package_default = {
202687
202733
  "@secondlayer/scaffold": "^1.6.2",
202688
202734
  "@secondlayer/sdk": "^15.0.3",
202689
202735
  "@secondlayer/shared": "^13.0.0",
202690
- "@secondlayer/stacks": "^6.2.2",
202691
- "@secondlayer/subgraphs": "^7.0.4",
202692
- "@secondlayer/verify": "^0.5.4",
202736
+ "@secondlayer/stacks": "^6.3.0",
202737
+ "@secondlayer/subgraphs": "^7.1.0",
202738
+ "@secondlayer/verify": "^0.6.0",
202693
202739
  esbuild: "^0.28.2",
202694
202740
  "smol-toml": "^1.9.1",
202695
202741
  zod: "^4.3.6"
@@ -204523,13 +204569,12 @@ function statusLabel(status) {
204523
204569
  return yellow("missing");
204524
204570
  }
204525
204571
  function attachVerifyCommand(cmd) {
204526
- return cmd.argument("[target]", "all | raw | decode:<name> | subgraph:<name>", "raw").option("--quick", "coverage/identity only (default)").option("--deep", "include semantic / scratch replay where available").option("--anchor", "require a verified archive signature").option("--against <manifest>", "archive manifest: an https URL or a local file path (required)").option("--from-block <n>", "first height to check").option("--to-block <n>", "last height to check").option("--counts", "also compare transaction/event row counts (slower)").option("--semantic", "also recompute per-partition semantic digests locally and compare (slow: full re-stream)").option("--public-key <pem>", "pin a signing key; default is the archive key built into this release").option("--insecure", "skip the manifest signature check (not recommended)").option("--json", "Output as JSON").addHelpText("after", `
204572
+ return cmd.argument("[target]", "all | raw (decode:<name> and subgraph:<name> have no archive digests yet)", "raw").option("--quick", "coverage/identity only (default)").option("--deep", "include semantic / scratch replay where available").option("--anchor", "require a verified archive signature").option("--against <manifest>", "archive manifest: an https URL or a local file path (required)").option("--from-block <n>", "first height to check").option("--to-block <n>", "last height to check").option("--counts", "also compare transaction/event row counts (slower)").option("--semantic", "also recompute per-partition semantic digests locally and compare (slow: full re-stream)").option("--public-key <pem>", "pin a signing key; default is the archive key built into this release").option("--insecure", "skip the manifest signature check (not recommended)").option("--json", "Output as JSON").addHelpText("after", `
204527
204573
  Examples:
204528
204574
  $ secondlayer verify --against https://archive.secondlayer.tools/.../snapshots/<digest>.json
204529
204575
  $ secondlayer verify raw --against ./snapshot.json --from-block 8000000 --to-block 8499999
204530
204576
  $ secondlayer verify all --against ./snapshot.json --json
204531
- $ secondlayer verify decode:ft_transfer --against ./snapshot.json --quick
204532
- $ secondlayer verify subgraph:sbtc --against ./snapshot.json --deep
204577
+ $ secondlayer verify subgraph <name> --replay
204533
204578
 
204534
204579
  Exit codes:
204535
204580
  0 local data matches the archive
@@ -204577,9 +204622,28 @@ Exit codes:
204577
204622
  });
204578
204623
  process.exit(VERIFY_EXIT.UNANCHORED);
204579
204624
  }
204580
- const reference = (manifest.range_digests ?? []).filter((d) => {
204581
- if (!datasetMatchesTarget(d.dataset, target))
204582
- return false;
204625
+ const unanchoredJson = (detail) => output({
204626
+ json: opts.json,
204627
+ data: {
204628
+ ...reportVerify({ target, mode, anchored: false, detail }),
204629
+ status: "unanchored",
204630
+ reference: origin,
204631
+ reason: detail
204632
+ },
204633
+ human: () => {}
204634
+ });
204635
+ const published = (manifest.range_digests ?? []).filter((d) => datasetMatchesTarget(d.dataset, target));
204636
+ if (published.length === 0) {
204637
+ const label = target.kind === "decode" ? `decode:${target.name}` : target.kind === "subgraph" ? `subgraph:${target.name}` : target.kind;
204638
+ const datasets = [
204639
+ ...new Set((manifest.range_digests ?? []).map((d) => d.dataset))
204640
+ ].sort();
204641
+ const hint = target.kind === "decode" ? "Check the events decoders read from with: secondlayer verify raw --against <manifest>" : target.kind === "subgraph" ? "Recompute a state subgraph's rows with: secondlayer verify subgraph <name> --replay" : "Check the manifest you passed to --against.";
204642
+ printError(`This archive publishes no digests for ${label}. It has: ${datasets.join(", ") || "none"}.`, { hint });
204643
+ unanchoredJson("no digests");
204644
+ process.exit(VERIFY_EXIT.UNANCHORED);
204645
+ }
204646
+ const reference = published.filter((d) => {
204583
204647
  if (fromBlock !== undefined && d.to_block < fromBlock)
204584
204648
  return false;
204585
204649
  if (toBlock !== undefined && d.from_block > toBlock)
@@ -204590,6 +204654,7 @@ Exit codes:
204590
204654
  printError("The reference publishes no digests for that range.", {
204591
204655
  hint: "Check --from-block/--to-block against the manifest's coverage."
204592
204656
  });
204657
+ unanchoredJson("no digests for that range");
204593
204658
  process.exit(VERIFY_EXIT.UNANCHORED);
204594
204659
  }
204595
204660
  const db = getDb3();
@@ -208409,5 +208474,5 @@ registerCreditsCommand(program);
208409
208474
  registerArchiveCommand(program);
208410
208475
  program.parse();
208411
208476
 
208412
- //# debugId=C5F366E55CEA893F64756E2164756E21
208477
+ //# debugId=36A335C6FBC2D29F64756E2164756E21
208413
208478
  //# sourceMappingURL=cli.js.map