@secondlayer/cli 1.6.0 → 1.6.1

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.
Files changed (3) hide show
  1. package/dist/cli.js +151 -141
  2. package/dist/cli.js.map +21 -21
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2229,8 +2229,8 @@ function migrateConfig(raw) {
2229
2229
  if (typeof old.dataDir === "string") {
2230
2230
  migrated.dataDir = old.dataDir;
2231
2231
  }
2232
- if (typeof old.defaultWebhookUrl === "string") {
2233
- migrated.defaultWebhookUrl = old.defaultWebhookUrl;
2232
+ if (typeof old.defaultEndpointUrl === "string") {
2233
+ migrated.defaultEndpointUrl = old.defaultEndpointUrl;
2234
2234
  }
2235
2235
  if (typeof old.nodeInstallPath === "string" || typeof old.nodeNetwork === "string") {
2236
2236
  migrated.node = {
@@ -2270,8 +2270,8 @@ async function loadConfig() {
2270
2270
  }
2271
2271
  }
2272
2272
  config = applyEnvOverrides(config);
2273
- if (!config.defaultWebhookUrl && config.network === "local") {
2274
- config.defaultWebhookUrl = LOCAL_WEBHOOK_URL;
2273
+ if (!config.defaultEndpointUrl && config.network === "local") {
2274
+ config.defaultEndpointUrl = LOCAL_ENDPOINT_URL;
2275
2275
  }
2276
2276
  return config;
2277
2277
  }
@@ -2301,12 +2301,15 @@ function applyEnvOverrides(config) {
2301
2301
  result.ports = { ...result.ports, indexer: port };
2302
2302
  }
2303
2303
  }
2304
- if (process.env.SL_WEBHOOK_PORT) {
2305
- const port = parseInt(process.env.SL_WEBHOOK_PORT, 10);
2304
+ if (process.env.SL_RECEIVER_PORT) {
2305
+ const port = parseInt(process.env.SL_RECEIVER_PORT, 10);
2306
2306
  if (!isNaN(port) && port > 0 && port <= 65535) {
2307
- result.ports = { ...result.ports, webhook: port };
2307
+ result.ports = { ...result.ports, receiver: port };
2308
2308
  }
2309
2309
  }
2310
+ if (process.env.STACKS_NODE_RPC_URL) {
2311
+ result.nodeRpcUrl = process.env.STACKS_NODE_RPC_URL;
2312
+ }
2310
2313
  if (process.env.DATABASE_URL) {
2311
2314
  result.database = { type: "external", url: process.env.DATABASE_URL };
2312
2315
  }
@@ -2395,13 +2398,13 @@ function isDefaultValue(config, key) {
2395
2398
  const defaultValue = getConfigValue(DEFAULT_CONFIG, key);
2396
2399
  return JSON.stringify(currentValue) === JSON.stringify(defaultValue);
2397
2400
  }
2398
- var PortsSchema, NodeSchema, DatabaseSchema, NetworkSchema, API_URLS, ConfigSchema, CONFIG_DIR, CONFIG_PATH, LOCAL_WEBHOOK_URL = "http://localhost:3900/webhook", DEFAULT_CONFIG;
2401
+ var PortsSchema, NodeSchema, DatabaseSchema, NetworkSchema, API_URLS, ConfigSchema, CONFIG_DIR, CONFIG_PATH, LOCAL_ENDPOINT_URL = "http://localhost:3900/receiver", DEFAULT_CONFIG;
2399
2402
  var init_config = __esm(() => {
2400
2403
  init_fs();
2401
2404
  PortsSchema = z.object({
2402
2405
  api: z.number().int().min(1).max(65535).default(3800),
2403
2406
  indexer: z.number().int().min(1).max(65535).default(3700),
2404
- webhook: z.number().int().min(1).max(65535).default(3900)
2407
+ receiver: z.number().int().min(1).max(65535).default(3900)
2405
2408
  });
2406
2409
  NodeSchema = z.object({
2407
2410
  installPath: z.string().min(1),
@@ -2421,8 +2424,9 @@ var init_config = __esm(() => {
2421
2424
  network: NetworkSchema.default("mainnet"),
2422
2425
  apiUrl: z.string().url().optional(),
2423
2426
  apiKey: z.string().optional(),
2427
+ nodeRpcUrl: z.string().url().optional(),
2424
2428
  dataDir: z.string().default("~/.secondlayer/data"),
2425
- defaultWebhookUrl: z.string().url().optional(),
2429
+ defaultEndpointUrl: z.string().url().optional(),
2426
2430
  node: NodeSchema.optional(),
2427
2431
  ports: PortsSchema.default({}),
2428
2432
  database: DatabaseSchema.default({})
@@ -2432,7 +2436,7 @@ var init_config = __esm(() => {
2432
2436
  DEFAULT_CONFIG = {
2433
2437
  network: "mainnet",
2434
2438
  dataDir: "~/.secondlayer/data",
2435
- ports: { api: 3800, indexer: 3700, webhook: 3900 },
2439
+ ports: { api: 3800, indexer: 3700, receiver: 3900 },
2436
2440
  database: { type: "docker" }
2437
2441
  };
2438
2442
  });
@@ -12432,13 +12436,16 @@ class StacksApiClient {
12432
12436
  static hasWarnedAboutApiKey = false;
12433
12437
  baseUrl;
12434
12438
  headers;
12439
+ usingHiro;
12435
12440
  constructor(network = "mainnet", apiKey, apiUrl) {
12436
- this.baseUrl = apiUrl || API_URLS2[network];
12441
+ const nodeRpcUrl = process.env.STACKS_NODE_RPC_URL;
12442
+ this.baseUrl = apiUrl || nodeRpcUrl || HIRO_URLS[network];
12443
+ this.usingHiro = !apiUrl && !nodeRpcUrl;
12437
12444
  this.headers = apiKey ? { "x-api-key": apiKey } : {};
12438
- if (!apiKey && !StacksApiClient.hasWarnedAboutApiKey) {
12439
- console.warn(`⚠️ No API key provided. You may be rate-limited.
12440
- ` + ` Set HIRO_API_KEY env var or use --api-key flag.
12441
- ` + " Get a free key at: https://platform.hiro.so/");
12445
+ if (this.usingHiro && !apiKey && !StacksApiClient.hasWarnedAboutApiKey) {
12446
+ console.warn(`⚠️ Using Hiro public API (no STACKS_NODE_RPC_URL set). You may be rate-limited.
12447
+ ` + ` Set STACKS_NODE_RPC_URL to use your own node, or set HIRO_API_KEY for Hiro.
12448
+ ` + " Get a free Hiro key at: https://platform.hiro.so/");
12442
12449
  StacksApiClient.hasWarnedAboutApiKey = true;
12443
12450
  }
12444
12451
  }
@@ -12471,7 +12478,7 @@ class StacksApiClient {
12471
12478
  return data.source;
12472
12479
  }
12473
12480
  }
12474
- var gotWithRetry, API_URLS2;
12481
+ var gotWithRetry, HIRO_URLS;
12475
12482
  var init_api = __esm(() => {
12476
12483
  init_source3();
12477
12484
  gotWithRetry = source_default2.extend({
@@ -12483,7 +12490,7 @@ var init_api = __esm(() => {
12483
12490
  calculateDelay: ({ attemptCount }) => attemptCount * 1000
12484
12491
  }
12485
12492
  });
12486
- API_URLS2 = {
12493
+ HIRO_URLS = {
12487
12494
  mainnet: "https://api.hiro.so",
12488
12495
  testnet: "https://api.testnet.hiro.so",
12489
12496
  devnet: "http://localhost:3999"
@@ -13189,9 +13196,9 @@ var init_api2 = __esm(() => {
13189
13196
  init_manager();
13190
13197
  });
13191
13198
 
13192
- // src/services/webhook-server.ts
13199
+ // src/services/receiver-server.ts
13193
13200
  import { verifySignatureHeader } from "@secondlayer/shared/crypto";
13194
- function startWebhookServer(options2 = {}) {
13201
+ function startReceiverServer(options2 = {}) {
13195
13202
  const port = options2.port ?? 3900;
13196
13203
  const responseCode = options2.responseCode ?? 200;
13197
13204
  server = Bun.serve({
@@ -13230,27 +13237,27 @@ function startWebhookServer(options2 = {}) {
13230
13237
  body,
13231
13238
  signatureValid
13232
13239
  };
13233
- if (options2.onWebhook) {
13234
- options2.onWebhook(event);
13240
+ if (options2.onDelivery) {
13241
+ options2.onDelivery(event);
13235
13242
  } else {
13236
- logWebhook(event);
13243
+ logDelivery(event);
13237
13244
  }
13238
13245
  return new Response("OK", { status: responseCode });
13239
13246
  }
13240
13247
  });
13241
13248
  return port;
13242
13249
  }
13243
- function stopWebhookServer() {
13250
+ function stopReceiverServer() {
13244
13251
  if (server) {
13245
13252
  server.stop();
13246
13253
  server = null;
13247
13254
  }
13248
13255
  }
13249
- function logWebhook(event) {
13256
+ function logDelivery(event) {
13250
13257
  const time = event.timestamp.toISOString();
13251
13258
  console.log("");
13252
13259
  console.log(blue("━".repeat(60)));
13253
- console.log(green("⚡ Webhook received"));
13260
+ console.log(green("⚡ Delivery received"));
13254
13261
  console.log(dim(` ${time}`));
13255
13262
  console.log(dim(` ${event.method} ${event.path}`));
13256
13263
  if (event.signatureValid === true) {
@@ -13272,7 +13279,7 @@ function logWebhook(event) {
13272
13279
  console.log(blue("━".repeat(60)));
13273
13280
  }
13274
13281
  var server = null;
13275
- var init_webhook_server = __esm(() => {
13282
+ var init_receiver_server = __esm(() => {
13276
13283
  init_output();
13277
13284
  });
13278
13285
 
@@ -13300,7 +13307,7 @@ var init_services = __esm(() => {
13300
13307
  init_indexer();
13301
13308
  init_worker();
13302
13309
  init_api2();
13303
- init_webhook_server();
13310
+ init_receiver_server();
13304
13311
  init_subgraph_processor();
13305
13312
  });
13306
13313
 
@@ -13344,7 +13351,7 @@ async function runBackground(options2) {
13344
13351
  const dataDir = getDataDir(config);
13345
13352
  const indexerPort = options2.stacksNode ? 3701 : parseInt(options2.indexerPort) || config.ports.indexer;
13346
13353
  const apiPort = parseInt(options2.apiPort) || config.ports.api;
13347
- const webhookPort = parseInt(options2.webhookPort) || config.ports.webhook;
13354
+ const receiverPort = parseInt(options2.receiverPort) || config.ports.receiver;
13348
13355
  if (options2.stacksNode && config.node) {
13349
13356
  const validation = await validateNetworkConsistency(config);
13350
13357
  if (!validation.valid) {
@@ -13454,24 +13461,24 @@ async function runBackground(options2) {
13454
13461
  };
13455
13462
  console.log(green(" ✓ Subgraph processor"), dim("processing subgraphs"));
13456
13463
  }
13457
- if (options2.webhook) {
13458
- const webhookLogFile = getLogFile("webhook");
13459
- const webhookArgs = ["bun", "run", resolve6(packagesDir, "packages/cli/src/services/webhook-standalone.ts")];
13460
- const webhookEnv = { ...process.env, PORT: String(webhookPort) };
13464
+ if (options2.receiver) {
13465
+ const receiverLogFile = getLogFile("receiver");
13466
+ const receiverArgs = ["bun", "run", resolve6(packagesDir, "packages/cli/src/services/receiver-standalone.ts")];
13467
+ const receiverEnv = { ...process.env, PORT: String(receiverPort) };
13461
13468
  if (options2.secret)
13462
- webhookEnv.WEBHOOK_SECRET = options2.secret;
13463
- const webhookProc = Bun.spawn(webhookArgs, {
13464
- env: webhookEnv,
13465
- stdout: Bun.file(webhookLogFile),
13466
- stderr: Bun.file(webhookLogFile)
13469
+ receiverEnv.SIGNING_SECRET = options2.secret;
13470
+ const receiverProc = Bun.spawn(receiverArgs, {
13471
+ env: receiverEnv,
13472
+ stdout: Bun.file(receiverLogFile),
13473
+ stderr: Bun.file(receiverLogFile)
13467
13474
  });
13468
- state.services.webhook = {
13469
- pid: webhookProc.pid,
13470
- port: webhookPort,
13475
+ state.services.receiver = {
13476
+ pid: receiverProc.pid,
13477
+ port: receiverPort,
13471
13478
  startedAt: new Date().toISOString(),
13472
- logFile: webhookLogFile
13479
+ logFile: receiverLogFile
13473
13480
  };
13474
- console.log(green(" ✓ Webhook server"), dim(`http://localhost:${webhookPort}`));
13481
+ console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
13475
13482
  }
13476
13483
  await Bun.sleep(500);
13477
13484
  for (const [name, service] of Object.entries(state.services)) {
@@ -13481,7 +13488,7 @@ async function runBackground(options2) {
13481
13488
  }
13482
13489
  await saveDevState(state);
13483
13490
  console.log("");
13484
- printUrls(indexerPort, apiPort, webhookPort, options2.webhook);
13491
+ printUrls(indexerPort, apiPort, receiverPort, options2.receiver);
13485
13492
  console.log("");
13486
13493
  success("Dev environment started in background");
13487
13494
  console.log("");
@@ -13519,14 +13526,14 @@ async function runForeground(options2) {
13519
13526
  const dataDir = getDataDir(config);
13520
13527
  const indexerPort = options2.stacksNode ? 3701 : parseInt(options2.indexerPort) || config.ports.indexer;
13521
13528
  const apiPort = parseInt(options2.apiPort) || config.ports.api;
13522
- const webhookPort = parseInt(options2.webhookPort) || config.ports.webhook;
13529
+ const receiverPort = parseInt(options2.receiverPort) || config.ports.receiver;
13523
13530
  let devPostgresStarted = false;
13524
13531
  const shutdown = async () => {
13525
13532
  console.log(`
13526
13533
  `);
13527
13534
  info("Shutting down services...");
13528
- if (options2.webhook) {
13529
- stopWebhookServer();
13535
+ if (options2.receiver) {
13536
+ stopReceiverServer();
13530
13537
  }
13531
13538
  await serviceManager.stopAll();
13532
13539
  if (devPostgresStarted) {
@@ -13573,9 +13580,9 @@ async function runForeground(options2) {
13573
13580
  console.log("");
13574
13581
  }
13575
13582
  process.env.DEV_MODE = "true";
13576
- if (options2.webhook) {
13577
- startWebhookServer({ port: webhookPort, secret: options2.secret });
13578
- console.log(green(" ✓ Webhook server"), dim(`http://localhost:${webhookPort}`));
13583
+ if (options2.receiver) {
13584
+ startReceiverServer({ port: receiverPort, secret: options2.secret });
13585
+ console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
13579
13586
  }
13580
13587
  await startApi({ port: apiPort, onLog: (line) => logService("api", line) });
13581
13588
  console.log(green(" ✓ API"), dim(`http://localhost:${apiPort}`));
@@ -13588,7 +13595,7 @@ async function runForeground(options2) {
13588
13595
  await startSubgraphProcessor({ onLog: (line) => logService("subgraphs", line) });
13589
13596
  console.log(green(" ✓ Subgraph processor"), dim("processing subgraphs"));
13590
13597
  console.log("");
13591
- printUrls(indexerPort, apiPort, webhookPort, options2.webhook);
13598
+ printUrls(indexerPort, apiPort, receiverPort, options2.receiver);
13592
13599
  console.log("");
13593
13600
  info("Press Ctrl+C to stop all services");
13594
13601
  console.log("");
@@ -13596,8 +13603,8 @@ async function runForeground(options2) {
13596
13603
  } catch (err) {
13597
13604
  error(`Failed to start services: ${err}`);
13598
13605
  await serviceManager.stopAll();
13599
- if (options2.webhook) {
13600
- stopWebhookServer();
13606
+ if (options2.receiver) {
13607
+ stopReceiverServer();
13601
13608
  }
13602
13609
  process.exit(1);
13603
13610
  }
@@ -13628,10 +13635,10 @@ async function showLogs(options2) {
13628
13635
  await showStaticLogs(serviceEntries, lines, verbose);
13629
13636
  }
13630
13637
  }
13631
- function formatWebhookSummary(jsonStr) {
13638
+ function formatDeliverySummary(jsonStr) {
13632
13639
  try {
13633
13640
  const data = JSON.parse(jsonStr);
13634
- if (data.type !== "webhook" || !data.body)
13641
+ if (data.type !== "delivery" || !data.body)
13635
13642
  return null;
13636
13643
  const { body, method, path, timestamp } = data;
13637
13644
  const streamName = body.streamName ?? body.streamId?.slice(0, 8) ?? "unknown";
@@ -13661,8 +13668,8 @@ function formatLogLine2(service, line, verbose) {
13661
13668
  return `${prefix} ${dimTimestamp} ${dim(level + ":")} ${dim(message)}`;
13662
13669
  }
13663
13670
  }
13664
- if (service === "webhook" && !verbose) {
13665
- const summary = formatWebhookSummary(line);
13671
+ if (service === "receiver" && !verbose) {
13672
+ const summary = formatDeliverySummary(line);
13666
13673
  if (summary)
13667
13674
  return `${prefix} ${summary}`;
13668
13675
  }
@@ -13838,21 +13845,21 @@ async function restartDev() {
13838
13845
  };
13839
13846
  console.log(green(" ✓ Worker"), dim("processing jobs"));
13840
13847
  }
13841
- if (state.services.webhook) {
13842
- const webhookPort = config.ports.webhook;
13843
- const webhookLogFile = getLogFile("webhook");
13844
- const webhookProc = Bun.spawn(["bun", "run", resolve6(packagesDir, "packages/cli/src/services/webhook-standalone.ts")], {
13845
- env: { ...process.env, PORT: String(webhookPort) },
13846
- stdout: Bun.file(webhookLogFile),
13847
- stderr: Bun.file(webhookLogFile)
13848
+ if (state.services.receiver) {
13849
+ const receiverPort = config.ports.receiver;
13850
+ const receiverLogFile = getLogFile("receiver");
13851
+ const receiverProc = Bun.spawn(["bun", "run", resolve6(packagesDir, "packages/cli/src/services/receiver-standalone.ts")], {
13852
+ env: { ...process.env, PORT: String(receiverPort) },
13853
+ stdout: Bun.file(receiverLogFile),
13854
+ stderr: Bun.file(receiverLogFile)
13848
13855
  });
13849
- newState.services.webhook = {
13850
- pid: webhookProc.pid,
13851
- port: webhookPort,
13856
+ newState.services.receiver = {
13857
+ pid: receiverProc.pid,
13858
+ port: receiverPort,
13852
13859
  startedAt: new Date().toISOString(),
13853
- logFile: webhookLogFile
13860
+ logFile: receiverLogFile
13854
13861
  };
13855
- console.log(green(" ✓ Webhook server"), dim(`http://localhost:${webhookPort}`));
13862
+ console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
13856
13863
  }
13857
13864
  if (state.services.subgraphs) {
13858
13865
  const subgraphsLogFile = getLogFile("subgraphs");
@@ -13928,7 +13935,7 @@ function printBanner2() {
13928
13935
  console.log(dim(" Starting services..."));
13929
13936
  console.log("");
13930
13937
  }
13931
- function printUrls(indexerPort, apiPort, webhookPort, webhookEnabled) {
13938
+ function printUrls(indexerPort, apiPort, receiverPort, receiverEnabled) {
13932
13939
  console.log(dim(" ─────────────────────────────────────────"));
13933
13940
  console.log("");
13934
13941
  console.log(" " + blue("API:"));
@@ -13939,9 +13946,9 @@ function printUrls(indexerPort, apiPort, webhookPort, webhookEnabled) {
13939
13946
  console.log(` Health check: curl http://localhost:${indexerPort}/health`);
13940
13947
  console.log(` Send block: curl -X POST http://localhost:${indexerPort}/new_block -d @block.json`);
13941
13948
  console.log("");
13942
- if (webhookEnabled) {
13943
- console.log(" " + blue("Test Webhook:"));
13944
- console.log(` Receives webhooks at http://localhost:${webhookPort}/`);
13949
+ if (receiverEnabled) {
13950
+ console.log(" " + blue("Test Receiver:"));
13951
+ console.log(` Receives deliveries at http://localhost:${receiverPort}/`);
13945
13952
  console.log(` Use this URL when creating streams for testing`);
13946
13953
  console.log("");
13947
13954
  }
@@ -14018,7 +14025,7 @@ var init_dev_impl = __esm(() => {
14018
14025
  indexer: cyan,
14019
14026
  worker: yellow,
14020
14027
  subgraphs: magenta,
14021
- webhook: green
14028
+ receiver: green
14022
14029
  };
14023
14030
  });
14024
14031
 
@@ -32268,7 +32275,7 @@ function deriveContractName(filePath) {
32268
32275
  const basename = path10.basename(filePath, ".clar");
32269
32276
  return basename.replace(/[-_](.)/g, (_2, char) => char.toUpperCase()).replace(/^(.)/, (_2, char) => char.toLowerCase()).replace(/^\d/, "_$&");
32270
32277
  }
32271
- async function buildConfigFromInputs(parsedInputs, outPath, apiKey, defaultAddress) {
32278
+ async function buildConfigFromInputs(parsedInputs, outPath, apiKey, defaultAddress, nodeRpcUrl) {
32272
32279
  const contracts = [];
32273
32280
  const deployer = defaultAddress || DEFAULT_DEVNET_ADDRESS;
32274
32281
  if (parsedInputs.files.length > 0 && !defaultAddress) {
@@ -32290,7 +32297,7 @@ async function buildConfigFromInputs(parsedInputs, outPath, apiKey, defaultAddre
32290
32297
  const { address, contractName } = parseContractId(contractId);
32291
32298
  const network = inferNetwork(address) ?? "mainnet";
32292
32299
  try {
32293
- const apiClient = new StacksApiClient(network, apiKey);
32300
+ const apiClient = new StacksApiClient(network, apiKey, nodeRpcUrl);
32294
32301
  const contractInfo = await apiClient.getContractInfo(contractId);
32295
32302
  const abi = parseApiResponse(contractInfo);
32296
32303
  const name = toCamelCase7(contractName);
@@ -32333,7 +32340,8 @@ No .clar files or contract addresses matched the provided inputs`));
32333
32340
  process.exit(1);
32334
32341
  }
32335
32342
  const apiKey = options3.apiKey || process.env.HIRO_API_KEY;
32336
- config = await buildConfigFromInputs(parsedInputs, options3.out, apiKey);
32343
+ const cliConfig = await loadConfig();
32344
+ config = await buildConfigFromInputs(parsedInputs, options3.out, apiKey, undefined, cliConfig.nodeRpcUrl);
32337
32345
  } else {
32338
32346
  config = await loadConfig2(options3.config);
32339
32347
  }
@@ -32462,6 +32470,7 @@ var import_fast_glob, DEFAULT_DEVNET_ADDRESS = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZ
32462
32470
  var init_generate = __esm(() => {
32463
32471
  init_source4();
32464
32472
  init_config2();
32473
+ init_config();
32465
32474
  init_api();
32466
32475
  init_clarity();
32467
32476
  init_contract();
@@ -32538,7 +32547,7 @@ var {
32538
32547
  // package.json
32539
32548
  var package_default = {
32540
32549
  name: "@secondlayer/cli",
32541
- version: "1.6.0",
32550
+ version: "1.6.1",
32542
32551
  description: "CLI for streams, subgraphs, and real-time blockchain indexing on Stacks",
32543
32552
  type: "module",
32544
32553
  bin: {
@@ -32930,7 +32939,7 @@ async function printConfigTree(cfg) {
32930
32939
  console.log(blue("ports:"));
32931
32940
  printValue(" api", cfg.ports.api, cfg.ports.api === defaults.ports.api, 2);
32932
32941
  printValue(" indexer", cfg.ports.indexer, cfg.ports.indexer === defaults.ports.indexer, 2);
32933
- printValue(" webhook", cfg.ports.webhook, cfg.ports.webhook === defaults.ports.webhook, 2);
32942
+ printValue(" receiver", cfg.ports.receiver, cfg.ports.receiver === defaults.ports.receiver, 2);
32934
32943
  console.log("");
32935
32944
  console.log(blue("database:"));
32936
32945
  printValue(" type", cfg.database.type, cfg.database.type === "docker", 2);
@@ -32976,13 +32985,13 @@ import { select as select2, input, confirm } from "@inquirer/prompts";
32976
32985
  init_config();
32977
32986
  var STREAMS_DIR = "streams";
32978
32987
  function registerSetupCommand(program2) {
32979
- program2.command("setup").description("Set up a streams project and configure settings").option("--detect-only", "Only detect existing Stacks nodes, don't initialize").option("-y, --yes", "Use defaults without prompts").option("--data-dir <path>", "Data directory path").option("--node-path <path>", "Path to Stacks node").option("--network <network>", "Network (local, testnet, or mainnet)").option("--webhook-url <url>", "Default webhook URL for new streams").action(async (options) => {
32988
+ program2.command("setup").description("Set up a streams project and configure settings").option("--detect-only", "Only detect existing Stacks nodes, don't initialize").option("-y, --yes", "Use defaults without prompts").option("--data-dir <path>", "Data directory path").option("--node-path <path>", "Path to Stacks node").option("--network <network>", "Network (local, testnet, or mainnet)").option("--endpoint-url <url>", "Default endpoint URL for new streams").action(async (options) => {
32980
32989
  try {
32981
32990
  if (options.detectOnly) {
32982
32991
  await runDetection();
32983
32992
  return;
32984
32993
  }
32985
- const hasFlags = options.yes || options.dataDir || options.nodePath || options.network || options.webhookUrl;
32994
+ const hasFlags = options.yes || options.dataDir || options.nodePath || options.network || options.endpointUrl;
32986
32995
  if (hasFlags) {
32987
32996
  await runNonInteractive(options);
32988
32997
  return;
@@ -33011,7 +33020,7 @@ async function runNonInteractive(options) {
33011
33020
  return;
33012
33021
  }
33013
33022
  config.dataDir = options.dataDir || config.dataDir || "~/.secondlayer/data";
33014
- config.defaultWebhookUrl = options.webhookUrl || config.defaultWebhookUrl;
33023
+ config.defaultEndpointUrl = options.endpointUrl || config.defaultEndpointUrl;
33015
33024
  if (options.nodePath) {
33016
33025
  config.node = {
33017
33026
  installPath: options.nodePath,
@@ -33055,8 +33064,8 @@ async function runWizard() {
33055
33064
  if (nodeConfig) {
33056
33065
  config.node = nodeConfig;
33057
33066
  }
33058
- const webhookUrl = await promptWebhookUrl(config);
33059
- config.defaultWebhookUrl = webhookUrl;
33067
+ const endpointUrl = await promptEndpointUrl(config);
33068
+ config.defaultEndpointUrl = endpointUrl;
33060
33069
  await saveConfig(config);
33061
33070
  await Bun.$`mkdir -p ${STREAMS_DIR}`.quiet();
33062
33071
  await Bun.write(`${STREAMS_DIR}/.gitkeep`, "");
@@ -33183,10 +33192,10 @@ async function promptNetwork() {
33183
33192
  });
33184
33193
  return network;
33185
33194
  }
33186
- async function promptWebhookUrl(config) {
33187
- const internalUrl = "http://localhost:3900/webhook";
33195
+ async function promptEndpointUrl(config) {
33196
+ const internalUrl = "http://localhost:3900/receiver";
33188
33197
  const choice = await select2({
33189
- message: "Default webhook URL for new streams?",
33198
+ message: "Default endpoint URL for new streams?",
33190
33199
  choices: [
33191
33200
  { name: `Internal test server (${internalUrl})`, value: "internal" },
33192
33201
  { name: "Custom URL...", value: "custom" }
@@ -33196,8 +33205,8 @@ async function promptWebhookUrl(config) {
33196
33205
  return internalUrl;
33197
33206
  }
33198
33207
  const customUrl = await input({
33199
- message: "Enter webhook URL:",
33200
- default: config.defaultWebhookUrl !== internalUrl ? config.defaultWebhookUrl : undefined,
33208
+ message: "Enter endpoint URL:",
33209
+ default: config.defaultEndpointUrl !== internalUrl ? config.defaultEndpointUrl : undefined,
33201
33210
  validate: (value) => {
33202
33211
  if (!value.trim())
33203
33212
  return "URL cannot be empty";
@@ -33295,8 +33304,8 @@ function printSummary(config) {
33295
33304
  console.log();
33296
33305
  console.log(" Settings:");
33297
33306
  console.log(` Data directory: ${config.dataDir}`);
33298
- if (config.defaultWebhookUrl) {
33299
- console.log(` Webhook URL: ${config.defaultWebhookUrl}`);
33307
+ if (config.defaultEndpointUrl) {
33308
+ console.log(` Endpoint URL: ${config.defaultEndpointUrl}`);
33300
33309
  }
33301
33310
  if (config.node) {
33302
33311
  console.log(` Node path: ${config.node.installPath}`);
@@ -33345,10 +33354,10 @@ function printNodeInfo(node) {
33345
33354
  import { join as join3 } from "node:path";
33346
33355
 
33347
33356
  // src/templates/stream.ts
33348
- function generateStreamTemplate(name, webhookUrl) {
33357
+ function generateStreamTemplate(name, endpointUrl) {
33349
33358
  return {
33350
33359
  name,
33351
- webhookUrl: webhookUrl || "https://example.com/webhook",
33360
+ endpointUrl: endpointUrl || "https://example.com/endpoint",
33352
33361
  filters: [
33353
33362
  {
33354
33363
  type: "contract_call",
@@ -33384,12 +33393,12 @@ function registerNewCommand(program2) {
33384
33393
  if (dir) {
33385
33394
  await ensureDir(dir);
33386
33395
  }
33387
- const template = generateStreamTemplate(name, config.defaultWebhookUrl);
33396
+ const template = generateStreamTemplate(name, config.defaultEndpointUrl);
33388
33397
  await writeTextFile(outputPath, JSON.stringify(template, null, 2) + `
33389
33398
  `);
33390
33399
  success(`Created ${outputPath}`);
33391
- if (!config.defaultWebhookUrl) {
33392
- warn("Edit the webhookUrl before registering — it must be a reachable HTTPS endpoint");
33400
+ if (!config.defaultEndpointUrl) {
33401
+ warn("Edit the endpointUrl before registering — it must be a reachable HTTPS endpoint");
33393
33402
  }
33394
33403
  console.log(`
33395
33404
  Edit the file to configure your stream, then run:`);
@@ -33452,7 +33461,7 @@ function registerGetCommand(program2) {
33452
33461
  ["ID", stream.id],
33453
33462
  ["Name", stream.name],
33454
33463
  ["Status", statusColor(stream.status)],
33455
- ["Webhook URL", stream.webhookUrl],
33464
+ ["Endpoint URL", stream.endpointUrl],
33456
33465
  ["Total Deliveries", stream.totalDeliveries.toString()],
33457
33466
  ["Failed Deliveries", stream.failedDeliveries.toString()],
33458
33467
  ["Last Triggered", stream.lastTriggeredAt || dim("never")],
@@ -33520,10 +33529,10 @@ function registerRegisterCommand(program2) {
33520
33529
  console.log(formatKeyValue([
33521
33530
  ["ID", result.stream.id],
33522
33531
  ["Name", result.stream.name],
33523
- ["Webhook Secret", result.webhookSecret]
33532
+ ["Signing Secret", result.signingSecret]
33524
33533
  ]));
33525
33534
  console.log(dim(`
33526
- Save the webhook secret - it won't be shown again!`));
33535
+ Save the signing secret - it won't be shown again!`));
33527
33536
  } catch (err) {
33528
33537
  handleApiError(err, "register stream");
33529
33538
  }
@@ -34019,12 +34028,12 @@ init_api_client();
34019
34028
  init_output();
34020
34029
  import { confirm as confirm3 } from "@inquirer/prompts";
34021
34030
  function registerRotateSecretCommand(program2) {
34022
- program2.command("rotate-secret <id>").description("Generate a new webhook secret for a stream").option("-y, --yes", "Skip confirmation prompt").action(async (id, options) => {
34031
+ program2.command("rotate-secret <id>").description("Generate a new signing secret for a stream").option("-y, --yes", "Skip confirmation prompt").action(async (id, options) => {
34023
34032
  try {
34024
34033
  const stream = await getStream(id);
34025
34034
  if (!options.yes) {
34026
34035
  const confirmed = await confirm3({
34027
- message: `Rotate webhook secret for "${stream.name}"? The current secret will be invalidated.`,
34036
+ message: `Rotate signing secret for "${stream.name}"? The current secret will be invalidated.`,
34028
34037
  default: false
34029
34038
  });
34030
34039
  if (!confirmed) {
@@ -34033,13 +34042,13 @@ function registerRotateSecretCommand(program2) {
34033
34042
  }
34034
34043
  }
34035
34044
  const result = await rotateSecret(stream.id);
34036
- success(`Rotated webhook secret for: ${stream.name}`);
34045
+ success(`Rotated signing secret for: ${stream.name}`);
34037
34046
  console.log(formatKeyValue([
34038
34047
  ["Stream", stream.name],
34039
- ["Webhook Secret", result.secret]
34048
+ ["Signing Secret", result.secret]
34040
34049
  ]));
34041
34050
  console.log(dim(`
34042
- Save the webhook secret - it won't be shown again!`));
34051
+ Save the signing secret - it won't be shown again!`));
34043
34052
  } catch (err) {
34044
34053
  handleApiError(err, "rotate secret");
34045
34054
  }
@@ -34722,15 +34731,15 @@ async function resyncDatabase(skipConfirm, backfill) {
34722
34731
  process.exit(1);
34723
34732
  }
34724
34733
  }
34725
- // src/commands/webhook.ts
34734
+ // src/commands/receiver.ts
34726
34735
  init_output();
34727
34736
  init_config();
34728
34737
  import { join as join5 } from "node:path";
34729
- function registerWebhookCommand(program2) {
34730
- const webhook = program2.command("webhook").description("Webhook development tools").hook("preAction", async () => {
34738
+ function registerReceiverCommand(program2) {
34739
+ const receiver = program2.command("receiver").description("Receiver development tools").hook("preAction", async () => {
34731
34740
  await requireLocalNetwork();
34732
34741
  });
34733
- webhook.command("init <directory>").description("Scaffold a webhook handler with types and signature verification").option("-n, --name <name>", "Stream name", "my-stream").option("--network <network>", "Network (mainnet/testnet)", "mainnet").option("-p, --port <port>", "Server port", "4000").action(async (directory, options) => {
34742
+ receiver.command("init <directory>").description("Scaffold a receiver handler with types and signature verification").option("-n, --name <name>", "Stream name", "my-stream").option("--network <network>", "Network (mainnet/testnet)", "mainnet").option("-p, --port <port>", "Server port", "4000").action(async (directory, options) => {
34734
34743
  try {
34735
34744
  const config = await loadConfig();
34736
34745
  const port = parseInt(options.port);
@@ -34744,13 +34753,13 @@ function registerWebhookCommand(program2) {
34744
34753
  await Bun.$`mkdir -p ${dir}`.quiet();
34745
34754
  await generateServerFile(dir, port);
34746
34755
  await generateTypesFile(dir);
34747
- await generateStreamJson(dir, options.name, network, port, config.defaultWebhookUrl);
34756
+ await generateStreamJson(dir, options.name, network, port, config.defaultEndpointUrl);
34748
34757
  await generateEnvFile(dir);
34749
34758
  await generatePackageJson(dir, options.name);
34750
- success(`Created webhook handler in ${directory}/`);
34759
+ success(`Created receiver handler in ${directory}/`);
34751
34760
  console.log("");
34752
34761
  console.log(" Files created:");
34753
- console.log(` ${dim("server.ts")} Webhook server with HMAC verification`);
34762
+ console.log(` ${dim("server.ts")} Receiver server with HMAC verification`);
34754
34763
  console.log(` ${dim("types.ts")} Payload type definitions`);
34755
34764
  console.log(` ${dim("stream.json")} Stream configuration`);
34756
34765
  console.log(` ${dim(".env")} Environment variables`);
@@ -34765,26 +34774,26 @@ function registerWebhookCommand(program2) {
34765
34774
  console.log(` sl streams register ${directory}/stream.json`);
34766
34775
  console.log("");
34767
34776
  } catch (err) {
34768
- error(`Failed to scaffold webhook: ${err}`);
34777
+ error(`Failed to scaffold receiver: ${err}`);
34769
34778
  process.exit(1);
34770
34779
  }
34771
34780
  });
34772
34781
  }
34773
34782
  async function generateServerFile(dir, port) {
34774
- const content = `import type { WebhookPayload } from "./types.ts";
34783
+ const content = `import type { DeliveryPayload } from "./types.ts";
34775
34784
 
34776
- const WEBHOOK_SECRET = process.env.STREAMS_WEBHOOK_SECRET;
34785
+ const SIGNING_SECRET = process.env.STREAMS_SIGNING_SECRET;
34777
34786
 
34778
34787
  /**
34779
34788
  * Verify HMAC signature from Stacks Streams
34780
34789
  */
34781
34790
  async function verifySignature(body: string, signature: string | null): Promise<boolean> {
34782
- if (!WEBHOOK_SECRET || !signature) return false;
34791
+ if (!SIGNING_SECRET || !signature) return false;
34783
34792
 
34784
34793
  const encoder = new TextEncoder();
34785
34794
  const key = await crypto.subtle.importKey(
34786
34795
  "raw",
34787
- encoder.encode(WEBHOOK_SECRET),
34796
+ encoder.encode(SIGNING_SECRET),
34788
34797
  { name: "HMAC", hash: "SHA-256" },
34789
34798
  false,
34790
34799
  ["sign"]
@@ -34797,9 +34806,9 @@ async function verifySignature(body: string, signature: string | null): Promise<
34797
34806
  }
34798
34807
 
34799
34808
  /**
34800
- * Handle incoming webhook payload
34809
+ * Handle incoming delivery payload
34801
34810
  */
34802
- async function handlePayload(payload: WebhookPayload): Promise<void> {
34811
+ async function handlePayload(payload: DeliveryPayload): Promise<void> {
34803
34812
  console.log(\`Block \${payload.block.height}: \${payload.matches.events.length} events\`);
34804
34813
 
34805
34814
  for (const event of payload.matches.events) {
@@ -34838,13 +34847,13 @@ Bun.serve({
34838
34847
  return new Response("ok");
34839
34848
  }
34840
34849
 
34841
- // Webhook endpoint
34850
+ // Receiver endpoint
34842
34851
  if (req.method === "POST" && url.pathname === "/payload") {
34843
34852
  const body = await req.text();
34844
34853
  const signature = req.headers.get("x-streams-signature");
34845
34854
 
34846
34855
  // Verify signature
34847
- if (WEBHOOK_SECRET) {
34856
+ if (SIGNING_SECRET) {
34848
34857
  const valid = await verifySignature(body, signature);
34849
34858
  if (!valid) {
34850
34859
  console.error("Invalid signature");
@@ -34853,7 +34862,7 @@ Bun.serve({
34853
34862
  }
34854
34863
 
34855
34864
  try {
34856
- const payload: WebhookPayload = JSON.parse(body);
34865
+ const payload: DeliveryPayload = JSON.parse(body);
34857
34866
  await handlePayload(payload);
34858
34867
  return new Response("ok");
34859
34868
  } catch (err) {
@@ -34866,18 +34875,18 @@ Bun.serve({
34866
34875
  },
34867
34876
  });
34868
34877
 
34869
- console.log(\`Webhook server listening on http://localhost:${port}/payload\`);
34878
+ console.log(\`Receiver server listening on http://localhost:${port}/payload\`);
34870
34879
  `;
34871
34880
  await Bun.write(join5(dir, "server.ts"), content);
34872
34881
  }
34873
34882
  async function generateTypesFile(dir) {
34874
34883
  const content = `/**
34875
- * Stacks Streams Webhook Payload Types
34884
+ * Stacks Streams Delivery Payload Types
34876
34885
  *
34877
34886
  * These types match the payload structure sent by Stacks Streams.
34878
34887
  */
34879
34888
 
34880
- export interface WebhookPayload {
34889
+ export interface DeliveryPayload {
34881
34890
  streamId: string;
34882
34891
  streamName: string;
34883
34892
  network: "mainnet" | "testnet";
@@ -34999,11 +35008,11 @@ export function isPrintEvent(event: EventMatch): event is PrintEvent {
34999
35008
  `;
35000
35009
  await Bun.write(join5(dir, "types.ts"), content);
35001
35010
  }
35002
- async function generateStreamJson(dir, name, network, port, _defaultWebhookUrl) {
35011
+ async function generateStreamJson(dir, name, network, port, _defaultEndpointUrl) {
35003
35012
  const content = {
35004
35013
  name,
35005
35014
  network,
35006
- webhookUrl: `http://localhost:${port}/payload`,
35015
+ endpointUrl: `http://localhost:${port}/payload`,
35007
35016
  filters: [
35008
35017
  {
35009
35018
  type: "stx_transfer",
@@ -35023,9 +35032,9 @@ async function generateStreamJson(dir, name, network, port, _defaultWebhookUrl)
35023
35032
  `);
35024
35033
  }
35025
35034
  async function generateEnvFile(dir) {
35026
- const content = `# Stacks Streams Webhook Secret
35035
+ const content = `# Stacks Streams Signing Secret
35027
35036
  # Get this from: sl streams register stream.json
35028
- STREAMS_WEBHOOK_SECRET=
35037
+ STREAMS_SIGNING_SECRET=
35029
35038
 
35030
35039
  # Add your database connection, etc.
35031
35040
  # DATABASE_URL=postgres://...
@@ -35034,7 +35043,7 @@ STREAMS_WEBHOOK_SECRET=
35034
35043
  }
35035
35044
  async function generatePackageJson(dir, name) {
35036
35045
  const content = {
35037
- name: `${name}-webhook`,
35046
+ name: `${name}-receiver`,
35038
35047
  version: "0.1.0",
35039
35048
  type: "module",
35040
35049
  scripts: {
@@ -35587,9 +35596,10 @@ ${rows.length} row(s)`));
35587
35596
  }
35588
35597
  const outPath = resolve(options2.output);
35589
35598
  const network = inferNetwork(contractAddress) ?? "mainnet";
35599
+ const config = await loadConfig();
35590
35600
  const apiKey = options2.apiKey ?? process.env.HIRO_API_KEY;
35591
35601
  info(`Fetching ABI for ${contractAddress}...`);
35592
- const client = new StacksApiClient(network, apiKey);
35602
+ const client = new StacksApiClient(network, apiKey, config.nodeRpcUrl);
35593
35603
  const contractInfo = await client.getContractInfo(contractAddress);
35594
35604
  const abi = parseApiResponse(contractInfo);
35595
35605
  info(`Generating scaffold...`);
@@ -35941,7 +35951,7 @@ async function checkHealth() {
35941
35951
  const portsToCheck = [
35942
35952
  { port: config.ports.api, name: "API" },
35943
35953
  { port: config.ports.indexer, name: "Indexer" },
35944
- { port: config.ports.webhook, name: "Webhook" },
35954
+ { port: config.ports.receiver, name: "Receiver" },
35945
35955
  { port: 20443, name: "Node RPC" }
35946
35956
  ];
35947
35957
  for (const { port, name } of portsToCheck) {
@@ -36413,14 +36423,14 @@ init_config();
36413
36423
  init_dev_state();
36414
36424
  init_node_manager();
36415
36425
  init_output();
36416
- var DEV_SERVICES = ["api", "indexer", "worker", "webhook", "subgraphs"];
36426
+ var DEV_SERVICES = ["api", "indexer", "worker", "receiver", "subgraphs"];
36417
36427
  function registerLocalCommand(program2) {
36418
36428
  const local = program2.command("local").description("Manage local development environment and Stacks node").hook("preAction", async (_thisCommand, actionCommand) => {
36419
36429
  if (actionCommand.name() === "help")
36420
36430
  return;
36421
36431
  await requireLocalNetwork();
36422
36432
  });
36423
- local.command("start").description("Start all local dev services (API, indexer, worker, webhook)").option("--indexer-port <port>", "Indexer port", "3700").option("--api-port <port>", "API port", "3800").option("--webhook-port <port>", "Test webhook server port", "3900").option("--no-webhook", "Skip test webhook server").option("--no-worker", "Skip worker service").option("--secret <secret>", "Webhook secret for signature verification").option("--stacks-node", "Use port 3701 for indexer (avoids conflict with stacks-blockchain-api)").option("-f, --foreground", "Run in foreground (blocking)").action(async (options2) => {
36433
+ local.command("start").description("Start all local dev services (API, indexer, worker, receiver)").option("--indexer-port <port>", "Indexer port", "3700").option("--api-port <port>", "API port", "3800").option("--receiver-port <port>", "Test receiver server port", "3900").option("--no-receiver", "Skip test receiver server").option("--no-worker", "Skip worker service").option("--secret <secret>", "Signing secret for signature verification").option("--stacks-node", "Use port 3701 for indexer (avoids conflict with stacks-blockchain-api)").option("-f, --foreground", "Run in foreground (blocking)").action(async (options2) => {
36424
36434
  const { runBackground: runBackground2, runForeground: runForeground2, isDevAlreadyRunning: isDevAlreadyRunning2 } = await Promise.resolve().then(() => (init_dev_impl(), exports_dev_impl));
36425
36435
  if (await isDevAlreadyRunning2()) {
36426
36436
  return;
@@ -36442,7 +36452,7 @@ function registerLocalCommand(program2) {
36442
36452
  local.command("status").description("Show local environment status").action(async () => {
36443
36453
  await showLocalStatus();
36444
36454
  });
36445
- local.command("logs").description("View local service logs (dev + node)").option("-s, --service <name>", "Filter by service (api, indexer, worker, webhook, subgraphs, node)").option("-f, --follow", "Follow log output").option("-n, --lines <n>", "Number of lines to show", "50").option("-q, --quiet", "Filter out common noise").option("-v, --verbose", "Show full payloads").action(async (options2) => {
36455
+ local.command("logs").description("View local service logs (dev + node)").option("-s, --service <name>", "Filter by service (api, indexer, worker, receiver, subgraphs, node)").option("-f, --follow", "Follow log output").option("-n, --lines <n>", "Number of lines to show", "50").option("-q, --quiet", "Filter out common noise").option("-v, --verbose", "Show full payloads").action(async (options2) => {
36446
36456
  await showLocalLogs(options2);
36447
36457
  });
36448
36458
  const node = local.command("node").description("Manage local Stacks node");
@@ -36519,7 +36529,7 @@ var serviceColors2 = {
36519
36529
  indexer: cyan,
36520
36530
  worker: yellow,
36521
36531
  subgraphs: magenta,
36522
- webhook: green,
36532
+ receiver: green,
36523
36533
  node: red
36524
36534
  };
36525
36535
  async function showLocalLogs(options2) {
@@ -36671,17 +36681,17 @@ function formatLogLine3(service, line, verbose) {
36671
36681
  return `${prefix} ${dimTimestamp} ${dim(level + ":")} ${dim(message)}`;
36672
36682
  }
36673
36683
  }
36674
- if (service === "webhook" && !verbose) {
36675
- const summary = formatWebhookSummary2(line);
36684
+ if (service === "receiver" && !verbose) {
36685
+ const summary = formatDeliverySummary2(line);
36676
36686
  if (summary)
36677
36687
  return `${prefix} ${summary}`;
36678
36688
  }
36679
36689
  return `${prefix} ${line}`;
36680
36690
  }
36681
- function formatWebhookSummary2(jsonStr) {
36691
+ function formatDeliverySummary2(jsonStr) {
36682
36692
  try {
36683
36693
  const data = JSON.parse(jsonStr);
36684
- if (data.type !== "webhook" || !data.body)
36694
+ if (data.type !== "delivery" || !data.body)
36685
36695
  return null;
36686
36696
  const { body, method, path, timestamp } = data;
36687
36697
  const streamName = body.streamName ?? body.streamId?.slice(0, 8) ?? "unknown";
@@ -36765,8 +36775,8 @@ registerSetupCommand(program);
36765
36775
  registerConfigCommand(program);
36766
36776
  registerAuthCommand(program);
36767
36777
  registerWhoamiCommand(program);
36768
- registerWebhookCommand(program);
36778
+ registerReceiverCommand(program);
36769
36779
  program.parse();
36770
36780
 
36771
- //# debugId=2320C06E5C8D182A64756E2164756E21
36781
+ //# debugId=9817C710C5B4B19A64756E2164756E21
36772
36782
  //# sourceMappingURL=cli.js.map