@secondlayer/cli 9.1.0 → 9.2.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 CHANGED
@@ -28919,6 +28919,12 @@ function sip010Balances(name) {
28919
28919
  * token by adding \`assetIdentifier: "SP...token::token-name"\` to each
28920
28920
  * source filter.
28921
28921
  *
28922
+ * Balances are moved with \`ctx.increment\`, which applies a DELTA in one
28923
+ * atomic statement. That matters: a read-modify-write (findOne → compute →
28924
+ * upsert) loses concurrent updates to the same row, and it is not replay-safe
28925
+ * under \`backfillMode: "concurrent"\`. Deltas commute, so order doesn't
28926
+ * matter and a reorg rewind reverses cleanly via the journal.
28927
+ *
28922
28928
  * Query examples once deployed:
28923
28929
  * GET /v1/subgraphs/${name}/balances?_search=SP1...
28924
28930
  * GET /v1/subgraphs/${name}/balances?holder=SP1...
@@ -28941,49 +28947,33 @@ export default defineSubgraph({
28941
28947
  holder: { type: "principal", indexed: true, search: true },
28942
28948
  amount: { type: "uint" },
28943
28949
  },
28950
+ // increment() upserts on this key.
28944
28951
  uniqueKeys: [["asset_identifier", "holder"]],
28945
28952
  },
28946
28953
  },
28947
28954
 
28948
28955
  handlers: {
28949
- transfer: async (event, ctx) => {
28956
+ transfer: (event, ctx) => {
28950
28957
  const amount = BigInt(event.amount ?? 0);
28951
28958
  if (event.sender) {
28952
- await adjust(ctx, event.assetIdentifier, event.sender, -amount);
28959
+ ctx.increment("balances", { asset_identifier: event.assetIdentifier, holder: event.sender }, { amount: -amount });
28953
28960
  }
28954
28961
  if (event.recipient) {
28955
- await adjust(ctx, event.assetIdentifier, event.recipient, amount);
28962
+ ctx.increment("balances", { asset_identifier: event.assetIdentifier, holder: event.recipient }, { amount });
28956
28963
  }
28957
28964
  },
28958
- mint: async (event, ctx) => {
28965
+ mint: (event, ctx) => {
28959
28966
  if (event.recipient) {
28960
- await adjust(ctx, event.assetIdentifier, event.recipient, BigInt(event.amount ?? 0));
28967
+ ctx.increment("balances", { asset_identifier: event.assetIdentifier, holder: event.recipient }, { amount: BigInt(event.amount ?? 0) });
28961
28968
  }
28962
28969
  },
28963
- burn: async (event, ctx) => {
28970
+ burn: (event, ctx) => {
28964
28971
  if (event.sender) {
28965
- await adjust(ctx, event.assetIdentifier, event.sender, -BigInt(event.amount ?? 0));
28972
+ ctx.increment("balances", { asset_identifier: event.assetIdentifier, holder: event.sender }, { amount: -BigInt(event.amount ?? 0) });
28966
28973
  }
28967
28974
  },
28968
28975
  },
28969
28976
  });
28970
-
28971
- async function adjust(
28972
- // biome-ignore lint/suspicious/noExplicitAny: subgraph runtime ctx shape
28973
- ctx: any,
28974
- assetIdentifier: string,
28975
- holder: string,
28976
- delta: bigint,
28977
- ): Promise<void> {
28978
- const existing = await ctx.findOne("balances", { asset_identifier: assetIdentifier, holder });
28979
- const current = existing ? BigInt(existing.amount) : 0n;
28980
- const next = current + delta;
28981
- await ctx.upsert(
28982
- "balances",
28983
- { asset_identifier: assetIdentifier, holder },
28984
- { asset_identifier: assetIdentifier, holder, amount: next },
28985
- );
28986
- }
28987
28977
  `;
28988
28978
  }
28989
28979
  function sbtcFlows(name) {
@@ -29206,6 +29196,223 @@ function deriveBaseUrl(apiUrl) {
29206
29196
  }
29207
29197
  }
29208
29198
 
29199
+ // src/commands/subgraph-test.ts
29200
+ var exports_subgraph_test = {};
29201
+ __export(exports_subgraph_test, {
29202
+ runSubgraphTest: () => runSubgraphTest
29203
+ });
29204
+ import { createHash } from "node:crypto";
29205
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
29206
+ import { dirname as dirname3, resolve as resolve2 } from "node:path";
29207
+ import { Index } from "@secondlayer/sdk";
29208
+ function filterHashOf(sources) {
29209
+ const stable = JSON.stringify(Object.fromEntries(Object.entries(sources).sort(([a4], [b2]) => a4.localeCompare(b2))), (_k, v2) => typeof v2 === "bigint" ? `${v2}n` : v2);
29210
+ return createHash("sha256").update(stable).digest("hex").slice(0, 16);
29211
+ }
29212
+ function cassettePath(name) {
29213
+ return resolve2(CASSETTE_DIR, `${name}.json`);
29214
+ }
29215
+ function loadCassette(name, filterHash) {
29216
+ const path11 = cassettePath(name);
29217
+ if (!existsSync2(path11))
29218
+ return null;
29219
+ let parsed;
29220
+ try {
29221
+ parsed = JSON.parse(readFileSync3(path11, "utf8"));
29222
+ } catch {
29223
+ return { stale: "unreadable" };
29224
+ }
29225
+ if (parsed.decoderVersion !== DECODER_VERSION) {
29226
+ return { stale: `recorded by decoder v${parsed.decoderVersion}` };
29227
+ }
29228
+ if (parsed.filterHash !== filterHash) {
29229
+ return { stale: "sources changed since it was recorded" };
29230
+ }
29231
+ return parsed;
29232
+ }
29233
+ function eventTypeFor(filter) {
29234
+ if (filter.type === "print_event")
29235
+ return "print";
29236
+ if (filter.type === "contract_call" || filter.type === "contract_deploy") {
29237
+ return null;
29238
+ }
29239
+ return filter.type;
29240
+ }
29241
+ async function runSubgraphTest(file, options3) {
29242
+ const absPath = resolve2(file);
29243
+ if (!existsSync2(absPath)) {
29244
+ error(`File not found: ${absPath}`);
29245
+ process.exit(1);
29246
+ }
29247
+ const { readFile: readFile3 } = await import("node:fs/promises");
29248
+ const { bundleSubgraphCode } = await import("@secondlayer/bundler");
29249
+ const { createTestContext, buildEvent } = await import("@secondlayer/subgraphs/testing");
29250
+ const source = await readFile3(absPath, "utf8");
29251
+ const bundled = await bundleSubgraphCode(source);
29252
+ const sources = bundled.sources ?? {};
29253
+ const filterHash = filterHashOf(sources);
29254
+ const mod = await import(`${absPath}?t=${Date.now()}`);
29255
+ const def = mod.default;
29256
+ if (!def?.handlers || !def.schema) {
29257
+ error("File must default-export a defineSubgraph() definition with handlers and schema.");
29258
+ process.exit(1);
29259
+ }
29260
+ const cached = loadCassette(bundled.name, filterHash);
29261
+ if (cached && "stale" in cached) {
29262
+ warn(`Cassette discarded (${cached.stale}) — re-recording.`);
29263
+ }
29264
+ const usable = cached && !("stale" in cached) ? cached : null;
29265
+ let events;
29266
+ let fromHeight;
29267
+ let toHeight;
29268
+ if (usable && options3.offline !== false && !options3.from) {
29269
+ info(`Replaying cassette: blocks ${usable.fromHeight}–${usable.toHeight}, recorded ${usable.recordedAt}`);
29270
+ events = usable.events;
29271
+ fromHeight = usable.fromHeight;
29272
+ toHeight = usable.toHeight;
29273
+ } else {
29274
+ if (options3.offline) {
29275
+ error("No usable cassette for --offline. Record one first: sl subgraphs test <file> --from <h> --to <h>");
29276
+ process.exit(1);
29277
+ }
29278
+ if (!options3.from) {
29279
+ error("--from <height> is required for the first run (Index reads are metered). Later runs replay the cassette.");
29280
+ process.exit(1);
29281
+ }
29282
+ fromHeight = Number(options3.from);
29283
+ toHeight = options3.to ? Number(options3.to) : fromHeight + 100;
29284
+ if (!Number.isInteger(fromHeight) || !Number.isInteger(toHeight)) {
29285
+ error("--from/--to must be integers.");
29286
+ process.exit(1);
29287
+ }
29288
+ const limit = options3.limit ? Number(options3.limit) : 500;
29289
+ const index = new Index;
29290
+ events = {};
29291
+ for (const [name, filter] of Object.entries(sources)) {
29292
+ const eventType = eventTypeFor(filter);
29293
+ if (eventType === null) {
29294
+ warn(`source "${name}" (${filter.type}) is not readable from index.events — skipped.`);
29295
+ continue;
29296
+ }
29297
+ info(`Fetching ${name} (${eventType}) blocks ${fromHeight}–${toHeight}…`);
29298
+ try {
29299
+ const envelope = await index.events.list({
29300
+ eventType,
29301
+ ...filter.contractId ? {
29302
+ contractId: Array.isArray(filter.contractId) ? filter.contractId : filter.contractId
29303
+ } : {},
29304
+ fromHeight,
29305
+ toHeight,
29306
+ limit
29307
+ });
29308
+ events[name] = envelope.events;
29309
+ } catch (err) {
29310
+ const e2 = err;
29311
+ if (e2?.status === 402) {
29312
+ const details = e2.body?.details;
29313
+ error(`Blocks ${fromHeight}–${toHeight} are below the free read window.${details?.oldest_seekable_height ? ` Try --from ${details.oldest_seekable_height}, or add a paid API key (SL_API_KEY) to test against older history.` : " Add a paid API key (SL_API_KEY) to test against older history."}`);
29314
+ process.exit(1);
29315
+ }
29316
+ throw err;
29317
+ }
29318
+ }
29319
+ if (options3.record !== false) {
29320
+ const cassette = {
29321
+ decoderVersion: DECODER_VERSION,
29322
+ filterHash,
29323
+ subgraph: bundled.name,
29324
+ fromHeight,
29325
+ toHeight,
29326
+ recordedAt: new Date().toISOString(),
29327
+ events
29328
+ };
29329
+ const path11 = cassettePath(bundled.name);
29330
+ mkdirSync(dirname3(path11), { recursive: true });
29331
+ writeFileSync2(path11, `${JSON.stringify(cassette, (_k, v2) => typeof v2 === "bigint" ? `${v2}n` : v2, 2)}
29332
+ `);
29333
+ info(`Recorded cassette → ${path11}`);
29334
+ }
29335
+ }
29336
+ const ctx = createTestContext(def.schema);
29337
+ let applied = 0;
29338
+ let failed = 0;
29339
+ const failures = [];
29340
+ for (const [name, rows] of Object.entries(events)) {
29341
+ const handler = def.handlers[name] ?? def.handlers["*"];
29342
+ if (typeof handler !== "function") {
29343
+ warn(`source "${name}": no handler — skipped.`);
29344
+ continue;
29345
+ }
29346
+ const filter = sources[name];
29347
+ for (const row of rows) {
29348
+ const payload = toHandlerPayload(filter, row);
29349
+ if (filter?.type === "print_event" && filter.topic && payload.topic !== filter.topic) {
29350
+ continue;
29351
+ }
29352
+ try {
29353
+ await handler(buildEvent(filter, payload), ctx);
29354
+ applied++;
29355
+ } catch (err) {
29356
+ failed++;
29357
+ if (failures.length < 5) {
29358
+ failures.push(` ${name} @ ${row.cursor}: ${err instanceof Error ? err.message : String(err)}`);
29359
+ }
29360
+ }
29361
+ }
29362
+ }
29363
+ info("");
29364
+ const tables = Object.keys(def.schema);
29365
+ let totalRows = 0;
29366
+ for (const table of tables) {
29367
+ const rows = await ctx.rows(table);
29368
+ totalRows += rows.length;
29369
+ info(` ${table.padEnd(24)} ${String(rows.length).padStart(6)} rows`);
29370
+ const sample = rows[0];
29371
+ if (sample) {
29372
+ const preview = Object.entries(sample).filter(([k2]) => !k2.startsWith("_")).slice(0, 4).map(([k2, v2]) => `${k2}=${String(v2).slice(0, 24)}`).join(" ");
29373
+ info(` ${"".padEnd(24)} ${preview}`);
29374
+ }
29375
+ }
29376
+ info("");
29377
+ if (failed > 0) {
29378
+ warn(`${failed} handler error${failed === 1 ? "" : "s"}:`);
29379
+ for (const f2 of failures)
29380
+ warn(f2);
29381
+ }
29382
+ const fetched = Object.values(events).reduce((n3, r2) => n3 + r2.length, 0);
29383
+ if (fetched === 0) {
29384
+ warn(`No events matched these sources in blocks ${fromHeight}–${toHeight}. Widen the range (--to) or check the source filters.`);
29385
+ return;
29386
+ }
29387
+ if (totalRows === 0) {
29388
+ error(`${applied} event${applied === 1 ? "" : "s"} applied, but NO rows were written — the shape of the field-mapping bug that shipped a 0-row subgraph. Check your handler's field names against the payload.`);
29389
+ process.exit(1);
29390
+ }
29391
+ success(`${applied} event${applied === 1 ? "" : "s"} → ${totalRows} row${totalRows === 1 ? "" : "s"} across ${tables.length} table${tables.length === 1 ? "" : "s"} (blocks ${fromHeight}–${toHeight})`);
29392
+ }
29393
+ function toHandlerPayload(_filter, row) {
29394
+ if (row.event_type === "print") {
29395
+ const payload = row.payload;
29396
+ return {
29397
+ contractId: row.contract_id ?? "",
29398
+ topic: payload?.topic ?? "",
29399
+ data: payload?.value ?? {}
29400
+ };
29401
+ }
29402
+ const r2 = row;
29403
+ return {
29404
+ ...r2.sender !== undefined ? { sender: r2.sender } : {},
29405
+ ...r2.recipient !== undefined ? { recipient: r2.recipient } : {},
29406
+ ...r2.amount !== undefined ? { amount: BigInt(String(r2.amount)) } : {},
29407
+ ...r2.asset_identifier !== undefined ? { assetIdentifier: r2.asset_identifier } : {},
29408
+ ...r2.value !== undefined ? { tokenId: r2.value } : {}
29409
+ };
29410
+ }
29411
+ var CASSETTE_DIR = "cassettes", DECODER_VERSION = 1;
29412
+ var init_subgraph_test = __esm(() => {
29413
+ init_output();
29414
+ });
29415
+
29209
29416
  // src/commands/subgraphs.ts
29210
29417
  var exports_subgraphs = {};
29211
29418
  __export(exports_subgraphs, {
@@ -29224,13 +29431,13 @@ __export(exports_subgraphs, {
29224
29431
  });
29225
29432
  import { spawn as spawn2 } from "node:child_process";
29226
29433
  import {
29227
- existsSync as existsSync2,
29228
- mkdirSync,
29229
- readFileSync as readFileSync3,
29434
+ existsSync as existsSync3,
29435
+ mkdirSync as mkdirSync2,
29436
+ readFileSync as readFileSync4,
29230
29437
  watch,
29231
- writeFileSync as writeFileSync2
29438
+ writeFileSync as writeFileSync3
29232
29439
  } from "node:fs";
29233
- import { basename, dirname as dirname3, extname, join as join4, resolve as resolve2 } from "node:path";
29440
+ import { basename, dirname as dirname4, extname, join as join4, resolve as resolve3 } from "node:path";
29234
29441
  import { fileURLToPath as fileURLToPath3 } from "node:url";
29235
29442
  import { confirm as confirm3 } from "@inquirer/prompts";
29236
29443
  import {
@@ -29319,8 +29526,8 @@ function ormFlagsConflictingWithPayloads(getOptionValueSource) {
29319
29526
  return Object.entries(ORM_ONLY_CODEGEN_FLAGS).filter(([key]) => getOptionValueSource(key) === "cli").map(([, flag]) => flag);
29320
29527
  }
29321
29528
  async function runPayloadsCodegen(file, output2) {
29322
- const absPath = resolve2(file);
29323
- if (!existsSync2(absPath)) {
29529
+ const absPath = resolve3(file);
29530
+ if (!existsSync3(absPath)) {
29324
29531
  error(`File not found: ${absPath}`);
29325
29532
  process.exit(1);
29326
29533
  }
@@ -29365,7 +29572,7 @@ async function runPayloadsCodegen(file, output2) {
29365
29572
  process.exit(1);
29366
29573
  }
29367
29574
  const out = generatePrintPayloadTypes({ sources });
29368
- const outPath = resolve2(output2 ?? join4(dirname3(absPath), `${basename(absPath, extname(absPath))}.payloads.d.ts`));
29575
+ const outPath = resolve3(output2 ?? join4(dirname4(absPath), `${basename(absPath, extname(absPath))}.payloads.d.ts`));
29369
29576
  await writeTextFile(outPath, out);
29370
29577
  success(`Wrote print payload types to ${outPath}`);
29371
29578
  }
@@ -29390,10 +29597,10 @@ async function writeOrPrintSubgraphSpec(spec, format2, output2) {
29390
29597
  process.stdout.write(text2);
29391
29598
  return;
29392
29599
  }
29393
- const outPath = resolve2(output2);
29394
- const dir = resolve2(outPath, "..");
29395
- if (!existsSync2(dir))
29396
- mkdirSync(dir, { recursive: true });
29600
+ const outPath = resolve3(output2);
29601
+ const dir = resolve3(outPath, "..");
29602
+ if (!existsSync3(dir))
29603
+ mkdirSync2(dir, { recursive: true });
29397
29604
  await writeTextFile(outPath, text2);
29398
29605
  success(`Created ${outPath}`);
29399
29606
  }
@@ -29484,15 +29691,15 @@ function createLocalSubgraphDetail(input2) {
29484
29691
  };
29485
29692
  }
29486
29693
  function readCliSubgraphsDependency() {
29487
- const here = dirname3(fileURLToPath3(import.meta.url));
29694
+ const here = dirname4(fileURLToPath3(import.meta.url));
29488
29695
  const candidates = [
29489
- resolve2(here, "..", "..", "package.json"),
29490
- resolve2(here, "..", "package.json")
29696
+ resolve3(here, "..", "..", "package.json"),
29697
+ resolve3(here, "..", "package.json")
29491
29698
  ];
29492
29699
  for (const candidate of candidates) {
29493
- if (!existsSync2(candidate))
29700
+ if (!existsSync3(candidate))
29494
29701
  continue;
29495
- const pkg = JSON.parse(readFileSync3(candidate, "utf8"));
29702
+ const pkg = JSON.parse(readFileSync4(candidate, "utf8"));
29496
29703
  const dep = pkg.dependencies?.["@secondlayer/subgraphs"];
29497
29704
  if (dep)
29498
29705
  return dep;
@@ -29502,8 +29709,8 @@ function readCliSubgraphsDependency() {
29502
29709
  function ensureScaffoldPackageJson(dir) {
29503
29710
  const packagePath = join4(dir, "package.json");
29504
29711
  const subgraphsDep = readCliSubgraphsDependency();
29505
- if (!existsSync2(packagePath)) {
29506
- writeFileSync2(packagePath, `${JSON.stringify({
29712
+ if (!existsSync3(packagePath)) {
29713
+ writeFileSync3(packagePath, `${JSON.stringify({
29507
29714
  type: "module",
29508
29715
  dependencies: {
29509
29716
  "@secondlayer/subgraphs": subgraphsDep
@@ -29512,14 +29719,14 @@ function ensureScaffoldPackageJson(dir) {
29512
29719
  `, "utf8");
29513
29720
  return;
29514
29721
  }
29515
- const pkg = JSON.parse(readFileSync3(packagePath, "utf8"));
29722
+ const pkg = JSON.parse(readFileSync4(packagePath, "utf8"));
29516
29723
  if (pkg.dependencies?.["@secondlayer/subgraphs"])
29517
29724
  return;
29518
29725
  pkg.dependencies = {
29519
29726
  ...pkg.dependencies ?? {},
29520
29727
  "@secondlayer/subgraphs": subgraphsDep
29521
29728
  };
29522
- writeFileSync2(packagePath, `${JSON.stringify(pkg, null, 2)}
29729
+ writeFileSync3(packagePath, `${JSON.stringify(pkg, null, 2)}
29523
29730
  `, "utf8");
29524
29731
  }
29525
29732
  async function runBunInstall(dir) {
@@ -29687,9 +29894,9 @@ ${SUBGRAPH_TEMPLATE_SLUGS.map((s2) => ` ${s2.padEnd(20)} ${SUBGRAPH_TEMPLATE_DE
29687
29894
  `)}`);
29688
29895
  process.exit(1);
29689
29896
  }
29690
- const dir = resolve2("subgraphs");
29691
- const filePath = resolve2(dir, `${name}.ts`);
29692
- if (existsSync2(filePath)) {
29897
+ const dir = resolve3("subgraphs");
29898
+ const filePath = resolve3(dir, `${name}.ts`);
29899
+ if (existsSync3(filePath)) {
29693
29900
  error(`File already exists: ${filePath}`);
29694
29901
  process.exit(1);
29695
29902
  }
@@ -29717,8 +29924,8 @@ Check the contract id, and that the contract has emitted print events (schemas a
29717
29924
  } else {
29718
29925
  content = generateSubgraphTemplate(name, slug);
29719
29926
  }
29720
- if (!existsSync2(dir)) {
29721
- mkdirSync(dir, { recursive: true });
29927
+ if (!existsSync3(dir)) {
29928
+ mkdirSync2(dir, { recursive: true });
29722
29929
  }
29723
29930
  await writeTextFile(filePath, content);
29724
29931
  success(`Created ${filePath}`);
@@ -29731,8 +29938,8 @@ Check the contract id, and that the contract has emitted print events (schemas a
29731
29938
  });
29732
29939
  subgraphs.command("dev <file>").description("Watch a subgraph file and auto-redeploy on change").action(async (file) => {
29733
29940
  await requireLocalNetwork();
29734
- const absPath = resolve2(file);
29735
- if (!existsSync2(absPath)) {
29941
+ const absPath = resolve3(file);
29942
+ if (!existsSync3(absPath)) {
29736
29943
  error(`File not found: ${absPath}`);
29737
29944
  process.exit(1);
29738
29945
  }
@@ -29792,7 +29999,7 @@ Stopped watching.`);
29792
29999
  });
29793
30000
  subgraphs.command("deploy <file>").alias("update").description("Deploy a subgraph definition file (alias: update — deploy is create-or-update)").option("--start-block <n>", "Override the subgraph definition startBlock for this deploy").option("--tip-first", "Go live at chain tip immediately; history backfills in the background (requires order-tolerant handlers — commutative or insert-only writes)").option("--dry-run", "Validate and preview deploy without writing changes").option("-y, --yes", "Skip the reindex confirmation prompt").option("--database-url <url>", "BYO data plane: write the subgraph's schema/rows to your own Postgres. With --dry-run, prints the DDL + grant script and verifies the connection.").option("--strict", "Run `tsc --noEmit` against the handler before deploy (slower; catches TS type errors)").option("--visibility <visibility>", "Read visibility: public (anon /v1 reads, global name claim) or private (your key only). Defaults: managed → public, BYO → private.").action(async (file, options3) => {
29794
30001
  try {
29795
- const absPath = resolve2(file);
30002
+ const absPath = resolve3(file);
29796
30003
  const config = await loadConfig2();
29797
30004
  if (config.network !== "local") {
29798
30005
  await requireAuth();
@@ -30093,8 +30300,8 @@ Synced — exiting watch.`));
30093
30300
  try {
30094
30301
  const format2 = parseSubgraphSpecFormat(options3.format);
30095
30302
  const specOptions = options3.server ? { serverUrl: options3.server } : undefined;
30096
- const absPath = resolve2(nameOrFile);
30097
- if (nameOrFile.endsWith(".ts") && !existsSync2(absPath)) {
30303
+ const absPath = resolve3(nameOrFile);
30304
+ if (nameOrFile.endsWith(".ts") && !existsSync3(absPath)) {
30098
30305
  error(`File not found: ${absPath}`);
30099
30306
  process.exit(1);
30100
30307
  }
@@ -30113,6 +30320,13 @@ Synced — exiting watch.`));
30113
30320
  deprecatedCodegenNotice("sl subgraphs codegen", options3.payloads ? "sl codegen prints" : "sl codegen subgraph");
30114
30321
  await runSubgraphSchemaCodegen(file, options3, (key) => command.getOptionValueSource(key));
30115
30322
  });
30323
+ 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", `
30324
+ Examples:
30325
+ $ sl subgraphs test subgraphs/bns-names.ts --from 167484 --to 167600
30326
+ $ sl subgraphs test subgraphs/bns-names.ts --offline`).action(async (file, options3) => {
30327
+ const { runSubgraphTest: runSubgraphTest2 } = await Promise.resolve().then(() => (init_subgraph_test(), exports_subgraph_test));
30328
+ await runSubgraphTest2(file, options3);
30329
+ });
30116
30330
  subgraphs.command("reindex <name>").description("Reindex a subgraph from historical blocks (drops + reprocesses)").option("--from-block <n>", "Start block height").option("--to-block <n>", "End block height").option("-y, --yes", "Skip confirmation").addHelpText("after", `
30117
30331
  Examples:
30118
30332
  $ sl subgraphs reindex my-graph -y
@@ -30372,7 +30586,7 @@ Examples:
30372
30586
  error("a <contractAddress> is required (or use --trait)");
30373
30587
  process.exit(1);
30374
30588
  }
30375
- const outPath = resolve2(options3.output);
30589
+ const outPath = resolve3(options3.output);
30376
30590
  let content;
30377
30591
  if (trait) {
30378
30592
  info(`Generating trait-scoped scaffold for ${trait}...`);
@@ -30392,9 +30606,9 @@ Examples:
30392
30606
  functions: options3.functions?.split(",").map((f2) => f2.trim()).filter(Boolean)
30393
30607
  });
30394
30608
  }
30395
- const dir = resolve2(outPath, "..");
30396
- if (!existsSync2(dir))
30397
- mkdirSync(dir, { recursive: true });
30609
+ const dir = resolve3(outPath, "..");
30610
+ if (!existsSync3(dir))
30611
+ mkdirSync2(dir, { recursive: true });
30398
30612
  await writeTextFile(outPath, content);
30399
30613
  ensureScaffoldPackageJson(dir);
30400
30614
  success(`Created ${outPath}`);
@@ -30427,14 +30641,14 @@ async function runSubgraphClientCodegen(subgraphName, options3) {
30427
30641
  error("--output <path> is required");
30428
30642
  process.exit(1);
30429
30643
  }
30430
- const outPath = resolve2(options3.output);
30644
+ const outPath = resolve3(options3.output);
30431
30645
  info(`Fetching subgraph metadata for "${subgraphName}"...`);
30432
30646
  const subgraphDetail = await getSubgraphApi(subgraphName);
30433
30647
  info("Generating typed client...");
30434
30648
  const content = await generateSubgraphConsumer(subgraphName, subgraphDetail);
30435
- const dir = resolve2(outPath, "..");
30436
- if (!existsSync2(dir))
30437
- mkdirSync(dir, { recursive: true });
30649
+ const dir = resolve3(outPath, "..");
30650
+ if (!existsSync3(dir))
30651
+ mkdirSync2(dir, { recursive: true });
30438
30652
  await writeTextFile(outPath, content);
30439
30653
  success(`Created ${outPath}`);
30440
30654
  } catch (err) {
@@ -30457,8 +30671,8 @@ async function runSubgraphSchemaCodegen(file, options3, optionSource, defaultTar
30457
30671
  error(`Unsupported --target "${target}" (supported: prisma, drizzle, kysely).`);
30458
30672
  process.exit(1);
30459
30673
  }
30460
- const absPath = resolve2(file);
30461
- if (!existsSync2(absPath)) {
30674
+ const absPath = resolve3(file);
30675
+ if (!existsSync3(absPath)) {
30462
30676
  error(`File not found: ${absPath}`);
30463
30677
  process.exit(1);
30464
30678
  }
@@ -30485,7 +30699,7 @@ async function runSubgraphSchemaCodegen(file, options3, optionSource, defaultTar
30485
30699
  modelsOnly: options3.modelsOnly
30486
30700
  });
30487
30701
  if (options3.output) {
30488
- await writeTextFile(resolve2(options3.output), out);
30702
+ await writeTextFile(resolve3(options3.output), out);
30489
30703
  success(`Wrote ${target} schema to ${options3.output}`);
30490
30704
  const next = target === "prisma" ? "point its datasource at your BYO database, then `prisma generate`." : target === "drizzle" ? "point your Drizzle connection at your BYO database (treat tables read-only)." : "import the `DB` type into `new Kysely<DB>()` against your BYO database.";
30491
30705
  info(`Next: ${next}`);
@@ -30527,10 +30741,10 @@ __export(exports_index_api, {
30527
30741
  runIndexCodegen: () => runIndexCodegen,
30528
30742
  registerIndexCommand: () => registerIndexCommand
30529
30743
  });
30530
- import { resolve as resolve3 } from "node:path";
30531
- import { Index } from "@secondlayer/sdk";
30744
+ import { resolve as resolve4 } from "node:path";
30745
+ import { Index as Index2 } from "@secondlayer/sdk";
30532
30746
  function client() {
30533
- return new Index({
30747
+ return new Index2({
30534
30748
  baseUrl: process.env.SL_API_URL ?? DEFAULT_BASE_URL,
30535
30749
  apiKey: resolveEnvKey()
30536
30750
  });
@@ -30719,7 +30933,7 @@ async function runIndexCodegen(o3) {
30719
30933
  datasourceEnv: o3.env
30720
30934
  });
30721
30935
  if (o3.output) {
30722
- await writeTextFile(resolve3(o3.output), out);
30936
+ await writeTextFile(resolve4(o3.output), out);
30723
30937
  success(`Wrote ${target} Index schema to ${o3.output}`);
30724
30938
  } else {
30725
30939
  process.stdout.write(out);
@@ -30831,9 +31045,9 @@ var init_query = __esm(() => {
30831
31045
  CLOSE = {};
30832
31046
  Query = class Query extends Promise {
30833
31047
  constructor(strings, args, handler, canceller, options3 = {}) {
30834
- let resolve4, reject;
31048
+ let resolve5, reject;
30835
31049
  super((a4, b2) => {
30836
- resolve4 = a4;
31050
+ resolve5 = a4;
30837
31051
  reject = b2;
30838
31052
  });
30839
31053
  this.tagged = Array.isArray(strings.raw);
@@ -30844,7 +31058,7 @@ var init_query = __esm(() => {
30844
31058
  this.options = options3;
30845
31059
  this.state = null;
30846
31060
  this.statement = null;
30847
- this.resolve = (x2) => (this.active = false, resolve4(x2));
31061
+ this.resolve = (x2) => (this.active = false, resolve5(x2));
30848
31062
  this.reject = (x2) => (this.active = false, reject(x2));
30849
31063
  this.active = false;
30850
31064
  this.cancelled = null;
@@ -30892,12 +31106,12 @@ var init_query = __esm(() => {
30892
31106
  if (this.executed && !this.active)
30893
31107
  return { done: true };
30894
31108
  prev && prev();
30895
- const promise = new Promise((resolve4, reject) => {
31109
+ const promise = new Promise((resolve5, reject) => {
30896
31110
  this.cursorFn = (value) => {
30897
- resolve4({ value, done: false });
31111
+ resolve5({ value, done: false });
30898
31112
  return new Promise((r2) => prev = r2);
30899
31113
  };
30900
- this.resolve = () => (this.active = false, resolve4({ done: true }));
31114
+ this.resolve = () => (this.active = false, resolve5({ done: true }));
30901
31115
  this.reject = (x2) => (this.active = false, reject(x2));
30902
31116
  });
30903
31117
  this.execute();
@@ -31451,12 +31665,12 @@ function Connection(options3, queues = {}, { onopen = noop4, onend = noop4, oncl
31451
31665
  x2.on("drain", drain);
31452
31666
  return x2;
31453
31667
  }
31454
- async function cancel({ pid, secret }, resolve4, reject) {
31668
+ async function cancel({ pid, secret }, resolve5, reject) {
31455
31669
  try {
31456
31670
  cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
31457
31671
  await connect();
31458
31672
  socket.once("error", reject);
31459
- socket.once("close", resolve4);
31673
+ socket.once("close", resolve5);
31460
31674
  } catch (error3) {
31461
31675
  reject(error3);
31462
31676
  }
@@ -32329,7 +32543,7 @@ var noop5 = () => {};
32329
32543
  // ../../node_modules/postgres/src/large.js
32330
32544
  import Stream2 from "stream";
32331
32545
  function largeObject(sql, oid, mode = 131072 | 262144) {
32332
- return new Promise(async (resolve4, reject) => {
32546
+ return new Promise(async (resolve5, reject) => {
32333
32547
  await sql.begin(async (sql2) => {
32334
32548
  let finish;
32335
32549
  !oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
@@ -32355,7 +32569,7 @@ function largeObject(sql, oid, mode = 131072 | 262144) {
32355
32569
  ) seek
32356
32570
  `
32357
32571
  };
32358
- resolve4(lo);
32572
+ resolve5(lo);
32359
32573
  return new Promise(async (r2) => finish = r2);
32360
32574
  async function readable2({
32361
32575
  highWaterMark = 2048 * 8,
@@ -32515,8 +32729,8 @@ function Postgres(a4, b3) {
32515
32729
  }
32516
32730
  async function reserve() {
32517
32731
  const queue = queue_default();
32518
- const c4 = open.length ? open.shift() : await new Promise((resolve4, reject) => {
32519
- const query = { reserve: resolve4, reject };
32732
+ const c4 = open.length ? open.shift() : await new Promise((resolve5, reject) => {
32733
+ const query = { reserve: resolve5, reject };
32520
32734
  queries.push(query);
32521
32735
  closed.length && connect(closed.shift(), query);
32522
32736
  });
@@ -32553,9 +32767,9 @@ function Postgres(a4, b3) {
32553
32767
  let uncaughtError, result;
32554
32768
  name && await sql2`savepoint ${sql2(name)}`;
32555
32769
  try {
32556
- result = await new Promise((resolve4, reject) => {
32770
+ result = await new Promise((resolve5, reject) => {
32557
32771
  const x2 = fn2(sql2);
32558
- Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(resolve4, reject);
32772
+ Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(resolve5, reject);
32559
32773
  });
32560
32774
  if (uncaughtError)
32561
32775
  throw uncaughtError;
@@ -32612,8 +32826,8 @@ function Postgres(a4, b3) {
32612
32826
  return c4.execute(query) ? move(c4, busy) : move(c4, full);
32613
32827
  }
32614
32828
  function cancel(query) {
32615
- return new Promise((resolve4, reject) => {
32616
- query.state ? query.active ? connection_default(options3).cancel(query.state, resolve4, reject) : query.cancelled = { resolve: resolve4, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve4());
32829
+ return new Promise((resolve5, reject) => {
32830
+ query.state ? query.active ? connection_default(options3).cancel(query.state, resolve5, reject) : query.cancelled = { resolve: resolve5, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve5());
32617
32831
  });
32618
32832
  }
32619
32833
  async function end({ timeout = null } = {}) {
@@ -32629,11 +32843,11 @@ function Postgres(a4, b3) {
32629
32843
  async function close() {
32630
32844
  await Promise.all(connections.map((c4) => c4.end()));
32631
32845
  }
32632
- async function destroy(resolve4) {
32846
+ async function destroy(resolve5) {
32633
32847
  await Promise.all(connections.map((c4) => c4.terminate()));
32634
32848
  while (queries.length)
32635
32849
  queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options3));
32636
- resolve4();
32850
+ resolve5();
32637
32851
  }
32638
32852
  function connect(c4, query) {
32639
32853
  move(c4, connecting);
@@ -33273,11 +33487,11 @@ var init_manager = __esm(() => {
33273
33487
  });
33274
33488
 
33275
33489
  // src/services/indexer.ts
33276
- import { dirname as dirname8, resolve as resolve5 } from "node:path";
33490
+ import { dirname as dirname9, resolve as resolve6 } from "node:path";
33277
33491
  async function startIndexer(options3) {
33278
33492
  const port = options3.port ?? 3700;
33279
- const rootDir = dirname8(dirname8(dirname8(dirname8(import.meta.dir))));
33280
- const indexerPath = resolve5(rootDir, "packages/indexer/src/index.ts");
33493
+ const rootDir = dirname9(dirname9(dirname9(dirname9(import.meta.dir))));
33494
+ const indexerPath = resolve6(rootDir, "packages/indexer/src/index.ts");
33281
33495
  await serviceManager.start(SERVICE_NAME, ["bun", "run", "--watch", indexerPath], {
33282
33496
  port,
33283
33497
  env: {
@@ -33293,10 +33507,10 @@ var init_indexer = __esm(() => {
33293
33507
  });
33294
33508
 
33295
33509
  // src/services/worker.ts
33296
- import { dirname as dirname9, resolve as resolve6 } from "node:path";
33510
+ import { dirname as dirname10, resolve as resolve7 } from "node:path";
33297
33511
  async function startWorker(options3) {
33298
- const rootDir = dirname9(dirname9(dirname9(dirname9(import.meta.dir))));
33299
- const workerPath = resolve6(rootDir, "packages/worker/src/index.ts");
33512
+ const rootDir = dirname10(dirname10(dirname10(dirname10(import.meta.dir))));
33513
+ const workerPath = resolve7(rootDir, "packages/worker/src/index.ts");
33300
33514
  await serviceManager.start(SERVICE_NAME2, ["bun", "run", "--watch", workerPath], {
33301
33515
  onStdout: options3.onLog,
33302
33516
  onStderr: options3.onLog
@@ -33308,11 +33522,11 @@ var init_worker = __esm(() => {
33308
33522
  });
33309
33523
 
33310
33524
  // src/services/api.ts
33311
- import { dirname as dirname10, resolve as resolve7 } from "node:path";
33525
+ import { dirname as dirname11, resolve as resolve8 } from "node:path";
33312
33526
  async function startApi(options3) {
33313
33527
  const port = options3.port ?? 3800;
33314
- const rootDir = dirname10(dirname10(dirname10(dirname10(import.meta.dir))));
33315
- const apiPath = resolve7(rootDir, "packages/api/src/index.ts");
33528
+ const rootDir = dirname11(dirname11(dirname11(dirname11(import.meta.dir))));
33529
+ const apiPath = resolve8(rootDir, "packages/api/src/index.ts");
33316
33530
  await serviceManager.start(SERVICE_NAME3, ["bun", "run", "--watch", apiPath], {
33317
33531
  port,
33318
33532
  env: {
@@ -33328,10 +33542,10 @@ var init_api2 = __esm(() => {
33328
33542
  });
33329
33543
 
33330
33544
  // src/services/subgraph-processor.ts
33331
- import { dirname as dirname11, resolve as resolve8 } from "node:path";
33545
+ import { dirname as dirname12, resolve as resolve9 } from "node:path";
33332
33546
  async function startSubgraphProcessor(options3) {
33333
- const rootDir = dirname11(dirname11(dirname11(dirname11(import.meta.dir))));
33334
- const servicePath = resolve8(rootDir, "packages/subgraphs/src/service.ts");
33547
+ const rootDir = dirname12(dirname12(dirname12(dirname12(import.meta.dir))));
33548
+ const servicePath = resolve9(rootDir, "packages/subgraphs/src/service.ts");
33335
33549
  await serviceManager.start(SERVICE_NAME4, ["bun", "run", "--watch", servicePath], {
33336
33550
  env: {
33337
33551
  SUBGRAPH_CONCURRENCY: String(options3.concurrency ?? 5)
@@ -33365,8 +33579,8 @@ __export(exports_dev_impl, {
33365
33579
  restartDev: () => restartDev,
33366
33580
  isDevAlreadyRunning: () => isDevAlreadyRunning
33367
33581
  });
33368
- import { mkdirSync as mkdirSync4 } from "node:fs";
33369
- import { dirname as dirname12, join as join11, resolve as resolve9 } from "node:path";
33582
+ import { mkdirSync as mkdirSync5 } from "node:fs";
33583
+ import { dirname as dirname13, join as join11, resolve as resolve10 } from "node:path";
33370
33584
  async function isDevAlreadyRunning() {
33371
33585
  if (await isDevRunning()) {
33372
33586
  const running = await getRunningServices();
@@ -33444,10 +33658,10 @@ async function runBackground(options3) {
33444
33658
  startedAt: new Date().toISOString()
33445
33659
  };
33446
33660
  try {
33447
- const packagesDir = dirname12(dirname12(dirname12(dirname12(import.meta.dir))));
33661
+ const packagesDir = dirname13(dirname13(dirname13(dirname13(import.meta.dir))));
33448
33662
  const env2 = { DATABASE_URL: databaseUrl, DEV_MODE: "true" };
33449
33663
  const apiLogFile = getLogFile("api");
33450
- const apiProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/api/src/index.ts")], {
33664
+ const apiProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/api/src/index.ts")], {
33451
33665
  env: { ...process.env, ...env2, PORT: String(apiPort) },
33452
33666
  stdout: Bun.file(apiLogFile),
33453
33667
  stderr: Bun.file(apiLogFile)
@@ -33460,7 +33674,7 @@ async function runBackground(options3) {
33460
33674
  };
33461
33675
  console.log(green(" ✓ API"), dim(`http://localhost:${apiPort}`));
33462
33676
  const indexerLogFile = getLogFile("indexer");
33463
- const indexerProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/indexer/src/index.ts")], {
33677
+ const indexerProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/indexer/src/index.ts")], {
33464
33678
  env: { ...process.env, ...env2, PORT: String(indexerPort) },
33465
33679
  stdout: Bun.file(indexerLogFile),
33466
33680
  stderr: Bun.file(indexerLogFile)
@@ -33474,7 +33688,7 @@ async function runBackground(options3) {
33474
33688
  console.log(green(" ✓ Indexer"), dim(`http://localhost:${indexerPort}`));
33475
33689
  if (options3.worker) {
33476
33690
  const workerLogFile = getLogFile("worker");
33477
- const workerProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/worker/src/index.ts")], {
33691
+ const workerProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/worker/src/index.ts")], {
33478
33692
  env: { ...process.env, ...env2 },
33479
33693
  stdout: Bun.file(workerLogFile),
33480
33694
  stderr: Bun.file(workerLogFile)
@@ -33492,7 +33706,7 @@ async function runBackground(options3) {
33492
33706
  const subgraphsProc = Bun.spawn([
33493
33707
  "bun",
33494
33708
  "run",
33495
- resolve9(packagesDir, "packages/subgraphs/src/service.ts")
33709
+ resolve10(packagesDir, "packages/subgraphs/src/service.ts")
33496
33710
  ], {
33497
33711
  env: { ...process.env, ...env2 },
33498
33712
  stdout: Bun.file(subgraphsLogFile),
@@ -33794,7 +34008,7 @@ async function restartDev() {
33794
34008
  await clearDevState();
33795
34009
  await clearLogs();
33796
34010
  const config = await loadConfig2();
33797
- const packagesDir = dirname12(dirname12(dirname12(dirname12(import.meta.dir))));
34011
+ const packagesDir = dirname13(dirname13(dirname13(dirname13(import.meta.dir))));
33798
34012
  const env2 = state.env;
33799
34013
  const newState = {
33800
34014
  services: {},
@@ -33804,7 +34018,7 @@ async function restartDev() {
33804
34018
  };
33805
34019
  const apiPort = config.ports.api;
33806
34020
  const apiLogFile = getLogFile("api");
33807
- const apiProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/api/src/index.ts")], {
34021
+ const apiProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/api/src/index.ts")], {
33808
34022
  env: { ...process.env, ...env2, PORT: String(apiPort) },
33809
34023
  stdout: Bun.file(apiLogFile),
33810
34024
  stderr: Bun.file(apiLogFile)
@@ -33818,7 +34032,7 @@ async function restartDev() {
33818
34032
  console.log(green(" ✓ API"), dim(`http://localhost:${apiPort}`));
33819
34033
  const indexerPort = config.ports.indexer;
33820
34034
  const indexerLogFile = getLogFile("indexer");
33821
- const indexerProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/indexer/src/index.ts")], {
34035
+ const indexerProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/indexer/src/index.ts")], {
33822
34036
  env: { ...process.env, ...env2, PORT: String(indexerPort) },
33823
34037
  stdout: Bun.file(indexerLogFile),
33824
34038
  stderr: Bun.file(indexerLogFile)
@@ -33832,7 +34046,7 @@ async function restartDev() {
33832
34046
  console.log(green(" ✓ Indexer"), dim(`http://localhost:${indexerPort}`));
33833
34047
  if (state.services.worker) {
33834
34048
  const workerLogFile = getLogFile("worker");
33835
- const workerProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/worker/src/index.ts")], {
34049
+ const workerProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/worker/src/index.ts")], {
33836
34050
  env: { ...process.env, ...env2 },
33837
34051
  stdout: Bun.file(workerLogFile),
33838
34052
  stderr: Bun.file(workerLogFile)
@@ -33847,7 +34061,7 @@ async function restartDev() {
33847
34061
  }
33848
34062
  if (state.services.subgraphs) {
33849
34063
  const subgraphsLogFile = getLogFile("subgraphs");
33850
- const subgraphsProc = Bun.spawn(["bun", "run", resolve9(packagesDir, "packages/subgraphs/src/service.ts")], {
34064
+ const subgraphsProc = Bun.spawn(["bun", "run", resolve10(packagesDir, "packages/subgraphs/src/service.ts")], {
33851
34065
  env: { ...process.env, ...env2 },
33852
34066
  stdout: Bun.file(subgraphsLogFile),
33853
34067
  stderr: Bun.file(subgraphsLogFile)
@@ -33976,7 +34190,7 @@ async function ensureDevPostgres(dataDir) {
33976
34190
  return false;
33977
34191
  }
33978
34192
  const pgDataDir = join11(dataDir, "postgres");
33979
- mkdirSync4(pgDataDir, { recursive: true });
34193
+ mkdirSync5(pgDataDir, { recursive: true });
33980
34194
  const stopped = await Bun.$`docker ps -aq -f name=secondlayer-dev-postgres`.quiet().nothrow();
33981
34195
  if (stopped.stdout.toString().trim()) {
33982
34196
  await Bun.$`docker rm secondlayer-dev-postgres`.quiet().nothrow();
@@ -33991,8 +34205,8 @@ async function ensureDevPostgres(dataDir) {
33991
34205
  throw new Error("PostgreSQL failed to start");
33992
34206
  }
33993
34207
  async function runMigrations(databaseUrl) {
33994
- const packagesDir = dirname12(dirname12(dirname12(dirname12(import.meta.dir))));
33995
- const migrateScript = resolve9(packagesDir, "packages/shared/src/db/migrate.ts");
34208
+ const packagesDir = dirname13(dirname13(dirname13(dirname13(import.meta.dir))));
34209
+ const migrateScript = resolve10(packagesDir, "packages/shared/src/db/migrate.ts");
33996
34210
  const result = await Bun.$`DATABASE_URL=${databaseUrl} bun run ${migrateScript}`.quiet().nothrow();
33997
34211
  if (result.exitCode !== 0) {
33998
34212
  throw new Error(`Migration failed: ${result.stderr.toString()}`);
@@ -34475,7 +34689,7 @@ var {
34475
34689
  // package.json
34476
34690
  var package_default = {
34477
34691
  name: "@secondlayer/cli",
34478
- version: "9.1.0",
34692
+ version: "9.2.0",
34479
34693
  repository: {
34480
34694
  type: "git",
34481
34695
  url: "git+https://github.com/ryanwaits/secondlayer.git",
@@ -34517,8 +34731,8 @@ var package_default = {
34517
34731
  "@secondlayer/scaffold": "^1.5.0",
34518
34732
  "@secondlayer/sdk": "^6.36.0",
34519
34733
  "@secondlayer/shared": "^7.0.3",
34520
- "@secondlayer/stacks": "^2.21.0",
34521
- "@secondlayer/subgraphs": "^3.21.0",
34734
+ "@secondlayer/stacks": "^2.21.1",
34735
+ "@secondlayer/subgraphs": "^3.22.0",
34522
34736
  "@biomejs/js-api": "^0.7.0",
34523
34737
  "@biomejs/wasm-nodejs": "^1.9.0",
34524
34738
  esbuild: "^0.27.4",
@@ -35213,14 +35427,14 @@ init_output();
35213
35427
  init_resolve_auth();
35214
35428
  import {
35215
35429
  copyFileSync,
35216
- existsSync as existsSync3,
35217
- mkdirSync as mkdirSync2,
35218
- readFileSync as readFileSync4,
35430
+ existsSync as existsSync4,
35431
+ mkdirSync as mkdirSync3,
35432
+ readFileSync as readFileSync5,
35219
35433
  readdirSync,
35220
35434
  statSync as statSync2,
35221
- writeFileSync as writeFileSync3
35435
+ writeFileSync as writeFileSync4
35222
35436
  } from "node:fs";
35223
- import { dirname as dirname4, join as join6, relative, resolve as resolve4 } from "node:path";
35437
+ import { dirname as dirname5, join as join6, relative, resolve as resolve5 } from "node:path";
35224
35438
  import { fileURLToPath as fileURLToPath4 } from "node:url";
35225
35439
  import { input as input2, select as select3 } from "@inquirer/prompts";
35226
35440
  import { SecondLayer as SecondLayer3 } from "@secondlayer/sdk";
@@ -35235,17 +35449,17 @@ var FORMAT_BY_RUNTIME = {
35235
35449
  node: "standard-webhooks"
35236
35450
  };
35237
35451
  function templatesRoot() {
35238
- const here = dirname4(fileURLToPath4(import.meta.url));
35239
- const candidateDist = resolve4(here, "..", "templates", "subscriptions");
35240
- if (existsSync3(candidateDist))
35452
+ const here = dirname5(fileURLToPath4(import.meta.url));
35453
+ const candidateDist = resolve5(here, "..", "templates", "subscriptions");
35454
+ if (existsSync4(candidateDist))
35241
35455
  return candidateDist;
35242
- return resolve4(here, "..", "..", "templates", "subscriptions");
35456
+ return resolve5(here, "..", "..", "templates", "subscriptions");
35243
35457
  }
35244
35458
  function copyTemplate(src2, dest, vars) {
35245
- if (!existsSync3(src2)) {
35459
+ if (!existsSync4(src2)) {
35246
35460
  throw new Error(`template dir missing: ${src2}`);
35247
35461
  }
35248
- mkdirSync2(dest, { recursive: true });
35462
+ mkdirSync3(dest, { recursive: true });
35249
35463
  const entries2 = readdirSync(src2);
35250
35464
  for (const entry of entries2) {
35251
35465
  const from = join6(src2, entry);
@@ -35254,9 +35468,9 @@ function copyTemplate(src2, dest, vars) {
35254
35468
  if (st.isDirectory()) {
35255
35469
  copyTemplate(from, to, vars);
35256
35470
  } else {
35257
- const raw = readFileSync4(from, "utf8");
35471
+ const raw = readFileSync5(from, "utf8");
35258
35472
  const rendered = raw.replace(/\{\{([A-Z_]+)\}\}/g, (match, key) => vars[key] ?? match);
35259
- writeFileSync3(to, rendered);
35473
+ writeFileSync4(to, rendered);
35260
35474
  }
35261
35475
  }
35262
35476
  }
@@ -35265,7 +35479,7 @@ function parseTriggersInput(opts) {
35265
35479
  if (opts.triggersFile) {
35266
35480
  let parsed;
35267
35481
  try {
35268
- parsed = JSON.parse(readFileSync4(opts.triggersFile, "utf8"));
35482
+ parsed = JSON.parse(readFileSync5(opts.triggersFile, "utf8"));
35269
35483
  } catch (err) {
35270
35484
  throw new Error(`Could not read/parse --triggers-file ${opts.triggersFile}: ${err instanceof Error ? err.message : String(err)}`);
35271
35485
  }
@@ -35350,9 +35564,9 @@ async function createSubscription(name, opts) {
35350
35564
  }
35351
35565
  }
35352
35566
  const eventName = `${subgraph}.${table}.created`;
35353
- const targetDir = resolve4(process.cwd(), name);
35567
+ const targetDir = resolve5(process.cwd(), name);
35354
35568
  if (!opts.scaffold === false) {
35355
- if (existsSync3(targetDir)) {
35569
+ if (existsSync4(targetDir)) {
35356
35570
  error(`Directory already exists: ${relative(process.cwd(), targetDir)}`);
35357
35571
  process.exit(1);
35358
35572
  }
@@ -35403,15 +35617,15 @@ async function createSubscription(name, opts) {
35403
35617
  if (signingSecret && !opts.scaffold === false) {
35404
35618
  const envTarget = join6(targetDir, ".env");
35405
35619
  const envExample = join6(targetDir, ".env.example");
35406
- if (existsSync3(envExample) && !existsSync3(envTarget)) {
35620
+ if (existsSync4(envExample) && !existsSync4(envTarget)) {
35407
35621
  copyFileSync(envExample, envTarget);
35408
35622
  }
35409
- if (!existsSync3(envTarget)) {
35410
- writeFileSync3(envTarget, `SIGNING_SECRET=${signingSecret}
35623
+ if (!existsSync4(envTarget)) {
35624
+ writeFileSync4(envTarget, `SIGNING_SECRET=${signingSecret}
35411
35625
  `);
35412
35626
  } else {
35413
- const cur = readFileSync4(envTarget, "utf8");
35414
- writeFileSync3(envTarget, cur.match(/^SIGNING_SECRET=/m) ? cur.replace(/^SIGNING_SECRET=.*/m, `SIGNING_SECRET=${signingSecret}`) : `${cur}
35627
+ const cur = readFileSync5(envTarget, "utf8");
35628
+ writeFileSync4(envTarget, cur.match(/^SIGNING_SECRET=/m) ? cur.replace(/^SIGNING_SECRET=.*/m, `SIGNING_SECRET=${signingSecret}`) : `${cur}
35415
35629
  SIGNING_SECRET=${signingSecret}
35416
35630
  `);
35417
35631
  }
@@ -36178,8 +36392,8 @@ POST result (client-side, not logged):`));
36178
36392
  }
36179
36393
  // src/commands/devnet.ts
36180
36394
  import { spawnSync as spawnSync2 } from "node:child_process";
36181
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "node:fs";
36182
- import { dirname as dirname6, join as join8 } from "node:path";
36395
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "node:fs";
36396
+ import { dirname as dirname7, join as join8 } from "node:path";
36183
36397
 
36184
36398
  // src/lib/devnet-compose.ts
36185
36399
  var DEFAULT_IMAGE_OWNER = "ryanwaits";
@@ -36321,24 +36535,24 @@ volumes:
36321
36535
  }
36322
36536
 
36323
36537
  // src/lib/devnet-config.ts
36324
- import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
36325
- import { dirname as dirname5, join as join7, parse as parsePath } from "node:path";
36538
+ import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
36539
+ import { dirname as dirname6, join as join7, parse as parsePath } from "node:path";
36326
36540
  import { parse as parseToml } from "smol-toml";
36327
36541
  var DEFAULT_INDEXER_OBSERVER = "host.docker.internal:3700";
36328
36542
  function findClarinetProject(startDir) {
36329
36543
  let dir = startDir;
36330
36544
  const { root } = parsePath(dir);
36331
36545
  while (true) {
36332
- if (existsSync4(join7(dir, "Clarinet.toml")))
36546
+ if (existsSync5(join7(dir, "Clarinet.toml")))
36333
36547
  return dir;
36334
36548
  if (dir === root)
36335
36549
  return null;
36336
- dir = dirname5(dir);
36550
+ dir = dirname6(dir);
36337
36551
  }
36338
36552
  }
36339
36553
  function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER) {
36340
- const exists = existsSync4(devnetTomlPath);
36341
- const original = exists ? readFileSync5(devnetTomlPath, "utf8") : "";
36554
+ const exists = existsSync5(devnetTomlPath);
36555
+ const original = exists ? readFileSync6(devnetTomlPath, "utf8") : "";
36342
36556
  if (original.trim()) {
36343
36557
  const parsed = parseToml(original);
36344
36558
  const observers = parsed.devnet?.stacks_node_events_observers;
@@ -36352,7 +36566,7 @@ function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER
36352
36566
  const at = (arrayStart.index ?? 0) + arrayStart[0].length;
36353
36567
  const next = original.slice(at).trimStart().startsWith("]") ? entry : `${entry}, `;
36354
36568
  const patched = original.slice(0, at) + next + original.slice(at);
36355
- writeFileSync4(devnetTomlPath, patched);
36569
+ writeFileSync5(devnetTomlPath, patched);
36356
36570
  return { status: "added" };
36357
36571
  }
36358
36572
  const header = original.match(/^\[devnet\]\s*$/m);
@@ -36360,7 +36574,7 @@ function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER
36360
36574
  const at = (header.index ?? 0) + header[0].length;
36361
36575
  const patched = `${original.slice(0, at)}
36362
36576
  stacks_node_events_observers = [${entry}]${original.slice(at)}`;
36363
- writeFileSync4(devnetTomlPath, patched);
36577
+ writeFileSync5(devnetTomlPath, patched);
36364
36578
  return { status: "added" };
36365
36579
  }
36366
36580
  const prefix = original && !original.endsWith(`
@@ -36370,7 +36584,7 @@ stacks_node_events_observers = [${entry}]${original.slice(at)}`;
36370
36584
  ` : ""}[devnet]
36371
36585
  stacks_node_events_observers = [${entry}]
36372
36586
  `;
36373
- writeFileSync4(devnetTomlPath, block);
36587
+ writeFileSync5(devnetTomlPath, block);
36374
36588
  return { status: exists ? "added" : "created" };
36375
36589
  }
36376
36590
 
@@ -36420,7 +36634,7 @@ function registerDevnetCommand(program2) {
36420
36634
  }
36421
36635
  function resolveProject(explicit) {
36422
36636
  if (explicit) {
36423
- if (!existsSync5(join8(explicit, "Clarinet.toml"))) {
36637
+ if (!existsSync6(join8(explicit, "Clarinet.toml"))) {
36424
36638
  error(`No Clarinet.toml in ${explicit}`);
36425
36639
  process.exit(1);
36426
36640
  }
@@ -36437,7 +36651,7 @@ function resolveProject(explicit) {
36437
36651
  async function connect(options3) {
36438
36652
  const project = resolveProject(options3.project);
36439
36653
  const devnetToml = join8(project, "settings", "Devnet.toml");
36440
- mkdirSync3(dirname6(devnetToml), { recursive: true });
36654
+ mkdirSync4(dirname7(devnetToml), { recursive: true });
36441
36655
  const result = ensureEventObserver(devnetToml, DEFAULT_INDEXER_OBSERVER);
36442
36656
  console.log(`${green("✓")} found Clarinet.toml`);
36443
36657
  if (result.status === "present") {
@@ -36447,8 +36661,8 @@ async function connect(options3) {
36447
36661
  console.log(dim(` + stacks_node_events_observers = ["${DEFAULT_INDEXER_OBSERVER}"]`));
36448
36662
  }
36449
36663
  const composePath = join8(project, COMPOSE_REL);
36450
- mkdirSync3(dirname6(composePath), { recursive: true });
36451
- writeFileSync5(composePath, buildDevnetCompose({ owner: options3.owner, imageTag: options3.imageTag }));
36664
+ mkdirSync4(dirname7(composePath), { recursive: true });
36665
+ writeFileSync6(composePath, buildDevnetCompose({ owner: options3.owner, imageTag: options3.imageTag }));
36452
36666
  console.log(`${green("✓")} wrote ${COMPOSE_REL}`);
36453
36667
  if (!options3.up) {
36454
36668
  console.log(dim(`
@@ -36477,7 +36691,7 @@ Stop with: sl devnet down`));
36477
36691
  async function down(options3) {
36478
36692
  const project = resolveProject(options3.project);
36479
36693
  const composePath = join8(project, COMPOSE_REL);
36480
- if (!existsSync5(composePath)) {
36694
+ if (!existsSync6(composePath)) {
36481
36695
  error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`sl devnet connect\` first.`);
36482
36696
  process.exit(1);
36483
36697
  }
@@ -36492,7 +36706,7 @@ async function down(options3) {
36492
36706
  async function logs(service, options3) {
36493
36707
  const project = resolveProject(options3.project);
36494
36708
  const composePath = join8(project, COMPOSE_REL);
36495
- if (!existsSync5(composePath)) {
36709
+ if (!existsSync6(composePath)) {
36496
36710
  error(`No ${COMPOSE_REL} in ${project} — run \`sl devnet connect\` first.`);
36497
36711
  process.exit(1);
36498
36712
  }
@@ -36617,7 +36831,7 @@ init_subgraphs2();
36617
36831
  init_output();
36618
36832
  init_resolve_auth();
36619
36833
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
36620
- import { dirname as dirname7, join as join9 } from "node:path";
36834
+ import { dirname as dirname8, join as join9 } from "node:path";
36621
36835
  import { createStreamsClient } from "@secondlayer/sdk";
36622
36836
  import { STREAMS_EVENT_TYPES } from "@secondlayer/shared";
36623
36837
  var DEFAULT_BASE_URL3 = "https://api.secondlayer.tools";
@@ -36794,7 +37008,7 @@ Examples:
36794
37008
  for (const file of files) {
36795
37009
  const bytes = await dumps.download(file);
36796
37010
  const dest = join9(options3.to, file.path);
36797
- await mkdir3(dirname7(dest), { recursive: true });
37011
+ await mkdir3(dirname8(dest), { recursive: true });
36798
37012
  await writeFile3(dest, bytes);
36799
37013
  process.stderr.write(`# ${file.path} (${file.row_count} rows, ${bytes.byteLength} bytes)
36800
37014
  `);
@@ -38080,10 +38294,10 @@ init_http();
38080
38294
  init_output();
38081
38295
 
38082
38296
  // src/lib/project-file.ts
38083
- import { existsSync as existsSync6 } from "node:fs";
38297
+ import { existsSync as existsSync7 } from "node:fs";
38084
38298
  import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
38085
38299
  import { homedir as homedir5 } from "node:os";
38086
- import { dirname as dirname13, join as join12, parse as parsePath2, resolve as resolve10 } from "node:path";
38300
+ import { dirname as dirname14, join as join12, parse as parsePath2, resolve as resolve11 } from "node:path";
38087
38301
  import { z as z4 } from "zod";
38088
38302
  var ProjectFileSchema = z4.object({
38089
38303
  slug: z4.string().min(1)
@@ -38091,23 +38305,23 @@ var ProjectFileSchema = z4.object({
38091
38305
  var FILENAME = "project";
38092
38306
  var DIRNAME = ".secondlayer";
38093
38307
  async function readActiveProject(cwd, globalDefault) {
38094
- let dir = resolve10(cwd);
38095
- const home2 = resolve10(homedir5());
38308
+ let dir = resolve11(cwd);
38309
+ const home2 = resolve11(homedir5());
38096
38310
  const fsRoot = parsePath2(dir).root;
38097
38311
  while (true) {
38098
38312
  const candidate = join12(dir, DIRNAME, FILENAME);
38099
- if (existsSync6(candidate)) {
38313
+ if (existsSync7(candidate)) {
38100
38314
  try {
38101
38315
  const raw = await readFile3(candidate, "utf8");
38102
38316
  const parsed = ProjectFileSchema.parse(JSON.parse(raw));
38103
38317
  return { slug: parsed.slug, resolvedFrom: candidate };
38104
38318
  } catch {}
38105
38319
  }
38106
- if (existsSync6(join12(dir, ".git")))
38320
+ if (existsSync7(join12(dir, ".git")))
38107
38321
  break;
38108
38322
  if (dir === home2 || dir === fsRoot)
38109
38323
  break;
38110
- const parent = dirname13(dir);
38324
+ const parent = dirname14(dir);
38111
38325
  if (parent === dir)
38112
38326
  break;
38113
38327
  dir = parent;
@@ -38121,7 +38335,7 @@ async function readActiveProject(cwd, globalDefault) {
38121
38335
  return null;
38122
38336
  }
38123
38337
  async function writeActiveProject(slug, cwd) {
38124
- const dir = join12(resolve10(cwd), DIRNAME);
38338
+ const dir = join12(resolve11(cwd), DIRNAME);
38125
38339
  await mkdir4(dir, { recursive: true });
38126
38340
  const file = join12(dir, FILENAME);
38127
38341
  await writeFile4(file, `${JSON.stringify({ slug }, null, 2)}
@@ -38345,5 +38559,5 @@ registerAccountCommand(program);
38345
38559
  registerKeysCommand(program);
38346
38560
  program.parse();
38347
38561
 
38348
- //# debugId=D8E1B996905C6BA564756E2164756E21
38562
+ //# debugId=FAEADBDE13DF788264756E2164756E21
38349
38563
  //# sourceMappingURL=cli.js.map