@secondlayer/cli 10.3.0 → 10.3.2
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 +63 -62
- package/dist/cli.js +167 -192
- package/dist/cli.js.map +39 -40
- 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
|
|
@@ -29334,21 +29334,6 @@ var init_subgraph = __esm(() => {
|
|
|
29334
29334
|
};
|
|
29335
29335
|
});
|
|
29336
29336
|
|
|
29337
|
-
// src/utils/urls.ts
|
|
29338
|
-
function deriveBaseUrl(apiUrl) {
|
|
29339
|
-
const override = process.env.SL_DASHBOARD_URL?.trim();
|
|
29340
|
-
if (override)
|
|
29341
|
-
return override.replace(/\/$/, "");
|
|
29342
|
-
try {
|
|
29343
|
-
const url = new URL(apiUrl);
|
|
29344
|
-
url.hostname = url.hostname.replace(/^api\./, "");
|
|
29345
|
-
url.pathname = "/";
|
|
29346
|
-
return url.toString().replace(/\/$/, "");
|
|
29347
|
-
} catch {
|
|
29348
|
-
return apiUrl.replace(/\/$/, "");
|
|
29349
|
-
}
|
|
29350
|
-
}
|
|
29351
|
-
|
|
29352
29337
|
// src/commands/subgraph-test.ts
|
|
29353
29338
|
var exports_subgraph_test = {};
|
|
29354
29339
|
__export(exports_subgraph_test, {
|
|
@@ -29430,7 +29415,7 @@ async function runSubgraphTest(file, options3) {
|
|
|
29430
29415
|
toHeight = usable.toHeight;
|
|
29431
29416
|
} else {
|
|
29432
29417
|
if (options3.offline) {
|
|
29433
|
-
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>");
|
|
29434
29419
|
process.exit(1);
|
|
29435
29420
|
}
|
|
29436
29421
|
if (!options3.from) {
|
|
@@ -30033,10 +30018,10 @@ function registerSubgraphsCommand(program2) {
|
|
|
30033
30018
|
const subgraphs = program2.command("subgraphs").description("Manage materialized subgraphs");
|
|
30034
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", `
|
|
30035
30020
|
Examples:
|
|
30036
|
-
$
|
|
30037
|
-
$
|
|
30038
|
-
$
|
|
30039
|
-
$
|
|
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) => {
|
|
30040
30025
|
if (opts.fromContract && opts.template) {
|
|
30041
30026
|
error("--from-contract and --template are mutually exclusive");
|
|
30042
30027
|
process.exit(1);
|
|
@@ -30092,7 +30077,7 @@ Check the contract id, and that the contract has emitted print events (schemas a
|
|
|
30092
30077
|
} else if (slug !== "basic") {
|
|
30093
30078
|
info(`Template: ${slug} — ${SUBGRAPH_TEMPLATE_DESCRIPTIONS[slug]}`);
|
|
30094
30079
|
}
|
|
30095
|
-
info(`Next:
|
|
30080
|
+
info(`Next: secondlayer subgraphs deploy subgraphs/${name}.ts`);
|
|
30096
30081
|
});
|
|
30097
30082
|
subgraphs.command("dev <file>").description("Watch a subgraph file and auto-redeploy on change").action(async (file) => {
|
|
30098
30083
|
await requireLocalNetwork();
|
|
@@ -30284,24 +30269,22 @@ Stopped watching.`);
|
|
|
30284
30269
|
const printDeployFooter = async () => {
|
|
30285
30270
|
try {
|
|
30286
30271
|
const { apiUrl } = await resolveAuth();
|
|
30287
|
-
const baseUrl = deriveBaseUrl(apiUrl);
|
|
30288
30272
|
const firstTable = Object.keys(effectiveDef.schema ?? {})[0];
|
|
30289
30273
|
const isPublic = result.visibility === "public";
|
|
30290
|
-
info(` Dashboard: ${baseUrl}/platform/subgraphs/${effectiveDef.name}`);
|
|
30291
30274
|
if (isPublic && firstTable) {
|
|
30292
30275
|
info(` Read: ${apiUrl}/v1/subgraphs/${effectiveDef.name}/${firstTable}`);
|
|
30293
30276
|
info(` Share: ${apiUrl}/v1/subgraphs/${effectiveDef.name} (public — no key needed)`);
|
|
30294
30277
|
} else if (firstTable) {
|
|
30295
30278
|
info(` REST: ${apiUrl}/api/subgraphs/${effectiveDef.name}/${firstTable}`);
|
|
30296
|
-
info(` Publish:
|
|
30279
|
+
info(` Publish: secondlayer subgraphs publish ${effectiveDef.name} (open anon /v1 reads)`);
|
|
30297
30280
|
}
|
|
30298
30281
|
if (result.reindexStarted) {
|
|
30299
30282
|
const denom = result.estimatedEvents != null ? ` ~${result.estimatedEvents.toLocaleString()} events —` : "";
|
|
30300
30283
|
info(` Reindex: ${denom} started in the background — check status in ~30s for an ETA`);
|
|
30301
30284
|
}
|
|
30302
|
-
info(` Watch:
|
|
30285
|
+
info(` Watch: secondlayer subgraphs status ${effectiveDef.name}`);
|
|
30303
30286
|
if (firstTable) {
|
|
30304
|
-
info(` Webhook:
|
|
30287
|
+
info(` Webhook: secondlayer subscriptions create ${effectiveDef.name}-hook --subgraph ${effectiveDef.name} --table ${firstTable} --url <your-endpoint>`);
|
|
30305
30288
|
}
|
|
30306
30289
|
} catch {}
|
|
30307
30290
|
};
|
|
@@ -30447,7 +30430,7 @@ ${data.length} subgraph(s) total`));
|
|
|
30447
30430
|
]));
|
|
30448
30431
|
if (sync && sync.gaps.count > 0) {
|
|
30449
30432
|
console.log(dim(`
|
|
30450
|
-
Run:
|
|
30433
|
+
Run: secondlayer subgraphs gaps ${name}`));
|
|
30451
30434
|
}
|
|
30452
30435
|
const tableEntries = Object.entries(subgraph.tables);
|
|
30453
30436
|
if (tableEntries.length > 0) {
|
|
@@ -30499,23 +30482,23 @@ Synced — exiting watch.`));
|
|
|
30499
30482
|
}
|
|
30500
30483
|
});
|
|
30501
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) => {
|
|
30502
|
-
deprecatedCodegenNotice("
|
|
30485
|
+
deprecatedCodegenNotice("secondlayer subgraphs codegen", options3.payloads ? "secondlayer codegen prints" : "secondlayer codegen subgraph");
|
|
30503
30486
|
await runSubgraphSchemaCodegen(file, options3, (key) => command.getOptionValueSource(key));
|
|
30504
30487
|
});
|
|
30505
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", `
|
|
30506
30489
|
Examples:
|
|
30507
|
-
$
|
|
30508
|
-
$
|
|
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) => {
|
|
30509
30492
|
const { runSubgraphTest: runSubgraphTest2 } = await Promise.resolve().then(() => (init_subgraph_test(), exports_subgraph_test));
|
|
30510
30493
|
await runSubgraphTest2(file, options3);
|
|
30511
30494
|
});
|
|
30512
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", `
|
|
30513
30496
|
Reindex is always whole-subgraph: it drops every row and rebuilds from the
|
|
30514
30497
|
subgraph's start block to chain tip. To process a specific block range without
|
|
30515
|
-
dropping anything, use "
|
|
30498
|
+
dropping anything, use "secondlayer subgraphs backfill".
|
|
30516
30499
|
|
|
30517
30500
|
Examples:
|
|
30518
|
-
$
|
|
30501
|
+
$ secondlayer subgraphs reindex my-graph -y`).action(async (name, options3) => {
|
|
30519
30502
|
try {
|
|
30520
30503
|
if (!options3.yes) {
|
|
30521
30504
|
if (!process.stdin.isTTY) {
|
|
@@ -30552,7 +30535,7 @@ Examples:
|
|
|
30552
30535
|
});
|
|
30553
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", `
|
|
30554
30537
|
Examples:
|
|
30555
|
-
$
|
|
30538
|
+
$ secondlayer subgraphs backfill my-graph --from-block 150000 --to-block 160000`).action(async (name, options3) => {
|
|
30556
30539
|
try {
|
|
30557
30540
|
const fromRaw = options3.fromBlock;
|
|
30558
30541
|
const toRaw = options3.toBlock;
|
|
@@ -30617,9 +30600,9 @@ ${result.meta.total} gap(s), ${result.meta.totalMissingBlocks} total missing blo
|
|
|
30617
30600
|
});
|
|
30618
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", `
|
|
30619
30602
|
Examples:
|
|
30620
|
-
$
|
|
30621
|
-
$
|
|
30622
|
-
$
|
|
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) => {
|
|
30623
30606
|
try {
|
|
30624
30607
|
let filters;
|
|
30625
30608
|
try {
|
|
@@ -30746,9 +30729,9 @@ ${rows.length} row(s)`));
|
|
|
30746
30729
|
});
|
|
30747
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", `
|
|
30748
30731
|
Examples:
|
|
30749
|
-
$
|
|
30750
|
-
$
|
|
30751
|
-
$
|
|
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) => {
|
|
30752
30735
|
try {
|
|
30753
30736
|
if (!options3.output) {
|
|
30754
30737
|
error("--output <path> is required");
|
|
@@ -30801,14 +30784,14 @@ Examples:
|
|
|
30801
30784
|
process.exit(1);
|
|
30802
30785
|
}
|
|
30803
30786
|
}
|
|
30804
|
-
info(`Next:
|
|
30787
|
+
info(`Next: secondlayer subgraphs deploy ${options3.output}`);
|
|
30805
30788
|
} catch (err) {
|
|
30806
30789
|
error(`Failed to scaffold subgraph: ${err}`);
|
|
30807
30790
|
process.exit(1);
|
|
30808
30791
|
}
|
|
30809
30792
|
});
|
|
30810
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) => {
|
|
30811
|
-
deprecatedCodegenNotice("
|
|
30794
|
+
deprecatedCodegenNotice("secondlayer subgraphs client", "secondlayer codegen client");
|
|
30812
30795
|
await runSubgraphClientCodegen(subgraphName, options3);
|
|
30813
30796
|
});
|
|
30814
30797
|
}
|
|
@@ -30973,7 +30956,7 @@ function emitOne(doc, label, json) {
|
|
|
30973
30956
|
function registerIndexCommand(program2) {
|
|
30974
30957
|
const index = program2.command("index").description("Query the decoded Index layer (events + contract calls)");
|
|
30975
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) => {
|
|
30976
|
-
deprecatedCodegenNotice("
|
|
30959
|
+
deprecatedCodegenNotice("secondlayer index codegen", "secondlayer codegen index");
|
|
30977
30960
|
await runIndexCodegen(o3);
|
|
30978
30961
|
});
|
|
30979
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");
|
|
@@ -33769,9 +33752,9 @@ async function isDevAlreadyRunning() {
|
|
|
33769
33752
|
printRunningServices(running);
|
|
33770
33753
|
console.log("");
|
|
33771
33754
|
console.log(dim("Commands:"));
|
|
33772
|
-
console.log(` ${green("
|
|
33773
|
-
console.log(` ${green("
|
|
33774
|
-
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")}`);
|
|
33775
33758
|
return true;
|
|
33776
33759
|
}
|
|
33777
33760
|
return false;
|
|
@@ -33913,9 +33896,9 @@ async function runBackground(options3) {
|
|
|
33913
33896
|
success("Dev environment started in background");
|
|
33914
33897
|
console.log("");
|
|
33915
33898
|
console.log(dim("Commands:"));
|
|
33916
|
-
console.log(` ${green("
|
|
33917
|
-
console.log(` ${green("
|
|
33918
|
-
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")}`);
|
|
33919
33902
|
console.log("");
|
|
33920
33903
|
process.exit(0);
|
|
33921
33904
|
} catch (err) {
|
|
@@ -34026,7 +34009,7 @@ async function showLogs(options3) {
|
|
|
34026
34009
|
const state = await loadDevState();
|
|
34027
34010
|
if (!state || Object.keys(state.services).length === 0) {
|
|
34028
34011
|
error("Dev environment is not running");
|
|
34029
|
-
console.log(dim("Start with:
|
|
34012
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34030
34013
|
process.exit(1);
|
|
34031
34014
|
}
|
|
34032
34015
|
const services = options3.service ? { [options3.service]: state.services[options3.service] } : state.services;
|
|
@@ -34165,7 +34148,7 @@ async function restartDev() {
|
|
|
34165
34148
|
const state = await loadDevState();
|
|
34166
34149
|
if (!state) {
|
|
34167
34150
|
info("Dev environment is not running");
|
|
34168
|
-
console.log(dim("Start with:
|
|
34151
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34169
34152
|
return;
|
|
34170
34153
|
}
|
|
34171
34154
|
info("Restarting dev services...");
|
|
@@ -34270,7 +34253,7 @@ async function showDevStatus() {
|
|
|
34270
34253
|
const state = await loadDevState();
|
|
34271
34254
|
if (!state) {
|
|
34272
34255
|
info("Dev environment is not running");
|
|
34273
|
-
console.log(dim("Start with:
|
|
34256
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34274
34257
|
return;
|
|
34275
34258
|
}
|
|
34276
34259
|
const running = await getRunningServices();
|
|
@@ -34505,9 +34488,9 @@ async function runSetupWizard() {
|
|
|
34505
34488
|
]));
|
|
34506
34489
|
console.log("");
|
|
34507
34490
|
console.log(dim("Next steps:"));
|
|
34508
|
-
console.log(` ${green("
|
|
34509
|
-
console.log(` ${green("
|
|
34510
|
-
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")}`);
|
|
34511
34494
|
console.log("");
|
|
34512
34495
|
}
|
|
34513
34496
|
async function startNode(pathOverride, withIndexer) {
|
|
@@ -34516,7 +34499,7 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34516
34499
|
const network = config.node?.network || "mainnet";
|
|
34517
34500
|
if (!nodePath) {
|
|
34518
34501
|
error("Node not configured");
|
|
34519
|
-
console.log(dim("Run '
|
|
34502
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34520
34503
|
process.exit(1);
|
|
34521
34504
|
}
|
|
34522
34505
|
if (!await isDockerRunning()) {
|
|
@@ -34525,8 +34508,8 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34525
34508
|
}
|
|
34526
34509
|
if (await isNodeRunning()) {
|
|
34527
34510
|
info("Node is already running");
|
|
34528
|
-
console.log(dim("Run '
|
|
34529
|
-
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"));
|
|
34530
34513
|
return;
|
|
34531
34514
|
}
|
|
34532
34515
|
const validation = await validateNetworkConsistency(config);
|
|
@@ -34553,13 +34536,13 @@ async function startNode(pathOverride, withIndexer) {
|
|
|
34553
34536
|
console.log("");
|
|
34554
34537
|
if (withIndexer) {
|
|
34555
34538
|
const port = config.ports?.indexer || 3700;
|
|
34556
|
-
console.log(dim("Tip: Start indexer with:
|
|
34539
|
+
console.log(dim("Tip: Start indexer with: secondlayer local start"));
|
|
34557
34540
|
console.log(dim(` Or manually: PORT=${port} bun run packages/indexer/src/index.ts`));
|
|
34558
34541
|
console.log("");
|
|
34559
34542
|
}
|
|
34560
34543
|
console.log(dim("Next steps:"));
|
|
34561
|
-
console.log(` ${green("
|
|
34562
|
-
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")}`);
|
|
34563
34546
|
console.log("");
|
|
34564
34547
|
}
|
|
34565
34548
|
async function stopNode(_pathOverride, force, _wait) {
|
|
@@ -34592,7 +34575,7 @@ async function restartNode(pathOverride, force, _wait) {
|
|
|
34592
34575
|
const network = config.node?.network || "mainnet";
|
|
34593
34576
|
if (!nodePath) {
|
|
34594
34577
|
error("Node not configured");
|
|
34595
|
-
console.log(dim("Run '
|
|
34578
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34596
34579
|
process.exit(1);
|
|
34597
34580
|
}
|
|
34598
34581
|
const wasRunning = await isNodeRunning();
|
|
@@ -34631,8 +34614,8 @@ async function restartNode(pathOverride, force, _wait) {
|
|
|
34631
34614
|
success("Node started!");
|
|
34632
34615
|
console.log("");
|
|
34633
34616
|
console.log(dim("Next steps:"));
|
|
34634
|
-
console.log(` ${green("
|
|
34635
|
-
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")}`);
|
|
34636
34619
|
console.log("");
|
|
34637
34620
|
}
|
|
34638
34621
|
async function showStatus(pathOverride, jsonOutput) {
|
|
@@ -34641,7 +34624,7 @@ async function showStatus(pathOverride, jsonOutput) {
|
|
|
34641
34624
|
const network = config.node?.network || "mainnet";
|
|
34642
34625
|
if (!nodePath) {
|
|
34643
34626
|
error("Node not configured");
|
|
34644
|
-
console.log(dim("Run '
|
|
34627
|
+
console.log(dim("Run 'secondlayer local node setup' or use --path flag"));
|
|
34645
34628
|
process.exit(1);
|
|
34646
34629
|
}
|
|
34647
34630
|
const running = await isNodeRunning();
|
|
@@ -34738,7 +34721,7 @@ async function showStatus(pathOverride, jsonOutput) {
|
|
|
34738
34721
|
if (config.node) {
|
|
34739
34722
|
console.log(blue("Indexer"));
|
|
34740
34723
|
console.log(` ${dim("-")} ${dim(`Not running (expected on port ${indexerPort})`)}`);
|
|
34741
|
-
console.log(dim(" Start with:
|
|
34724
|
+
console.log(dim(" Start with: secondlayer local start"));
|
|
34742
34725
|
console.log("");
|
|
34743
34726
|
}
|
|
34744
34727
|
}
|
|
@@ -34750,7 +34733,7 @@ async function showConfig() {
|
|
|
34750
34733
|
console.log("");
|
|
34751
34734
|
if (!config.node?.installPath) {
|
|
34752
34735
|
warn("Node not configured");
|
|
34753
|
-
console.log(dim("Run '
|
|
34736
|
+
console.log(dim("Run 'secondlayer local node setup' to configure"));
|
|
34754
34737
|
console.log("");
|
|
34755
34738
|
return;
|
|
34756
34739
|
}
|
|
@@ -34761,7 +34744,7 @@ async function showConfig() {
|
|
|
34761
34744
|
]));
|
|
34762
34745
|
console.log("");
|
|
34763
34746
|
console.log(dim("Config file: ~/.secondlayer/config.json"));
|
|
34764
|
-
console.log(dim("Run '
|
|
34747
|
+
console.log(dim("Run 'secondlayer local node config --edit' to modify"));
|
|
34765
34748
|
console.log("");
|
|
34766
34749
|
}
|
|
34767
34750
|
async function showConfigCheck(indexerPort) {
|
|
@@ -34789,7 +34772,7 @@ async function showConfigCheck(indexerPort) {
|
|
|
34789
34772
|
}
|
|
34790
34773
|
} catch {
|
|
34791
34774
|
warn(`Indexer not detected on port ${indexerPort}`);
|
|
34792
|
-
console.log(dim("Start with:
|
|
34775
|
+
console.log(dim("Start with: secondlayer local start"));
|
|
34793
34776
|
}
|
|
34794
34777
|
console.log("");
|
|
34795
34778
|
}
|
|
@@ -34806,7 +34789,7 @@ init_esm();
|
|
|
34806
34789
|
// package.json
|
|
34807
34790
|
var package_default = {
|
|
34808
34791
|
name: "@secondlayer/cli",
|
|
34809
|
-
version: "10.3.
|
|
34792
|
+
version: "10.3.2",
|
|
34810
34793
|
repository: {
|
|
34811
34794
|
type: "git",
|
|
34812
34795
|
url: "git+https://github.com/ryanwaits/secondlayer.git",
|
|
@@ -34849,7 +34832,7 @@ var package_default = {
|
|
|
34849
34832
|
"@inquirer/prompts": "^8.2.0",
|
|
34850
34833
|
"@secondlayer/bundler": "^0.5.0",
|
|
34851
34834
|
"@secondlayer/scaffold": "^1.5.1",
|
|
34852
|
-
"@secondlayer/sdk": "^6.54.
|
|
34835
|
+
"@secondlayer/sdk": "^6.54.1",
|
|
34853
34836
|
"@secondlayer/shared": "^7.11.1",
|
|
34854
34837
|
"@secondlayer/stacks": "^3.3.1",
|
|
34855
34838
|
"@secondlayer/subgraphs": "^3.26.4",
|
|
@@ -34893,13 +34876,16 @@ async function runBillingStatus(json) {
|
|
|
34893
34876
|
output({ json, data: res, human: () => renderBillingStatus(res) });
|
|
34894
34877
|
}
|
|
34895
34878
|
function addBillingCommand(parent) {
|
|
34896
|
-
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));
|
|
34897
34880
|
}
|
|
34898
34881
|
function renderBillingStatus(res) {
|
|
34899
34882
|
if (!res.subscription) {
|
|
34900
34883
|
console.log(formatKeyValue([
|
|
34901
|
-
["Credits", dim("
|
|
34902
|
-
[
|
|
34884
|
+
["Credits", dim("secondlayer credits balance")],
|
|
34885
|
+
[
|
|
34886
|
+
"Buy",
|
|
34887
|
+
dim("secondlayer credits buy --email you@example.com --pack 25")
|
|
34888
|
+
]
|
|
34903
34889
|
]));
|
|
34904
34890
|
return;
|
|
34905
34891
|
}
|
|
@@ -35032,7 +35018,7 @@ async function runBuy(opts) {
|
|
|
35032
35018
|
human: () => {
|
|
35033
35019
|
success(`Checkout for $${amount} → ${email}`);
|
|
35034
35020
|
console.log(res.url);
|
|
35035
|
-
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"));
|
|
35036
35022
|
}
|
|
35037
35023
|
});
|
|
35038
35024
|
}
|
|
@@ -35060,7 +35046,10 @@ async function runBalance(opts) {
|
|
|
35060
35046
|
"Refill",
|
|
35061
35047
|
refill?.belowUsd != null ? `on — below $${refill.belowUsd} buy $${refill.packUsd}` : dim("off")
|
|
35062
35048
|
],
|
|
35063
|
-
[
|
|
35049
|
+
[
|
|
35050
|
+
"Buy",
|
|
35051
|
+
dim("secondlayer credits buy --email you@example.com --pack 25")
|
|
35052
|
+
]
|
|
35064
35053
|
]));
|
|
35065
35054
|
}
|
|
35066
35055
|
});
|
|
@@ -35371,9 +35360,9 @@ function registerConfigCommand(program2) {
|
|
|
35371
35360
|
});
|
|
35372
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", `
|
|
35373
35362
|
Examples:
|
|
35374
|
-
$
|
|
35375
|
-
$
|
|
35376
|
-
$
|
|
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) => {
|
|
35377
35366
|
try {
|
|
35378
35367
|
await setConfigValue(key, value);
|
|
35379
35368
|
success(`Set ${key} = ${value}`);
|
|
@@ -35462,7 +35451,7 @@ async function printConfigTree(cfg) {
|
|
|
35462
35451
|
const status = node.running ? green("●") : dim("○");
|
|
35463
35452
|
console.log(dim(` ${status} ${node.path} (${node.network})`));
|
|
35464
35453
|
}
|
|
35465
|
-
console.log(dim(" Run '
|
|
35454
|
+
console.log(dim(" Run 'secondlayer init' to configure"));
|
|
35466
35455
|
}
|
|
35467
35456
|
} catch {}
|
|
35468
35457
|
}
|
|
@@ -35802,17 +35791,15 @@ async function createSubscription(name, opts) {
|
|
|
35802
35791
|
} catch (err) {
|
|
35803
35792
|
provisioningFailed = true;
|
|
35804
35793
|
warn(`Subscription provisioning failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
35805
|
-
info("Template copied, but the subscription was not created.
|
|
35794
|
+
info("Template copied, but the subscription was not created. Fix the API error, remove the template directory, and rerun.");
|
|
35806
35795
|
}
|
|
35807
35796
|
}
|
|
35808
|
-
let subscriptionId;
|
|
35809
35797
|
let subscriptionStatus;
|
|
35810
35798
|
if (sl) {
|
|
35811
35799
|
try {
|
|
35812
35800
|
const list = await sl.subscriptions.list();
|
|
35813
35801
|
const rows = list.data ?? [];
|
|
35814
35802
|
const created = rows.find((s2) => s2.name === name);
|
|
35815
|
-
subscriptionId = created?.id;
|
|
35816
35803
|
subscriptionStatus = created?.status;
|
|
35817
35804
|
} catch {}
|
|
35818
35805
|
}
|
|
@@ -35840,23 +35827,15 @@ SIGNING_SECRET=${signingSecret}
|
|
|
35840
35827
|
error("Subscription was not created.");
|
|
35841
35828
|
process.exit(1);
|
|
35842
35829
|
}
|
|
35843
|
-
let dashboardLine = "";
|
|
35844
|
-
try {
|
|
35845
|
-
const { apiUrl } = await resolveAuth();
|
|
35846
|
-
const base2 = deriveBaseUrl(apiUrl);
|
|
35847
|
-
dashboardLine = subscriptionId ? `Dashboard: ${base2}/platform/subgraphs/${subgraph}/subscriptions/${subscriptionId}
|
|
35848
|
-
` : `Dashboard: ${base2}/platform/subgraphs/${subgraph}/subscriptions
|
|
35849
|
-
`;
|
|
35850
|
-
} catch {}
|
|
35851
35830
|
const pausedLine = subscriptionStatus === "paused" ? `Subscription is paused. Resume:
|
|
35852
|
-
|
|
35831
|
+
secondlayer subscriptions resume ${name}
|
|
35853
35832
|
` : "";
|
|
35854
35833
|
const runHint = opts.scaffold === false ? `View deliveries:
|
|
35855
|
-
|
|
35834
|
+
secondlayer subscriptions get ${name}` : `cd ${name}
|
|
35856
35835
|
bun install
|
|
35857
35836
|
bun run dev`;
|
|
35858
35837
|
success(`Done. Next:
|
|
35859
|
-
${
|
|
35838
|
+
${pausedLine}${runHint}`);
|
|
35860
35839
|
}
|
|
35861
35840
|
async function createChainSubscription(name, opts) {
|
|
35862
35841
|
for (const [flag, value] of [
|
|
@@ -35901,17 +35880,10 @@ async function createChainSubscription(name, opts) {
|
|
|
35901
35880
|
process.exit(1);
|
|
35902
35881
|
}
|
|
35903
35882
|
info(`Signing secret (store securely): ${signingSecret}`);
|
|
35904
|
-
let dashboardLine = "";
|
|
35905
|
-
try {
|
|
35906
|
-
const { apiUrl } = await resolveAuth();
|
|
35907
|
-
const base2 = deriveBaseUrl(apiUrl);
|
|
35908
|
-
dashboardLine = `Dashboard: ${base2}/platform/subscriptions/${subscriptionId}
|
|
35909
|
-
`;
|
|
35910
|
-
} catch {}
|
|
35911
35883
|
console.log();
|
|
35912
35884
|
success(`Done. Next:
|
|
35913
|
-
|
|
35914
|
-
|
|
35885
|
+
View deliveries:
|
|
35886
|
+
secondlayer subscriptions get ${name}`);
|
|
35915
35887
|
}
|
|
35916
35888
|
async function getSubscriptionClient() {
|
|
35917
35889
|
const { apiUrl, ephemeralKey } = await resolveAuth();
|
|
@@ -35933,7 +35905,7 @@ Examples:
|
|
|
35933
35905
|
function addSubscriptionsCreateCommand(subscriptions) {
|
|
35934
35906
|
addSubscriptionScaffold(subscriptions, "create <name>", {
|
|
35935
35907
|
description: "Create a subscription receiver for a runtime",
|
|
35936
|
-
examplePrefix: "
|
|
35908
|
+
examplePrefix: "secondlayer subscriptions create"
|
|
35937
35909
|
});
|
|
35938
35910
|
}
|
|
35939
35911
|
|
|
@@ -36076,19 +36048,19 @@ function buildDoctorReport(input3) {
|
|
|
36076
36048
|
} : null;
|
|
36077
36049
|
const hints = [];
|
|
36078
36050
|
if (input3.subscription.status === "paused") {
|
|
36079
|
-
hints.push(`Resume when the receiver is healthy:
|
|
36051
|
+
hints.push(`Resume when the receiver is healthy: secondlayer subscriptions resume ${input3.subscription.id}`);
|
|
36080
36052
|
}
|
|
36081
36053
|
if (input3.subscription.lastError) {
|
|
36082
|
-
hints.push("Run
|
|
36054
|
+
hints.push("Run secondlayer subscriptions test to reproduce the receiver request.");
|
|
36083
36055
|
}
|
|
36084
36056
|
if (input3.subscription.circuitOpenedAt || input3.subscription.circuitFailures > 0) {
|
|
36085
36057
|
hints.push("Circuit breaker has failures; inspect receiver logs and delivery status codes.");
|
|
36086
36058
|
}
|
|
36087
36059
|
if (input3.dead.length > 0) {
|
|
36088
|
-
hints.push(`Dead-letter rows exist; inspect with
|
|
36060
|
+
hints.push(`Dead-letter rows exist; inspect with secondlayer subscriptions dead ${input3.subscription.id} and requeue selected rows.`);
|
|
36089
36061
|
}
|
|
36090
36062
|
if (subgraph?.gapCount && subgraph.gapCount > 0) {
|
|
36091
|
-
hints.push(`Linked subgraph has gaps; run
|
|
36063
|
+
hints.push(`Linked subgraph has gaps; run secondlayer subgraphs gaps ${input3.subscription.subgraphName}.`);
|
|
36092
36064
|
}
|
|
36093
36065
|
if (subgraph?.syncStatus === "catching_up") {
|
|
36094
36066
|
hints.push("Linked subgraph is still catching up; new matching rows may arrive later.");
|
|
@@ -36351,9 +36323,9 @@ ${data.length} subscription(s) total`));
|
|
|
36351
36323
|
});
|
|
36352
36324
|
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", `
|
|
36353
36325
|
Examples:
|
|
36354
|
-
$
|
|
36355
|
-
$
|
|
36356
|
-
$
|
|
36326
|
+
$ secondlayer subscriptions update my-sub --url https://example.com/hook
|
|
36327
|
+
$ secondlayer subscriptions update my-sub --filter amount.gte=1000 --max-retries 5
|
|
36328
|
+
$ secondlayer subscriptions update my-sub --clear-filter`).action(async (idOrName, options3) => {
|
|
36357
36329
|
try {
|
|
36358
36330
|
const client2 = await getSubscriptionClient();
|
|
36359
36331
|
const patch = buildUpdatePatch(options3);
|
|
@@ -36482,7 +36454,7 @@ Examples:
|
|
|
36482
36454
|
});
|
|
36483
36455
|
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", `
|
|
36484
36456
|
Examples:
|
|
36485
|
-
$
|
|
36457
|
+
$ secondlayer subscriptions replay my-sub --from-block 150000 --to-block 160000 -y`).action(async (idOrName, options3) => {
|
|
36486
36458
|
try {
|
|
36487
36459
|
const fromBlock = requireIntegerOption(options3.fromBlock, "--from-block");
|
|
36488
36460
|
const toBlock = requireIntegerOption(options3.toBlock, "--to-block");
|
|
@@ -36610,7 +36582,7 @@ function buildDevnetCompose(opts = {}) {
|
|
|
36610
36582
|
const dbUrl = "postgres://secondlayer:secondlayer@postgres:5432/secondlayer";
|
|
36611
36583
|
const DEV_SECRETS_KEY = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
|
|
36612
36584
|
const DEV_INSTANCE_TOKEN = "dev-instance-token";
|
|
36613
|
-
return `# Generated by \`
|
|
36585
|
+
return `# Generated by \`secondlayer devnet connect\` — do not edit by hand.
|
|
36614
36586
|
# Secondlayer app services for local clarinet devnet development.
|
|
36615
36587
|
name: secondlayer-devnet
|
|
36616
36588
|
|
|
@@ -36849,8 +36821,8 @@ function parseAmount(value) {
|
|
|
36849
36821
|
function registerFaucetCommand(devnetCommand) {
|
|
36850
36822
|
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", `
|
|
36851
36823
|
Examples:
|
|
36852
|
-
$
|
|
36853
|
-
$
|
|
36824
|
+
$ secondlayer devnet faucet --to ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
|
|
36825
|
+
$ secondlayer devnet faucet --to ST2... --amount 5000000
|
|
36854
36826
|
|
|
36855
36827
|
Requires a devnet running with the sBTC contract set deployed by your
|
|
36856
36828
|
Clarinet deployer — that deployer is the signer set on your own chain, which
|
|
@@ -36858,7 +36830,7 @@ is what makes minting possible without Bitcoin.`).action(async (opts) => {
|
|
|
36858
36830
|
try {
|
|
36859
36831
|
const network = process.env.STACKS_NETWORK ?? "devnet";
|
|
36860
36832
|
if (network !== "devnet" && network !== "local") {
|
|
36861
|
-
printError(`
|
|
36833
|
+
printError(`secondlayer devnet faucet only works on devnet, not ${network}.`, {
|
|
36862
36834
|
hint: "Mock sBTC is mintable because you deployed the contracts. On testnet or mainnet the signer set is not yours."
|
|
36863
36835
|
});
|
|
36864
36836
|
process.exit(2);
|
|
@@ -36959,7 +36931,7 @@ function registerDevnetCommand(program2) {
|
|
|
36959
36931
|
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) => {
|
|
36960
36932
|
await connect(options3);
|
|
36961
36933
|
});
|
|
36962
|
-
devnet2.command("down").description("Stop the local Secondlayer stack started by `
|
|
36934
|
+
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) => {
|
|
36963
36935
|
await down(options3);
|
|
36964
36936
|
});
|
|
36965
36937
|
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) => {
|
|
@@ -37021,15 +36993,15 @@ ${bold("Secondlayer stack up")}`);
|
|
|
37021
36993
|
console.log(`
|
|
37022
36994
|
${bold("Next:")}`);
|
|
37023
36995
|
console.log(` ${yellow("clarinet devnet start")} ${dim("# auto-deploys + streams to the indexer")}`);
|
|
37024
|
-
console.log(` ${yellow("SL_API_URL=http://localhost:3800 SL_API_KEY=dummy
|
|
36996
|
+
console.log(` ${yellow("SL_API_URL=http://localhost:3800 SL_API_KEY=dummy secondlayer subgraphs deploy ./subgraph.ts")}`);
|
|
37025
36997
|
console.log(dim(`
|
|
37026
|
-
Stop with:
|
|
36998
|
+
Stop with: secondlayer devnet down`));
|
|
37027
36999
|
}
|
|
37028
37000
|
async function down(options3) {
|
|
37029
37001
|
const project = resolveProject(options3.project);
|
|
37030
37002
|
const composePath = join9(project, COMPOSE_REL);
|
|
37031
37003
|
if (!existsSync6(composePath)) {
|
|
37032
|
-
error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`
|
|
37004
|
+
error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`secondlayer devnet connect\` first.`);
|
|
37033
37005
|
process.exit(1);
|
|
37034
37006
|
}
|
|
37035
37007
|
ensureDocker();
|
|
@@ -37044,7 +37016,7 @@ async function logs(service, options3) {
|
|
|
37044
37016
|
const project = resolveProject(options3.project);
|
|
37045
37017
|
const composePath = join9(project, COMPOSE_REL);
|
|
37046
37018
|
if (!existsSync6(composePath)) {
|
|
37047
|
-
error(`No ${COMPOSE_REL} in ${project} — run \`
|
|
37019
|
+
error(`No ${COMPOSE_REL} in ${project} — run \`secondlayer devnet connect\` first.`);
|
|
37048
37020
|
process.exit(1);
|
|
37049
37021
|
}
|
|
37050
37022
|
if (service && !SERVICES.includes(service)) {
|
|
@@ -37092,7 +37064,7 @@ async function renderStatus(limit) {
|
|
|
37092
37064
|
out.push(` ${apiHealth ? green("●") : red("●")} api ${apiHealth ? "healthy" : "down"} ${dim(":3800")}`);
|
|
37093
37065
|
if (!health) {
|
|
37094
37066
|
out.push("");
|
|
37095
|
-
out.push(dim(" indexer unreachable — is `
|
|
37067
|
+
out.push(dim(" indexer unreachable — is `secondlayer devnet connect` running?"));
|
|
37096
37068
|
return out.join(`
|
|
37097
37069
|
`);
|
|
37098
37070
|
}
|
|
@@ -37107,7 +37079,7 @@ async function renderStatus(limit) {
|
|
|
37107
37079
|
out.push("");
|
|
37108
37080
|
out.push(bold("SUBGRAPHS"));
|
|
37109
37081
|
if (subs.length === 0) {
|
|
37110
|
-
out.push(dim(" none deployed —
|
|
37082
|
+
out.push(dim(" none deployed — secondlayer subgraphs deploy ./subgraph.ts"));
|
|
37111
37083
|
} else {
|
|
37112
37084
|
for (const sg of subs) {
|
|
37113
37085
|
const st = sg.status === "active" ? green(sg.status) : yellow(String(sg.status));
|
|
@@ -37147,7 +37119,7 @@ async function status(options3) {
|
|
|
37147
37119
|
const tick = async () => {
|
|
37148
37120
|
const body = await renderStatus(limit);
|
|
37149
37121
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
37150
|
-
console.log(`${dim("
|
|
37122
|
+
console.log(`${dim("secondlayer devnet status")} ${dim("· ctrl-c to stop")}
|
|
37151
37123
|
`);
|
|
37152
37124
|
console.log(body);
|
|
37153
37125
|
};
|
|
@@ -37240,10 +37212,10 @@ function registerStreamsCommand(program2) {
|
|
|
37240
37212
|
});
|
|
37241
37213
|
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", `
|
|
37242
37214
|
Examples:
|
|
37243
|
-
$
|
|
37244
|
-
$
|
|
37245
|
-
$
|
|
37246
|
-
$
|
|
37215
|
+
$ secondlayer streams events --types stx_transfer,print --limit 50
|
|
37216
|
+
$ secondlayer streams events --not-types print --contract-id SP00....token,SP01....token
|
|
37217
|
+
$ secondlayer streams events --sender SP1...,SP2... --from-block 150000 --to-block 160000
|
|
37218
|
+
$ secondlayer streams events --cursor 150000:3`).action(async (options3) => {
|
|
37247
37219
|
try {
|
|
37248
37220
|
const envelope = await client2().events.list({
|
|
37249
37221
|
types: parseTypes(options3.types ?? options3.eventType),
|
|
@@ -37273,8 +37245,8 @@ Examples:
|
|
|
37273
37245
|
});
|
|
37274
37246
|
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", `
|
|
37275
37247
|
Examples:
|
|
37276
|
-
$
|
|
37277
|
-
$
|
|
37248
|
+
$ secondlayer streams consume --types print --cursor 150000:0
|
|
37249
|
+
$ secondlayer streams consume --not-types print --sender SP1...,SP2... --batch-size 500 --max-pages 10`).action(async (options3) => {
|
|
37278
37250
|
try {
|
|
37279
37251
|
const batchSize = parseLimit(options3.batchSize) ?? 100;
|
|
37280
37252
|
const maxPages = options3.maxPages ? Number.parseInt(options3.maxPages, 10) : undefined;
|
|
@@ -37320,8 +37292,8 @@ Examples:
|
|
|
37320
37292
|
});
|
|
37321
37293
|
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", `
|
|
37322
37294
|
Examples:
|
|
37323
|
-
$
|
|
37324
|
-
$
|
|
37295
|
+
$ secondlayer streams pull --to ./dump
|
|
37296
|
+
$ secondlayer streams pull --to ./dump --from-block 150000 --to-block 200000`).action(async (options3) => {
|
|
37325
37297
|
try {
|
|
37326
37298
|
const fromBlock = parseHeight(options3.fromBlock, "--from-block");
|
|
37327
37299
|
const toBlock = parseHeight(options3.toBlock, "--to-block");
|
|
@@ -37749,7 +37721,7 @@ function markFrozen(cmd) {
|
|
|
37749
37721
|
if (warned)
|
|
37750
37722
|
return;
|
|
37751
37723
|
warned = true;
|
|
37752
|
-
process.stderr.write(`⚠ \`
|
|
37724
|
+
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.
|
|
37753
37725
|
`);
|
|
37754
37726
|
};
|
|
37755
37727
|
cmd.hook("preAction", warn2);
|
|
@@ -37782,7 +37754,7 @@ Subcommands:
|
|
|
37782
37754
|
truncate Truncate all indexed data
|
|
37783
37755
|
resync Reset database and restart indexer
|
|
37784
37756
|
|
|
37785
|
-
Run \`
|
|
37757
|
+
Run \`secondlayer db\` with no subcommand to print an overview.`).hook("preAction", async () => {
|
|
37786
37758
|
await requireLocalNetwork();
|
|
37787
37759
|
}).action(async () => {
|
|
37788
37760
|
await showOverview(10);
|
|
@@ -37843,14 +37815,14 @@ async function showOverview(_limit) {
|
|
|
37843
37815
|
console.log(` Time: ${time}`);
|
|
37844
37816
|
console.log("");
|
|
37845
37817
|
}
|
|
37846
|
-
console.log(dim(`Use '
|
|
37818
|
+
console.log(dim(`Use 'secondlayer db blocks|txs|events' to see records`));
|
|
37847
37819
|
console.log("");
|
|
37848
37820
|
process.exit(0);
|
|
37849
37821
|
} catch (err) {
|
|
37850
37822
|
error(`Failed to query database: ${err}`);
|
|
37851
37823
|
console.log(dim(`
|
|
37852
37824
|
Make sure PostgreSQL is running.`));
|
|
37853
|
-
console.log(dim("Run '
|
|
37825
|
+
console.log(dim("Run 'secondlayer local start' to start all services."));
|
|
37854
37826
|
process.exit(1);
|
|
37855
37827
|
}
|
|
37856
37828
|
}
|
|
@@ -37998,7 +37970,7 @@ async function resetDatabase(skipConfirm) {
|
|
|
37998
37970
|
console.log("");
|
|
37999
37971
|
success("Database reset complete");
|
|
38000
37972
|
console.log("");
|
|
38001
|
-
console.log(dim("Run '
|
|
37973
|
+
console.log(dim("Run 'secondlayer local restart' to restart the indexer for fresh sync."));
|
|
38002
37974
|
console.log("");
|
|
38003
37975
|
process.exit(0);
|
|
38004
37976
|
} catch (err) {
|
|
@@ -38047,13 +38019,13 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
38047
38019
|
}
|
|
38048
38020
|
console.log(green(" ✓ Indexer stopped"));
|
|
38049
38021
|
console.log("");
|
|
38050
|
-
info("Run '
|
|
38022
|
+
info("Run 'secondlayer local restart' to start fresh sync");
|
|
38051
38023
|
} else {
|
|
38052
38024
|
console.log("");
|
|
38053
38025
|
success("Database reset complete");
|
|
38054
38026
|
console.log("");
|
|
38055
38027
|
if (!backfill) {
|
|
38056
|
-
console.log(dim("Indexer not running. Start with '
|
|
38028
|
+
console.log(dim("Indexer not running. Start with 'secondlayer local start' to begin sync."));
|
|
38057
38029
|
}
|
|
38058
38030
|
}
|
|
38059
38031
|
if (backfill) {
|
|
@@ -38063,14 +38035,14 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
38063
38035
|
const healthy = await nodeClient.isHealthy();
|
|
38064
38036
|
if (!healthy) {
|
|
38065
38037
|
warn(`Cannot reach Stacks node at ${nodeClient.getRpcUrl()}`);
|
|
38066
|
-
console.log(dim("Run '
|
|
38038
|
+
console.log(dim("Run 'secondlayer sync --from 1 --to <tip>' manually once the node is available."));
|
|
38067
38039
|
console.log("");
|
|
38068
38040
|
process.exit(0);
|
|
38069
38041
|
}
|
|
38070
38042
|
const nodeInfo = await nodeClient.getInfo();
|
|
38071
38043
|
const tip = nodeInfo.stacks_tip_height;
|
|
38072
38044
|
info(`Node tip: block ${tip}. Fetching blocks 1 to ${tip}...`);
|
|
38073
|
-
console.log(dim(`This may take a while. Run '
|
|
38045
|
+
console.log(dim(`This may take a while. Run 'secondlayer sync --from 1 --to ${tip}' if interrupted.`));
|
|
38074
38046
|
console.log("");
|
|
38075
38047
|
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config2(), exports_config));
|
|
38076
38048
|
const config = await loadConfig3();
|
|
@@ -38159,7 +38131,7 @@ async function stackStart(options3) {
|
|
|
38159
38131
|
if (options3.node) {
|
|
38160
38132
|
const nodePath = config.node?.installPath;
|
|
38161
38133
|
if (!nodePath) {
|
|
38162
|
-
warn("No node configured, skipping. Run '
|
|
38134
|
+
warn("No node configured, skipping. Run 'secondlayer local node setup' to configure.");
|
|
38163
38135
|
} else if (await isNodeRunning()) {
|
|
38164
38136
|
info("Node already running");
|
|
38165
38137
|
} else {
|
|
@@ -38224,7 +38196,7 @@ async function stackStart(options3) {
|
|
|
38224
38196
|
}
|
|
38225
38197
|
console.log("");
|
|
38226
38198
|
success("Stack started");
|
|
38227
|
-
console.log(dim("Run '
|
|
38199
|
+
console.log(dim("Run 'secondlayer status' to check health"));
|
|
38228
38200
|
console.log("");
|
|
38229
38201
|
}
|
|
38230
38202
|
async function stackStop(options3) {
|
|
@@ -38454,7 +38426,7 @@ async function showLocalLogs(options3) {
|
|
|
38454
38426
|
async function showNodeLogs(options3) {
|
|
38455
38427
|
if (!await isNodeRunning()) {
|
|
38456
38428
|
error("Node is not running");
|
|
38457
|
-
console.log(dim("Run '
|
|
38429
|
+
console.log(dim("Run 'secondlayer local node start' first"));
|
|
38458
38430
|
process.exit(1);
|
|
38459
38431
|
}
|
|
38460
38432
|
const logs2 = await getNodeLogs({
|
|
@@ -38648,7 +38620,7 @@ function registerWhoamiCommand(program2) {
|
|
|
38648
38620
|
try {
|
|
38649
38621
|
auth = await resolveAuth();
|
|
38650
38622
|
} catch {
|
|
38651
|
-
error("Not logged in. Run:
|
|
38623
|
+
error("Not logged in. Run: secondlayer login");
|
|
38652
38624
|
process.exit(1);
|
|
38653
38625
|
}
|
|
38654
38626
|
let account;
|
|
@@ -38656,7 +38628,7 @@ function registerWhoamiCommand(program2) {
|
|
|
38656
38628
|
account = await httpPlatform("/api/accounts/me");
|
|
38657
38629
|
} catch (err) {
|
|
38658
38630
|
if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED") {
|
|
38659
|
-
error("Session expired. Run:
|
|
38631
|
+
error("Session expired. Run: secondlayer login");
|
|
38660
38632
|
process.exit(1);
|
|
38661
38633
|
}
|
|
38662
38634
|
throw err;
|
|
@@ -38683,7 +38655,10 @@ function registerWhoamiCommand(program2) {
|
|
|
38683
38655
|
rows.push(["Project", active.slug]);
|
|
38684
38656
|
rows.push(["Project source", dim(active.resolvedFrom)]);
|
|
38685
38657
|
} else {
|
|
38686
|
-
rows.push([
|
|
38658
|
+
rows.push([
|
|
38659
|
+
"Project",
|
|
38660
|
+
dim("(none — run `secondlayer project use <slug>`)")
|
|
38661
|
+
]);
|
|
38687
38662
|
}
|
|
38688
38663
|
console.log(formatKeyValue(rows));
|
|
38689
38664
|
}
|
|
@@ -38755,7 +38730,7 @@ function registerProjectCommand(program2) {
|
|
|
38755
38730
|
await httpPlatform(`/api/projects/${encodeURIComponent(slug)}`);
|
|
38756
38731
|
} catch (err) {
|
|
38757
38732
|
if (err instanceof CliHttpError && err.status === 404) {
|
|
38758
|
-
error(`Project "${slug}" not found — run '
|
|
38733
|
+
error(`Project "${slug}" not found — run 'secondlayer project list' to see available projects`);
|
|
38759
38734
|
process.exit(1);
|
|
38760
38735
|
}
|
|
38761
38736
|
handleProjectError(err);
|
|
@@ -38774,7 +38749,7 @@ function registerProjectCommand(program2) {
|
|
|
38774
38749
|
human: () => {
|
|
38775
38750
|
if (!active) {
|
|
38776
38751
|
info("No active project.");
|
|
38777
|
-
info(dim("Run '
|
|
38752
|
+
info(dim("Run 'secondlayer project use <slug>' to bind this directory."));
|
|
38778
38753
|
return;
|
|
38779
38754
|
}
|
|
38780
38755
|
console.log(active.slug);
|
|
@@ -38786,7 +38761,7 @@ function registerProjectCommand(program2) {
|
|
|
38786
38761
|
function handleProjectError(err) {
|
|
38787
38762
|
if (err instanceof CliHttpError) {
|
|
38788
38763
|
if (err.code === "SESSION_EXPIRED") {
|
|
38789
|
-
error("Session expired. Run:
|
|
38764
|
+
error("Session expired. Run: secondlayer login");
|
|
38790
38765
|
process.exit(1);
|
|
38791
38766
|
}
|
|
38792
38767
|
error(err.message);
|
|
@@ -38954,11 +38929,11 @@ function statusLabel(status2) {
|
|
|
38954
38929
|
function registerVerifyCommand(program2) {
|
|
38955
38930
|
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", `
|
|
38956
38931
|
Examples:
|
|
38957
|
-
$
|
|
38958
|
-
$
|
|
38959
|
-
$
|
|
38960
|
-
$
|
|
38961
|
-
$
|
|
38932
|
+
$ secondlayer verify --against https://archive.secondlayer.tools/.../snapshots/<digest>.json
|
|
38933
|
+
$ secondlayer verify raw --against ./snapshot.json --from-block 8000000 --to-block 8499999
|
|
38934
|
+
$ secondlayer verify all --against ./snapshot.json --json
|
|
38935
|
+
$ secondlayer verify decode:ft_transfer --against ./snapshot.json --quick
|
|
38936
|
+
$ secondlayer verify subgraph:sbtc --against ./snapshot.json --deep
|
|
38962
38937
|
|
|
38963
38938
|
Exit codes:
|
|
38964
38939
|
0 local data matches the archive
|
|
@@ -39122,7 +39097,7 @@ Exit codes:
|
|
|
39122
39097
|
console.error(dim("These ranges hold different data than the signed archive. Repair with:"));
|
|
39123
39098
|
const first = diverged[0];
|
|
39124
39099
|
if (first) {
|
|
39125
|
-
console.error(dim(`
|
|
39100
|
+
console.error(dim(` secondlayer repair --from-block ${first.from_block} --to-block ${first.to_block}`));
|
|
39126
39101
|
}
|
|
39127
39102
|
}
|
|
39128
39103
|
});
|
|
@@ -39256,9 +39231,9 @@ async function applyFixes(db, reference, partition, fixes) {
|
|
|
39256
39231
|
function registerRepairCommand(program2) {
|
|
39257
39232
|
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", `
|
|
39258
39233
|
Examples:
|
|
39259
|
-
$
|
|
39260
|
-
$
|
|
39261
|
-
$
|
|
39234
|
+
$ secondlayer repair --against ./snapshot.json # plan only
|
|
39235
|
+
$ secondlayer repair --against ./snapshot.json --apply # write the fix
|
|
39236
|
+
$ secondlayer repair --against ./snapshot.json --from-block 8500000 --to-block 8549999
|
|
39262
39237
|
|
|
39263
39238
|
Exit codes:
|
|
39264
39239
|
0 nothing to repair, or the repair completed and re-verified clean
|
|
@@ -39488,8 +39463,8 @@ async function loadPartition(reference, partition, rawClient) {
|
|
|
39488
39463
|
function attachBootstrapCommand(cmd) {
|
|
39489
39464
|
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", `
|
|
39490
39465
|
Examples:
|
|
39491
|
-
$
|
|
39492
|
-
$
|
|
39466
|
+
$ secondlayer bootstrap --against https://archive.secondlayer.tools/.../snapshots/<digest>.json
|
|
39467
|
+
$ secondlayer bootstrap --against ./snapshot.json --to-block 4000000 --yes
|
|
39493
39468
|
|
|
39494
39469
|
Exit codes:
|
|
39495
39470
|
0 restored and verified
|
|
@@ -39522,7 +39497,7 @@ Exit codes:
|
|
|
39522
39497
|
});
|
|
39523
39498
|
if (resume.action === "refuse") {
|
|
39524
39499
|
printError(resume.reason, {
|
|
39525
|
-
hint: "Bootstrap is for a fresh instance. To fix an existing one, use `
|
|
39500
|
+
hint: "Bootstrap is for a fresh instance. To fix an existing one, use `secondlayer repair`."
|
|
39526
39501
|
});
|
|
39527
39502
|
process.exit(BOOTSTRAP_EXIT.REFUSED);
|
|
39528
39503
|
}
|
|
@@ -39646,7 +39621,7 @@ Exit codes:
|
|
|
39646
39621
|
}
|
|
39647
39622
|
} else {
|
|
39648
39623
|
warn(`Restored ${loaded.blocks.toLocaleString()} blocks but ${divergent} ranges do not match the archive.`);
|
|
39649
|
-
console.error(dim(" Investigate with:
|
|
39624
|
+
console.error(dim(" Investigate with: secondlayer verify --against <manifest>"));
|
|
39650
39625
|
}
|
|
39651
39626
|
}
|
|
39652
39627
|
});
|
|
@@ -39725,7 +39700,7 @@ function buildInstanceEnv(input4) {
|
|
|
39725
39700
|
}
|
|
39726
39701
|
function renderInstanceEnv(env2) {
|
|
39727
39702
|
const lines2 = [
|
|
39728
|
-
"# Generated by
|
|
39703
|
+
"# Generated by secondlayer init. Do not commit.",
|
|
39729
39704
|
`INSTANCE_MODE=${env2.INSTANCE_MODE}`,
|
|
39730
39705
|
`STACKS_NETWORK=${env2.STACKS_NETWORK}`,
|
|
39731
39706
|
`INSTANCE_TOKEN=${env2.INSTANCE_TOKEN}`,
|
|
@@ -39902,7 +39877,7 @@ function registerStartCommand(program2) {
|
|
|
39902
39877
|
}
|
|
39903
39878
|
// src/cli.ts
|
|
39904
39879
|
var { version } = package_default;
|
|
39905
|
-
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 `
|
|
39880
|
+
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)");
|
|
39906
39881
|
program.hook("preAction", (thisCommand) => {
|
|
39907
39882
|
const { network, apiKey, apiUrl } = thisCommand.opts();
|
|
39908
39883
|
if (network)
|
|
@@ -39914,10 +39889,10 @@ program.hook("preAction", (thisCommand) => {
|
|
|
39914
39889
|
});
|
|
39915
39890
|
program.addHelpText("after", `
|
|
39916
39891
|
Quickstart:
|
|
39917
|
-
$
|
|
39918
|
-
$
|
|
39919
|
-
$
|
|
39920
|
-
$
|
|
39892
|
+
$ secondlayer init --network mainnet
|
|
39893
|
+
$ secondlayer bootstrap --against <manifest>
|
|
39894
|
+
$ secondlayer subgraphs create my-watcher --template sip-010-balances
|
|
39895
|
+
$ secondlayer subgraphs deploy subgraphs/my-watcher.ts
|
|
39921
39896
|
`);
|
|
39922
39897
|
program.commandsGroup("Getting started:");
|
|
39923
39898
|
registerInitCommand(program);
|
|
@@ -39937,7 +39912,7 @@ registerProjectCommand(program);
|
|
|
39937
39912
|
registerCodegenCommand(program);
|
|
39938
39913
|
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) => {
|
|
39939
39914
|
const { deprecatedCodegenNotice: deprecatedCodegenNotice2 } = await Promise.resolve().then(() => (init_codegen(), exports_codegen));
|
|
39940
|
-
deprecatedCodegenNotice2("
|
|
39915
|
+
deprecatedCodegenNotice2("secondlayer contracts generate", "secondlayer codegen contracts");
|
|
39941
39916
|
options3.out = options3.output;
|
|
39942
39917
|
const { generate: generate2 } = await Promise.resolve().then(() => (init_generate(), exports_generate));
|
|
39943
39918
|
await generate2(files, options3);
|
|
@@ -39945,9 +39920,9 @@ var configureGenerate = (cmd) => cmd.option("-c, --config <path>", "Path to conf
|
|
|
39945
39920
|
var contracts = program.command("contracts").description("Work with Clarity contracts");
|
|
39946
39921
|
configureGenerate(contracts.command("generate [files...]").aliases(["gen"]).description("Generate TypeScript interfaces from Clarity contracts")).addHelpText("after", `
|
|
39947
39922
|
Examples:
|
|
39948
|
-
$
|
|
39949
|
-
$
|
|
39950
|
-
$
|
|
39923
|
+
$ secondlayer contracts generate
|
|
39924
|
+
$ secondlayer contracts generate ./contracts/pool.clar -o ./src/generated.ts
|
|
39925
|
+
$ secondlayer contracts generate --config secondlayer.config.ts --watch`);
|
|
39951
39926
|
program.commandsGroup("Local development:");
|
|
39952
39927
|
registerLocalCommand(program);
|
|
39953
39928
|
registerDevnetCommand(program);
|
|
@@ -39964,5 +39939,5 @@ registerAccountCommand(program);
|
|
|
39964
39939
|
registerKeysCommand(program);
|
|
39965
39940
|
program.parse();
|
|
39966
39941
|
|
|
39967
|
-
//# debugId=
|
|
39942
|
+
//# debugId=0D2E887299BDADAE64756E2164756E21
|
|
39968
39943
|
//# sourceMappingURL=cli.js.map
|