@secondlayer/cli 17.0.3 → 18.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
@@ -29430,7 +29430,7 @@ var init_git_status = () => {};
29430
29430
 
29431
29431
  // ../../node_modules/typescript/lib/typescript.js
29432
29432
  var require_typescript = __commonJS(function(exports, module) {
29433
- var __dirname = "/Users/ryan/projects/secondlayer/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/node_modules/typescript/lib/typescript.js";
29433
+ var __dirname = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a6a189c1bc1696e94/node_modules/typescript/lib", __filename = "/Users/ryan/projects/secondlayer/.claude/worktrees/agent-a6a189c1bc1696e94/node_modules/typescript/lib/typescript.js";
29434
29434
  /*! *****************************************************************************
29435
29435
  Copyright (c) Microsoft Corporation. All rights reserved.
29436
29436
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -202495,7 +202495,7 @@ var {
202495
202495
  // package.json
202496
202496
  var package_default = {
202497
202497
  name: "@secondlayer/cli",
202498
- version: "17.0.3",
202498
+ version: "18.1.0",
202499
202499
  description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
202500
202500
  repository: {
202501
202501
  type: "git",
@@ -202534,8 +202534,8 @@ var package_default = {
202534
202534
  "@inquirer/prompts": "^8.2.0",
202535
202535
  "@secondlayer/bundler": "^0.6.1",
202536
202536
  "@secondlayer/scaffold": "^1.6.1",
202537
- "@secondlayer/sdk": "^12.3.0",
202538
- "@secondlayer/shared": "^11.12.4",
202537
+ "@secondlayer/sdk": "^13.0.0",
202538
+ "@secondlayer/shared": "^11.15.1",
202539
202539
  "@secondlayer/stacks": "^6.1.0",
202540
202540
  "@secondlayer/subgraphs": "^6.2.5",
202541
202541
  esbuild: "^0.28.2",
@@ -203516,6 +203516,193 @@ async function reverify(db, reference, ranges) {
203516
203516
  }
203517
203517
  return remaining;
203518
203518
  }
203519
+ function findChildPartition(partitions, dataset, fromBlock, toBlock) {
203520
+ return partitions.find((p) => p.dataset === dataset && p.from_block === fromBlock && p.to_block === toBlock);
203521
+ }
203522
+ function expectedZeroRows(zeroRecordRanges, dataset, fromBlock, toBlock) {
203523
+ return zeroRecordRanges.some((r) => r.dataset === dataset && r.from_block === fromBlock && r.to_block === toBlock);
203524
+ }
203525
+ async function planChildPartitionDivergence(db, partitions, zeroRecordRanges, inRange) {
203526
+ const ranges = new Map;
203527
+ for (const p of partitions) {
203528
+ if (p.dataset !== "transactions" && p.dataset !== "events")
203529
+ continue;
203530
+ if (!inRange(p.from_block, p.to_block))
203531
+ continue;
203532
+ ranges.set(`${p.from_block}-${p.to_block}`, {
203533
+ from: p.from_block,
203534
+ to: p.to_block
203535
+ });
203536
+ }
203537
+ const mismatches = [];
203538
+ for (const { from, to } of ranges.values()) {
203539
+ const txPartition = findChildPartition(partitions, "transactions", from, to);
203540
+ const evPartition = findChildPartition(partitions, "events", from, to);
203541
+ const expectedTx = txPartition?.row_count ?? (expectedZeroRows(zeroRecordRanges, "transactions", from, to) ? 0 : null);
203542
+ const expectedEv = evPartition?.row_count ?? (expectedZeroRows(zeroRecordRanges, "events", from, to) ? 0 : null);
203543
+ if (expectedTx === null && expectedEv === null)
203544
+ continue;
203545
+ const actualTx = (await computeRangeDigest2(db, "transactions", from, to)).row_count;
203546
+ const actualEv = (await computeRangeDigest2(db, "events", from, to)).row_count;
203547
+ if (expectedTx !== null && actualTx !== expectedTx || expectedEv !== null && actualEv !== expectedEv) {
203548
+ mismatches.push({
203549
+ from_block: from,
203550
+ to_block: to,
203551
+ transactions: { expected: expectedTx ?? actualTx, actual: actualTx },
203552
+ events: { expected: expectedEv ?? actualEv, actual: actualEv }
203553
+ });
203554
+ }
203555
+ }
203556
+ return mismatches;
203557
+ }
203558
+ async function applyChildRangeFix(rawClient, reference, mismatch, gate) {
203559
+ const partitions = reference.manifest.partitions ?? [];
203560
+ const txPartition = findChildPartition(partitions, "transactions", mismatch.from_block, mismatch.to_block);
203561
+ const evPartition = findChildPartition(partitions, "events", mismatch.from_block, mismatch.to_block);
203562
+ const txBytes = txPartition ? await fetchVerifiedPartition(reference, txPartition, gate) : null;
203563
+ const evBytes = evPartition ? await fetchVerifiedPartition(reference, evPartition, gate) : null;
203564
+ const written = { transactions: 0, events: 0 };
203565
+ await rawClient.begin(async (tx) => {
203566
+ await tx.unsafe("DELETE FROM events WHERE block_height BETWEEN $1 AND $2", [
203567
+ mismatch.from_block,
203568
+ mismatch.to_block
203569
+ ]);
203570
+ await tx.unsafe("DELETE FROM transactions WHERE block_height BETWEEN $1 AND $2", [mismatch.from_block, mismatch.to_block]);
203571
+ if (txBytes) {
203572
+ const writable = await tx.unsafe(copyStatement2("transactions")).writable();
203573
+ written.transactions = await writeRowsToCopyStream2({
203574
+ writable,
203575
+ dataset: "transactions",
203576
+ rows: readPartitionRows(txBytes, `repair-transactions-${mismatch.from_block}`)
203577
+ });
203578
+ }
203579
+ if (evBytes) {
203580
+ const writable = await tx.unsafe(copyStatement2("events")).writable();
203581
+ written.events = await writeRowsToCopyStream2({
203582
+ writable,
203583
+ dataset: "events",
203584
+ rows: readPartitionRows(evBytes, `repair-events-${mismatch.from_block}`)
203585
+ });
203586
+ }
203587
+ });
203588
+ return written;
203589
+ }
203590
+ async function runChildOnlyRepair(params) {
203591
+ const { reference, childMismatches, apply, json, yes } = params;
203592
+ if (childMismatches.length === 0) {
203593
+ success("Nothing to repair — local data matches the archive.");
203594
+ output({ json, data: { status: "clean", fixes: [] }, human: () => {} });
203595
+ process.exit(REPAIR_EXIT.OK);
203596
+ }
203597
+ const partitions = reference.manifest.partitions ?? [];
203598
+ const fetchPaths = childMismatches.flatMap((m) => {
203599
+ const tx = findChildPartition(partitions, "transactions", m.from_block, m.to_block);
203600
+ const ev = findChildPartition(partitions, "events", m.from_block, m.to_block);
203601
+ return [tx?.path, ev?.path].filter((p) => p !== undefined);
203602
+ });
203603
+ let gate;
203604
+ let quoteLine;
203605
+ if (apply && isOfficialArchive(reference)) {
203606
+ const result = await quoteArchiveFetch(fetchPaths, "repair");
203607
+ if (!result.ok) {
203608
+ printError(result.kind === "not_configured" ? ARCHIVE_GATE_NOT_CONFIGURED_MESSAGE : result.message);
203609
+ process.exit(REPAIR_EXIT.UNANCHORED);
203610
+ }
203611
+ if (!result.quote.sufficient) {
203612
+ printError(formatInsufficientMessage(result.quote));
203613
+ process.exit(REPAIR_EXIT.UNANCHORED);
203614
+ }
203615
+ quoteLine = formatQuoteValue(result.quote, "repair");
203616
+ note(` metered: ${quoteLine}`);
203617
+ if (shouldPromptForGatedFetch({ yes })) {
203618
+ if (json) {
203619
+ writeData(JSON.stringify(confirmationRequiredPayload(result.quote)));
203620
+ process.exit(REPAIR_EXIT.UNANCHORED);
203621
+ }
203622
+ const proceed = await confirmDestructive({
203623
+ message: `Fetch ${fetchPaths.length} partition(s) from the archive?`,
203624
+ yes
203625
+ });
203626
+ if (!proceed) {
203627
+ note("Nothing was fetched.");
203628
+ process.exit(REPAIR_EXIT.UNANCHORED);
203629
+ }
203630
+ }
203631
+ gate = createGatedFetcher(fetchPaths, "repair");
203632
+ }
203633
+ const applied = { transactions: 0, events: 0 };
203634
+ if (apply) {
203635
+ const rawClient = getRawClient2("source");
203636
+ for (const mismatch of childMismatches) {
203637
+ const result = await applyChildRangeFix(rawClient, reference, mismatch, gate);
203638
+ applied.transactions += result.transactions;
203639
+ applied.events += result.events;
203640
+ }
203641
+ }
203642
+ const db = getDb2();
203643
+ let remaining = childMismatches.length;
203644
+ if (apply) {
203645
+ remaining = 0;
203646
+ for (const mismatch of childMismatches) {
203647
+ const [actualTx, actualEv] = await Promise.all([
203648
+ computeRangeDigest2(db, "transactions", mismatch.from_block, mismatch.to_block),
203649
+ computeRangeDigest2(db, "events", mismatch.from_block, mismatch.to_block)
203650
+ ]);
203651
+ if (actualTx.row_count !== mismatch.transactions.expected || actualEv.row_count !== mismatch.events.expected) {
203652
+ remaining++;
203653
+ }
203654
+ }
203655
+ }
203656
+ const complete = apply && remaining === 0;
203657
+ const report = {
203658
+ status: apply ? complete ? "repaired" : "incomplete" : "plan",
203659
+ reference: reference.origin,
203660
+ divergent_ranges: 0,
203661
+ blocks_to_replace: 0,
203662
+ blocks_to_insert: 0,
203663
+ local_only_heights: [],
203664
+ applied: 0,
203665
+ rows_written: { blocks: 0, ...applied },
203666
+ datasets_rewritten: apply ? ["transactions", "events"] : [],
203667
+ heights_missing_child_partitions: [],
203668
+ child_partition_mismatches: childMismatches,
203669
+ fixes: [],
203670
+ metered: quoteLine ?? null
203671
+ };
203672
+ output({
203673
+ json,
203674
+ data: report,
203675
+ human: () => {
203676
+ if (apply) {
203677
+ const written = `${applied.transactions} transactions, ${applied.events} events`;
203678
+ if (complete) {
203679
+ success(`Repaired ${childMismatches.length} range(s) (rewrote ${written}); blocks were already correct.`);
203680
+ } else {
203681
+ warn(`Rewrote ${written} but ${remaining} range(s) still diverge from the archive.`);
203682
+ }
203683
+ } else {
203684
+ warn(`${childMismatches.length} range(s) have transactions/events that diverge from the archive, while their blocks match.`);
203685
+ console.error("");
203686
+ console.error(formatTable([
203687
+ "RANGE",
203688
+ "TX EXPECTED",
203689
+ "TX LOCAL",
203690
+ "EVENTS EXPECTED",
203691
+ "EVENTS LOCAL"
203692
+ ], childMismatches.slice(0, 20).map((m) => [
203693
+ `${m.from_block}-${m.to_block}`,
203694
+ String(m.transactions.expected),
203695
+ String(m.transactions.actual),
203696
+ String(m.events.expected),
203697
+ String(m.events.actual)
203698
+ ])));
203699
+ console.error("");
203700
+ console.error(dim("(dry-run — pass --apply to write the repair)"));
203701
+ }
203702
+ }
203703
+ });
203704
+ process.exit(complete ? REPAIR_EXIT.OK : REPAIR_EXIT.DIVERGENCE_REMAINS);
203705
+ }
203519
203706
  function attachRepairCommand(cmd) {
203520
203707
  return cmd.requiredOption("--against <manifest>", "archive manifest: an https URL or a local file path").option("--from-block <n>", "first height to consider").option("--to-block <n>", "last height to consider").option("--apply", "write the repair (default is a dry-run plan)").option("--public-key <pem>", "pin a signing key; default is the archive key built into this release").option("-y, --yes", "skip the confirmation prompt for a metered fetch").option("--json", "Output as JSON").addHelpText("after", `
203521
203708
  Examples:
@@ -203528,6 +203715,11 @@ archive's partitions for that height. When the reference carries no
203528
203715
  transactions or events partition for a height, the block is rewritten alone,
203529
203716
  the run names the height, and it exits 1.
203530
203717
 
203718
+ When blocks already match the archive but a transactions or events partition
203719
+ does not, that range's transactions and events are replaced outright — there
203720
+ is no block or fork boundary to preserve, only stale rows underneath one that
203721
+ was never wrong.
203722
+
203531
203723
  Exit codes:
203532
203724
  0 nothing to repair, or the repair completed and re-verified clean
203533
203725
  1 divergence remains (dry-run, or repair did not fully resolve it)
@@ -203565,13 +203757,15 @@ Exit codes:
203565
203757
  }
203566
203758
  const divergent = compareRangeDigests(local, referenceDigests).filter((c) => c.status !== "match");
203567
203759
  if (divergent.length === 0) {
203568
- success("Nothing to repair — local blocks match the archive.");
203569
- output({
203570
- json: opts.json,
203571
- data: { status: "clean", fixes: [] },
203572
- human: () => {}
203760
+ const childMismatches = await planChildPartitionDivergence(db, reference.manifest.partitions ?? [], reference.manifest.zero_record_ranges ?? [], inRange);
203761
+ await runChildOnlyRepair({
203762
+ reference,
203763
+ childMismatches,
203764
+ apply: !!opts.apply,
203765
+ json: !!opts.json,
203766
+ yes: !!opts.yes
203573
203767
  });
203574
- process.exit(REPAIR_EXIT.OK);
203768
+ return;
203575
203769
  }
203576
203770
  const partitions = (reference.manifest.partitions ?? []).filter((p) => p.dataset === "blocks" && divergent.some((d) => d.from_block === p.from_block && d.to_block === p.to_block));
203577
203771
  const childPartitions = opts.apply ? (reference.manifest.partitions ?? []).filter((p) => (p.dataset === "transactions" || p.dataset === "events") && divergent.some((d) => p.from_block <= d.to_block && p.to_block >= d.from_block)) : [];
@@ -203672,7 +203866,7 @@ Exit codes:
203672
203866
  warn(` the reference has no ${dataset} partition for ${heights.length} height(s): ${heights.slice(0, 5).join(", ")}${heights.length > 5 ? ", …" : ""}`);
203673
203867
  }
203674
203868
  for (const height of missingHeights.slice(0, 5)) {
203675
- console.error(dim(` transactions/events at ${height}: run \`secondlayer bootstrap --from-block ${height} --to-block ${height}\``));
203869
+ console.error(dim(` the archive has no transactions/events at ${height} either: it cannot be repaired in place; re-ingest ${height} from your own node, or bootstrap a fresh database from the archive`));
203676
203870
  }
203677
203871
  }
203678
203872
  output({
@@ -205255,6 +205449,10 @@ function formatWebhookTarget(sub) {
205255
205449
  }
205256
205450
  return `${sub.subgraphName}.${sub.tableName}`;
205257
205451
  }
205452
+ function formatAuthLine(auth) {
205453
+ const scheme = auth.type === "bearer" ? auth.hasSecret ? "bearer token (set, hidden)" : "bearer (no token set)" : auth.type === "basic" ? auth.hasSecret ? "basic auth (set, hidden)" : "basic (no credentials set)" : "none";
205454
+ return auth.headerNames.length > 0 ? `${scheme}, headers: ${auth.headerNames.join(", ")}` : scheme;
205455
+ }
205258
205456
  function printWebhookDetail(sub) {
205259
205457
  console.log(formatKeyValue([
205260
205458
  ["ID", sub.id],
@@ -205264,6 +205462,7 @@ function printWebhookDetail(sub) {
205264
205462
  ["Format", sub.format],
205265
205463
  ["Runtime", sub.runtime ?? "none"],
205266
205464
  ["URL", sub.url],
205465
+ ["Auth", formatAuthLine(sub.auth)],
205267
205466
  ["Last Delivery", sub.lastDeliveryAt ?? "none"],
205268
205467
  ["Last Success", sub.lastSuccessAt ?? "none"],
205269
205468
  ["Circuit Failures", String(sub.circuitFailures)],
@@ -205279,11 +205478,6 @@ function printWebhookDetail(sub) {
205279
205478
  console.log(dim(`
205280
205479
  Filter:`));
205281
205480
  console.log(JSON.stringify(sub.filter, null, 2));
205282
- if (Object.keys(sub.authConfig).length > 0) {
205283
- console.log(dim(`
205284
- Auth config:`));
205285
- console.log(JSON.stringify(sub.authConfig, null, 2));
205286
- }
205287
205481
  }
205288
205482
  var DOCTOR_ISSUE_TITLES = {
205289
205483
  warning: "This webhook can't fire yet",
@@ -209059,5 +209253,5 @@ registerCreditsCommand(program);
209059
209253
  registerArchiveCommand(program);
209060
209254
  program.parse();
209061
209255
 
209062
- //# debugId=071DD5EE0E04E9D664756E2164756E21
209256
+ //# debugId=24E0496FE3D50C6164756E2164756E21
209063
209257
  //# sourceMappingURL=cli.js.map