@secondlayer/cli 5.9.0 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +157 -22
- package/dist/cli.js.map +3 -3
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -13977,8 +13977,8 @@ function printRunningServices(services) {
|
|
|
13977
13977
|
console.log(blue("Services"));
|
|
13978
13978
|
for (const [name, service] of Object.entries(services)) {
|
|
13979
13979
|
const portInfo = service.port ? dim(`http://localhost:${service.port}`) : dim("background");
|
|
13980
|
-
const
|
|
13981
|
-
console.log(` ${
|
|
13980
|
+
const status2 = isProcessRunning(service.pid) ? green("✓") : red("✗");
|
|
13981
|
+
console.log(` ${status2} ${name.padEnd(10)} ${portInfo} ${dim(`(pid ${service.pid})`)}`);
|
|
13982
13982
|
}
|
|
13983
13983
|
}
|
|
13984
13984
|
async function isContainerRunning(name) {
|
|
@@ -26266,14 +26266,14 @@ var require_enoent = __commonJS((exports, module) => {
|
|
|
26266
26266
|
return originalEmit.apply(cp, arguments);
|
|
26267
26267
|
};
|
|
26268
26268
|
}
|
|
26269
|
-
function verifyENOENT(
|
|
26270
|
-
if (isWin &&
|
|
26269
|
+
function verifyENOENT(status2, parsed) {
|
|
26270
|
+
if (isWin && status2 === 1 && !parsed.file) {
|
|
26271
26271
|
return notFoundError(parsed.original, "spawn");
|
|
26272
26272
|
}
|
|
26273
26273
|
return null;
|
|
26274
26274
|
}
|
|
26275
|
-
function verifyENOENTSync(
|
|
26276
|
-
if (isWin &&
|
|
26275
|
+
function verifyENOENTSync(status2, parsed) {
|
|
26276
|
+
if (isWin && status2 === 1 && !parsed.file) {
|
|
26277
26277
|
return notFoundError(parsed.original, "spawnSync");
|
|
26278
26278
|
}
|
|
26279
26279
|
return null;
|
|
@@ -32324,7 +32324,7 @@ var {
|
|
|
32324
32324
|
// package.json
|
|
32325
32325
|
var package_default = {
|
|
32326
32326
|
name: "@secondlayer/cli",
|
|
32327
|
-
version: "5.
|
|
32327
|
+
version: "5.10.0",
|
|
32328
32328
|
repository: {
|
|
32329
32329
|
type: "git",
|
|
32330
32330
|
url: "git+https://github.com/ryanwaits/secondlayer.git",
|
|
@@ -32373,8 +32373,8 @@ var package_default = {
|
|
|
32373
32373
|
dependencies: {
|
|
32374
32374
|
"@inquirer/prompts": "^8.2.0",
|
|
32375
32375
|
"@secondlayer/bundler": "^0.3.7",
|
|
32376
|
-
"@secondlayer/sdk": "^5.
|
|
32377
|
-
"@secondlayer/shared": "^6.
|
|
32376
|
+
"@secondlayer/sdk": "^5.7.0",
|
|
32377
|
+
"@secondlayer/shared": "^6.10.0",
|
|
32378
32378
|
"@secondlayer/stacks": "^2.3.0",
|
|
32379
32379
|
"@secondlayer/subgraphs": "^3.4.0",
|
|
32380
32380
|
"@biomejs/js-api": "^0.7.0",
|
|
@@ -34640,6 +34640,15 @@ function dockerCompose(composePath, args) {
|
|
|
34640
34640
|
});
|
|
34641
34641
|
return res.status ?? 1;
|
|
34642
34642
|
}
|
|
34643
|
+
var API_URL = process.env.SL_API_URL ?? "http://localhost:3800";
|
|
34644
|
+
var INDEXER_URL = process.env.INDEXER_URL ?? "http://localhost:3700";
|
|
34645
|
+
var SERVICES = [
|
|
34646
|
+
"indexer",
|
|
34647
|
+
"api",
|
|
34648
|
+
"subgraph-processor",
|
|
34649
|
+
"postgres",
|
|
34650
|
+
"migrate"
|
|
34651
|
+
];
|
|
34643
34652
|
function registerDevnetCommand(program2) {
|
|
34644
34653
|
const devnet = program2.command("devnet").description("Run Secondlayer services against a local Clarinet devnet");
|
|
34645
34654
|
devnet.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 (options) => {
|
|
@@ -34648,6 +34657,12 @@ function registerDevnetCommand(program2) {
|
|
|
34648
34657
|
devnet.command("down").description("Stop the local Secondlayer stack started by `sl devnet connect`").option("--project <dir>", "Clarinet project directory").option("--purge", "Also remove volumes (wipes the local index)").action(async (options) => {
|
|
34649
34658
|
await down(options);
|
|
34650
34659
|
});
|
|
34660
|
+
devnet.command("status").description("Snapshot of the local stack: ingest, subgraphs, and recent activity").option("-w, --watch", "Refresh every 2s until Ctrl-C").option("-n, --limit <n>", "Recent activity rows to show", "12").action(async (options) => {
|
|
34661
|
+
await status(options);
|
|
34662
|
+
});
|
|
34663
|
+
devnet.command("logs [service]").description("Tail stack logs — all services, or one of: indexer, api, subgraph-processor, postgres").option("--project <dir>", "Clarinet project directory").option("-f, --follow", "Follow log output").option("-n, --tail <n>", "Lines to show from the end of each log", "200").action(async (service, options) => {
|
|
34664
|
+
await logs(service, options);
|
|
34665
|
+
});
|
|
34651
34666
|
}
|
|
34652
34667
|
function resolveProject(explicit) {
|
|
34653
34668
|
if (explicit) {
|
|
@@ -34720,6 +34735,126 @@ async function down(options) {
|
|
|
34720
34735
|
}
|
|
34721
34736
|
console.log(`${green("✓")}${options.purge ? " stack stopped, volumes removed" : " stack stopped"}`);
|
|
34722
34737
|
}
|
|
34738
|
+
async function logs(service, options) {
|
|
34739
|
+
const project = resolveProject(options.project);
|
|
34740
|
+
const composePath = join7(project, COMPOSE_REL);
|
|
34741
|
+
if (!existsSync3(composePath)) {
|
|
34742
|
+
error(`No ${COMPOSE_REL} in ${project} — run \`sl devnet connect\` first.`);
|
|
34743
|
+
process.exit(1);
|
|
34744
|
+
}
|
|
34745
|
+
if (service && !SERVICES.includes(service)) {
|
|
34746
|
+
error(`Unknown service "${service}". Choose one of: ${SERVICES.join(", ")}`);
|
|
34747
|
+
process.exit(1);
|
|
34748
|
+
}
|
|
34749
|
+
ensureDocker();
|
|
34750
|
+
const args = ["logs", "--tail", options.tail];
|
|
34751
|
+
if (options.follow)
|
|
34752
|
+
args.push("-f");
|
|
34753
|
+
if (service)
|
|
34754
|
+
args.push(service);
|
|
34755
|
+
process.exit(dockerCompose(composePath, args));
|
|
34756
|
+
}
|
|
34757
|
+
async function jget(url) {
|
|
34758
|
+
try {
|
|
34759
|
+
const r = await fetch(url, { signal: AbortSignal.timeout(1500) });
|
|
34760
|
+
return r.ok ? await r.json() : null;
|
|
34761
|
+
} catch {
|
|
34762
|
+
return null;
|
|
34763
|
+
}
|
|
34764
|
+
}
|
|
34765
|
+
var SYS_COLS = new Set([
|
|
34766
|
+
"_id",
|
|
34767
|
+
"_block_height",
|
|
34768
|
+
"_tx_id",
|
|
34769
|
+
"_created_at",
|
|
34770
|
+
"block_height",
|
|
34771
|
+
"tx_id"
|
|
34772
|
+
]);
|
|
34773
|
+
function shortVal(v) {
|
|
34774
|
+
const s = String(v);
|
|
34775
|
+
return s.length > 18 ? `${s.slice(0, 6)}…${s.slice(-4)}` : s;
|
|
34776
|
+
}
|
|
34777
|
+
async function renderStatus(limit) {
|
|
34778
|
+
const [health, integrity, subsRes, apiHealth] = await Promise.all([
|
|
34779
|
+
jget(`${INDEXER_URL}/health`),
|
|
34780
|
+
jget(`${INDEXER_URL}/health/integrity`),
|
|
34781
|
+
jget(`${API_URL}/api/subgraphs`),
|
|
34782
|
+
jget(`${API_URL}/health`)
|
|
34783
|
+
]);
|
|
34784
|
+
const out = [];
|
|
34785
|
+
out.push(bold("STACK"));
|
|
34786
|
+
out.push(` ${health ? green("●") : red("●")} indexer ${health ? "healthy" : "down"} ${dim(":3700")}`);
|
|
34787
|
+
out.push(` ${apiHealth ? green("●") : red("●")} api ${apiHealth ? "healthy" : "down"} ${dim(":3800")}`);
|
|
34788
|
+
if (!health) {
|
|
34789
|
+
out.push("");
|
|
34790
|
+
out.push(dim(" indexer unreachable — is `sl devnet connect` running?"));
|
|
34791
|
+
return out.join(`
|
|
34792
|
+
`);
|
|
34793
|
+
}
|
|
34794
|
+
const tip = Number(health.lastSeenHeight ?? integrity?.lastIndexedBlock ?? 0);
|
|
34795
|
+
const indexed = Number(integrity?.lastIndexedBlock ?? tip);
|
|
34796
|
+
const lag = Math.max(0, tip - indexed);
|
|
34797
|
+
const ago = health.lastBlockReceivedSecondsAgo;
|
|
34798
|
+
out.push("");
|
|
34799
|
+
out.push(bold("INGEST"));
|
|
34800
|
+
out.push(` chain tip ${cyan(String(tip))} indexed ${indexed} lag ${lag === 0 ? green("caught up") : yellow(`${lag} blk`)} ${dim(`last block ${ago != null ? `${ago}s ago` : "?"}`)}`);
|
|
34801
|
+
const subs = subsRes?.data ?? [];
|
|
34802
|
+
out.push("");
|
|
34803
|
+
out.push(bold("SUBGRAPHS"));
|
|
34804
|
+
if (subs.length === 0) {
|
|
34805
|
+
out.push(dim(" none deployed — sl subgraphs deploy ./subgraph.ts"));
|
|
34806
|
+
} else {
|
|
34807
|
+
for (const sg of subs) {
|
|
34808
|
+
const st = sg.status === "active" ? green(sg.status) : yellow(String(sg.status));
|
|
34809
|
+
const tables = (sg.tables ?? []).join(", ");
|
|
34810
|
+
out.push(` ${sg.name} ${st} ${dim(`block ${sg.lastProcessedBlock}`)} ${tables} ${dim(`· ${sg.totalRows ?? 0} rows`)}`);
|
|
34811
|
+
}
|
|
34812
|
+
}
|
|
34813
|
+
out.push("");
|
|
34814
|
+
out.push(bold("ACTIVITY") + dim(" (recent)"));
|
|
34815
|
+
const rows = [];
|
|
34816
|
+
for (const sg of subs) {
|
|
34817
|
+
for (const table of sg.tables ?? []) {
|
|
34818
|
+
const res = await jget(`${API_URL}/api/subgraphs/${sg.name}/${table}?_limit=${limit}&_sort=_block_height&_order=desc`);
|
|
34819
|
+
for (const row of res?.data ?? []) {
|
|
34820
|
+
const summary = Object.entries(row).filter(([k]) => !SYS_COLS.has(k)).map(([, v]) => shortVal(v)).join(" ");
|
|
34821
|
+
rows.push({ block: Number(row._block_height ?? 0), table, summary });
|
|
34822
|
+
}
|
|
34823
|
+
}
|
|
34824
|
+
}
|
|
34825
|
+
rows.sort((a, b2) => b2.block - a.block);
|
|
34826
|
+
if (rows.length === 0) {
|
|
34827
|
+
out.push(dim(" no indexed rows yet — fire a contract call"));
|
|
34828
|
+
} else {
|
|
34829
|
+
for (const r of rows.slice(0, limit)) {
|
|
34830
|
+
out.push(` ${dim(String(r.block).padStart(5))} ${r.table.padEnd(16)} ${r.summary}`);
|
|
34831
|
+
}
|
|
34832
|
+
}
|
|
34833
|
+
return out.join(`
|
|
34834
|
+
`);
|
|
34835
|
+
}
|
|
34836
|
+
async function status(options) {
|
|
34837
|
+
const limit = Math.max(1, Number(options.limit) || 12);
|
|
34838
|
+
if (!options.watch) {
|
|
34839
|
+
console.log(await renderStatus(limit));
|
|
34840
|
+
return;
|
|
34841
|
+
}
|
|
34842
|
+
const tick = async () => {
|
|
34843
|
+
const body = await renderStatus(limit);
|
|
34844
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
34845
|
+
console.log(`${dim("sl devnet status")} ${dim("· ctrl-c to stop")}
|
|
34846
|
+
`);
|
|
34847
|
+
console.log(body);
|
|
34848
|
+
};
|
|
34849
|
+
await tick();
|
|
34850
|
+
const id = setInterval(() => void tick(), 2000);
|
|
34851
|
+
process.on("SIGINT", () => {
|
|
34852
|
+
clearInterval(id);
|
|
34853
|
+
process.stdout.write(`
|
|
34854
|
+
`);
|
|
34855
|
+
process.exit(0);
|
|
34856
|
+
});
|
|
34857
|
+
}
|
|
34723
34858
|
// src/commands/subgraphs.ts
|
|
34724
34859
|
import { spawn } from "node:child_process";
|
|
34725
34860
|
import {
|
|
@@ -36348,8 +36483,8 @@ ${rows.length} row(s)`));
|
|
|
36348
36483
|
success(result.message);
|
|
36349
36484
|
} catch (delErr) {
|
|
36350
36485
|
const msg = delErr instanceof Error ? delErr.message : String(delErr);
|
|
36351
|
-
const
|
|
36352
|
-
if (
|
|
36486
|
+
const status2 = delErr?.status;
|
|
36487
|
+
if (status2 === 404 || /not found/i.test(msg)) {
|
|
36353
36488
|
info(`Subgraph "${name}" not found (already deleted?)`);
|
|
36354
36489
|
return;
|
|
36355
36490
|
}
|
|
@@ -36879,15 +37014,15 @@ async function checkHealth() {
|
|
|
36879
37014
|
try {
|
|
36880
37015
|
const c = JSON.parse(line);
|
|
36881
37016
|
const name = c.Names || c.Name;
|
|
36882
|
-
const
|
|
37017
|
+
const status2 = c.Status || "unknown";
|
|
36883
37018
|
let health = "unknown";
|
|
36884
|
-
if (
|
|
37019
|
+
if (status2.includes("healthy"))
|
|
36885
37020
|
health = "healthy";
|
|
36886
|
-
else if (
|
|
37021
|
+
else if (status2.includes("unhealthy"))
|
|
36887
37022
|
health = "unhealthy";
|
|
36888
|
-
else if (
|
|
37023
|
+
else if (status2.includes("Up"))
|
|
36889
37024
|
health = "running";
|
|
36890
|
-
else if (
|
|
37025
|
+
else if (status2.includes("Exited"))
|
|
36891
37026
|
health = "exited";
|
|
36892
37027
|
let restartCount = 0;
|
|
36893
37028
|
try {
|
|
@@ -36896,7 +37031,7 @@ async function checkHealth() {
|
|
|
36896
37031
|
restartCount = Number.parseInt(inspect2.stdout.toString().trim()) || 0;
|
|
36897
37032
|
}
|
|
36898
37033
|
} catch {}
|
|
36899
|
-
containers.push({ name, status, health, restartCount });
|
|
37034
|
+
containers.push({ name, status: status2, health, restartCount });
|
|
36900
37035
|
if (health === "unhealthy") {
|
|
36901
37036
|
issues.push(`Container ${name} is unhealthy`);
|
|
36902
37037
|
}
|
|
@@ -37310,13 +37445,13 @@ async function showNodeLogs(options2) {
|
|
|
37310
37445
|
console.log(dim("Run 'sl local node start' first"));
|
|
37311
37446
|
process.exit(1);
|
|
37312
37447
|
}
|
|
37313
|
-
const
|
|
37448
|
+
const logs2 = await getNodeLogs({
|
|
37314
37449
|
follow: options2.follow,
|
|
37315
37450
|
lines: Number.parseInt(options2.lines),
|
|
37316
37451
|
quiet: options2.quiet,
|
|
37317
37452
|
format: true
|
|
37318
37453
|
});
|
|
37319
|
-
for await (const line of
|
|
37454
|
+
for await (const line of logs2) {
|
|
37320
37455
|
console.log(line);
|
|
37321
37456
|
}
|
|
37322
37457
|
}
|
|
@@ -37342,8 +37477,8 @@ async function showStaticCombinedLogs(showDev, showNode, lines, quiet) {
|
|
|
37342
37477
|
}
|
|
37343
37478
|
}
|
|
37344
37479
|
if (showNode && await isNodeRunning()) {
|
|
37345
|
-
const
|
|
37346
|
-
for await (const line of
|
|
37480
|
+
const logs2 = await getNodeLogs({ lines, quiet, format: true });
|
|
37481
|
+
for await (const line of logs2) {
|
|
37347
37482
|
const tsMatch = line.match(/\[(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\]/);
|
|
37348
37483
|
const timestamp = tsMatch ? new Date(tsMatch[1]) : new Date(0);
|
|
37349
37484
|
allLines.push({ service: "node", line, timestamp });
|
|
@@ -37696,5 +37831,5 @@ registerAccountCommand(program);
|
|
|
37696
37831
|
registerBillingCommand(program);
|
|
37697
37832
|
program.parse();
|
|
37698
37833
|
|
|
37699
|
-
//# debugId=
|
|
37834
|
+
//# debugId=98906583902E571F64756E2164756E21
|
|
37700
37835
|
//# sourceMappingURL=cli.js.map
|