@secondlayer/cli 15.0.1 → 16.0.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 +31 -33
- package/dist/cli.js.map +9 -9
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ No account. Writes `.env.local`, restores history, prints the Stacks observer st
|
|
|
82
82
|
| `secondlayer setup [--network …] [--node-mode external\|stacks\|full] [--api-port <spec>] [--dir <path>] [--against <manifest>] [--skip-bootstrap] [--skip-verify] [--yes] [--force]` | Guided self-host onboarding — secrets, compose + `.env`, docker up, observer stanza, bootstrap, verify. TUI when interactive; flags-only (no prompts) with `--yes` or no TTY |
|
|
83
83
|
| `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 |
|
|
84
84
|
| `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 |
|
|
85
|
-
| `secondlayer observer [--mode indexer\|signer-shared] [--endpoint host:port] [--
|
|
85
|
+
| `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` |
|
|
86
86
|
| `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 |
|
|
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
|
@@ -197993,7 +197993,8 @@ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, wr
|
|
|
197993
197993
|
import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
197994
197994
|
import { Index, resolveApiKey as resolveApiKey3, resolveBaseUrl } from "@secondlayer/sdk";
|
|
197995
197995
|
import {
|
|
197996
|
-
DECODED_EVENT_TYPES
|
|
197996
|
+
DECODED_EVENT_TYPES,
|
|
197997
|
+
VM_EVENT_TYPES
|
|
197997
197998
|
} from "@secondlayer/stacks/filters";
|
|
197998
197999
|
import {
|
|
197999
198000
|
runSubgraphTest as applySubgraphTest,
|
|
@@ -198030,7 +198031,13 @@ function eventTypeFor(filter) {
|
|
|
198030
198031
|
return null;
|
|
198031
198032
|
}
|
|
198032
198033
|
const candidate = filter.type === "print_event" ? "print" : filter.type;
|
|
198033
|
-
|
|
198034
|
+
if (DECODED_EVENT_TYPES.includes(candidate)) {
|
|
198035
|
+
return candidate;
|
|
198036
|
+
}
|
|
198037
|
+
if (VM_EVENT_TYPES.includes(candidate)) {
|
|
198038
|
+
return candidate;
|
|
198039
|
+
}
|
|
198040
|
+
return null;
|
|
198034
198041
|
}
|
|
198035
198042
|
function indexApiUrl() {
|
|
198036
198043
|
return resolveBaseUrl();
|
|
@@ -202446,13 +202453,6 @@ function parseObserverMode(value) {
|
|
|
202446
202453
|
}
|
|
202447
202454
|
throw new UnsupportedObserverError(`observer mode must be indexer or signer-shared (got ${value})`);
|
|
202448
202455
|
}
|
|
202449
|
-
function parseRecoverySource(value) {
|
|
202450
|
-
const source = value.trim().toLowerCase();
|
|
202451
|
-
if (RECOVERY_SOURCES.includes(source)) {
|
|
202452
|
-
return source;
|
|
202453
|
-
}
|
|
202454
|
-
throw new UnsupportedObserverError(`recovery source must be journal or archive (got ${value})`);
|
|
202455
|
-
}
|
|
202456
202456
|
function parseObserverEndpoint(value) {
|
|
202457
202457
|
const trimmed = value.trim();
|
|
202458
202458
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) || trimmed.startsWith("unix:")) {
|
|
@@ -202474,9 +202474,6 @@ function validateObserverStanza(input3) {
|
|
|
202474
202474
|
if (input3.network !== "devnet" && LOOPBACK_HOSTS.has(host.toLowerCase())) {
|
|
202475
202475
|
throw new UnsupportedObserverError(`loopback observer endpoint is not container-visible on ${input3.network}; use a docker DNS name such as indexer:3700`);
|
|
202476
202476
|
}
|
|
202477
|
-
if (input3.mode === "signer-shared" && !input3.recovery) {
|
|
202478
|
-
throw new UnsupportedObserverError("signer-shared mode requires --recovery journal or --recovery archive");
|
|
202479
|
-
}
|
|
202480
202477
|
return { endpoint };
|
|
202481
202478
|
}
|
|
202482
202479
|
function renderObserverStanza(input3) {
|
|
@@ -202484,7 +202481,7 @@ function renderObserverStanza(input3) {
|
|
|
202484
202481
|
const indexer = input3.mode === "indexer";
|
|
202485
202482
|
const timeoutMs = indexer ? 2000 : 500;
|
|
202486
202483
|
const disableRetries = !indexer;
|
|
202487
|
-
const comment = indexer ? "# Pure indexer: retry delivery. A slow observer can stall the node." : "# Signer-shared: do not retry.
|
|
202484
|
+
const comment = indexer ? "# Pure indexer: retry delivery. A slow observer can stall the node." : "# Signer-shared: do not retry. A missed block stays a gap until `secondlayer repair`.";
|
|
202488
202485
|
return [
|
|
202489
202486
|
comment,
|
|
202490
202487
|
"[[events_observer]]",
|
|
@@ -202501,10 +202498,9 @@ function defaultObserverEndpoint(network) {
|
|
|
202501
202498
|
return "127.0.0.1:3700";
|
|
202502
202499
|
return "indexer:3700";
|
|
202503
202500
|
}
|
|
202504
|
-
var OBSERVER_MODES,
|
|
202501
|
+
var OBSERVER_MODES, UnsupportedObserverError, LOOPBACK_HOSTS;
|
|
202505
202502
|
var init_observer_stanza = __esm(() => {
|
|
202506
202503
|
OBSERVER_MODES = ["indexer", "signer-shared"];
|
|
202507
|
-
RECOVERY_SOURCES = ["journal", "archive"];
|
|
202508
202504
|
UnsupportedObserverError = class UnsupportedObserverError extends Error {
|
|
202509
202505
|
name = "UnsupportedObserverError";
|
|
202510
202506
|
};
|
|
@@ -202706,7 +202702,7 @@ function resolveNonInteractiveConfig(flags) {
|
|
|
202706
202702
|
throw new MissingSetupFlagError("--node-mode", "Missing --node-mode <external|stacks|full>. Non-interactive setup requires it explicitly — there is no safe default.");
|
|
202707
202703
|
}
|
|
202708
202704
|
if (!flags.against && !flags.skipBootstrap) {
|
|
202709
|
-
throw new MissingSetupFlagError("--against", "Missing --against <manifest-url>. Pass an archive manifest to bootstrap from, or --skip-bootstrap to
|
|
202705
|
+
throw new MissingSetupFlagError("--against", "Missing --against <manifest-url>. Pass an archive manifest to bootstrap from, or --skip-bootstrap to index only what your node sends from now on.");
|
|
202710
202706
|
}
|
|
202711
202707
|
const network = parseInstanceNetwork(flags.network);
|
|
202712
202708
|
const nodeMode = parseSetupNodeMode(flags.nodeMode);
|
|
@@ -203894,7 +203890,7 @@ var {
|
|
|
203894
203890
|
// package.json
|
|
203895
203891
|
var package_default = {
|
|
203896
203892
|
name: "@secondlayer/cli",
|
|
203897
|
-
version: "
|
|
203893
|
+
version: "16.0.0",
|
|
203898
203894
|
description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
|
|
203899
203895
|
repository: {
|
|
203900
203896
|
type: "git",
|
|
@@ -203935,10 +203931,10 @@ var package_default = {
|
|
|
203935
203931
|
"@opentui/react": "^0.5.3",
|
|
203936
203932
|
"@secondlayer/bundler": "^0.5.3",
|
|
203937
203933
|
"@secondlayer/scaffold": "^1.5.7",
|
|
203938
|
-
"@secondlayer/sdk": "^10.4.
|
|
203939
|
-
"@secondlayer/shared": "^11.
|
|
203940
|
-
"@secondlayer/stacks": "^6.
|
|
203941
|
-
"@secondlayer/subgraphs": "^4.
|
|
203934
|
+
"@secondlayer/sdk": "^10.4.3",
|
|
203935
|
+
"@secondlayer/shared": "^11.7.0",
|
|
203936
|
+
"@secondlayer/stacks": "^6.1.0",
|
|
203937
|
+
"@secondlayer/subgraphs": "^4.4.0",
|
|
203942
203938
|
esbuild: "^0.28.2",
|
|
203943
203939
|
react: "^19.1.0",
|
|
203944
203940
|
"smol-toml": "^1.8.0",
|
|
@@ -204515,10 +204511,13 @@ Exit codes:
|
|
|
204515
204511
|
console.error(dim(` Scope starts at ${startHeight.toLocaleString()} — earlier history is declared out of scope, not missing.`));
|
|
204516
204512
|
}
|
|
204517
204513
|
if (seam) {
|
|
204518
|
-
console.error(dim(`
|
|
204519
|
-
console.error(dim(
|
|
204514
|
+
console.error(dim(`Your node was at ${seam.nodeTip.toLocaleString()} when the restore started, ${seam.gap.toLocaleString()} blocks past the archive tip.`));
|
|
204515
|
+
console.error(dim(` The index has a gap from ${(tipHeight + 1).toLocaleString()} to ${seam.nodeTip.toLocaleString()}. Blocks your node sent during the restore are ingested; nothing fills the gap on its own.`));
|
|
204516
|
+
console.error(dim(` After the next archive publish covers it: secondlayer repair --against ${opts.against} --from-block ${tipHeight + 1} --to-block ${seam.nodeTip} --apply`));
|
|
204517
|
+
} else if (nodeTipAtStart === null) {
|
|
204518
|
+
console.error(dim(" Start the indexer to continue from there. Node unreachable, so any gap past the archive tip is unknown; `secondlayer verify` finds it once the archive covers it."));
|
|
204520
204519
|
} else {
|
|
204521
|
-
console.error(dim(" Start the indexer to continue from there.
|
|
204520
|
+
console.error(dim(" Start the indexer to continue from there."));
|
|
204522
204521
|
}
|
|
204523
204522
|
} else {
|
|
204524
204523
|
const byDataset = verifyDatasets.map((d) => `${divergentRanges.filter((r) => r.dataset === d).length} ${d}`).join(", ");
|
|
@@ -208961,7 +208960,7 @@ init_observer_stanza();
|
|
|
208961
208960
|
init_output();
|
|
208962
208961
|
init_resolve_auth();
|
|
208963
208962
|
function registerObserverCommand(program2) {
|
|
208964
|
-
program2.command("observer").description("Print the Stacks events_observer stanza for this node mode").option("--mode <mode>", "indexer (retry) or signer-shared (no retry)", "indexer").option("--endpoint <host:port>", "Observer callback the node will POST to").
|
|
208963
|
+
program2.command("observer").description("Print the Stacks events_observer stanza for this node mode").option("--mode <mode>", "indexer (retry) or signer-shared (no retry)", "indexer").option("--endpoint <host:port>", "Observer callback the node will POST to").addHelpText("after", `
|
|
208965
208964
|
--network <mainnet|testnet|devnet> is the top-level global flag (see
|
|
208966
208965
|
\`secondlayer --help\`) — default mainnet, same as before.
|
|
208967
208966
|
`).action((opts) => {
|
|
@@ -208969,11 +208968,10 @@ function registerObserverCommand(program2) {
|
|
|
208969
208968
|
const mode = parseObserverMode(opts.mode);
|
|
208970
208969
|
const network = instanceNetworkFromEnv();
|
|
208971
208970
|
const endpoint = opts.endpoint ?? defaultObserverEndpoint(network);
|
|
208972
|
-
const recovery = opts.recovery ? parseRecoverySource(opts.recovery) : undefined;
|
|
208973
208971
|
if (mode === "signer-shared") {
|
|
208974
|
-
note("Signer-shared nodes skip observer retries.
|
|
208972
|
+
note("Signer-shared nodes skip observer retries. A missed block stays a gap until `secondlayer repair` fills it from the archive.");
|
|
208975
208973
|
}
|
|
208976
|
-
writeData(renderObserverStanza({ mode, endpoint, network
|
|
208974
|
+
writeData(renderObserverStanza({ mode, endpoint, network }));
|
|
208977
208975
|
});
|
|
208978
208976
|
}
|
|
208979
208977
|
// src/commands/setup.ts
|
|
@@ -209056,9 +209054,9 @@ async function promptSetupConfig(flags) {
|
|
|
209056
209054
|
description: "Enter your own"
|
|
209057
209055
|
},
|
|
209058
209056
|
{
|
|
209059
|
-
name: "
|
|
209057
|
+
name: "Skip the archive",
|
|
209060
209058
|
value: "skip",
|
|
209061
|
-
description: "
|
|
209059
|
+
description: "Index only what your node sends from now on"
|
|
209062
209060
|
}
|
|
209063
209061
|
]
|
|
209064
209062
|
});
|
|
@@ -209093,7 +209091,7 @@ async function promptSetupConfig(flags) {
|
|
|
209093
209091
|
console.error(` node mode ${config.nodeMode}`);
|
|
209094
209092
|
console.error(` dir ${config.dir}`);
|
|
209095
209093
|
console.error(` api port ${config.apiPort}`);
|
|
209096
|
-
console.error(` bootstrap ${config.skipBootstrap ? "skip (
|
|
209094
|
+
console.error(` bootstrap ${config.skipBootstrap ? "skip (from the node's tip)" : config.against}`);
|
|
209097
209095
|
console.error("");
|
|
209098
209096
|
const proceed = await confirm4({ message: "Start setup?", default: true });
|
|
209099
209097
|
if (!proceed)
|
|
@@ -209172,7 +209170,7 @@ async function runPromptedInteractive(flags) {
|
|
|
209172
209170
|
await executeAndRender(config);
|
|
209173
209171
|
}
|
|
209174
209172
|
function registerSetupCommand(program2) {
|
|
209175
|
-
program2.command("setup").description("Guided self-host onboarding: secrets, config, docker, bootstrap, verify — one command").option("--node-mode <mode>", "external, stacks, or full (required)").option("--api-port <spec>", "API publish spec", "127.0.0.1:3800").option("--dir <path>", "Target directory for compose + .env", ".").option("--against <manifest>", `Archive manifest to bootstrap from (suggested default: ${DEFAULT_ARCHIVE_MANIFEST})`).option("--skip-bootstrap", "
|
|
209173
|
+
program2.command("setup").description("Guided self-host onboarding: secrets, config, docker, bootstrap, verify — one command").option("--node-mode <mode>", "external, stacks, or full (required)").option("--api-port <spec>", "API publish spec", "127.0.0.1:3800").option("--dir <path>", "Target directory for compose + .env", ".").option("--against <manifest>", `Archive manifest to bootstrap from (suggested default: ${DEFAULT_ARCHIVE_MANIFEST})`).option("--skip-bootstrap", "Skip the archive restore; index only what your node sends from now on").option("--skip-verify", "Skip the post-bootstrap verify pass").option("--yes", "Non-interactive: skip the TUI, require flags, never prompt").option("--force", "Regenerate secrets even if a .env already exists in --dir").option("--owner <owner>", "ghcr image owner (namespace) to pull from").option("--image-tag <tag>", "Published image tag to run").addHelpText("after", `
|
|
209176
209174
|
--network <mainnet|testnet|devnet> is the top-level global flag (see
|
|
209177
209175
|
\`secondlayer --help\`) — required here too, just parsed one level up.
|
|
209178
209176
|
|
|
@@ -209266,5 +209264,5 @@ registerCreditsCommand(program);
|
|
|
209266
209264
|
registerArchiveCommand(program);
|
|
209267
209265
|
program.parse();
|
|
209268
209266
|
|
|
209269
|
-
//# debugId=
|
|
209267
|
+
//# debugId=F035865DCA2A5BEE64756E2164756E21
|
|
209270
209268
|
//# sourceMappingURL=cli.js.map
|