@secondlayer/cli 10.3.1 → 10.4.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 +60 -58
- package/dist/cli.js +225 -155
- package/dist/cli.js.map +42 -41
- package/package.json +2 -2
- package/templates/subscriptions/cloudflare/README.md +2 -2
- package/templates/subscriptions/node/README.md +2 -2
- package/templates/subscriptions/node/src/index.ts +2 -2
- package/templates/subscriptions/trigger/README.md +2 -2
package/dist/cli.js
CHANGED
|
@@ -2567,7 +2567,7 @@ async function resolveAuth() {
|
|
|
2567
2567
|
}
|
|
2568
2568
|
const session = await readSession();
|
|
2569
2569
|
if (!session) {
|
|
2570
|
-
const err = new Error("Not logged in — run `
|
|
2570
|
+
const err = new Error("Not logged in — run `secondlayer login`");
|
|
2571
2571
|
err.code = "SESSION_EXPIRED";
|
|
2572
2572
|
throw err;
|
|
2573
2573
|
}
|
|
@@ -2619,7 +2619,7 @@ async function httpPlatform(path2, opts = {}) {
|
|
|
2619
2619
|
try {
|
|
2620
2620
|
auth = await resolveAuth();
|
|
2621
2621
|
} catch {
|
|
2622
|
-
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, isOssMode() ? "Not authenticated — set SL_API_KEY from `
|
|
2622
|
+
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, isOssMode() ? "Not authenticated — set SL_API_KEY from `secondlayer init`" : "Not logged in — run `secondlayer login`");
|
|
2623
2623
|
}
|
|
2624
2624
|
return request(`${auth.apiUrl}${path2}`, {
|
|
2625
2625
|
...opts,
|
|
@@ -2640,7 +2640,7 @@ async function httpArchiveOps(path2, opts = {}) {
|
|
|
2640
2640
|
const session = envKey ? null : await readSession();
|
|
2641
2641
|
const bearer = envKey ?? session?.token;
|
|
2642
2642
|
if (!bearer) {
|
|
2643
|
-
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, "Not logged in — run `SL_API_URL=https://api.secondlayer.tools
|
|
2643
|
+
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, "Not logged in — run `SL_API_URL=https://api.secondlayer.tools secondlayer login`");
|
|
2644
2644
|
}
|
|
2645
2645
|
return request(`${resolveArchiveOpsUrl()}${path2}`, {
|
|
2646
2646
|
...opts,
|
|
@@ -2778,7 +2778,7 @@ function nextStepHint(status) {
|
|
|
2778
2778
|
if (status === undefined)
|
|
2779
2779
|
return;
|
|
2780
2780
|
if (status === 403)
|
|
2781
|
-
return "You may not have access — check your active project with `
|
|
2781
|
+
return "You may not have access — check your active project with `secondlayer whoami`.";
|
|
2782
2782
|
if (status === 404)
|
|
2783
2783
|
return "Check the name/slug — run the matching `list` command to see what exists.";
|
|
2784
2784
|
if (status === 400 || status === 422)
|
|
@@ -2786,14 +2786,14 @@ function nextStepHint(status) {
|
|
|
2786
2786
|
if (status === 429)
|
|
2787
2787
|
return "Rate limited — wait a moment and retry.";
|
|
2788
2788
|
if (status >= 500)
|
|
2789
|
-
return "Server error — retry shortly, or check `
|
|
2789
|
+
return "Server error — retry shortly, or check `secondlayer status`.";
|
|
2790
2790
|
return;
|
|
2791
2791
|
}
|
|
2792
2792
|
function handleApiError(err, action) {
|
|
2793
2793
|
const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
|
|
2794
2794
|
if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
|
|
2795
2795
|
printError("Authentication required.", {
|
|
2796
|
-
hint: isOssMode() ? "Set SL_API_KEY / INSTANCE_TOKEN from `
|
|
2796
|
+
hint: isOssMode() ? "Set SL_API_KEY / INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
|
|
2797
2797
|
});
|
|
2798
2798
|
process.exit(1);
|
|
2799
2799
|
}
|
|
@@ -28616,12 +28616,12 @@ function getDefaultConfig() {
|
|
|
28616
28616
|
async function requireLocalNetwork() {
|
|
28617
28617
|
const config = await loadConfig2();
|
|
28618
28618
|
if (config.network !== "local") {
|
|
28619
|
-
console.error(`Error: '
|
|
28619
|
+
console.error(`Error: 'secondlayer local' commands require local mode.`);
|
|
28620
28620
|
console.error(` Current context: ${config.network} (hosted)`);
|
|
28621
28621
|
console.error("");
|
|
28622
|
-
console.error(" To check system status, use:
|
|
28622
|
+
console.error(" To check system status, use: secondlayer status");
|
|
28623
28623
|
console.error("");
|
|
28624
|
-
console.error(" To switch to local mode:
|
|
28624
|
+
console.error(" To switch to local mode: secondlayer config set network local");
|
|
28625
28625
|
process.exit(1);
|
|
28626
28626
|
}
|
|
28627
28627
|
return config;
|
|
@@ -28783,7 +28783,7 @@ async function readStdin() {
|
|
|
28783
28783
|
async function runTokenLogin() {
|
|
28784
28784
|
const token = await readStdin();
|
|
28785
28785
|
if (!token) {
|
|
28786
|
-
error('No token on stdin. Usage: echo "$KEY" |
|
|
28786
|
+
error('No token on stdin. Usage: echo "$KEY" | secondlayer login --with-token');
|
|
28787
28787
|
process.exit(1);
|
|
28788
28788
|
}
|
|
28789
28789
|
process.env.SL_API_KEY = token;
|
|
@@ -28808,7 +28808,7 @@ async function runLoginFlow(options3 = {}) {
|
|
|
28808
28808
|
if (existing) {
|
|
28809
28809
|
info(`Already logged in as ${existing.email}.`);
|
|
28810
28810
|
if (!process.stdin.isTTY) {
|
|
28811
|
-
info(dim("Run '
|
|
28811
|
+
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
28812
28812
|
return;
|
|
28813
28813
|
}
|
|
28814
28814
|
try {
|
|
@@ -28817,11 +28817,11 @@ async function runLoginFlow(options3 = {}) {
|
|
|
28817
28817
|
default: false
|
|
28818
28818
|
});
|
|
28819
28819
|
if (!proceed) {
|
|
28820
|
-
info(dim("Run '
|
|
28820
|
+
info(dim("Run 'secondlayer logout' to sign out."));
|
|
28821
28821
|
return;
|
|
28822
28822
|
}
|
|
28823
28823
|
} catch {
|
|
28824
|
-
info(dim("Run '
|
|
28824
|
+
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
28825
28825
|
return;
|
|
28826
28826
|
}
|
|
28827
28827
|
}
|
|
@@ -28863,7 +28863,7 @@ async function runLoginFlow(options3 = {}) {
|
|
|
28863
28863
|
expiresAt: sessionExpiry()
|
|
28864
28864
|
});
|
|
28865
28865
|
success(`Logged in as ${verified.account.email}`);
|
|
28866
|
-
info(dim("Run '
|
|
28866
|
+
info(dim("Run 'secondlayer whoami' to see your account status."));
|
|
28867
28867
|
} catch (err) {
|
|
28868
28868
|
if (err instanceof CliHttpError) {
|
|
28869
28869
|
error(err.message);
|
|
@@ -28876,8 +28876,8 @@ async function runLoginFlow(options3 = {}) {
|
|
|
28876
28876
|
function registerLoginCommand(program2) {
|
|
28877
28877
|
program2.command("login", { hidden: true }).description("Log in to Secondlayer (magic-link email)").option("--force", "Skip the already-logged-in check and re-run the flow").option("--with-token", "Read an API key from stdin (non-interactive)").addHelpText("after", `
|
|
28878
28878
|
Examples:
|
|
28879
|
-
$
|
|
28880
|
-
$ echo "$SL_API_KEY" |
|
|
28879
|
+
$ secondlayer login
|
|
28880
|
+
$ echo "$SL_API_KEY" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin() : runLoginFlow({ force: opts.force }));
|
|
28881
28881
|
}
|
|
28882
28882
|
var init_login = __esm(() => {
|
|
28883
28883
|
init_http();
|
|
@@ -28927,12 +28927,12 @@ function nextStepsHeader(name) {
|
|
|
28927
28927
|
//
|
|
28928
28928
|
// 1. Edit the source filter + schema below to match what you want to track.
|
|
28929
28929
|
// 2. Edit the handler at the bottom — it runs once per matching event.
|
|
28930
|
-
// 3. Deploy:
|
|
28930
|
+
// 3. Deploy: secondlayer subgraphs deploy ${name}.ts
|
|
28931
28931
|
// (You'll be prompted to log in if this is your first remote deploy.)
|
|
28932
|
-
// 4. Wait for sync:
|
|
28932
|
+
// 4. Wait for sync: secondlayer subgraphs status ${name}
|
|
28933
28933
|
// Mainnet backfill from genesis can take an hour or more depending on
|
|
28934
28934
|
// your filter scope. Use --start-block to skip ahead.
|
|
28935
|
-
// 5. Query:
|
|
28935
|
+
// 5. Query: secondlayer subgraphs query ${name} <table-name>
|
|
28936
28936
|
// Or hit the auto-generated REST endpoint listed in the deploy output.
|
|
28937
28937
|
//
|
|
28938
28938
|
// Bind a typed Subscription to any table you write here — see
|
|
@@ -29415,7 +29415,7 @@ async function runSubgraphTest(file, options3) {
|
|
|
29415
29415
|
toHeight = usable.toHeight;
|
|
29416
29416
|
} else {
|
|
29417
29417
|
if (options3.offline) {
|
|
29418
|
-
error("No usable cassette for --offline. Record one first:
|
|
29418
|
+
error("No usable cassette for --offline. Record one first: secondlayer subgraphs test <file> --from <h> --to <h>");
|
|
29419
29419
|
process.exit(1);
|
|
29420
29420
|
}
|
|
29421
29421
|
if (!options3.from) {
|
|
@@ -30018,10 +30018,10 @@ function registerSubgraphsCommand(program2) {
|
|
|
30018
30018
|
const subgraphs = program2.command("subgraphs").description("Manage materialized subgraphs");
|
|
30019
30019
|
subgraphs.command("create <name>").description("Create a new subgraph definition file").option("--template <slug>", `Starter template (one of: ${SUBGRAPH_TEMPLATE_SLUGS.join(", ")})`).option("--from-contract <contractId>", "Generate sources/schema/handlers from the contract's observed print events (requires network)").option("--table-per-topic", "With --from-contract: one table per print topic instead of a single wide table").addHelpText("after", `
|
|
30020
30020
|
Examples:
|
|
30021
|
-
$
|
|
30022
|
-
$
|
|
30023
|
-
$
|
|
30024
|
-
$
|
|
30021
|
+
$ secondlayer subgraphs create my-graph
|
|
30022
|
+
$ secondlayer subgraphs create token-balances --template sip-010-balances
|
|
30023
|
+
$ secondlayer subgraphs create sbtc-flows --from-contract SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry
|
|
30024
|
+
$ secondlayer subgraphs create sbtc-flows --from-contract SM3....sbtc-registry --table-per-topic`).action(async (name, opts) => {
|
|
30025
30025
|
if (opts.fromContract && opts.template) {
|
|
30026
30026
|
error("--from-contract and --template are mutually exclusive");
|
|
30027
30027
|
process.exit(1);
|
|
@@ -30077,7 +30077,7 @@ Check the contract id, and that the contract has emitted print events (schemas a
|
|
|
30077
30077
|
} else if (slug !== "basic") {
|
|
30078
30078
|
info(`Template: ${slug} — ${SUBGRAPH_TEMPLATE_DESCRIPTIONS[slug]}`);
|
|
30079
30079
|
}
|
|
30080
|
-
info(`Next:
|
|
30080
|
+
info(`Next: secondlayer subgraphs deploy subgraphs/${name}.ts`);
|
|
30081
30081
|
});
|
|
30082
30082
|
subgraphs.command("dev <file>").description("Watch a subgraph file and auto-redeploy on change").action(async (file) => {
|
|
30083
30083
|
await requireLocalNetwork();
|
|
@@ -30276,15 +30276,15 @@ Stopped watching.`);
|
|
|
30276
30276
|
info(` Share: ${apiUrl}/v1/subgraphs/${effectiveDef.name} (public — no key needed)`);
|
|
30277
30277
|
} else if (firstTable) {
|
|
30278
30278
|
info(` REST: ${apiUrl}/api/subgraphs/${effectiveDef.name}/${firstTable}`);
|
|
30279
|
-
info(` Publish:
|
|
30279
|
+
info(` Publish: secondlayer subgraphs publish ${effectiveDef.name} (open anon /v1 reads)`);
|
|
30280
30280
|
}
|
|
30281
30281
|
if (result.reindexStarted) {
|
|
30282
30282
|
const denom = result.estimatedEvents != null ? ` ~${result.estimatedEvents.toLocaleString()} events —` : "";
|
|
30283
30283
|
info(` Reindex: ${denom} started in the background — check status in ~30s for an ETA`);
|
|
30284
30284
|
}
|
|
30285
|
-
info(` Watch:
|
|
30285
|
+
info(` Watch: secondlayer subgraphs status ${effectiveDef.name}`);
|
|
30286
30286
|
if (firstTable) {
|
|
30287
|
-
info(` Webhook:
|
|
30287
|
+
info(` Webhook: secondlayer subscriptions create ${effectiveDef.name}-hook --subgraph ${effectiveDef.name} --table ${firstTable} --url <your-endpoint>`);
|
|
30288
30288
|
}
|
|
30289
30289
|
} catch {}
|
|
30290
30290
|
};
|
|
@@ -30430,7 +30430,7 @@ ${data.length} subgraph(s) total`));
|
|
|
30430
30430
|
]));
|
|
30431
30431
|
if (sync && sync.gaps.count > 0) {
|
|
30432
30432
|
console.log(dim(`
|
|
30433
|
-
Run:
|
|
30433
|
+
Run: secondlayer subgraphs gaps ${name}`));
|
|
30434
30434
|
}
|
|
30435
30435
|
const tableEntries = Object.entries(subgraph.tables);
|
|
30436
30436
|
if (tableEntries.length > 0) {
|
|
@@ -30482,23 +30482,23 @@ Synced — exiting watch.`));
|
|
|
30482
30482
|
}
|
|
30483
30483
|
});
|
|
30484
30484
|
subgraphs.command("codegen <file>").description("Generate an ORM schema (Prisma, Drizzle, or Kysely) for a subgraph's tables — point it at your BYO database").option("--target <orm>", "ORM target: prisma | drizzle | kysely", "prisma").option("--schema <name>", "Postgres schema name (defaults to subgraph_<name>)").option("--env <var>", "datasource url env var", "DATABASE_URL").option("--models-only", "Emit only Prisma models (compose via prismaSchemaFolder)").option("--payloads", "Emit a .d.ts of print payload types for pinned print_event sources, inferred from observed on-chain events (requires network)").option("-o, --output <path>", "Write to a file (defaults to stdout)").action(async (file, options3, command) => {
|
|
30485
|
-
deprecatedCodegenNotice("
|
|
30485
|
+
deprecatedCodegenNotice("secondlayer subgraphs codegen", options3.payloads ? "secondlayer codegen prints" : "secondlayer codegen subgraph");
|
|
30486
30486
|
await runSubgraphSchemaCodegen(file, options3, (key) => command.getOptionValueSource(key));
|
|
30487
30487
|
});
|
|
30488
30488
|
subgraphs.command("test <file>").description("Run a subgraph's handlers against real chain data without deploying").option("--from <height>", "Start block height (required on first run)").option("--to <height>", "End block height (defaults to --from + 100)").option("--offline", "Replay the recorded cassette; never hit the network").option("--no-record", "Don't write a cassette").option("--limit <n>", "Max events per source", "500").addHelpText("after", `
|
|
30489
30489
|
Examples:
|
|
30490
|
-
$
|
|
30491
|
-
$
|
|
30490
|
+
$ secondlayer subgraphs test subgraphs/bns-names.ts --from 167484 --to 167600
|
|
30491
|
+
$ secondlayer subgraphs test subgraphs/bns-names.ts --offline`).action(async (file, options3) => {
|
|
30492
30492
|
const { runSubgraphTest: runSubgraphTest2 } = await Promise.resolve().then(() => (init_subgraph_test(), exports_subgraph_test));
|
|
30493
30493
|
await runSubgraphTest2(file, options3);
|
|
30494
30494
|
});
|
|
30495
30495
|
subgraphs.command("reindex <name>").description("Drop a subgraph's data and rebuild it from its start block (destructive)").option("-y, --yes", "Skip confirmation").addHelpText("after", `
|
|
30496
30496
|
Reindex is always whole-subgraph: it drops every row and rebuilds from the
|
|
30497
30497
|
subgraph's start block to chain tip. To process a specific block range without
|
|
30498
|
-
dropping anything, use "
|
|
30498
|
+
dropping anything, use "secondlayer subgraphs backfill".
|
|
30499
30499
|
|
|
30500
30500
|
Examples:
|
|
30501
|
-
$
|
|
30501
|
+
$ secondlayer subgraphs reindex my-graph -y`).action(async (name, options3) => {
|
|
30502
30502
|
try {
|
|
30503
30503
|
if (!options3.yes) {
|
|
30504
30504
|
if (!process.stdin.isTTY) {
|
|
@@ -30535,7 +30535,7 @@ Examples:
|
|
|
30535
30535
|
});
|
|
30536
30536
|
subgraphs.command("backfill <name>").description("Backfill a block range without dropping existing data").option("--from-block <n>", "Start block height").option("--to-block <n>", "End block height").addHelpText("after", `
|
|
30537
30537
|
Examples:
|
|
30538
|
-
$
|
|
30538
|
+
$ secondlayer subgraphs backfill my-graph --from-block 150000 --to-block 160000`).action(async (name, options3) => {
|
|
30539
30539
|
try {
|
|
30540
30540
|
const fromRaw = options3.fromBlock;
|
|
30541
30541
|
const toRaw = options3.toBlock;
|
|
@@ -30600,9 +30600,9 @@ ${result.meta.total} gap(s), ${result.meta.totalMissingBlocks} total missing blo
|
|
|
30600
30600
|
});
|
|
30601
30601
|
subgraphs.command("query <name> <table>").description("Query a subgraph table").option("--sort <column>", "Sort by column").option("--order <dir>", "Sort direction (asc|desc)", "asc").option("--limit <n>", "Max rows to return", "20").option("--offset <n>", "Skip first N rows").option("--fields <cols>", "Comma-separated columns to include").option("--filter <kv...>", "Filter as key=value (supports .gte/.lte/.gt/.lt/.neq suffixes)").option("--count", "Return row count only").option("--json", "Output as JSON").addHelpText("after", `
|
|
30602
30602
|
Examples:
|
|
30603
|
-
$
|
|
30604
|
-
$
|
|
30605
|
-
$
|
|
30603
|
+
$ secondlayer subgraphs query my-graph balances --filter holder=SP2J6ZY... --limit 50
|
|
30604
|
+
$ secondlayer subgraphs query my-graph transfers --filter amount.gte=1000 --sort _block_height --order desc
|
|
30605
|
+
$ secondlayer subgraphs query my-graph balances --count`).action(async (name, table, options3) => {
|
|
30606
30606
|
try {
|
|
30607
30607
|
let filters;
|
|
30608
30608
|
try {
|
|
@@ -30729,9 +30729,9 @@ ${rows.length} row(s)`));
|
|
|
30729
30729
|
});
|
|
30730
30730
|
subgraphs.command("scaffold [contractAddress]").description("Scaffold a defineSubgraph() file from a contract or trait").option("-o, --output <path>", "Output file path (required)").option("-k, --api-key <key>", "Stacks node API key for direct RPC URLs").option("--functions <names>", "Comma-separated public functions to index as typed contract_call tables").option("--trait <std>", "Scaffold a trait-scoped source (sip-009|sip-010|sip-013) — no contract needed").option("--no-install", "Skip bun install after writing package.json").addHelpText("after", `
|
|
30731
30731
|
Examples:
|
|
30732
|
-
$
|
|
30733
|
-
$
|
|
30734
|
-
$
|
|
30732
|
+
$ secondlayer subgraphs scaffold SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft -o subgraphs/apes.ts
|
|
30733
|
+
$ secondlayer subgraphs scaffold SP00...token --functions transfer,mint -o subgraphs/token.ts
|
|
30734
|
+
$ secondlayer subgraphs scaffold --trait sip-010 -o subgraphs/all-ft.ts`).action(async (contractAddress, options3) => {
|
|
30735
30735
|
try {
|
|
30736
30736
|
if (!options3.output) {
|
|
30737
30737
|
error("--output <path> is required");
|
|
@@ -30784,14 +30784,14 @@ Examples:
|
|
|
30784
30784
|
process.exit(1);
|
|
30785
30785
|
}
|
|
30786
30786
|
}
|
|
30787
|
-
info(`Next:
|
|
30787
|
+
info(`Next: secondlayer subgraphs deploy ${options3.output}`);
|
|
30788
30788
|
} catch (err) {
|
|
30789
30789
|
error(`Failed to scaffold subgraph: ${err}`);
|
|
30790
30790
|
process.exit(1);
|
|
30791
30791
|
}
|
|
30792
30792
|
});
|
|
30793
30793
|
subgraphs.command("client <subgraphName>").description("Generate a typed query client for a deployed subgraph").option("-o, --output <path>", "Output file path (required)").action(async (subgraphName, options3) => {
|
|
30794
|
-
deprecatedCodegenNotice("
|
|
30794
|
+
deprecatedCodegenNotice("secondlayer subgraphs client", "secondlayer codegen client");
|
|
30795
30795
|
await runSubgraphClientCodegen(subgraphName, options3);
|
|
30796
30796
|
});
|
|
30797
30797
|
}
|
|
@@ -30956,7 +30956,7 @@ function emitOne(doc, label, json) {
|
|
|
30956
30956
|
function registerIndexCommand(program2) {
|
|
30957
30957
|
const index = program2.command("index").description("Query the decoded Index layer (events + contract calls)");
|
|
30958
30958
|
index.command("codegen").description("Generate a typed schema (Prisma, Kysely, Drizzle, or JSON-Schema) for the Index domain tables — point it at your BYO database mirror").option("--target <orm>", "prisma | kysely | drizzle | json-schema", "kysely").option("--schema <name>", "Postgres schema to qualify table names with").option("--tables <list>", "Comma-separated subset of Index tables (default: all)").option("--env <var>", "Prisma datasource url env var", "DATABASE_URL").option("-o, --output <path>", "Write to a file (defaults to stdout)").action(async (o3) => {
|
|
30959
|
-
deprecatedCodegenNotice("
|
|
30959
|
+
deprecatedCodegenNotice("secondlayer index codegen", "secondlayer codegen index");
|
|
30960
30960
|
await runIndexCodegen(o3);
|
|
30961
30961
|
});
|
|
30962
30962
|
const rangeFlags = (cmd) => cmd.option("--contract-id <id>", "Filter by contract id").option("--from-height <n>", "Start block height (inclusive)").option("--to-height <n>", "End block height (inclusive)").option("--cursor <cursor>", "Resume token from a previous next_cursor").option("--limit <n>", "Rows per page").option("--json", "Print the full envelope as JSON");
|
|
@@ -33752,9 +33752,9 @@ async function isDevAlreadyRunning() {
|
|
|
33752
33752
|
printRunningServices(running);
|
|
33753
33753
|
console.log("");
|
|
33754
33754
|
console.log(dim("Commands:"));
|
|
33755
|
-
console.log(` ${green("
|
|
33756
|
-
console.log(` ${green("
|
|
33757
|
-
console.log(` ${green("
|
|
33755
|
+
console.log(` ${green("secondlayer local logs")} ${dim("View logs")}`);
|
|
33756
|
+
console.log(` ${green("secondlayer local stop")} ${dim("Stop all services")}`);
|
|
33757
|
+
console.log(` ${green("secondlayer local status")} ${dim("Show status")}`);
|
|
33758
33758
|
return true;
|
|
33759
33759
|
}
|
|
33760
33760
|
return false;
|
|
@@ -33896,9 +33896,9 @@ async function runBackground(options3) {
|
|
|
33896
33896
|
success("Dev environment started in background");
|
|
33897
33897
|
console.log("");
|
|
33898
33898
|
console.log(dim("Commands:"));
|
|
33899
|
-
console.log(` ${green("
|
|
33900
|
-
console.log(` ${green("
|
|
33901
|
-
console.log(` ${green("
|
|
33899
|
+
console.log(` ${green("secondlayer local logs -f")} ${dim("Follow logs")}`);
|
|
33900
|
+
console.log(` ${green("secondlayer local stop")} ${dim("Stop all services")}`);
|
|
33901
|
+
console.log(` ${green("secondlayer local status")} ${dim("Show status")}`);
|
|
33902
33902
|
console.log("");
|
|
33903
33903
|
process.exit(0);
|
|
33904
33904
|
} catch (err) {
|
|
@@ -34009,7 +34009,7 @@ async function showLogs(options3) {
|
|
|
34009
34009
|
const state = await loadDevState();
|
|
34010
34010
|
if (!state || Object.keys(state.services).length === 0) {
|
|
34011
34011
|
error("Dev environment is not running");
|
|
34012
|
-
console.log(dim("Start with:
|
|
34012
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34013
34013
|
process.exit(1);
|
|
34014
34014
|
}
|
|
34015
34015
|
const services = options3.service ? { [options3.service]: state.services[options3.service] } : state.services;
|
|
@@ -34148,7 +34148,7 @@ async function restartDev() {
|
|
|
34148
34148
|
const state = await loadDevState();
|
|
34149
34149
|
if (!state) {
|
|
34150
34150
|
info("Dev environment is not running");
|
|
34151
|
-
console.log(dim("Start with:
|
|
34151
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34152
34152
|
return;
|
|
34153
34153
|
}
|
|
34154
34154
|
info("Restarting dev services...");
|
|
@@ -34253,7 +34253,7 @@ async function showDevStatus() {
|
|
|
34253
34253
|
const state = await loadDevState();
|
|
34254
34254
|
if (!state) {
|
|
34255
34255
|
info("Dev environment is not running");
|
|
34256
|
-
console.log(dim("Start with:
|
|
34256
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34257
34257
|
return;
|
|
34258
34258
|
}
|
|
34259
34259
|
const running = await getRunningServices();
|
|
@@ -34488,9 +34488,9 @@ async function runSetupWizard() {
|
|
|
34488
34488
|
]));
|
|
34489
34489
|
console.log("");
|
|
34490
34490
|
console.log(dim("Next steps:"));
|
|
34491
|
-
console.log(` ${green("
|
|
34492
|
-
console.log(` ${green("
|
|
34493
|
-
console.log(` ${green("
|
|
34491
|
+
console.log(` ${green("secondlayer local node start")}${dim(" - Start the Stacks node")}`);
|
|
34492
|
+
console.log(` ${green("secondlayer local node status")}${dim(" - Check sync progress")}`);
|
|
34493
|
+
console.log(` ${green("secondlayer local node logs")}${dim(" - View logs")}`);
|
|
34494
34494
|
console.log("");
|
|
34495
34495
|
}
|
|
34496
34496
|
async function startNode(pathOverride, withIndexer) {
|
|
@@ -34499,7 +34499,7 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34499
34499
|
const network = config.node?.network || "mainnet";
|
|
34500
34500
|
if (!nodePath) {
|
|
34501
34501
|
error("Node not configured");
|
|
34502
|
-
console.log(dim("Run '
|
|
34502
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34503
34503
|
process.exit(1);
|
|
34504
34504
|
}
|
|
34505
34505
|
if (!await isDockerRunning()) {
|
|
@@ -34508,8 +34508,8 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34508
34508
|
}
|
|
34509
34509
|
if (await isNodeRunning()) {
|
|
34510
34510
|
info("Node is already running");
|
|
34511
|
-
console.log(dim("Run '
|
|
34512
|
-
console.log(dim("Run '
|
|
34511
|
+
console.log(dim("Run 'secondlayer local node logs' to view output"));
|
|
34512
|
+
console.log(dim("Run 'secondlayer local node stop' to stop"));
|
|
34513
34513
|
return;
|
|
34514
34514
|
}
|
|
34515
34515
|
const validation = await validateNetworkConsistency(config);
|
|
@@ -34536,13 +34536,13 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34536
34536
|
console.log("");
|
|
34537
34537
|
if (withIndexer) {
|
|
34538
34538
|
const port = config.ports?.indexer || 3700;
|
|
34539
|
-
console.log(dim("Tip: Start indexer with:
|
|
34539
|
+
console.log(dim("Tip: Start indexer with: secondlayer local start"));
|
|
34540
34540
|
console.log(dim(` Or manually: PORT=${port} bun run packages/indexer/src/index.ts`));
|
|
34541
34541
|
console.log("");
|
|
34542
34542
|
}
|
|
34543
34543
|
console.log(dim("Next steps:"));
|
|
34544
|
-
console.log(` ${green("
|
|
34545
|
-
console.log(` ${green("
|
|
34544
|
+
console.log(` ${green("secondlayer local node status")}${dim(" - Check sync progress")}`);
|
|
34545
|
+
console.log(` ${green("secondlayer local node logs -f")}${dim(" - Follow logs")}`);
|
|
34546
34546
|
console.log("");
|
|
34547
34547
|
}
|
|
34548
34548
|
async function stopNode(_pathOverride, force, _wait) {
|
|
@@ -34575,7 +34575,7 @@ async function restartNode(pathOverride, force, _wait) {
|
|
|
34575
34575
|
const network = config.node?.network || "mainnet";
|
|
34576
34576
|
if (!nodePath) {
|
|
34577
34577
|
error("Node not configured");
|
|
34578
|
-
console.log(dim("Run '
|
|
34578
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34579
34579
|
process.exit(1);
|
|
34580
34580
|
}
|
|
34581
34581
|
const wasRunning = await isNodeRunning();
|
|
@@ -34614,8 +34614,8 @@ async function restartNode(pathOverride, force, _wait) {
|
|
|
34614
34614
|
success("Node started!");
|
|
34615
34615
|
console.log("");
|
|
34616
34616
|
console.log(dim("Next steps:"));
|
|
34617
|
-
console.log(` ${green("
|
|
34618
|
-
console.log(` ${green("
|
|
34617
|
+
console.log(` ${green("secondlayer local node status")}${dim(" - Check sync progress")}`);
|
|
34618
|
+
console.log(` ${green("secondlayer local node logs -f")}${dim(" - Follow logs")}`);
|
|
34619
34619
|
console.log("");
|
|
34620
34620
|
}
|
|
34621
34621
|
async function showStatus(pathOverride, jsonOutput) {
|
|
@@ -34624,7 +34624,7 @@ async function showStatus(pathOverride, jsonOutput) {
|
|
|
34624
34624
|
const network = config.node?.network || "mainnet";
|
|
34625
34625
|
if (!nodePath) {
|
|
34626
34626
|
error("Node not configured");
|
|
34627
|
-
console.log(dim("Run '
|
|
34627
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34628
34628
|
process.exit(1);
|
|
34629
34629
|
}
|
|
34630
34630
|
const running = await isNodeRunning();
|
|
@@ -34721,7 +34721,7 @@ async function showStatus(pathOverride, jsonOutput) {
|
|
|
34721
34721
|
if (config.node) {
|
|
34722
34722
|
console.log(blue("Indexer"));
|
|
34723
34723
|
console.log(` ${dim("-")} ${dim(`Not running (expected on port ${indexerPort})`)}`);
|
|
34724
|
-
console.log(dim(" Start with:
|
|
34724
|
+
console.log(dim(" Start with: secondlayer local start"));
|
|
34725
34725
|
console.log("");
|
|
34726
34726
|
}
|
|
34727
34727
|
}
|
|
@@ -34733,7 +34733,7 @@ async function showConfig() {
|
|
|
34733
34733
|
console.log("");
|
|
34734
34734
|
if (!config.node?.installPath) {
|
|
34735
34735
|
warn("Node not configured");
|
|
34736
|
-
console.log(dim("Run '
|
|
34736
|
+
console.log(dim("Run 'secondlayer local node setup' to configure"));
|
|
34737
34737
|
console.log("");
|
|
34738
34738
|
return;
|
|
34739
34739
|
}
|
|
@@ -34744,7 +34744,7 @@ async function showConfig() {
|
|
|
34744
34744
|
]));
|
|
34745
34745
|
console.log("");
|
|
34746
34746
|
console.log(dim("Config file: ~/.secondlayer/config.json"));
|
|
34747
|
-
console.log(dim("Run '
|
|
34747
|
+
console.log(dim("Run 'secondlayer local node config --edit' to modify"));
|
|
34748
34748
|
console.log("");
|
|
34749
34749
|
}
|
|
34750
34750
|
async function showConfigCheck(indexerPort) {
|
|
@@ -34772,7 +34772,7 @@ async function showConfigCheck(indexerPort) {
|
|
|
34772
34772
|
}
|
|
34773
34773
|
} catch {
|
|
34774
34774
|
warn(`Indexer not detected on port ${indexerPort}`);
|
|
34775
|
-
console.log(dim("Start with:
|
|
34775
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34776
34776
|
}
|
|
34777
34777
|
console.log("");
|
|
34778
34778
|
}
|
|
@@ -34789,7 +34789,7 @@ init_esm();
|
|
|
34789
34789
|
// package.json
|
|
34790
34790
|
var package_default = {
|
|
34791
34791
|
name: "@secondlayer/cli",
|
|
34792
|
-
version: "10.
|
|
34792
|
+
version: "10.4.0",
|
|
34793
34793
|
repository: {
|
|
34794
34794
|
type: "git",
|
|
34795
34795
|
url: "git+https://github.com/ryanwaits/secondlayer.git",
|
|
@@ -34833,7 +34833,7 @@ var package_default = {
|
|
|
34833
34833
|
"@secondlayer/bundler": "^0.5.0",
|
|
34834
34834
|
"@secondlayer/scaffold": "^1.5.1",
|
|
34835
34835
|
"@secondlayer/sdk": "^6.54.1",
|
|
34836
|
-
"@secondlayer/shared": "^7.11.
|
|
34836
|
+
"@secondlayer/shared": "^7.11.2",
|
|
34837
34837
|
"@secondlayer/stacks": "^3.3.1",
|
|
34838
34838
|
"@secondlayer/subgraphs": "^3.26.4",
|
|
34839
34839
|
esbuild: "^0.27.4",
|
|
@@ -34876,13 +34876,16 @@ async function runBillingStatus(json) {
|
|
|
34876
34876
|
output({ json, data: res, human: () => renderBillingStatus(res) });
|
|
34877
34877
|
}
|
|
34878
34878
|
function addBillingCommand(parent) {
|
|
34879
|
-
parent.command("billing").description("Show archive credit balance (hidden; use
|
|
34879
|
+
parent.command("billing").description("Show archive credit balance (hidden; use secondlayer credits)").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
|
|
34880
34880
|
}
|
|
34881
34881
|
function renderBillingStatus(res) {
|
|
34882
34882
|
if (!res.subscription) {
|
|
34883
34883
|
console.log(formatKeyValue([
|
|
34884
|
-
["Credits", dim("
|
|
34885
|
-
[
|
|
34884
|
+
["Credits", dim("secondlayer credits balance")],
|
|
34885
|
+
[
|
|
34886
|
+
"Buy",
|
|
34887
|
+
dim("secondlayer credits buy --email you@example.com --pack 25")
|
|
34888
|
+
]
|
|
34886
34889
|
]));
|
|
34887
34890
|
return;
|
|
34888
34891
|
}
|
|
@@ -35015,7 +35018,7 @@ async function runBuy(opts) {
|
|
|
35015
35018
|
human: () => {
|
|
35016
35019
|
success(`Checkout for $${amount} → ${email}`);
|
|
35017
35020
|
console.log(res.url);
|
|
35018
|
-
console.log(dim("After payment: SL_API_URL=https://api.secondlayer.tools
|
|
35021
|
+
console.log(dim("After payment: SL_API_URL=https://api.secondlayer.tools secondlayer login && secondlayer credits balance"));
|
|
35019
35022
|
}
|
|
35020
35023
|
});
|
|
35021
35024
|
}
|
|
@@ -35043,7 +35046,10 @@ async function runBalance(opts) {
|
|
|
35043
35046
|
"Refill",
|
|
35044
35047
|
refill?.belowUsd != null ? `on — below $${refill.belowUsd} buy $${refill.packUsd}` : dim("off")
|
|
35045
35048
|
],
|
|
35046
|
-
[
|
|
35049
|
+
[
|
|
35050
|
+
"Buy",
|
|
35051
|
+
dim("secondlayer credits buy --email you@example.com --pack 25")
|
|
35052
|
+
]
|
|
35047
35053
|
]));
|
|
35048
35054
|
}
|
|
35049
35055
|
});
|
|
@@ -35354,9 +35360,9 @@ function registerConfigCommand(program2) {
|
|
|
35354
35360
|
});
|
|
35355
35361
|
config.command("set <key> <value>").description("Set a configuration value (supports dot notation: ports.api)").option("--no-validate", "Skip connection validation for database/redis URLs").addHelpText("after", `
|
|
35356
35362
|
Examples:
|
|
35357
|
-
$
|
|
35358
|
-
$
|
|
35359
|
-
$
|
|
35363
|
+
$ secondlayer config set network local
|
|
35364
|
+
$ secondlayer config set ports.api 3800
|
|
35365
|
+
$ secondlayer config set database.url postgres://localhost:5432/secondlayer_dev`).action(async (key, value, options3) => {
|
|
35360
35366
|
try {
|
|
35361
35367
|
await setConfigValue(key, value);
|
|
35362
35368
|
success(`Set ${key} = ${value}`);
|
|
@@ -35445,7 +35451,7 @@ async function printConfigTree(cfg) {
|
|
|
35445
35451
|
const status = node.running ? green("●") : dim("○");
|
|
35446
35452
|
console.log(dim(` ${status} ${node.path} (${node.network})`));
|
|
35447
35453
|
}
|
|
35448
|
-
console.log(dim(" Run '
|
|
35454
|
+
console.log(dim(" Run 'secondlayer init' to configure"));
|
|
35449
35455
|
}
|
|
35450
35456
|
} catch {}
|
|
35451
35457
|
}
|
|
@@ -35491,6 +35497,65 @@ async function validateDatabaseConnection(url) {
|
|
|
35491
35497
|
console.log(dim("The URL was saved but connection failed. Check your database settings."));
|
|
35492
35498
|
}
|
|
35493
35499
|
}
|
|
35500
|
+
// src/commands/console.ts
|
|
35501
|
+
init_output();
|
|
35502
|
+
init_resolve_auth();
|
|
35503
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
35504
|
+
var DEFAULT_CONSOLE_URL = "http://localhost:3801/console";
|
|
35505
|
+
var CONSOLE_PORT = 3801;
|
|
35506
|
+
function resolveConsoleUrl(override) {
|
|
35507
|
+
if (override)
|
|
35508
|
+
return override.replace(/\/+$/, "");
|
|
35509
|
+
const apiUrl = process.env.SL_API_URL;
|
|
35510
|
+
if (apiUrl && isOssMode()) {
|
|
35511
|
+
try {
|
|
35512
|
+
const { protocol, hostname } = new URL(apiUrl);
|
|
35513
|
+
return `${protocol}//${hostname}:${CONSOLE_PORT}/console`;
|
|
35514
|
+
} catch {}
|
|
35515
|
+
}
|
|
35516
|
+
return DEFAULT_CONSOLE_URL;
|
|
35517
|
+
}
|
|
35518
|
+
async function isReachable(url) {
|
|
35519
|
+
try {
|
|
35520
|
+
await fetch(url, { signal: AbortSignal.timeout(2000) });
|
|
35521
|
+
return true;
|
|
35522
|
+
} catch {
|
|
35523
|
+
return false;
|
|
35524
|
+
}
|
|
35525
|
+
}
|
|
35526
|
+
function openBrowser(url) {
|
|
35527
|
+
const opener = process.platform === "darwin" ? "open" : process.platform === "linux" ? "xdg-open" : undefined;
|
|
35528
|
+
if (!opener)
|
|
35529
|
+
return Promise.resolve(false);
|
|
35530
|
+
return new Promise((resolve5) => {
|
|
35531
|
+
const child = spawn3(opener, [url], { stdio: "ignore", detached: true });
|
|
35532
|
+
child.once("error", () => resolve5(false));
|
|
35533
|
+
child.once("spawn", () => {
|
|
35534
|
+
child.unref();
|
|
35535
|
+
resolve5(true);
|
|
35536
|
+
});
|
|
35537
|
+
});
|
|
35538
|
+
}
|
|
35539
|
+
function registerConsoleCommand(program2) {
|
|
35540
|
+
program2.command("console").description("Open the console UI in a browser").option("--url <url>", `Console URL (default ${DEFAULT_CONSOLE_URL})`).option("--no-open", "Print the console URL instead of opening a browser").action(async (options3) => {
|
|
35541
|
+
const url = resolveConsoleUrl(options3.url);
|
|
35542
|
+
if (options3.open === false) {
|
|
35543
|
+
writeData(url);
|
|
35544
|
+
return;
|
|
35545
|
+
}
|
|
35546
|
+
if (!await isReachable(url)) {
|
|
35547
|
+
printError(`Console not reachable at ${url}`, {
|
|
35548
|
+
hint: "docker compose --profile console up -d"
|
|
35549
|
+
});
|
|
35550
|
+
process.exit(1);
|
|
35551
|
+
}
|
|
35552
|
+
if (await openBrowser(url)) {
|
|
35553
|
+
success(`console: ${url}`);
|
|
35554
|
+
} else {
|
|
35555
|
+
writeData(url);
|
|
35556
|
+
}
|
|
35557
|
+
});
|
|
35558
|
+
}
|
|
35494
35559
|
// src/commands/context.ts
|
|
35495
35560
|
init_output();
|
|
35496
35561
|
init_resolve_auth();
|
|
@@ -35822,10 +35887,10 @@ SIGNING_SECRET=${signingSecret}
|
|
|
35822
35887
|
process.exit(1);
|
|
35823
35888
|
}
|
|
35824
35889
|
const pausedLine = subscriptionStatus === "paused" ? `Subscription is paused. Resume:
|
|
35825
|
-
|
|
35890
|
+
secondlayer subscriptions resume ${name}
|
|
35826
35891
|
` : "";
|
|
35827
35892
|
const runHint = opts.scaffold === false ? `View deliveries:
|
|
35828
|
-
|
|
35893
|
+
secondlayer subscriptions get ${name}` : `cd ${name}
|
|
35829
35894
|
bun install
|
|
35830
35895
|
bun run dev`;
|
|
35831
35896
|
success(`Done. Next:
|
|
@@ -35877,7 +35942,7 @@ async function createChainSubscription(name, opts) {
|
|
|
35877
35942
|
console.log();
|
|
35878
35943
|
success(`Done. Next:
|
|
35879
35944
|
View deliveries:
|
|
35880
|
-
|
|
35945
|
+
secondlayer subscriptions get ${name}`);
|
|
35881
35946
|
}
|
|
35882
35947
|
async function getSubscriptionClient() {
|
|
35883
35948
|
const { apiUrl, ephemeralKey } = await resolveAuth();
|
|
@@ -35899,7 +35964,7 @@ Examples:
|
|
|
35899
35964
|
function addSubscriptionsCreateCommand(subscriptions) {
|
|
35900
35965
|
addSubscriptionScaffold(subscriptions, "create <name>", {
|
|
35901
35966
|
description: "Create a subscription receiver for a runtime",
|
|
35902
|
-
examplePrefix: "
|
|
35967
|
+
examplePrefix: "secondlayer subscriptions create"
|
|
35903
35968
|
});
|
|
35904
35969
|
}
|
|
35905
35970
|
|
|
@@ -36042,19 +36107,19 @@ function buildDoctorReport(input3) {
|
|
|
36042
36107
|
} : null;
|
|
36043
36108
|
const hints = [];
|
|
36044
36109
|
if (input3.subscription.status === "paused") {
|
|
36045
|
-
hints.push(`Resume when the receiver is healthy:
|
|
36110
|
+
hints.push(`Resume when the receiver is healthy: secondlayer subscriptions resume ${input3.subscription.id}`);
|
|
36046
36111
|
}
|
|
36047
36112
|
if (input3.subscription.lastError) {
|
|
36048
|
-
hints.push("Run
|
|
36113
|
+
hints.push("Run secondlayer subscriptions test to reproduce the receiver request.");
|
|
36049
36114
|
}
|
|
36050
36115
|
if (input3.subscription.circuitOpenedAt || input3.subscription.circuitFailures > 0) {
|
|
36051
36116
|
hints.push("Circuit breaker has failures; inspect receiver logs and delivery status codes.");
|
|
36052
36117
|
}
|
|
36053
36118
|
if (input3.dead.length > 0) {
|
|
36054
|
-
hints.push(`Dead-letter rows exist; inspect with
|
|
36119
|
+
hints.push(`Dead-letter rows exist; inspect with secondlayer subscriptions dead ${input3.subscription.id} and requeue selected rows.`);
|
|
36055
36120
|
}
|
|
36056
36121
|
if (subgraph?.gapCount && subgraph.gapCount > 0) {
|
|
36057
|
-
hints.push(`Linked subgraph has gaps; run
|
|
36122
|
+
hints.push(`Linked subgraph has gaps; run secondlayer subgraphs gaps ${input3.subscription.subgraphName}.`);
|
|
36058
36123
|
}
|
|
36059
36124
|
if (subgraph?.syncStatus === "catching_up") {
|
|
36060
36125
|
hints.push("Linked subgraph is still catching up; new matching rows may arrive later.");
|
|
@@ -36317,9 +36382,9 @@ ${data.length} subscription(s) total`));
|
|
|
36317
36382
|
});
|
|
36318
36383
|
subscriptions.command("update <idOrName>").description("Update subscription config").option("--name <name>", "Rename subscription").option("--url <url>", "Webhook URL").option("--auth-token <token>", "Set bearer token auth config").option("--format <format>", "standard-webhooks | inngest | trigger | cloudflare | cloudevents | raw").option("--runtime <runtime>", "inngest | trigger | cloudflare | node | none").option("--filter <kv...>", "Filter as key=value (supports .eq/.neq/.gt/.gte/.lt/.lte suffixes)").option("--clear-filter", "Replace filter with {}").option("--max-retries <n>", "Maximum delivery retries").option("--timeout-ms <n>", "Delivery timeout in milliseconds").option("--concurrency <n>", "Per-subscription delivery concurrency").option("--json", "Output as JSON").addHelpText("after", `
|
|
36319
36384
|
Examples:
|
|
36320
|
-
$
|
|
36321
|
-
$
|
|
36322
|
-
$
|
|
36385
|
+
$ secondlayer subscriptions update my-sub --url https://example.com/hook
|
|
36386
|
+
$ secondlayer subscriptions update my-sub --filter amount.gte=1000 --max-retries 5
|
|
36387
|
+
$ secondlayer subscriptions update my-sub --clear-filter`).action(async (idOrName, options3) => {
|
|
36323
36388
|
try {
|
|
36324
36389
|
const client2 = await getSubscriptionClient();
|
|
36325
36390
|
const patch = buildUpdatePatch(options3);
|
|
@@ -36448,7 +36513,7 @@ Examples:
|
|
|
36448
36513
|
});
|
|
36449
36514
|
subscriptions.command("replay <idOrName>").description("Replay a block range").requiredOption("--from-block <n>", "Start block height").requiredOption("--to-block <n>", "End block height").option("-y, --yes", "Skip confirmation").option("--json", "Output as JSON").addHelpText("after", `
|
|
36450
36515
|
Examples:
|
|
36451
|
-
$
|
|
36516
|
+
$ secondlayer subscriptions replay my-sub --from-block 150000 --to-block 160000 -y`).action(async (idOrName, options3) => {
|
|
36452
36517
|
try {
|
|
36453
36518
|
const fromBlock = requireIntegerOption(options3.fromBlock, "--from-block");
|
|
36454
36519
|
const toBlock = requireIntegerOption(options3.toBlock, "--to-block");
|
|
@@ -36576,7 +36641,7 @@ function buildDevnetCompose(opts = {}) {
|
|
|
36576
36641
|
const dbUrl = "postgres://secondlayer:secondlayer@postgres:5432/secondlayer";
|
|
36577
36642
|
const DEV_SECRETS_KEY = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
|
|
36578
36643
|
const DEV_INSTANCE_TOKEN = "dev-instance-token";
|
|
36579
|
-
return `# Generated by \`
|
|
36644
|
+
return `# Generated by \`secondlayer devnet connect\` — do not edit by hand.
|
|
36580
36645
|
# Secondlayer app services for local clarinet devnet development.
|
|
36581
36646
|
name: secondlayer-devnet
|
|
36582
36647
|
|
|
@@ -36815,8 +36880,8 @@ function parseAmount(value) {
|
|
|
36815
36880
|
function registerFaucetCommand(devnetCommand) {
|
|
36816
36881
|
devnetCommand.command("faucet").description("Mint mock sBTC to an address on your devnet").requiredOption("--to <address>", "recipient Stacks address").option("--amount <sats>", `amount in sats (default ${DEFAULT_AMOUNT_SATS}, minimum ${DUST_LIMIT_SATS})`).option("--contract <id>", "sBTC deposit contract (default: <deployer>.sbtc-deposit)").option("--rpc-url <url>", "devnet node RPC (default http://localhost:3999)").option("--json", "Output as JSON").addHelpText("after", `
|
|
36817
36882
|
Examples:
|
|
36818
|
-
$
|
|
36819
|
-
$
|
|
36883
|
+
$ secondlayer devnet faucet --to ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
|
|
36884
|
+
$ secondlayer devnet faucet --to ST2... --amount 5000000
|
|
36820
36885
|
|
|
36821
36886
|
Requires a devnet running with the sBTC contract set deployed by your
|
|
36822
36887
|
Clarinet deployer — that deployer is the signer set on your own chain, which
|
|
@@ -36824,7 +36889,7 @@ is what makes minting possible without Bitcoin.`).action(async (opts) => {
|
|
|
36824
36889
|
try {
|
|
36825
36890
|
const network = process.env.STACKS_NETWORK ?? "devnet";
|
|
36826
36891
|
if (network !== "devnet" && network !== "local") {
|
|
36827
|
-
printError(`
|
|
36892
|
+
printError(`secondlayer devnet faucet only works on devnet, not ${network}.`, {
|
|
36828
36893
|
hint: "Mock sBTC is mintable because you deployed the contracts. On testnet or mainnet the signer set is not yours."
|
|
36829
36894
|
});
|
|
36830
36895
|
process.exit(2);
|
|
@@ -36925,7 +36990,7 @@ function registerDevnetCommand(program2) {
|
|
|
36925
36990
|
devnet2.command("connect").description("Point your clarinet project's devnet at a local Secondlayer stack and start it").option("--project <dir>", "Clarinet project directory (defaults to the nearest Clarinet.toml)").option("--image-tag <tag>", "Published image tag to run", DEFAULT_IMAGE_TAG).option("--owner <owner>", "ghcr image owner (namespace) to pull from").option("--no-up", "Patch config + write compose without starting docker").action(async (options3) => {
|
|
36926
36991
|
await connect(options3);
|
|
36927
36992
|
});
|
|
36928
|
-
devnet2.command("down").description("Stop the local Secondlayer stack started by `
|
|
36993
|
+
devnet2.command("down").description("Stop the local Secondlayer stack started by `secondlayer devnet connect`").option("--project <dir>", "Clarinet project directory").option("--purge", "Also remove volumes (wipes the local index)").action(async (options3) => {
|
|
36929
36994
|
await down(options3);
|
|
36930
36995
|
});
|
|
36931
36996
|
devnet2.command("status").description("Snapshot of the local stack: ingest, subgraphs, and recent activity").option("-w, --watch", "Refresh every 2s until Ctrl-C").option("--limit <n>", "Recent activity rows to show", "12").action(async (options3) => {
|
|
@@ -36987,15 +37052,15 @@ ${bold("Secondlayer stack up")}`);
|
|
|
36987
37052
|
console.log(`
|
|
36988
37053
|
${bold("Next:")}`);
|
|
36989
37054
|
console.log(` ${yellow("clarinet devnet start")} ${dim("# auto-deploys + streams to the indexer")}`);
|
|
36990
|
-
console.log(` ${yellow("SL_API_URL=http://localhost:3800 SL_API_KEY=dummy
|
|
37055
|
+
console.log(` ${yellow("SL_API_URL=http://localhost:3800 SL_API_KEY=dummy secondlayer subgraphs deploy ./subgraph.ts")}`);
|
|
36991
37056
|
console.log(dim(`
|
|
36992
|
-
Stop with:
|
|
37057
|
+
Stop with: secondlayer devnet down`));
|
|
36993
37058
|
}
|
|
36994
37059
|
async function down(options3) {
|
|
36995
37060
|
const project = resolveProject(options3.project);
|
|
36996
37061
|
const composePath = join9(project, COMPOSE_REL);
|
|
36997
37062
|
if (!existsSync6(composePath)) {
|
|
36998
|
-
error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`
|
|
37063
|
+
error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`secondlayer devnet connect\` first.`);
|
|
36999
37064
|
process.exit(1);
|
|
37000
37065
|
}
|
|
37001
37066
|
ensureDocker();
|
|
@@ -37010,7 +37075,7 @@ async function logs(service, options3) {
|
|
|
37010
37075
|
const project = resolveProject(options3.project);
|
|
37011
37076
|
const composePath = join9(project, COMPOSE_REL);
|
|
37012
37077
|
if (!existsSync6(composePath)) {
|
|
37013
|
-
error(`No ${COMPOSE_REL} in ${project} — run \`
|
|
37078
|
+
error(`No ${COMPOSE_REL} in ${project} — run \`secondlayer devnet connect\` first.`);
|
|
37014
37079
|
process.exit(1);
|
|
37015
37080
|
}
|
|
37016
37081
|
if (service && !SERVICES.includes(service)) {
|
|
@@ -37058,7 +37123,7 @@ async function renderStatus(limit) {
|
|
|
37058
37123
|
out.push(` ${apiHealth ? green("●") : red("●")} api ${apiHealth ? "healthy" : "down"} ${dim(":3800")}`);
|
|
37059
37124
|
if (!health) {
|
|
37060
37125
|
out.push("");
|
|
37061
|
-
out.push(dim(" indexer unreachable — is `
|
|
37126
|
+
out.push(dim(" indexer unreachable — is `secondlayer devnet connect` running?"));
|
|
37062
37127
|
return out.join(`
|
|
37063
37128
|
`);
|
|
37064
37129
|
}
|
|
@@ -37073,7 +37138,7 @@ async function renderStatus(limit) {
|
|
|
37073
37138
|
out.push("");
|
|
37074
37139
|
out.push(bold("SUBGRAPHS"));
|
|
37075
37140
|
if (subs.length === 0) {
|
|
37076
|
-
out.push(dim(" none deployed —
|
|
37141
|
+
out.push(dim(" none deployed — secondlayer subgraphs deploy ./subgraph.ts"));
|
|
37077
37142
|
} else {
|
|
37078
37143
|
for (const sg of subs) {
|
|
37079
37144
|
const st = sg.status === "active" ? green(sg.status) : yellow(String(sg.status));
|
|
@@ -37113,7 +37178,7 @@ async function status(options3) {
|
|
|
37113
37178
|
const tick = async () => {
|
|
37114
37179
|
const body = await renderStatus(limit);
|
|
37115
37180
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
37116
|
-
console.log(`${dim("
|
|
37181
|
+
console.log(`${dim("secondlayer devnet status")} ${dim("· ctrl-c to stop")}
|
|
37117
37182
|
`);
|
|
37118
37183
|
console.log(body);
|
|
37119
37184
|
};
|
|
@@ -37206,10 +37271,10 @@ function registerStreamsCommand(program2) {
|
|
|
37206
37271
|
});
|
|
37207
37272
|
const events = streams.command("events").description("List events (cursor-paginated; one page per call)").option("--types <types>", `comma-separated event types (${VALID_TYPES.join(", ")})`).option("--event-type <type>", "alias for a single-value --types (the Index spelling)").option("--not-types <types>", "comma-separated event types to exclude").option("--contract-id <ids>", "comma-separated contract identifier(s)").option("--sender <addrs>", "comma-separated sender principal(s)").option("--recipient <addrs>", "comma-separated recipient principal(s)").option("--cursor <cursor>", "start cursor (block_height:event_index)").option("--from-block <n>", "filter to blocks >= n").option("--to-block <n>", "filter to blocks <= n").option("--limit <n>", "page size (1-1000, default 100)", "100").option("--json", "Output as JSON (streams always emits JSON)").addHelpText("after", `
|
|
37208
37273
|
Examples:
|
|
37209
|
-
$
|
|
37210
|
-
$
|
|
37211
|
-
$
|
|
37212
|
-
$
|
|
37274
|
+
$ secondlayer streams events --types stx_transfer,print --limit 50
|
|
37275
|
+
$ secondlayer streams events --not-types print --contract-id SP00....token,SP01....token
|
|
37276
|
+
$ secondlayer streams events --sender SP1...,SP2... --from-block 150000 --to-block 160000
|
|
37277
|
+
$ secondlayer streams events --cursor 150000:3`).action(async (options3) => {
|
|
37213
37278
|
try {
|
|
37214
37279
|
const envelope = await client2().events.list({
|
|
37215
37280
|
types: parseTypes(options3.types ?? options3.eventType),
|
|
@@ -37239,8 +37304,8 @@ Examples:
|
|
|
37239
37304
|
});
|
|
37240
37305
|
streams.command("consume").description("Long-running pull from a cursor; emits one event per line (jsonl) until SIGINT or --max-pages").option("--types <types>", `comma-separated event types (${VALID_TYPES.join(", ")})`).option("--not-types <types>", "comma-separated event types to exclude").option("--contract-id <ids>", "comma-separated contract identifier(s)").option("--sender <addrs>", "comma-separated sender principal(s)").option("--recipient <addrs>", "comma-separated recipient principal(s)").option("--cursor <cursor>", "start cursor (block_height:event_index)").option("--batch-size <n>", "events per batch (1-1000, default 100)", "100").option("--max-pages <n>", "stop after N pages (default: run until SIGINT)").addHelpText("after", `
|
|
37241
37306
|
Examples:
|
|
37242
|
-
$
|
|
37243
|
-
$
|
|
37307
|
+
$ secondlayer streams consume --types print --cursor 150000:0
|
|
37308
|
+
$ secondlayer streams consume --not-types print --sender SP1...,SP2... --batch-size 500 --max-pages 10`).action(async (options3) => {
|
|
37244
37309
|
try {
|
|
37245
37310
|
const batchSize = parseLimit(options3.batchSize) ?? 100;
|
|
37246
37311
|
const maxPages = options3.maxPages ? Number.parseInt(options3.maxPages, 10) : undefined;
|
|
@@ -37286,8 +37351,8 @@ Examples:
|
|
|
37286
37351
|
});
|
|
37287
37352
|
streams.command("pull").description("Download finalized bulk parquet dumps to a local dir (verifies sha256)").requiredOption("--to <dir>", "output directory").option("--dumps-url <url>", "public dumps base URL (or SL_STREAMS_DUMPS_URL)").option("--from-block <n>", "only files covering blocks >= n").option("--to-block <n>", "only files covering blocks <= n").addHelpText("after", `
|
|
37288
37353
|
Examples:
|
|
37289
|
-
$
|
|
37290
|
-
$
|
|
37354
|
+
$ secondlayer streams pull --to ./dump
|
|
37355
|
+
$ secondlayer streams pull --to ./dump --from-block 150000 --to-block 200000`).action(async (options3) => {
|
|
37291
37356
|
try {
|
|
37292
37357
|
const fromBlock = parseHeight(options3.fromBlock, "--from-block");
|
|
37293
37358
|
const toBlock = parseHeight(options3.toBlock, "--to-block");
|
|
@@ -37715,7 +37780,7 @@ function markFrozen(cmd) {
|
|
|
37715
37780
|
if (warned)
|
|
37716
37781
|
return;
|
|
37717
37782
|
warned = true;
|
|
37718
|
-
process.stderr.write(`⚠ \`
|
|
37783
|
+
process.stderr.write(`⚠ \`secondlayer ${cmd.name()}\` is frozen — no further investment; it may be removed in a future major. The hosted dev loop (secondlayer subgraphs create/deploy) is the supported path.
|
|
37719
37784
|
`);
|
|
37720
37785
|
};
|
|
37721
37786
|
cmd.hook("preAction", warn2);
|
|
@@ -37748,7 +37813,7 @@ Subcommands:
|
|
|
37748
37813
|
truncate Truncate all indexed data
|
|
37749
37814
|
resync Reset database and restart indexer
|
|
37750
37815
|
|
|
37751
|
-
Run \`
|
|
37816
|
+
Run \`secondlayer db\` with no subcommand to print an overview.`).hook("preAction", async () => {
|
|
37752
37817
|
await requireLocalNetwork();
|
|
37753
37818
|
}).action(async () => {
|
|
37754
37819
|
await showOverview(10);
|
|
@@ -37809,14 +37874,14 @@ async function showOverview(_limit) {
|
|
|
37809
37874
|
console.log(` Time: ${time}`);
|
|
37810
37875
|
console.log("");
|
|
37811
37876
|
}
|
|
37812
|
-
console.log(dim(`Use '
|
|
37877
|
+
console.log(dim(`Use 'secondlayer db blocks|txs|events' to see records`));
|
|
37813
37878
|
console.log("");
|
|
37814
37879
|
process.exit(0);
|
|
37815
37880
|
} catch (err) {
|
|
37816
37881
|
error(`Failed to query database: ${err}`);
|
|
37817
37882
|
console.log(dim(`
|
|
37818
37883
|
Make sure PostgreSQL is running.`));
|
|
37819
|
-
console.log(dim("Run '
|
|
37884
|
+
console.log(dim("Run 'secondlayer local start' to start all services."));
|
|
37820
37885
|
process.exit(1);
|
|
37821
37886
|
}
|
|
37822
37887
|
}
|
|
@@ -37964,7 +38029,7 @@ async function resetDatabase(skipConfirm) {
|
|
|
37964
38029
|
console.log("");
|
|
37965
38030
|
success("Database reset complete");
|
|
37966
38031
|
console.log("");
|
|
37967
|
-
console.log(dim("Run '
|
|
38032
|
+
console.log(dim("Run 'secondlayer local restart' to restart the indexer for fresh sync."));
|
|
37968
38033
|
console.log("");
|
|
37969
38034
|
process.exit(0);
|
|
37970
38035
|
} catch (err) {
|
|
@@ -38013,13 +38078,13 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
38013
38078
|
}
|
|
38014
38079
|
console.log(green(" ✓ Indexer stopped"));
|
|
38015
38080
|
console.log("");
|
|
38016
|
-
info("Run '
|
|
38081
|
+
info("Run 'secondlayer local restart' to start fresh sync");
|
|
38017
38082
|
} else {
|
|
38018
38083
|
console.log("");
|
|
38019
38084
|
success("Database reset complete");
|
|
38020
38085
|
console.log("");
|
|
38021
38086
|
if (!backfill) {
|
|
38022
|
-
console.log(dim("Indexer not running. Start with '
|
|
38087
|
+
console.log(dim("Indexer not running. Start with 'secondlayer local start' to begin sync."));
|
|
38023
38088
|
}
|
|
38024
38089
|
}
|
|
38025
38090
|
if (backfill) {
|
|
@@ -38029,14 +38094,14 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
38029
38094
|
const healthy = await nodeClient.isHealthy();
|
|
38030
38095
|
if (!healthy) {
|
|
38031
38096
|
warn(`Cannot reach Stacks node at ${nodeClient.getRpcUrl()}`);
|
|
38032
|
-
console.log(dim("Run '
|
|
38097
|
+
console.log(dim("Run 'secondlayer sync --from 1 --to <tip>' manually once the node is available."));
|
|
38033
38098
|
console.log("");
|
|
38034
38099
|
process.exit(0);
|
|
38035
38100
|
}
|
|
38036
38101
|
const nodeInfo = await nodeClient.getInfo();
|
|
38037
38102
|
const tip = nodeInfo.stacks_tip_height;
|
|
38038
38103
|
info(`Node tip: block ${tip}. Fetching blocks 1 to ${tip}...`);
|
|
38039
|
-
console.log(dim(`This may take a while. Run '
|
|
38104
|
+
console.log(dim(`This may take a while. Run 'secondlayer sync --from 1 --to ${tip}' if interrupted.`));
|
|
38040
38105
|
console.log("");
|
|
38041
38106
|
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
38042
38107
|
const config = await loadConfig3();
|
|
@@ -38125,7 +38190,7 @@ async function stackStart(options3) {
|
|
|
38125
38190
|
if (options3.node) {
|
|
38126
38191
|
const nodePath = config.node?.installPath;
|
|
38127
38192
|
if (!nodePath) {
|
|
38128
|
-
warn("No node configured, skipping. Run '
|
|
38193
|
+
warn("No node configured, skipping. Run 'secondlayer local node setup' to configure.");
|
|
38129
38194
|
} else if (await isNodeRunning()) {
|
|
38130
38195
|
info("Node already running");
|
|
38131
38196
|
} else {
|
|
@@ -38190,7 +38255,7 @@ async function stackStart(options3) {
|
|
|
38190
38255
|
}
|
|
38191
38256
|
console.log("");
|
|
38192
38257
|
success("Stack started");
|
|
38193
|
-
console.log(dim("Run '
|
|
38258
|
+
console.log(dim("Run 'secondlayer status' to check health"));
|
|
38194
38259
|
console.log("");
|
|
38195
38260
|
}
|
|
38196
38261
|
async function stackStop(options3) {
|
|
@@ -38420,7 +38485,7 @@ async function showLocalLogs(options3) {
|
|
|
38420
38485
|
async function showNodeLogs(options3) {
|
|
38421
38486
|
if (!await isNodeRunning()) {
|
|
38422
38487
|
error("Node is not running");
|
|
38423
|
-
console.log(dim("Run '
|
|
38488
|
+
console.log(dim("Run 'secondlayer local node start' first"));
|
|
38424
38489
|
process.exit(1);
|
|
38425
38490
|
}
|
|
38426
38491
|
const logs2 = await getNodeLogs({
|
|
@@ -38614,7 +38679,7 @@ function registerWhoamiCommand(program2) {
|
|
|
38614
38679
|
try {
|
|
38615
38680
|
auth = await resolveAuth();
|
|
38616
38681
|
} catch {
|
|
38617
|
-
error("Not logged in. Run:
|
|
38682
|
+
error("Not logged in. Run: secondlayer login");
|
|
38618
38683
|
process.exit(1);
|
|
38619
38684
|
}
|
|
38620
38685
|
let account;
|
|
@@ -38622,7 +38687,7 @@ function registerWhoamiCommand(program2) {
|
|
|
38622
38687
|
account = await httpPlatform("/api/accounts/me");
|
|
38623
38688
|
} catch (err) {
|
|
38624
38689
|
if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED") {
|
|
38625
|
-
error("Session expired. Run:
|
|
38690
|
+
error("Session expired. Run: secondlayer login");
|
|
38626
38691
|
process.exit(1);
|
|
38627
38692
|
}
|
|
38628
38693
|
throw err;
|
|
@@ -38649,7 +38714,10 @@ function registerWhoamiCommand(program2) {
|
|
|
38649
38714
|
rows.push(["Project", active.slug]);
|
|
38650
38715
|
rows.push(["Project source", dim(active.resolvedFrom)]);
|
|
38651
38716
|
} else {
|
|
38652
|
-
rows.push([
|
|
38717
|
+
rows.push([
|
|
38718
|
+
"Project",
|
|
38719
|
+
dim("(none — run `secondlayer project use <slug>`)")
|
|
38720
|
+
]);
|
|
38653
38721
|
}
|
|
38654
38722
|
console.log(formatKeyValue(rows));
|
|
38655
38723
|
}
|
|
@@ -38721,7 +38789,7 @@ function registerProjectCommand(program2) {
|
|
|
38721
38789
|
await httpPlatform(`/api/projects/${encodeURIComponent(slug)}`);
|
|
38722
38790
|
} catch (err) {
|
|
38723
38791
|
if (err instanceof CliHttpError && err.status === 404) {
|
|
38724
|
-
error(`Project "${slug}" not found — run '
|
|
38792
|
+
error(`Project "${slug}" not found — run 'secondlayer project list' to see available projects`);
|
|
38725
38793
|
process.exit(1);
|
|
38726
38794
|
}
|
|
38727
38795
|
handleProjectError(err);
|
|
@@ -38740,7 +38808,7 @@ function registerProjectCommand(program2) {
|
|
|
38740
38808
|
human: () => {
|
|
38741
38809
|
if (!active) {
|
|
38742
38810
|
info("No active project.");
|
|
38743
|
-
info(dim("Run '
|
|
38811
|
+
info(dim("Run 'secondlayer project use <slug>' to bind this directory."));
|
|
38744
38812
|
return;
|
|
38745
38813
|
}
|
|
38746
38814
|
console.log(active.slug);
|
|
@@ -38752,7 +38820,7 @@ function registerProjectCommand(program2) {
|
|
|
38752
38820
|
function handleProjectError(err) {
|
|
38753
38821
|
if (err instanceof CliHttpError) {
|
|
38754
38822
|
if (err.code === "SESSION_EXPIRED") {
|
|
38755
|
-
error("Session expired. Run:
|
|
38823
|
+
error("Session expired. Run: secondlayer login");
|
|
38756
38824
|
process.exit(1);
|
|
38757
38825
|
}
|
|
38758
38826
|
error(err.message);
|
|
@@ -38920,11 +38988,11 @@ function statusLabel(status2) {
|
|
|
38920
38988
|
function registerVerifyCommand(program2) {
|
|
38921
38989
|
program2.command("verify").description("Compare local chain data against a signed archive (read-only; nothing is uploaded)").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").requiredOption("--against <manifest>", "archive manifest: an https URL or a local file path").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 the signing key instead of fetching it").option("--insecure", "skip the manifest signature check (not recommended)").option("--json", "Output as JSON").addHelpText("after", `
|
|
38922
38990
|
Examples:
|
|
38923
|
-
$
|
|
38924
|
-
$
|
|
38925
|
-
$
|
|
38926
|
-
$
|
|
38927
|
-
$
|
|
38991
|
+
$ secondlayer verify --against https://archive.secondlayer.tools/.../snapshots/<digest>.json
|
|
38992
|
+
$ secondlayer verify raw --against ./snapshot.json --from-block 8000000 --to-block 8499999
|
|
38993
|
+
$ secondlayer verify all --against ./snapshot.json --json
|
|
38994
|
+
$ secondlayer verify decode:ft_transfer --against ./snapshot.json --quick
|
|
38995
|
+
$ secondlayer verify subgraph:sbtc --against ./snapshot.json --deep
|
|
38928
38996
|
|
|
38929
38997
|
Exit codes:
|
|
38930
38998
|
0 local data matches the archive
|
|
@@ -39088,7 +39156,7 @@ Exit codes:
|
|
|
39088
39156
|
console.error(dim("These ranges hold different data than the signed archive. Repair with:"));
|
|
39089
39157
|
const first = diverged[0];
|
|
39090
39158
|
if (first) {
|
|
39091
|
-
console.error(dim(`
|
|
39159
|
+
console.error(dim(` secondlayer repair --from-block ${first.from_block} --to-block ${first.to_block}`));
|
|
39092
39160
|
}
|
|
39093
39161
|
}
|
|
39094
39162
|
});
|
|
@@ -39222,9 +39290,9 @@ async function applyFixes(db, reference, partition, fixes) {
|
|
|
39222
39290
|
function registerRepairCommand(program2) {
|
|
39223
39291
|
program2.command("repair").description("Replace local chain data that diverges from a signed archive (dry-run by default)").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 the signing key instead of fetching it").option("--json", "Output as JSON").addHelpText("after", `
|
|
39224
39292
|
Examples:
|
|
39225
|
-
$
|
|
39226
|
-
$
|
|
39227
|
-
$
|
|
39293
|
+
$ secondlayer repair --against ./snapshot.json # plan only
|
|
39294
|
+
$ secondlayer repair --against ./snapshot.json --apply # write the fix
|
|
39295
|
+
$ secondlayer repair --against ./snapshot.json --from-block 8500000 --to-block 8549999
|
|
39228
39296
|
|
|
39229
39297
|
Exit codes:
|
|
39230
39298
|
0 nothing to repair, or the repair completed and re-verified clean
|
|
@@ -39454,8 +39522,8 @@ async function loadPartition(reference, partition, rawClient) {
|
|
|
39454
39522
|
function attachBootstrapCommand(cmd) {
|
|
39455
39523
|
return cmd.requiredOption("--against <manifest>", "archive manifest: an https URL or a local file path").option("--to-block <n>", "stop at this height instead of the archive tip").option("--public-key <pem>", "pin the signing key instead of fetching it").option("-y, --yes", "skip the confirmation prompt").option("--json", "Output as JSON").addHelpText("after", `
|
|
39456
39524
|
Examples:
|
|
39457
|
-
$
|
|
39458
|
-
$
|
|
39525
|
+
$ secondlayer bootstrap --against https://archive.secondlayer.tools/.../snapshots/<digest>.json
|
|
39526
|
+
$ secondlayer bootstrap --against ./snapshot.json --to-block 4000000 --yes
|
|
39459
39527
|
|
|
39460
39528
|
Exit codes:
|
|
39461
39529
|
0 restored and verified
|
|
@@ -39488,7 +39556,7 @@ Exit codes:
|
|
|
39488
39556
|
});
|
|
39489
39557
|
if (resume.action === "refuse") {
|
|
39490
39558
|
printError(resume.reason, {
|
|
39491
|
-
hint: "Bootstrap is for a fresh instance. To fix an existing one, use `
|
|
39559
|
+
hint: "Bootstrap is for a fresh instance. To fix an existing one, use `secondlayer repair`."
|
|
39492
39560
|
});
|
|
39493
39561
|
process.exit(BOOTSTRAP_EXIT.REFUSED);
|
|
39494
39562
|
}
|
|
@@ -39612,7 +39680,7 @@ Exit codes:
|
|
|
39612
39680
|
}
|
|
39613
39681
|
} else {
|
|
39614
39682
|
warn(`Restored ${loaded.blocks.toLocaleString()} blocks but ${divergent} ranges do not match the archive.`);
|
|
39615
|
-
console.error(dim(" Investigate with:
|
|
39683
|
+
console.error(dim(" Investigate with: secondlayer verify --against <manifest>"));
|
|
39616
39684
|
}
|
|
39617
39685
|
}
|
|
39618
39686
|
});
|
|
@@ -39691,7 +39759,7 @@ function buildInstanceEnv(input4) {
|
|
|
39691
39759
|
}
|
|
39692
39760
|
function renderInstanceEnv(env2) {
|
|
39693
39761
|
const lines2 = [
|
|
39694
|
-
"# Generated by
|
|
39762
|
+
"# Generated by secondlayer init. Do not commit.",
|
|
39695
39763
|
`INSTANCE_MODE=${env2.INSTANCE_MODE}`,
|
|
39696
39764
|
`STACKS_NETWORK=${env2.STACKS_NETWORK}`,
|
|
39697
39765
|
`INSTANCE_TOKEN=${env2.INSTANCE_TOKEN}`,
|
|
@@ -39864,11 +39932,12 @@ function registerStartCommand(program2) {
|
|
|
39864
39932
|
}
|
|
39865
39933
|
success(`config ok (${parsed.config.NETWORK}, ${parsed.config.NODE_MODE})`);
|
|
39866
39934
|
console.log(cmd);
|
|
39935
|
+
note(" console UI (optional): add --profile console, then `secondlayer console`");
|
|
39867
39936
|
});
|
|
39868
39937
|
}
|
|
39869
39938
|
// src/cli.ts
|
|
39870
39939
|
var { version } = package_default;
|
|
39871
|
-
program.name("secondlayer").alias("sl").description("Secondlayer CLI — self-hosted Stacks data runtime").version(version).option("--network <network>", "Override network (local, testnet, mainnet)").option("--api-key <key>", "API credential (overrides SL_API_KEY)").option("--api-url <url>", "API endpoint (overrides SL_API_URL)").showSuggestionAfterError(true).showHelpAfterError("(run `
|
|
39940
|
+
program.name("secondlayer").alias("sl").description("Secondlayer CLI — self-hosted Stacks data runtime").version(version).option("--network <network>", "Override network (local, testnet, mainnet)").option("--api-key <key>", "API credential (overrides SL_API_KEY)").option("--api-url <url>", "API endpoint (overrides SL_API_URL)").showSuggestionAfterError(true).showHelpAfterError("(run `secondlayer --help` to see available commands)");
|
|
39872
39941
|
program.hook("preAction", (thisCommand) => {
|
|
39873
39942
|
const { network, apiKey, apiUrl } = thisCommand.opts();
|
|
39874
39943
|
if (network)
|
|
@@ -39880,16 +39949,17 @@ program.hook("preAction", (thisCommand) => {
|
|
|
39880
39949
|
});
|
|
39881
39950
|
program.addHelpText("after", `
|
|
39882
39951
|
Quickstart:
|
|
39883
|
-
$
|
|
39884
|
-
$
|
|
39885
|
-
$
|
|
39886
|
-
$
|
|
39952
|
+
$ secondlayer init --network mainnet
|
|
39953
|
+
$ secondlayer bootstrap --against <manifest>
|
|
39954
|
+
$ secondlayer subgraphs create my-watcher --template sip-010-balances
|
|
39955
|
+
$ secondlayer subgraphs deploy subgraphs/my-watcher.ts
|
|
39887
39956
|
`);
|
|
39888
39957
|
program.commandsGroup("Getting started:");
|
|
39889
39958
|
registerInitCommand(program);
|
|
39890
39959
|
registerBootstrapCommand(program);
|
|
39891
39960
|
registerObserverCommand(program);
|
|
39892
39961
|
registerStartCommand(program);
|
|
39962
|
+
registerConsoleCommand(program);
|
|
39893
39963
|
registerLoginCommand(program);
|
|
39894
39964
|
registerLogoutCommand(program);
|
|
39895
39965
|
registerWhoamiCommand(program);
|
|
@@ -39903,7 +39973,7 @@ registerProjectCommand(program);
|
|
|
39903
39973
|
registerCodegenCommand(program);
|
|
39904
39974
|
var configureGenerate = (cmd) => cmd.option("-c, --config <path>", "Path to config file").option("-o, --output <path>", "Output file path (required when using direct files)").option("-k, --api-key <key>", "Stacks node API key for direct RPC URLs").option("-w, --watch", "Watch for changes").action(async (files, options3) => {
|
|
39905
39975
|
const { deprecatedCodegenNotice: deprecatedCodegenNotice2 } = await Promise.resolve().then(() => (init_codegen(), exports_codegen));
|
|
39906
|
-
deprecatedCodegenNotice2("
|
|
39976
|
+
deprecatedCodegenNotice2("secondlayer contracts generate", "secondlayer codegen contracts");
|
|
39907
39977
|
options3.out = options3.output;
|
|
39908
39978
|
const { generate: generate2 } = await Promise.resolve().then(() => (init_generate(), exports_generate));
|
|
39909
39979
|
await generate2(files, options3);
|
|
@@ -39911,9 +39981,9 @@ var configureGenerate = (cmd) => cmd.option("-c, --config <path>", "Path to conf
|
|
|
39911
39981
|
var contracts = program.command("contracts").description("Work with Clarity contracts");
|
|
39912
39982
|
configureGenerate(contracts.command("generate [files...]").aliases(["gen"]).description("Generate TypeScript interfaces from Clarity contracts")).addHelpText("after", `
|
|
39913
39983
|
Examples:
|
|
39914
|
-
$
|
|
39915
|
-
$
|
|
39916
|
-
$
|
|
39984
|
+
$ secondlayer contracts generate
|
|
39985
|
+
$ secondlayer contracts generate ./contracts/pool.clar -o ./src/generated.ts
|
|
39986
|
+
$ secondlayer contracts generate --config secondlayer.config.ts --watch`);
|
|
39917
39987
|
program.commandsGroup("Local development:");
|
|
39918
39988
|
registerLocalCommand(program);
|
|
39919
39989
|
registerDevnetCommand(program);
|
|
@@ -39930,5 +40000,5 @@ registerAccountCommand(program);
|
|
|
39930
40000
|
registerKeysCommand(program);
|
|
39931
40001
|
program.parse();
|
|
39932
40002
|
|
|
39933
|
-
//# debugId=
|
|
40003
|
+
//# debugId=1A69CC6C65B95E8B64756E2164756E21
|
|
39934
40004
|
//# sourceMappingURL=cli.js.map
|