@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 +1 -1
- package/dist/cli.js +79 -14
- package/dist/cli.js.map +4 -4
- package/package.json +4 -4
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
202691
|
-
"@secondlayer/subgraphs": "^7.0
|
|
202692
|
-
"@secondlayer/verify": "^0.
|
|
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
|
|
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
|
|
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
|
|
204581
|
-
|
|
204582
|
-
|
|
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=
|
|
208477
|
+
//# debugId=36A335C6FBC2D29F64756E2164756E21
|
|
208413
208478
|
//# sourceMappingURL=cli.js.map
|