@secondlayer/cli 22.0.1 → 22.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/dist/cli.js CHANGED
@@ -29488,7 +29488,7 @@ var init_git_status = () => {};
29488
29488
 
29489
29489
  // ../../node_modules/typescript/lib/typescript.js
29490
29490
  var require_typescript = __commonJS(function(exports, module) {
29491
- var __dirname = "/Users/ryan/projects/secondlayer/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/node_modules/typescript/lib/typescript.js";
29491
+ var __dirname = "/Users/ryan/projects/secondlayer/.claude/worktrees/rel313/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/.claude/worktrees/rel313/node_modules/typescript/lib/typescript.js";
29492
29492
  /*! *****************************************************************************
29493
29493
  Copyright (c) Microsoft Corporation. All rights reserved.
29494
29494
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -202711,7 +202711,7 @@ var {
202711
202711
  // package.json
202712
202712
  var package_default = {
202713
202713
  name: "@secondlayer/cli",
202714
- version: "22.0.1",
202714
+ version: "22.1.0",
202715
202715
  description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
202716
202716
  repository: {
202717
202717
  type: "git",
@@ -204184,6 +204184,126 @@ import {
204184
204184
  reportVerify
204185
204185
  } from "@secondlayer/shared/coverage";
204186
204186
  import { getDb as getDb3 } from "@secondlayer/shared/db";
204187
+
204188
+ // src/lib/archive-heights.ts
204189
+ import {
204190
+ PerHeightDigestAccumulator
204191
+ } from "@secondlayer/shared/archive/per-height-digest";
204192
+ import {
204193
+ streamHeightDigests
204194
+ } from "@secondlayer/shared/archive/semantic-digest-builder";
204195
+ var PART_FOR_DATASET = {
204196
+ blocks: "block",
204197
+ transactions: "transactions",
204198
+ events: "events"
204199
+ };
204200
+ async function localPerHeightDigests(db, fromBlock, toBlock, datasets = ["blocks", "transactions", "events"]) {
204201
+ const accumulator = new PerHeightDigestAccumulator;
204202
+ for await (const { height, digest } of streamHeightDigests(db, "blocks", fromBlock, toBlock)) {
204203
+ accumulator.setBlockDigest(height, digest);
204204
+ }
204205
+ if (datasets.includes("transactions")) {
204206
+ for await (const { height, digest } of streamHeightDigests(db, "transactions", fromBlock, toBlock)) {
204207
+ accumulator.appendTransactionDigest(height, digest);
204208
+ }
204209
+ }
204210
+ if (datasets.includes("events")) {
204211
+ for await (const { height, digest } of streamHeightDigests(db, "events", fromBlock, toBlock)) {
204212
+ accumulator.appendEventDigest(height, digest);
204213
+ }
204214
+ }
204215
+ const rows = new Map;
204216
+ for (const row of accumulator.drain(fromBlock, toBlock)) {
204217
+ rows.set(row.height, row);
204218
+ }
204219
+ return rows;
204220
+ }
204221
+ function sidecarsCovering(digestIndex, fromBlock, toBlock) {
204222
+ return (digestIndex ?? []).filter((p) => p.from_block <= toBlock && p.to_block >= fromBlock);
204223
+ }
204224
+ async function fetchSidecarRows(reference, partition) {
204225
+ const bytes = await fetchVerifiedPartition(reference, partition);
204226
+ const rows = [];
204227
+ for await (const raw of readPartitionRows(bytes, `digests-${partition.from_block}-${partition.to_block}`)) {
204228
+ const row = raw;
204229
+ rows.push({
204230
+ height: Number(row.height),
204231
+ block_digest: String(row.block_digest),
204232
+ transactions_rollup: row.transactions_rollup == null ? null : String(row.transactions_rollup),
204233
+ events_rollup: row.events_rollup == null ? null : String(row.events_rollup)
204234
+ });
204235
+ }
204236
+ return rows;
204237
+ }
204238
+ function compareHeights(params) {
204239
+ const { dataset, fromBlock, toBlock, local, archive, covered } = params;
204240
+ const inCoverage = (h) => covered.some((c) => h >= c.from_block && h <= c.to_block);
204241
+ const heights = new Set;
204242
+ for (const h of archive.keys())
204243
+ heights.add(h);
204244
+ for (const h of local.keys())
204245
+ if (inCoverage(h))
204246
+ heights.add(h);
204247
+ const out = [];
204248
+ for (const height of [...heights].sort((a, b) => a - b)) {
204249
+ if (height < fromBlock || height > toBlock)
204250
+ continue;
204251
+ const mine = local.get(height);
204252
+ const theirs = archive.get(height);
204253
+ if (!mine && theirs) {
204254
+ out.push({ height, parts: ["missing-local"] });
204255
+ } else if (mine && !theirs) {
204256
+ out.push({ height, parts: ["missing-archive"] });
204257
+ } else if (mine && theirs && !partsMatch(dataset, mine, theirs)) {
204258
+ out.push({ height, parts: [PART_FOR_DATASET[dataset]] });
204259
+ }
204260
+ }
204261
+ return out;
204262
+ }
204263
+ function partsMatch(dataset, a, b) {
204264
+ if (dataset === "blocks")
204265
+ return a.block_digest === b.block_digest;
204266
+ if (dataset === "transactions") {
204267
+ return a.transactions_rollup === b.transactions_rollup;
204268
+ }
204269
+ return a.events_rollup === b.events_rollup;
204270
+ }
204271
+ async function divergentHeightsForRange(params) {
204272
+ const { db, reference, dataset, fromBlock, toBlock } = params;
204273
+ const sidecars = sidecarsCovering(params.digestIndex, fromBlock, toBlock);
204274
+ if (sidecars.length === 0)
204275
+ return null;
204276
+ const archive = new Map;
204277
+ for (const sidecar of sidecars) {
204278
+ for (const row of await fetchSidecarRows(reference, sidecar)) {
204279
+ archive.set(row.height, row);
204280
+ }
204281
+ }
204282
+ const local = await localPerHeightDigests(db, fromBlock, toBlock, [dataset]);
204283
+ return compareHeights({
204284
+ dataset,
204285
+ fromBlock,
204286
+ toBlock,
204287
+ local,
204288
+ archive,
204289
+ covered: sidecars
204290
+ });
204291
+ }
204292
+ function mergeRepairRanges(ranges) {
204293
+ const sorted = [...ranges].sort((a, b) => a.from_block - b.from_block || a.to_block - b.to_block);
204294
+ const merged = [];
204295
+ for (const range of sorted) {
204296
+ const last = merged[merged.length - 1];
204297
+ if (last && range.from_block <= last.to_block + 1) {
204298
+ last.to_block = Math.max(last.to_block, range.to_block);
204299
+ } else {
204300
+ merged.push({ from_block: range.from_block, to_block: range.to_block });
204301
+ }
204302
+ }
204303
+ return merged;
204304
+ }
204305
+
204306
+ // src/commands/verify.ts
204187
204307
  init_output();
204188
204308
  init_resolve_auth();
204189
204309
 
@@ -204578,6 +204698,7 @@ function parseHeight3(value, flag) {
204578
204698
  }
204579
204699
  return parsed;
204580
204700
  }
204701
+ var MAX_HEIGHTS_SHOWN = 20;
204581
204702
  function statusLabel(status) {
204582
204703
  if (status === "match")
204583
204704
  return green("ok");
@@ -204616,9 +204737,10 @@ Exit codes:
204616
204737
  envPem: process.env.ARCHIVE_SIGNING_PUBLIC_KEY ?? process.env.STREAMS_SIGNING_PUBLIC_KEY,
204617
204738
  allowHostedApi: !isOssMode()
204618
204739
  });
204619
- const { manifest, origin } = await loadReference(opts.against, {
204740
+ const loaded = await loadReference(opts.against, {
204620
204741
  publicKeyPem: publicKey
204621
204742
  });
204743
+ const { manifest, origin } = loaded;
204622
204744
  const signature = checkSignature(manifest, publicKey, !!opts.insecure);
204623
204745
  if (!signature.verified && !opts.insecure) {
204624
204746
  printError(`Cannot trust the reference: ${signature.reason}.`, {
@@ -204751,6 +204873,30 @@ Exit codes:
204751
204873
  }))
204752
204874
  ];
204753
204875
  const diverged = all.filter((c) => c.status !== "match");
204876
+ const digestIndex = manifest.digest_index;
204877
+ const heightNotes = [];
204878
+ if (diverged.length > 0 && !digestIndex?.length) {
204879
+ heightNotes.push("This snapshot has no per-height digests; exact diverging heights need a newer snapshot.");
204880
+ } else {
204881
+ for (const range of diverged) {
204882
+ try {
204883
+ const heights = await divergentHeightsForRange({
204884
+ db,
204885
+ reference: loaded,
204886
+ digestIndex,
204887
+ dataset: range.dataset,
204888
+ fromBlock: range.from_block,
204889
+ toBlock: range.to_block
204890
+ });
204891
+ if (heights)
204892
+ range.divergent_heights = heights;
204893
+ else
204894
+ heightNotes.push(`No per-height digests cover ${range.from_block}-${range.to_block}.`);
204895
+ } catch (err) {
204896
+ heightNotes.push(`Could not narrow ${range.from_block}-${range.to_block} to heights: ${err instanceof Error ? err.message : String(err)}`);
204897
+ }
204898
+ }
204899
+ }
204754
204900
  const verdict = reportVerify({
204755
204901
  target,
204756
204902
  mode,
@@ -204763,7 +204909,8 @@ Exit codes:
204763
204909
  signature_verified: signature.verified,
204764
204910
  ranges_checked: all.length,
204765
204911
  semantic_checks: semanticChecks.length,
204766
- divergent_ranges: diverged
204912
+ divergent_ranges: diverged,
204913
+ ...heightNotes.length > 0 ? { note: heightNotes.join(" ") } : {}
204767
204914
  };
204768
204915
  output({
204769
204916
  json: opts.json,
@@ -204783,11 +204930,28 @@ Exit codes:
204783
204930
  String(d.expected_rows),
204784
204931
  String(d.actual_rows)
204785
204932
  ])));
204933
+ for (const range of diverged) {
204934
+ const heights = range.divergent_heights;
204935
+ if (!heights)
204936
+ continue;
204937
+ console.error("");
204938
+ console.error(`${range.from_block}-${range.to_block} ${range.dataset}: ${heights.length} diverging height${heights.length === 1 ? "" : "s"}`);
204939
+ for (const h of heights.slice(0, MAX_HEIGHTS_SHOWN)) {
204940
+ console.error(` ${h.height} ${h.parts.join(", ")}`);
204941
+ }
204942
+ if (heights.length > MAX_HEIGHTS_SHOWN) {
204943
+ console.error(dim(` and ${heights.length - MAX_HEIGHTS_SHOWN} more (see --json)`));
204944
+ }
204945
+ }
204946
+ if (heightNotes.length > 0) {
204947
+ console.error("");
204948
+ for (const line of heightNotes)
204949
+ console.error(dim(` ${line}`));
204950
+ }
204786
204951
  console.error("");
204787
204952
  console.error(dim("These ranges hold different data than the signed archive. Repair with:"));
204788
- const first = diverged[0];
204789
- if (first) {
204790
- console.error(dim(` secondlayer repair --from-block ${first.from_block} --to-block ${first.to_block}`));
204953
+ for (const range of mergeRepairRanges(diverged)) {
204954
+ console.error(dim(` secondlayer repair --from-block ${range.from_block} --to-block ${range.to_block}`));
204791
204955
  }
204792
204956
  }
204793
204957
  });
@@ -208690,5 +208854,5 @@ registerCreditsCommand(program);
208690
208854
  registerArchiveCommand(program);
208691
208855
  program.parse();
208692
208856
 
208693
- //# debugId=77FBD5CCBD0906B064756E2164756E21
208857
+ //# debugId=32F86A2D9F7E084964756E2164756E21
208694
208858
  //# sourceMappingURL=cli.js.map