@secondlayer/cli 3.5.5 → 3.6.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 CHANGED
@@ -27,6 +27,11 @@ sl subgraphs deploy subgraphs/my-contract.ts --start-block <recent-block>
27
27
  sl subgraphs query my-contract <table> --sort _block_height --order desc
28
28
  ```
29
29
 
30
+ `sl subgraphs scaffold` writes the definition file, creates or updates
31
+ `package.json`, and runs `bun install` by default so the generated import is
32
+ deployable immediately. Pass `--no-install` to skip the install and run
33
+ `bun install` manually in the output directory.
34
+
30
35
  Then wire a receiver:
31
36
 
32
37
  ```bash
@@ -128,7 +133,7 @@ invocation. No long-lived key on disk.
128
133
  | `sl subgraphs stop <name>` | Pause processing |
129
134
  | `sl subgraphs gaps <name>` | List missing block ranges |
130
135
  | `sl subgraphs delete <name>` | Drop the subgraph + its schema |
131
- | `sl subgraphs scaffold <SP...::contract>` | Generate a starter subgraph from a deployed contract |
136
+ | `sl subgraphs scaffold <SP...::contract> [-o <path>] [--no-install]` | Generate a starter subgraph from a deployed contract, write/amend `package.json`, and install dependencies unless skipped |
132
137
  | `sl subgraphs generate <name>` | Regenerate TS types for an existing subgraph |
133
138
 
134
139
  ### Local dev + OSS
package/dist/cli.js CHANGED
@@ -26406,7 +26406,7 @@ var require_cross_spawn = __commonJS((exports, module) => {
26406
26406
  var cp = __require("child_process");
26407
26407
  var parse2 = require_parse3();
26408
26408
  var enoent = require_enoent();
26409
- function spawn(command, args, options3) {
26409
+ function spawn2(command, args, options3) {
26410
26410
  const parsed = parse2(command, args, options3);
26411
26411
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
26412
26412
  enoent.hookChildProcess(spawned, parsed);
@@ -26418,8 +26418,8 @@ var require_cross_spawn = __commonJS((exports, module) => {
26418
26418
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
26419
26419
  return result;
26420
26420
  }
26421
- module.exports = spawn;
26422
- module.exports.spawn = spawn;
26421
+ module.exports = spawn2;
26422
+ module.exports.spawn = spawn2;
26423
26423
  module.exports.sync = spawnSync;
26424
26424
  module.exports._parse = parse2;
26425
26425
  module.exports._enoent = enoent;
@@ -31750,7 +31750,7 @@ var init_promise = __esm(() => {
31750
31750
 
31751
31751
  // ../../node_modules/execa/lib/methods/main-async.js
31752
31752
  import { setMaxListeners } from "node:events";
31753
- import { spawn } from "node:child_process";
31753
+ import { spawn as spawn2 } from "node:child_process";
31754
31754
  var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
31755
31755
  const { file, commandArguments, command, escapedCommand, startTime, verboseInfo, options: options3, fileDescriptors } = handleAsyncArguments(rawFile, rawArguments, rawOptions);
31756
31756
  const { subprocess, promise } = spawnSubprocessAsync({
@@ -31795,7 +31795,7 @@ var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
31795
31795
  }, spawnSubprocessAsync = ({ file, commandArguments, options: options3, startTime, verboseInfo, command, escapedCommand, fileDescriptors }) => {
31796
31796
  let subprocess;
31797
31797
  try {
31798
- subprocess = spawn(...concatenateShell(file, commandArguments, options3));
31798
+ subprocess = spawn2(...concatenateShell(file, commandArguments, options3));
31799
31799
  } catch (error2) {
31800
31800
  return handleEarlyError({
31801
31801
  error: error2,
@@ -32439,7 +32439,7 @@ var {
32439
32439
  // package.json
32440
32440
  var package_default = {
32441
32441
  name: "@secondlayer/cli",
32442
- version: "3.5.5",
32442
+ version: "3.6.0",
32443
32443
  description: "CLI for subgraphs and blockchain indexing on Stacks",
32444
32444
  type: "module",
32445
32445
  bin: {
@@ -32482,8 +32482,8 @@ var package_default = {
32482
32482
  dependencies: {
32483
32483
  "@inquirer/prompts": "^8.2.0",
32484
32484
  "@secondlayer/bundler": "^0.3.2",
32485
- "@secondlayer/sdk": "^3.2.2",
32486
- "@secondlayer/shared": "^4.3.4",
32485
+ "@secondlayer/sdk": "^3.3.0",
32486
+ "@secondlayer/shared": "^4.4.0",
32487
32487
  "@secondlayer/stacks": "^2.0.0",
32488
32488
  "@secondlayer/subgraphs": "^1.3.2",
32489
32489
  "@biomejs/js-api": "^0.7.0",
@@ -32555,6 +32555,15 @@ async function listSubgraphsApi() {
32555
32555
  async function getSubgraphApi(name) {
32556
32556
  return (await getTenantClient()).subgraphs.get(name);
32557
32557
  }
32558
+ async function getSubgraphOpenApi(name, options) {
32559
+ return (await getTenantClient()).subgraphs.openapi(name, options);
32560
+ }
32561
+ async function getSubgraphAgentSchema(name, options) {
32562
+ return (await getTenantClient()).subgraphs.schema(name, options);
32563
+ }
32564
+ async function getSubgraphMarkdown(name, options) {
32565
+ return (await getTenantClient()).subgraphs.markdown(name, options);
32566
+ }
32558
32567
  async function reindexSubgraphApi(name, options) {
32559
32568
  return (await getTenantClient()).subgraphs.reindex(name, options);
32560
32569
  }
@@ -34315,6 +34324,7 @@ async function resyncDatabase(skipConfirm, backfill) {
34315
34324
  }
34316
34325
  }
34317
34326
  // src/commands/subgraphs.ts
34327
+ import { spawn } from "node:child_process";
34318
34328
  import {
34319
34329
  existsSync as existsSync3,
34320
34330
  mkdirSync as mkdirSync2,
@@ -34598,6 +34608,91 @@ function parseStartBlockOption(value) {
34598
34608
  }
34599
34609
  return parsed;
34600
34610
  }
34611
+ function parseSubgraphSpecFormat(value) {
34612
+ const format = value ?? "openapi";
34613
+ if (format === "openapi" || format === "agent" || format === "markdown") {
34614
+ return format;
34615
+ }
34616
+ throw new Error("--format must be one of: openapi, agent, markdown");
34617
+ }
34618
+ function formatSubgraphSpecOutput(spec, format) {
34619
+ if (typeof spec === "string")
34620
+ return spec;
34621
+ if (format === "markdown")
34622
+ return String(spec);
34623
+ return `${JSON.stringify(spec, null, 2)}
34624
+ `;
34625
+ }
34626
+ async function writeOrPrintSubgraphSpec(spec, format, output) {
34627
+ const text = formatSubgraphSpecOutput(spec, format);
34628
+ if (!output) {
34629
+ process.stdout.write(text);
34630
+ return;
34631
+ }
34632
+ const outPath = resolve3(output);
34633
+ const dir = resolve3(outPath, "..");
34634
+ if (!existsSync3(dir))
34635
+ mkdirSync2(dir, { recursive: true });
34636
+ await writeTextFile(outPath, text);
34637
+ success(`Created ${outPath}`);
34638
+ }
34639
+ function createLocalSubgraphDetail(input2) {
34640
+ const tables = {};
34641
+ for (const [tableName, rawTable] of Object.entries(input2.schema)) {
34642
+ const table = rawTable;
34643
+ const columns = {};
34644
+ for (const [columnName, column] of Object.entries(table.columns ?? {})) {
34645
+ columns[columnName] = {
34646
+ type: column.type ?? "text",
34647
+ ...column.nullable && { nullable: true },
34648
+ ...column.indexed && { indexed: true },
34649
+ ...column.search && { searchable: true },
34650
+ ...column.default !== undefined && { default: column.default }
34651
+ };
34652
+ }
34653
+ columns._id = { type: "serial" };
34654
+ columns._block_height = { type: "bigint" };
34655
+ columns._tx_id = { type: "text" };
34656
+ columns._created_at = { type: "timestamp" };
34657
+ tables[tableName] = {
34658
+ endpoint: `/subgraphs/${input2.name}/${tableName}`,
34659
+ columns,
34660
+ rowCount: 0,
34661
+ example: `/subgraphs/${input2.name}/${tableName}?_sort=_block_height&_order=desc&_limit=10`,
34662
+ ...table.indexes && { indexes: table.indexes },
34663
+ ...table.uniqueKeys && { uniqueKeys: table.uniqueKeys }
34664
+ };
34665
+ }
34666
+ return {
34667
+ name: input2.name,
34668
+ version: input2.version ?? "0.0.0",
34669
+ schemaHash: input2.schemaHash,
34670
+ status: "local",
34671
+ lastProcessedBlock: 0,
34672
+ ...input2.description && { description: input2.description },
34673
+ sources: input2.sources,
34674
+ health: {
34675
+ totalProcessed: 0,
34676
+ totalErrors: 0,
34677
+ errorRate: 0,
34678
+ lastError: null,
34679
+ lastErrorAt: null
34680
+ },
34681
+ sync: {
34682
+ status: "synced",
34683
+ startBlock: 0,
34684
+ lastProcessedBlock: 0,
34685
+ chainTip: 0,
34686
+ blocksRemaining: 0,
34687
+ progress: 1,
34688
+ gaps: { count: 0, totalMissingBlocks: 0, ranges: [] },
34689
+ integrity: "complete"
34690
+ },
34691
+ tables,
34692
+ createdAt: new Date(0).toISOString(),
34693
+ updatedAt: new Date(0).toISOString()
34694
+ };
34695
+ }
34601
34696
  function readCliSubgraphsDependency() {
34602
34697
  const here = dirname4(fileURLToPath2(import.meta.url));
34603
34698
  const candidates = [
@@ -34638,15 +34733,24 @@ function ensureScaffoldPackageJson(dir) {
34638
34733
  `, "utf8");
34639
34734
  }
34640
34735
  async function runBunInstall(dir) {
34641
- const proc = Bun.spawn(["bun", "install"], {
34642
- cwd: dir,
34643
- stdout: "inherit",
34644
- stderr: "inherit"
34736
+ await new Promise((resolvePromise, reject) => {
34737
+ const proc = spawn("bun", ["install"], {
34738
+ cwd: dir,
34739
+ stdio: "inherit"
34740
+ });
34741
+ proc.on("error", reject);
34742
+ proc.on("close", (exitCode, signal) => {
34743
+ if (exitCode === 0) {
34744
+ resolvePromise();
34745
+ return;
34746
+ }
34747
+ if (exitCode !== null) {
34748
+ reject(new Error(`bun install exited with code ${exitCode}`));
34749
+ return;
34750
+ }
34751
+ reject(new Error(`bun install exited with signal ${signal}`));
34752
+ });
34645
34753
  });
34646
- const exitCode = await proc.exited;
34647
- if (exitCode !== 0) {
34648
- throw new Error(`bun install exited with code ${exitCode}`);
34649
- }
34650
34754
  }
34651
34755
  async function installScaffoldDependencies(dir, options2 = {}) {
34652
34756
  if (options2.install === false)
@@ -34993,6 +35097,66 @@ Table endpoints:`));
34993
35097
  handleApiError(err, "get subgraph status");
34994
35098
  }
34995
35099
  });
35100
+ subgraphs.command("spec <name>").description("Output API documentation for a deployed subgraph").option("--format <format>", "Output format: openapi, agent, markdown", "openapi").option("-o, --output <path>", "Write output to a file").option("--server <url>", "Override the server URL in generated docs").action(async (name, options2) => {
35101
+ try {
35102
+ const format = parseSubgraphSpecFormat(options2.format);
35103
+ const specOptions = options2.server ? { serverUrl: options2.server } : undefined;
35104
+ const spec = format === "openapi" ? await getSubgraphOpenApi(name, specOptions) : format === "agent" ? await getSubgraphAgentSchema(name, specOptions) : await getSubgraphMarkdown(name, specOptions);
35105
+ await writeOrPrintSubgraphSpec(spec, format, options2.output);
35106
+ } catch (err) {
35107
+ if (err instanceof Error && err.message.startsWith("--format")) {
35108
+ error(err.message);
35109
+ process.exit(1);
35110
+ }
35111
+ handleApiError(err, "generate subgraph spec");
35112
+ }
35113
+ });
35114
+ subgraphs.command("inspect <file>").description("Output API documentation for a local subgraph file").option("--format <format>", "Output format: openapi, agent, markdown", "agent").option("-o, --output <path>", "Write output to a file").option("--server <url>", "Override the server URL in generated docs").action(async (file, options2) => {
35115
+ try {
35116
+ const format = parseSubgraphSpecFormat(options2.format);
35117
+ const absPath = resolve3(file);
35118
+ if (!existsSync3(absPath)) {
35119
+ error(`File not found: ${absPath}`);
35120
+ process.exit(1);
35121
+ }
35122
+ const { readFile: readFile4 } = await import("node:fs/promises");
35123
+ const { bundleSubgraphCode } = await import("@secondlayer/bundler");
35124
+ const { generateSubgraphSQL } = await import("@secondlayer/subgraphs");
35125
+ const {
35126
+ generateSubgraphAgentSchema,
35127
+ generateSubgraphMarkdown,
35128
+ generateSubgraphOpenApi
35129
+ } = await import("@secondlayer/shared/subgraphs/spec");
35130
+ const source = await readFile4(absPath, "utf8");
35131
+ const bundled = await bundleSubgraphCode(source);
35132
+ const { hash } = generateSubgraphSQL({
35133
+ name: bundled.name,
35134
+ version: bundled.version,
35135
+ description: bundled.description,
35136
+ sources: bundled.sources,
35137
+ schema: bundled.schema,
35138
+ handlers: {}
35139
+ });
35140
+ const detail = createLocalSubgraphDetail({
35141
+ name: bundled.name,
35142
+ version: bundled.version,
35143
+ description: bundled.description,
35144
+ sources: bundled.sources,
35145
+ schema: bundled.schema,
35146
+ schemaHash: hash
35147
+ });
35148
+ const specOptions = options2.server ? { serverUrl: options2.server } : undefined;
35149
+ const spec = format === "openapi" ? generateSubgraphOpenApi(detail, specOptions) : format === "agent" ? generateSubgraphAgentSchema(detail, specOptions) : generateSubgraphMarkdown(detail, specOptions);
35150
+ await writeOrPrintSubgraphSpec(spec, format, options2.output);
35151
+ } catch (err) {
35152
+ if (err instanceof Error && err.message.startsWith("--format")) {
35153
+ error(err.message);
35154
+ process.exit(1);
35155
+ }
35156
+ error(`Failed to inspect subgraph: ${err}`);
35157
+ process.exit(1);
35158
+ }
35159
+ });
34996
35160
  subgraphs.command("reindex <name>").description("Reindex a subgraph from historical blocks").option("--from <block>", "Start block height").option("--to <block>", "End block height").action(async (name, options2) => {
34997
35161
  try {
34998
35162
  info(`Reindexing subgraph "${name}"...`);
@@ -36628,5 +36792,5 @@ registerLocalCommand(program);
36628
36792
  registerAccountCommand(program);
36629
36793
  program.parse();
36630
36794
 
36631
- //# debugId=3944D78DF47F7DD164756E2164756E21
36795
+ //# debugId=9B4F6BACEC00400164756E2164756E21
36632
36796
  //# sourceMappingURL=cli.js.map