@secondlayer/cli 19.4.2 → 20.0.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
@@ -29360,11 +29360,10 @@ function parseFilterArg(input) {
29360
29360
  return {
29361
29361
  field,
29362
29362
  operator,
29363
- value,
29364
- explicitOperator: true
29363
+ value
29365
29364
  };
29366
29365
  }
29367
- return { field: key, operator: "eq", value, explicitOperator: false };
29366
+ return { field: key, operator: "eq", value };
29368
29367
  }
29369
29368
  function parseFilterArgs(args) {
29370
29369
  return (args ?? []).map(parseFilterArg);
@@ -29377,25 +29376,6 @@ function parseQueryFilters(args) {
29377
29376
  }
29378
29377
  return Object.keys(filters).length > 0 ? filters : undefined;
29379
29378
  }
29380
- function parseWebhookFilter(args) {
29381
- const filters = {};
29382
- const seenFields = new Set;
29383
- for (const filter of parseFilterArgs(args)) {
29384
- if (filter.operator === "like") {
29385
- throw new Error(`Webhook filters do not support ".like". Supported operators: ${FILTER_OPERATORS.join(", ")}.`);
29386
- }
29387
- if (seenFields.has(filter.field)) {
29388
- throw new Error(`Webhook filters support one condition per field; got multiple filters for "${filter.field}".`);
29389
- }
29390
- seenFields.add(filter.field);
29391
- if (!filter.explicitOperator || filter.operator === "eq") {
29392
- filters[filter.field] = filter.value;
29393
- } else {
29394
- filters[filter.field] = { [filter.operator]: filter.value };
29395
- }
29396
- }
29397
- return Object.keys(filters).length > 0 ? filters : undefined;
29398
- }
29399
29379
  var FILTER_OPERATORS, QUERY_ONLY_OPERATORS, ALL_OPERATORS, ALL_OPERATOR_LABELS;
29400
29380
  var init_filter_params = __esm(() => {
29401
29381
  FILTER_OPERATORS = ["eq", "neq", "gt", "gte", "lt", "lte"];
@@ -198809,11 +198789,6 @@ import {
198809
198789
  deriveVerification as deriveVerification2,
198810
198790
  isDeterminismViolation
198811
198791
  } from "@secondlayer/subgraphs/verification";
198812
- function webhookHint(apiUrl, name, firstTable) {
198813
- if (!firstTable || isMerchantUrl(apiUrl))
198814
- return null;
198815
- return `secondlayer webhooks create ${name}-hook --subgraph ${name} --table ${firstTable} --url <your-endpoint>`;
198816
- }
198817
198792
  async function loadSubgraphWithDepCheck(absPath) {
198818
198793
  try {
198819
198794
  return await import(absPath);
@@ -199604,9 +199579,6 @@ deploy does not backfill from genesis.`).action(async (file, options) => {
199604
199579
  info(` Reindex: ${denom} started in the background — check status in ~30s for an ETA`);
199605
199580
  }
199606
199581
  info(` Watch: secondlayer subgraphs status ${effectiveDef.name}`);
199607
- const hint = webhookHint(apiUrl, effectiveDef.name, firstTable);
199608
- if (hint)
199609
- info(` Webhook: ${hint}`);
199610
199582
  } catch {}
199611
199583
  };
199612
199584
  if (result.action === "unchanged") {
@@ -200273,7 +200245,6 @@ var init_subgraphs2 = __esm(() => {
200273
200245
  init_subgraphs();
200274
200246
  init_api_client();
200275
200247
  init_derive_abi();
200276
- init_api_url();
200277
200248
  init_config2();
200278
200249
  init_filter_params();
200279
200250
  init_fs();
@@ -202507,7 +202478,7 @@ var init_src = __esm(() => {
202507
202478
 
202508
202479
  // src/lib/dev-state.ts
202509
202480
  import { homedir as homedir4 } from "node:os";
202510
- import { join as join13 } from "node:path";
202481
+ import { join as join12 } from "node:path";
202511
202482
  function getLogsDir() {
202512
202483
  return LOGS_DIR;
202513
202484
  }
@@ -202532,9 +202503,9 @@ function isProcessRunning(pid) {
202532
202503
  }
202533
202504
  var STATE_DIR, DEV_STATE_PATH, LOGS_DIR;
202534
202505
  var init_dev_state = __esm(() => {
202535
- STATE_DIR = join13(homedir4(), ".secondlayer");
202536
- DEV_STATE_PATH = join13(STATE_DIR, "dev.json");
202537
- LOGS_DIR = join13(STATE_DIR, "logs");
202506
+ STATE_DIR = join12(homedir4(), ".secondlayer");
202507
+ DEV_STATE_PATH = join12(STATE_DIR, "dev.json");
202508
+ LOGS_DIR = join12(STATE_DIR, "logs");
202538
202509
  });
202539
202510
 
202540
202511
  // ../../node_modules/commander/index.js
@@ -202598,7 +202569,7 @@ var {
202598
202569
  // package.json
202599
202570
  var package_default = {
202600
202571
  name: "@secondlayer/cli",
202601
- version: "19.4.2",
202572
+ version: "20.0.0",
202602
202573
  description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
202603
202574
  repository: {
202604
202575
  type: "git",
@@ -202619,7 +202590,7 @@ var package_default = {
202619
202590
  import: "./dist/index.js"
202620
202591
  }
202621
202592
  },
202622
- files: ["dist", "templates", "README.md"],
202593
+ files: ["dist", "README.md"],
202623
202594
  scripts: {
202624
202595
  build: "bunup",
202625
202596
  dev: "bunup --watch",
@@ -202635,15 +202606,15 @@ var package_default = {
202635
202606
  "@biomejs/wasm-nodejs": "^1.9.0",
202636
202607
  "@dsnp/parquetjs": "~1.8.8",
202637
202608
  "@inquirer/prompts": "^8.2.0",
202638
- "@secondlayer/bundler": "^0.7.0",
202639
- "@secondlayer/scaffold": "^1.6.1",
202640
- "@secondlayer/sdk": "^14.5.1",
202641
- "@secondlayer/shared": "^11.24.1",
202609
+ "@secondlayer/bundler": "^0.7.1",
202610
+ "@secondlayer/scaffold": "^1.6.2",
202611
+ "@secondlayer/sdk": "^15.0.0",
202612
+ "@secondlayer/shared": "^12.0.0",
202642
202613
  "@secondlayer/stacks": "^6.2.0",
202643
- "@secondlayer/subgraphs": "^6.5.0",
202644
- "@secondlayer/verify": "^0.3.0",
202614
+ "@secondlayer/subgraphs": "^7.0.0",
202615
+ "@secondlayer/verify": "^0.4.0",
202645
202616
  esbuild: "^0.28.2",
202646
- "smol-toml": "^1.8.0",
202617
+ "smol-toml": "^1.9.1",
202647
202618
  zod: "^4.3.6"
202648
202619
  },
202649
202620
  peerDependencies: {
@@ -204121,7 +204092,7 @@ async function readCheckpoint(path) {
204121
204092
  function defaultSource(node) {
204122
204093
  const api = new SecondlayerProofSource({
204123
204094
  baseUrl: resolveApiUrl(),
204124
- apiKey: resolveDataPlaneKey() ?? ""
204095
+ apiKey: resolveDataPlaneKey()
204125
204096
  });
204126
204097
  return node ? { ...api, ...new NodeRpcProofSource({ nodeUrl: node }) } : api;
204127
204098
  }
@@ -204335,13 +204306,13 @@ function parseHeight2(raw, flag) {
204335
204306
  throw new InputError(`${flag} must be a block height, got "${raw}"`);
204336
204307
  return Number(raw);
204337
204308
  }
204338
- async function readTable(fetchRows, name, table) {
204309
+ async function readTable(fetchRows, name, table, pageSize = PAGE) {
204339
204310
  const out = [];
204340
204311
  let cursor;
204341
204312
  for (;; ) {
204342
204313
  const page = await fetchRows(name, table, cursor);
204343
204314
  out.push(...page.rows);
204344
- if (!page.next_cursor || page.rows.length === 0)
204315
+ if (!page.next_cursor || page.rows.length < pageSize)
204345
204316
  return out;
204346
204317
  cursor = page.next_cursor;
204347
204318
  }
@@ -205574,84 +205545,19 @@ function printPublicStatus(status, diagnosis) {
205574
205545
  }
205575
205546
  // src/commands/webhooks.ts
205576
205547
  init_api_client();
205577
- init_filter_params();
205578
205548
  init_output();
205579
205549
  init_resolve_auth();
205580
205550
  import { buildDoctorReport, isSuccessDelivery } from "@secondlayer/sdk";
205581
205551
  import { sign } from "@secondlayer/shared/crypto/standard-webhooks";
205582
205552
 
205583
- // src/lib/webhook-validation.ts
205584
- import {
205585
- validateWebhookFilterForTable
205586
- } from "@secondlayer/shared/schemas/webhooks";
205587
- async function validateWebhookTargetFromApi(client, input) {
205588
- const subgraph = await client.subgraphs.status(input.subgraphName);
205589
- const errors = validateWebhookFilterForTable({
205590
- subgraphName: input.subgraphName,
205591
- tableName: input.tableName,
205592
- filter: input.filter,
205593
- tables: subgraph.tables
205594
- });
205595
- if (errors.length > 0) {
205596
- throw new Error(errors.join(`
205597
- `));
205598
- }
205599
- }
205600
-
205601
205553
  // src/commands/create.ts
205602
- init_filter_params();
205603
205554
  init_output();
205604
205555
  init_resolve_auth();
205605
- import {
205606
- chmodSync,
205607
- copyFileSync,
205608
- existsSync as existsSync5,
205609
- mkdirSync as mkdirSync3,
205610
- readFileSync as readFileSync5,
205611
- readdirSync,
205612
- statSync as statSync2,
205613
- writeFileSync as writeFileSync4
205614
- } from "node:fs";
205615
- import { dirname as dirname6, join as join9, relative as relative2, resolve as resolve7 } from "node:path";
205616
- import { fileURLToPath as fileURLToPath4 } from "node:url";
205617
- import { input, select as select3 } from "@inquirer/prompts";
205556
+ import { readFileSync as readFileSync5 } from "node:fs";
205618
205557
  import { SecondLayer as SecondLayer4 } from "@secondlayer/sdk";
205619
205558
  import {
205620
205559
  ChainTriggerSchema
205621
205560
  } from "@secondlayer/shared/schemas/webhooks";
205622
- var RUNTIMES = ["inngest", "trigger", "cloudflare", "node"];
205623
- var FORMAT_BY_RUNTIME = {
205624
- inngest: "inngest",
205625
- trigger: "trigger",
205626
- cloudflare: "cloudflare",
205627
- node: "standard-webhooks"
205628
- };
205629
- function templatesRoot() {
205630
- const here = dirname6(fileURLToPath4(import.meta.url));
205631
- const candidateDist = resolve7(here, "..", "templates", "webhooks");
205632
- if (existsSync5(candidateDist))
205633
- return candidateDist;
205634
- return resolve7(here, "..", "..", "templates", "webhooks");
205635
- }
205636
- function copyTemplate(src, dest, vars) {
205637
- if (!existsSync5(src)) {
205638
- throw new Error(`template dir missing: ${src}`);
205639
- }
205640
- mkdirSync3(dest, { recursive: true });
205641
- const entries = readdirSync(src);
205642
- for (const entry of entries) {
205643
- const from = join9(src, entry);
205644
- const to = join9(dest, entry);
205645
- const st = statSync2(from);
205646
- if (st.isDirectory()) {
205647
- copyTemplate(from, to, vars);
205648
- } else {
205649
- const raw = readFileSync5(from, "utf8");
205650
- const rendered = raw.replace(/\{\{([A-Z_]+)\}\}/g, (match, key) => vars[key] ?? match);
205651
- writeFileSync4(to, rendered);
205652
- }
205653
- }
205654
- }
205655
205561
  function parseTriggersInput(opts) {
205656
205562
  const raw = [];
205657
205563
  if (opts.triggersFile) {
@@ -205684,53 +205590,6 @@ function parseTriggersInput(opts) {
205684
205590
  return result.data;
205685
205591
  });
205686
205592
  }
205687
- function resolveRuntime(opts) {
205688
- if (opts.runtime)
205689
- return opts.runtime;
205690
- const scripted = opts.subgraph !== undefined || opts.table !== undefined || opts.url !== undefined || opts.scaffold === false;
205691
- return scripted ? "node" : undefined;
205692
- }
205693
- function requireTtyFor(flag) {
205694
- if (process.stdin.isTTY)
205695
- return;
205696
- error(`${flag} is required when stdin is not a TTY (no prompt can run). Pass it, or run from a terminal.`);
205697
- process.exit(1);
205698
- }
205699
- async function promptFor(_name, opts) {
205700
- let runtime = resolveRuntime(opts);
205701
- if (runtime === undefined) {
205702
- requireTtyFor("--runtime");
205703
- runtime = await select3({
205704
- message: "Runtime?",
205705
- choices: RUNTIMES.map((r) => ({ name: r, value: r }))
205706
- });
205707
- }
205708
- let subgraph = opts.subgraph;
205709
- if (subgraph === undefined) {
205710
- requireTtyFor("--subgraph");
205711
- subgraph = await input({
205712
- message: "Subgraph name (must already be deployed):",
205713
- validate: (v) => v.trim().length > 0 ? true : "required"
205714
- });
205715
- }
205716
- let table = opts.table;
205717
- if (table === undefined) {
205718
- requireTtyFor("--table");
205719
- table = await input({
205720
- message: "Table to subscribe to:",
205721
- validate: (v) => v.trim().length > 0 ? true : "required"
205722
- });
205723
- }
205724
- let url = opts.url;
205725
- if (url === undefined) {
205726
- requireTtyFor("--url");
205727
- url = await input({
205728
- message: runtime === "inngest" ? "Inngest event endpoint URL (e.g. https://inn.gs/e/<KEY> or http://localhost:8288/e/<KEY>):" : runtime === "trigger" ? "Trigger.dev task URL (e.g. https://api.trigger.dev/api/v1/tasks/<TASK_ID>/trigger):" : runtime === "cloudflare" ? "Cloudflare Workflows instances URL:" : "Your HTTP receiver URL (e.g. https://yourapp.example/webhook):",
205729
- validate: (v) => v.startsWith("http://") || v.startsWith("https://") ? true : "must be http(s) URL"
205730
- });
205731
- }
205732
- return { runtime, subgraph, table, url };
205733
- }
205734
205593
  function buildWebhookAuthConfig(authToken) {
205735
205594
  if (authToken === undefined)
205736
205595
  return;
@@ -205740,139 +205599,9 @@ function buildWebhookAuthConfig(authToken) {
205740
205599
  }
205741
205600
  return { authType: "bearer", token };
205742
205601
  }
205743
- function writeSigningSecretEnv(targetDir, signingSecret) {
205744
- const envTarget = join9(targetDir, ".env");
205745
- const envExample = join9(targetDir, ".env.example");
205746
- if (existsSync5(envExample) && !existsSync5(envTarget)) {
205747
- copyFileSync(envExample, envTarget);
205748
- chmodSync(envTarget, 384);
205749
- }
205750
- if (!existsSync5(envTarget)) {
205751
- writeFileSync4(envTarget, `SIGNING_SECRET=${signingSecret}
205752
- `, {
205753
- mode: 384
205754
- });
205755
- } else {
205756
- const cur = readFileSync5(envTarget, "utf8");
205757
- writeFileSync4(envTarget, cur.match(/^SIGNING_SECRET=/m) ? cur.replace(/^SIGNING_SECRET=.*/m, `SIGNING_SECRET=${signingSecret}`) : `${cur}
205758
- SIGNING_SECRET=${signingSecret}
205759
- `, { mode: 384 });
205760
- chmodSync(envTarget, 384);
205761
- }
205762
- return envTarget;
205763
- }
205764
- async function createWebhook(name, opts) {
205765
- if (opts.runtime && !RUNTIMES.includes(opts.runtime)) {
205766
- error(`Unknown --runtime "${opts.runtime}". Valid: ${RUNTIMES.join(", ")}`);
205767
- process.exit(1);
205768
- }
205769
- const { runtime, subgraph, table, url } = await promptFor(name, opts);
205770
- let filter;
205771
- let authConfig;
205772
- try {
205773
- filter = parseWebhookFilter(opts.filter);
205774
- authConfig = buildWebhookAuthConfig(opts.authToken);
205775
- } catch (err) {
205776
- error(err instanceof Error ? err.message : String(err));
205777
- process.exit(1);
205778
- }
205779
- let sl = null;
205780
- if (!opts.skipApi) {
205781
- try {
205782
- sl = await getWebhookClient();
205783
- await validateWebhookTargetFromApi(sl, {
205784
- subgraphName: subgraph,
205785
- tableName: table,
205786
- filter
205787
- });
205788
- } catch (err) {
205789
- error(err instanceof Error ? err.message : String(err));
205790
- process.exit(1);
205791
- }
205792
- }
205793
- const eventName = `${subgraph}.${table}.created`;
205794
- const targetDir = resolve7(process.cwd(), name);
205795
- if (opts.scaffold !== false) {
205796
- if (existsSync5(targetDir)) {
205797
- error(`Directory already exists: ${relative2(process.cwd(), targetDir)}`);
205798
- process.exit(1);
205799
- }
205800
- const tplRoot = templatesRoot();
205801
- const tplDir = join9(tplRoot, runtime);
205802
- info(`Scaffolding ${blue(runtime)} template at ${blue(targetDir)}`);
205803
- copyTemplate(tplDir, targetDir, {
205804
- NAME: name,
205805
- EVENT_NAME: eventName,
205806
- TASK_ID: `${subgraph}-${table}`
205807
- });
205808
- }
205809
- let signingSecret = null;
205810
- let provisioningFailed = false;
205811
- if (!opts.skipApi) {
205812
- try {
205813
- if (!sl)
205814
- sl = await getWebhookClient();
205815
- const res = await sl.webhooks.create({
205816
- name,
205817
- subgraphName: subgraph,
205818
- tableName: table,
205819
- url,
205820
- format: FORMAT_BY_RUNTIME[runtime],
205821
- runtime,
205822
- ...filter ? { filter } : {},
205823
- ...authConfig ? { authConfig } : {}
205824
- });
205825
- signingSecret = res.signingSecret;
205826
- success(`Webhook provisioned: ${blue(res.webhook.id)}`);
205827
- } catch (err) {
205828
- provisioningFailed = true;
205829
- warn(`Webhook provisioning failed: ${err instanceof Error ? err.message : String(err)}`);
205830
- info("Template copied, but the webhook was not created. Fix the API error, remove the template directory, and rerun.");
205831
- }
205832
- }
205833
- let webhookStatus;
205834
- if (sl) {
205835
- try {
205836
- const list = await sl.webhooks.list();
205837
- const rows = list.data ?? [];
205838
- const created = rows.find((s) => s.name === name);
205839
- webhookStatus = created?.status;
205840
- } catch {}
205841
- }
205842
- if (signingSecret && opts.scaffold !== false) {
205843
- const envTarget = writeSigningSecretEnv(targetDir, signingSecret);
205844
- success(`Signing secret written to ${relative2(process.cwd(), envTarget)}`);
205845
- } else if (signingSecret && opts.scaffold === false) {
205846
- info(`Signing secret (store securely): ${signingSecret}`);
205847
- }
205848
- console.log();
205849
- if (provisioningFailed) {
205850
- error("Webhook was not created.");
205851
- process.exit(1);
205852
- }
205853
- const pausedLine = webhookStatus === "paused" ? `Webhook is paused. Resume:
205854
- secondlayer webhooks resume ${name}
205855
- ` : "";
205856
- const runHint = opts.scaffold === false ? `View deliveries:
205857
- secondlayer webhooks get ${name}` : `cd ${name}
205858
- bun install
205859
- bun run dev`;
205860
- success(`Done. Next:
205861
- ${pausedLine}${runHint}`);
205862
- }
205863
205602
  async function createChainWebhook(name, opts) {
205864
- for (const [flag, value] of [
205865
- ["--subgraph", opts.subgraph],
205866
- ["--table", opts.table],
205867
- ["--runtime", opts.runtime]
205868
- ]) {
205869
- if (value !== undefined) {
205870
- error(`${flag} is not valid with --trigger/--triggers-file (chain mode)`);
205871
- process.exit(1);
205872
- }
205873
- }
205874
205603
  if (!opts.url) {
205875
- error("--url is required when creating a chain webhook");
205604
+ error("--url is required");
205876
205605
  process.exit(1);
205877
205606
  }
205878
205607
  let triggers;
@@ -205897,7 +205626,7 @@ async function createChainWebhook(name, opts) {
205897
205626
  });
205898
205627
  webhookId = res.webhook.id;
205899
205628
  signingSecret = res.signingSecret;
205900
- success(`Chain webhook provisioned: ${blue(webhookId)}`);
205629
+ success(`Webhook provisioned: ${blue(webhookId)}`);
205901
205630
  } catch (err) {
205902
205631
  error(`Webhook provisioning failed: ${err instanceof Error ? err.message : String(err)}`);
205903
205632
  process.exit(1);
@@ -205912,24 +205641,11 @@ async function getWebhookClient() {
205912
205641
  const { apiUrl, ephemeralKey } = await resolveHostedAuth();
205913
205642
  return new SecondLayer4({ baseUrl: apiUrl, apiKey: ephemeralKey });
205914
205643
  }
205915
- function addWebhookScaffold(parent, commandSpec, opts) {
205916
- parent.command(commandSpec).description(opts.description).option("-r, --runtime <runtime>", "inngest | trigger | cloudflare | node (default: node once -s/-t/-u or --no-scaffold is given; prompts only in a terminal with no flags)").option("-s, --subgraph <name>", "Subgraph to subscribe to").option("-t, --table <name>", "Table to subscribe to").option("-u, --url <url>", "Webhook URL").option("--auth-token <token>", "Bearer token for receiver API auth; a flag lands in shell history and ps, so set it in the receiver's env and pass it here only for a throwaway token").option("--filter <kv...>", "Filter as key=value (supports .eq/.neq/.gt/.gte/.lt/.lte suffixes)").option("--trigger <json...>", `Chain-webhook trigger as JSON (repeatable), e.g. '{"type":"sbtc_deposit"}'`).option("--triggers-file <path>", "Chain-webhook triggers as a JSON array file").option("--format <format>", "Chain mode delivery format (default standard-webhooks)").option("--skip-api", "Copy template only, don't call the API").option("--no-scaffold", "Skip the local runtime template directory (webhook-only setups)").addHelpText("after", `
205917
- Examples:
205918
- $ ${opts.examplePrefix} my-sub -s my-graph -t transfers -u https://example.com/webhook
205919
- $ ${opts.examplePrefix} my-sub -s my-graph -t balances -r inngest --filter amount.gte=1000
205920
- $ ${opts.examplePrefix} my-hook -u https://example.com/webhook --trigger '{"type":"sbtc_deposit"}'`).action(async (name, options) => {
205921
- if (options.trigger?.length || options.triggersFile) {
205922
- await createChainWebhook(name, options);
205923
- return;
205924
- }
205925
- await createWebhook(name, options);
205926
- });
205927
- }
205928
205644
  function addWebhooksCreateCommand(parent) {
205929
- addWebhookScaffold(parent, "create <name>", {
205930
- description: "Create a webhook receiver for a runtime",
205931
- examplePrefix: "secondlayer webhooks create"
205932
- });
205645
+ parent.command("create <name>").description("Create a webhook on raw chain events").option("-u, --url <url>", "Webhook URL").option("--auth-token <token>", "Bearer token for receiver API auth; a flag lands in shell history and ps, so set it in the receiver's env and pass it here only for a throwaway token").option("--trigger <json...>", `Chain trigger as JSON (repeatable), e.g. '{"type":"sbtc_deposit"}'`).option("--triggers-file <path>", "Chain triggers as a JSON array file").option("--format <format>", "Delivery format (default standard-webhooks)").addHelpText("after", `
205646
+ Examples:
205647
+ $ secondlayer webhooks create my-hook -u https://example.com/webhook --trigger '{"type":"sbtc_deposit"}'
205648
+ $ secondlayer webhooks create my-hook -u https://example.com/webhook --triggers-file triggers.json`).action(createChainWebhook);
205933
205649
  }
205934
205650
 
205935
205651
  // src/commands/webhooks.ts
@@ -205999,17 +205715,6 @@ function buildWebhookUpdatePatch(options) {
205999
205715
  if (options.format) {
206000
205716
  patch.format = options.format;
206001
205717
  }
206002
- if (options.runtime !== undefined) {
206003
- patch.runtime = options.runtime === "none" || options.runtime === "null" ? null : options.runtime;
206004
- }
206005
- if (options.clearFilter)
206006
- patch.filter = {};
206007
- if (options.filter) {
206008
- if (options.clearFilter) {
206009
- throw new Error("Use either --filter or --clear-filter, not both");
206010
- }
206011
- patch.filter = parseWebhookFilter(options.filter) ?? {};
206012
- }
206013
205718
  const maxRetries = parseIntegerOption(options.maxRetries, "--max-retries", 0);
206014
205719
  if (maxRetries !== undefined)
206015
205720
  patch.maxRetries = maxRetries;
@@ -206025,11 +205730,8 @@ function buildWebhookUpdatePatch(options) {
206025
205730
  return patch;
206026
205731
  }
206027
205732
  function formatWebhookTarget(sub) {
206028
- if (sub.kind === "chain") {
206029
- const types = sub.triggers?.map((t) => t.type);
206030
- return types && types.length > 0 ? `chain.${types.join(",")}` : "chain";
206031
- }
206032
- return `${sub.subgraphName}.${sub.tableName}`;
205733
+ const types = "triggers" in sub ? sub.triggers.map((t) => t.type) : [];
205734
+ return types.length > 0 ? `chain.${types.join(",")}` : "chain";
206033
205735
  }
206034
205736
  function formatAuthLine(auth) {
206035
205737
  const scheme = auth.type === "bearer" ? auth.hasSecret ? "bearer token (set, hidden)" : "bearer (no token set)" : auth.type === "basic" ? auth.hasSecret ? "basic auth (set, hidden)" : "basic (no credentials set)" : "none";
@@ -206042,7 +205744,6 @@ function printWebhookDetail(sub) {
206042
205744
  ["Status", sub.status],
206043
205745
  ["Target", formatWebhookTarget(sub)],
206044
205746
  ["Format", sub.format],
206045
- ["Runtime", sub.runtime ?? "none"],
206046
205747
  ["URL", sub.url],
206047
205748
  ["Auth", formatAuthLine(sub.auth)],
206048
205749
  ["Last Delivery", sub.lastDeliveryAt ?? "none"],
@@ -206058,8 +205759,8 @@ function printWebhookDetail(sub) {
206058
205759
  ["Updated", sub.updatedAt]
206059
205760
  ]));
206060
205761
  console.log(dim(`
206061
- Filter:`));
206062
- console.log(JSON.stringify(sub.filter, null, 2));
205762
+ Triggers:`));
205763
+ console.log(JSON.stringify(sub.triggers, null, 2));
206063
205764
  }
206064
205765
  var DOCTOR_ISSUE_TITLES = {
206065
205766
  warning: "This webhook can't fire yet",
@@ -206067,8 +205768,6 @@ var DOCTOR_ISSUE_TITLES = {
206067
205768
  last_error: "The last delivery failed",
206068
205769
  circuit: "Your receiver is failing",
206069
205770
  dead_letters: "Some events exhausted every retry",
206070
- subgraph_gaps: "The linked subgraph has gaps",
206071
- subgraph_catching_up: "The linked subgraph is still catching up",
206072
205771
  no_deliveries: "No deliveries yet",
206073
205772
  receiver_rate_limited: "Your receiver is rate-limiting us",
206074
205773
  receiver_down: "Your receiver looks down",
@@ -206100,7 +205799,6 @@ function formatDoctorReport(report) {
206100
205799
  ["Status", sub.status],
206101
205800
  ["Target", formatWebhookTarget(sub)],
206102
205801
  ["Format", sub.format],
206103
- ["Runtime", sub.runtime ?? "none"],
206104
205802
  ["URL", sub.url],
206105
205803
  [
206106
205804
  "Circuit",
@@ -206126,24 +205824,6 @@ Delivery summary:`),
206126
205824
  ].join(`
206127
205825
  `)
206128
205826
  ];
206129
- if (report.subgraph) {
206130
- sections.push([
206131
- dim(`
206132
- Linked subgraph:`),
206133
- formatKeyValue([
206134
- ["Name", report.subgraph.name],
206135
- ["Status", report.subgraph.status],
206136
- ["Sync", report.subgraph.syncStatus],
206137
- [
206138
- "Blocks",
206139
- `${report.subgraph.lastProcessedBlock} / ${report.subgraph.chainTip}`
206140
- ],
206141
- ["Integrity", report.subgraph.integrity],
206142
- ["Gaps", String(report.subgraph.gapCount)]
206143
- ])
206144
- ].join(`
206145
- `));
206146
- }
206147
205827
  if (report.primary)
206148
205828
  sections.push(formatPrimaryInsight(report.primary));
206149
205829
  const primaryIndex = report.primary ? report.issues.indexOf(report.primary) : -1;
@@ -206159,35 +205839,6 @@ Next steps:`), ...rest.map((hint) => ` - ${hint}`)].join(`
206159
205839
  function printDoctorReport(report) {
206160
205840
  console.log(formatDoctorReport(report));
206161
205841
  }
206162
- function syntheticValue(type) {
206163
- switch (type) {
206164
- case "uint":
206165
- case "int":
206166
- return "1000";
206167
- case "boolean":
206168
- return true;
206169
- case "timestamp":
206170
- return new Date(0).toISOString();
206171
- case "jsonb":
206172
- return {};
206173
- case "principal":
206174
- return "SP000000000000000000002Q6VF78";
206175
- default:
206176
- return "example";
206177
- }
206178
- }
206179
- function buildSyntheticRow(subgraph, tableName) {
206180
- const table = subgraph?.tables[tableName];
206181
- if (!table)
206182
- return { id: "example", value: "example" };
206183
- const row = {};
206184
- for (const [column, def] of Object.entries(table.columns)) {
206185
- if (column.startsWith("_"))
206186
- continue;
206187
- row[column] = syntheticValue(def.type);
206188
- }
206189
- return Object.keys(row).length > 0 ? row : { id: "example", value: "example" };
206190
- }
206191
205842
  function resolveSigningSecret(options, env = process.env) {
206192
205843
  const secret = options.signingSecret ?? env.SIGNING_SECRET;
206193
205844
  if (!secret) {
@@ -206201,17 +205852,16 @@ function shellQuote(value) {
206201
205852
  function buildWebhookTestFixture(input) {
206202
205853
  const nowSeconds = input.nowSeconds ?? Math.floor(Date.now() / 1000);
206203
205854
  const sub = input.webhook;
206204
- const isChain = sub.kind === "chain";
206205
- const type = isChain ? `chain.${sub.triggers?.[0]?.type ?? "event"}.apply` : `${sub.subgraphName}.${sub.tableName}.created`;
206206
- const data = isChain ? {
205855
+ const type = `chain.${sub.triggers[0]?.type ?? "event"}.apply`;
205856
+ const data = {
206207
205857
  action: "apply",
206208
205858
  canonical: true,
206209
205859
  block_hash: "0xexampleblock",
206210
205860
  block_height: 0,
206211
205861
  tx_id: input.row.tx_id ?? "0xexampletransaction",
206212
- trigger: sub.triggers?.[0]?.type ?? "event",
205862
+ trigger: sub.triggers[0]?.type ?? "event",
206213
205863
  event: input.row
206214
- } : input.row;
205864
+ };
206215
205865
  const body = JSON.stringify({
206216
205866
  type,
206217
205867
  timestamp: new Date(nowSeconds * 1000).toISOString(),
@@ -206234,25 +205884,12 @@ function buildWebhookTestFixture(input) {
206234
205884
  `);
206235
205885
  return { body, headers, curl };
206236
205886
  }
206237
- async function representativeRow(client, sub, subgraph) {
206238
- if (sub.kind === "chain" || !sub.subgraphName || !sub.tableName) {
206239
- return {
206240
- tx_id: "0xexampletransaction",
206241
- contract_id: "SP000000000000000000002Q6VF78.example",
206242
- ...sub.triggers?.[0]?.type === "contract_call" ? { function_name: "example-fn" } : {}
206243
- };
206244
- }
206245
- try {
206246
- const { rows } = await client.subgraphs.rows(sub.subgraphName, sub.tableName, {
206247
- sort: "_block_height",
206248
- order: "desc",
206249
- limit: 1
206250
- });
206251
- const row = rows[0];
206252
- if (row && typeof row === "object")
206253
- return row;
206254
- } catch {}
206255
- return buildSyntheticRow(subgraph, sub.tableName);
205887
+ function representativeRow(sub) {
205888
+ return {
205889
+ tx_id: "0xexampletransaction",
205890
+ contract_id: "SP000000000000000000002Q6VF78.example",
205891
+ ...sub.triggers[0]?.type === "contract_call" ? { function_name: "example-fn" } : {}
205892
+ };
206256
205893
  }
206257
205894
  function printDeliveries(rows) {
206258
205895
  if (rows.length === 0) {
@@ -206329,22 +205966,14 @@ ${data.length} webhook(s) total`));
206329
205966
  handleApiError(err, "get webhook");
206330
205967
  }
206331
205968
  });
206332
- parent.command("update <idOrName>").description("Update webhook config").option("--name <name>", "Rename webhook").option("--url <url>", "Webhook URL").option("--auth-token <token>", "Set bearer token auth config; a flag lands in shell history and ps, so pass it here only for a throwaway token").option("--format <format>", "standard-webhooks | inngest | trigger | cloudflare | cloudevents | raw").option("--runtime <runtime>", "inngest | trigger | cloudflare | node | none").option("--filter <kv...>", "Filter as key=value (supports .eq/.neq/.gt/.gte/.lt/.lte suffixes)").option("--clear-filter", "Replace filter with {}").option("--max-retries <n>", "Maximum delivery retries").option("--timeout-ms <n>", "Delivery timeout in milliseconds").option("--concurrency <n>", "Per-webhook delivery concurrency").option("--json", "Output as JSON").addHelpText("after", `
205969
+ parent.command("update <idOrName>").description("Update webhook config").option("--name <name>", "Rename webhook").option("--url <url>", "Webhook URL").option("--auth-token <token>", "Set bearer token auth config; a flag lands in shell history and ps, so pass it here only for a throwaway token").option("--format <format>", "standard-webhooks | inngest | trigger | cloudflare | cloudevents | raw").option("--max-retries <n>", "Maximum delivery retries").option("--timeout-ms <n>", "Delivery timeout in milliseconds").option("--concurrency <n>", "Per-webhook delivery concurrency").option("--json", "Output as JSON").addHelpText("after", `
206333
205970
  Examples:
206334
205971
  $ secondlayer webhooks update my-sub --url https://example.com/hook
206335
- $ secondlayer webhooks update my-sub --filter amount.gte=1000 --max-retries 5
206336
- $ secondlayer webhooks update my-sub --clear-filter`).action(async (idOrName, options) => {
205972
+ $ secondlayer webhooks update my-sub --max-retries 5 --timeout-ms 20000`).action(async (idOrName, options) => {
206337
205973
  try {
206338
205974
  const client = await getWebhookClient();
206339
205975
  const patch = buildWebhookUpdatePatch(options);
206340
- const { id, detail } = await resolveWebhookRef(client, idOrName);
206341
- if (patch.filter !== undefined && detail.subgraphName && detail.tableName) {
206342
- await validateWebhookTargetFromApi(client, {
206343
- subgraphName: detail.subgraphName,
206344
- tableName: detail.tableName,
206345
- filter: patch.filter
206346
- });
206347
- }
205976
+ const { id } = await resolveWebhookRef(client, idOrName);
206348
205977
  const updated = await client.webhooks.update(id, patch);
206349
205978
  if (options.json)
206350
205979
  printJson(updated);
@@ -206495,16 +206124,14 @@ Examples:
206495
206124
  try {
206496
206125
  const client = await getWebhookClient();
206497
206126
  const { id, detail } = await resolveWebhookRef(client, idOrName);
206498
- const [deliveries, dead, subgraph] = await Promise.allSettled([
206127
+ const [deliveries, dead] = await Promise.allSettled([
206499
206128
  client.webhooks.deliveries(id),
206500
- client.webhooks.dead(id),
206501
- detail.subgraphName ? client.subgraphs.status(detail.subgraphName) : Promise.resolve(null)
206129
+ client.webhooks.dead(id)
206502
206130
  ]);
206503
206131
  const report = buildDoctorReport({
206504
206132
  webhook: detail,
206505
206133
  deliveries: deliveries.status === "fulfilled" ? deliveries.value.data : [],
206506
- dead: dead.status === "fulfilled" ? dead.value.data : [],
206507
- subgraph: subgraph.status === "fulfilled" ? subgraph.value : null
206134
+ dead: dead.status === "fulfilled" ? dead.value.data : []
206508
206135
  });
206509
206136
  if (options.json)
206510
206137
  printJson(report);
@@ -206519,8 +206146,7 @@ Examples:
206519
206146
  const signingSecret = resolveSigningSecret(options);
206520
206147
  const client = await getWebhookClient();
206521
206148
  const { detail } = await resolveWebhookRef(client, idOrName);
206522
- const subgraph = detail.subgraphName ? await client.subgraphs.status(detail.subgraphName).catch(() => null) : null;
206523
- const row = await representativeRow(client, detail, subgraph);
206149
+ const row = representativeRow(detail);
206524
206150
  const fixture = buildWebhookTestFixture({
206525
206151
  webhook: detail,
206526
206152
  row,
@@ -206580,8 +206206,8 @@ function registerWebhooksCommand(program) {
206580
206206
  }
206581
206207
  // src/commands/devnet.ts
206582
206208
  import { spawnSync as spawnSync3 } from "node:child_process";
206583
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "node:fs";
206584
- import { dirname as dirname8, join as join12 } from "node:path";
206209
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "node:fs";
206210
+ import { dirname as dirname7, join as join11 } from "node:path";
206585
206211
 
206586
206212
  // src/lib/devnet-compose.ts
206587
206213
  var DEFAULT_IMAGE_OWNER = "ryanwaits";
@@ -206735,23 +206361,23 @@ volumes:
206735
206361
  }
206736
206362
 
206737
206363
  // src/lib/devnet-config.ts
206738
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
206739
- import { dirname as dirname7, join as join10, parse as parsePath } from "node:path";
206364
+ import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
206365
+ import { dirname as dirname6, join as join9, parse as parsePath } from "node:path";
206740
206366
  import { parse as parseToml } from "smol-toml";
206741
206367
  var DEFAULT_INDEXER_OBSERVER = "host.docker.internal:3700";
206742
206368
  function findClarinetProject(startDir) {
206743
206369
  let dir = startDir;
206744
206370
  const { root } = parsePath(dir);
206745
206371
  while (true) {
206746
- if (existsSync6(join10(dir, "Clarinet.toml")))
206372
+ if (existsSync5(join9(dir, "Clarinet.toml")))
206747
206373
  return dir;
206748
206374
  if (dir === root)
206749
206375
  return null;
206750
- dir = dirname7(dir);
206376
+ dir = dirname6(dir);
206751
206377
  }
206752
206378
  }
206753
206379
  function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER) {
206754
- const exists = existsSync6(devnetTomlPath);
206380
+ const exists = existsSync5(devnetTomlPath);
206755
206381
  const original = exists ? readFileSync6(devnetTomlPath, "utf8") : "";
206756
206382
  if (original.trim()) {
206757
206383
  const parsed = parseToml(original);
@@ -206766,7 +206392,7 @@ function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER
206766
206392
  const at = (arrayStart.index ?? 0) + arrayStart[0].length;
206767
206393
  const next = original.slice(at).trimStart().startsWith("]") ? entry : `${entry}, `;
206768
206394
  const patched = original.slice(0, at) + next + original.slice(at);
206769
- writeFileSync5(devnetTomlPath, patched);
206395
+ writeFileSync4(devnetTomlPath, patched);
206770
206396
  return { status: "added" };
206771
206397
  }
206772
206398
  const header = original.match(/^\[devnet\]\s*$/m);
@@ -206774,7 +206400,7 @@ function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER
206774
206400
  const at = (header.index ?? 0) + header[0].length;
206775
206401
  const patched = `${original.slice(0, at)}
206776
206402
  stacks_node_events_observers = [${entry}]${original.slice(at)}`;
206777
- writeFileSync5(devnetTomlPath, patched);
206403
+ writeFileSync4(devnetTomlPath, patched);
206778
206404
  return { status: "added" };
206779
206405
  }
206780
206406
  const prefix = original && !original.endsWith(`
@@ -206784,7 +206410,7 @@ stacks_node_events_observers = [${entry}]${original.slice(at)}`;
206784
206410
  ` : ""}[devnet]
206785
206411
  stacks_node_events_observers = [${entry}]
206786
206412
  `;
206787
- writeFileSync5(devnetTomlPath, block);
206413
+ writeFileSync4(devnetTomlPath, block);
206788
206414
  return { status: exists ? "added" : "created" };
206789
206415
  }
206790
206416
 
@@ -206795,7 +206421,7 @@ init_resolve_auth();
206795
206421
  // src/commands/faucet.ts
206796
206422
  import { randomBytes as randomBytes2 } from "node:crypto";
206797
206423
  import { readFile as readFile5 } from "node:fs/promises";
206798
- import { join as join11 } from "node:path";
206424
+ import { join as join10 } from "node:path";
206799
206425
  import { http as http3, createWalletClient } from "@secondlayer/stacks";
206800
206426
  import { mnemonicToAccount } from "@secondlayer/stacks/accounts";
206801
206427
  import { devnet } from "@secondlayer/stacks/chains";
@@ -206805,7 +206431,7 @@ init_output();
206805
206431
  var DUST_LIMIT_SATS = 546n;
206806
206432
  var DEFAULT_AMOUNT_SATS = 1000000n;
206807
206433
  async function readDeployerMnemonic(projectDir) {
206808
- const path = join11(projectDir, "settings", "Devnet.toml");
206434
+ const path = join10(projectDir, "settings", "Devnet.toml");
206809
206435
  let raw;
206810
206436
  try {
206811
206437
  raw = await readFile5(path, "utf8");
@@ -206922,7 +206548,7 @@ is what makes minting possible without Bitcoin.`).action(async (opts) => {
206922
206548
  }
206923
206549
 
206924
206550
  // src/commands/devnet.ts
206925
- var COMPOSE_REL = join12(".secondlayer", "docker-compose.yml");
206551
+ var COMPOSE_REL = join11(".secondlayer", "docker-compose.yml");
206926
206552
  function ensureDocker() {
206927
206553
  const probe = spawnSync3("docker", ["info"], { stdio: "ignore" });
206928
206554
  if (probe.error || probe.status !== 0) {
@@ -206967,7 +206593,7 @@ function registerDevnetCommand(program) {
206967
206593
  }
206968
206594
  function resolveProject(explicit) {
206969
206595
  if (explicit) {
206970
- if (!existsSync7(join12(explicit, "Clarinet.toml"))) {
206596
+ if (!existsSync6(join11(explicit, "Clarinet.toml"))) {
206971
206597
  error(`No Clarinet.toml in ${explicit}`);
206972
206598
  process.exit(1);
206973
206599
  }
@@ -206983,8 +206609,8 @@ function resolveProject(explicit) {
206983
206609
  }
206984
206610
  async function connect(options) {
206985
206611
  const project = resolveProject(options.project);
206986
- const devnetToml = join12(project, "settings", "Devnet.toml");
206987
- mkdirSync4(dirname8(devnetToml), { recursive: true });
206612
+ const devnetToml = join11(project, "settings", "Devnet.toml");
206613
+ mkdirSync3(dirname7(devnetToml), { recursive: true });
206988
206614
  const result = ensureEventObserver(devnetToml, DEFAULT_INDEXER_OBSERVER);
206989
206615
  console.log(`${green("✓")} found Clarinet.toml`);
206990
206616
  if (result.status === "present") {
@@ -206993,9 +206619,9 @@ async function connect(options) {
206993
206619
  console.log(`${green("✓")} ${result.status === "created" ? "created" : "patched"} settings/Devnet.toml`);
206994
206620
  console.log(dim(` + stacks_node_events_observers = ["${DEFAULT_INDEXER_OBSERVER}"]`));
206995
206621
  }
206996
- const composePath = join12(project, COMPOSE_REL);
206997
- mkdirSync4(dirname8(composePath), { recursive: true });
206998
- writeFileSync6(composePath, buildDevnetCompose({ owner: options.owner, imageTag: options.imageTag }));
206622
+ const composePath = join11(project, COMPOSE_REL);
206623
+ mkdirSync3(dirname7(composePath), { recursive: true });
206624
+ writeFileSync5(composePath, buildDevnetCompose({ owner: options.owner, imageTag: options.imageTag }));
206999
206625
  console.log(`${green("✓")} wrote ${COMPOSE_REL}`);
207000
206626
  if (!options.up) {
207001
206627
  console.log(dim(`
@@ -207026,8 +206652,8 @@ Stop with: secondlayer devnet down`));
207026
206652
  }
207027
206653
  async function down(options) {
207028
206654
  const project = resolveProject(options.project);
207029
- const composePath = join12(project, COMPOSE_REL);
207030
- if (!existsSync7(composePath)) {
206655
+ const composePath = join11(project, COMPOSE_REL);
206656
+ if (!existsSync6(composePath)) {
207031
206657
  error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`secondlayer devnet connect\` first.`);
207032
206658
  process.exit(1);
207033
206659
  }
@@ -207041,8 +206667,8 @@ async function down(options) {
207041
206667
  }
207042
206668
  async function logs(service, options) {
207043
206669
  const project = resolveProject(options.project);
207044
- const composePath = join12(project, COMPOSE_REL);
207045
- if (!existsSync7(composePath)) {
206670
+ const composePath = join11(project, COMPOSE_REL);
206671
+ if (!existsSync6(composePath)) {
207046
206672
  error(`No ${COMPOSE_REL} in ${project} — run \`secondlayer devnet connect\` first.`);
207047
206673
  process.exit(1);
207048
206674
  }
@@ -207174,7 +206800,7 @@ init_output();
207174
206800
  init_resolve_auth();
207175
206801
  import { createHash as createHash5 } from "node:crypto";
207176
206802
  import { mkdir as mkdir3, open as open2, rename as rename2 } from "node:fs/promises";
207177
- import { dirname as dirname9, isAbsolute, resolve as resolve8, sep as sep2 } from "node:path";
206803
+ import { dirname as dirname8, isAbsolute, resolve as resolve7, sep as sep2 } from "node:path";
207178
206804
  import { createStreamsClient } from "@secondlayer/sdk";
207179
206805
  import { STREAMS_EVENT_TYPES } from "@secondlayer/shared";
207180
206806
  var VALID_TYPES = STREAMS_EVENT_TYPES;
@@ -207197,12 +206823,12 @@ function dumpsClient(dumpsUrl) {
207197
206823
  });
207198
206824
  }
207199
206825
  function resolveDumpDest(to, filePath) {
207200
- const root = resolve8(to);
206826
+ const root = resolve7(to);
207201
206827
  const segments = filePath.split(/[\\/]/);
207202
206828
  if (filePath.length === 0 || isAbsolute(filePath) || filePath.includes("\\") || segments.some((s) => s === "..")) {
207203
206829
  throw new Error(`refusing dump path "${filePath}": paths must be relative and stay under ${root}`);
207204
206830
  }
207205
- const dest = resolve8(root, filePath);
206831
+ const dest = resolve7(root, filePath);
207206
206832
  if (!dest.startsWith(root + sep2)) {
207207
206833
  throw new Error(`refusing dump path "${filePath}": resolves outside ${root}`);
207208
206834
  }
@@ -207213,7 +206839,7 @@ async function downloadDumpTo(file, dest, fetchImpl, url) {
207213
206839
  if (!res.ok || !res.body) {
207214
206840
  throw new Error(`could not download dump ${file.path} (${res.status})`);
207215
206841
  }
207216
- await mkdir3(dirname9(dest), { recursive: true });
206842
+ await mkdir3(dirname8(dest), { recursive: true });
207217
206843
  const part = `${dest}.part`;
207218
206844
  const hash = createHash5("sha256");
207219
206845
  let bytes = 0;
@@ -207897,10 +207523,10 @@ init_output();
207897
207523
  import { resolveApiKey as resolveApiKey4 } from "@secondlayer/sdk";
207898
207524
 
207899
207525
  // src/lib/project-file.ts
207900
- import { existsSync as existsSync8 } from "node:fs";
207526
+ import { existsSync as existsSync7 } from "node:fs";
207901
207527
  import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
207902
207528
  import { homedir as homedir5 } from "node:os";
207903
- import { dirname as dirname10, join as join14, parse as parsePath2, resolve as resolve9 } from "node:path";
207529
+ import { dirname as dirname9, join as join13, parse as parsePath2, resolve as resolve8 } from "node:path";
207904
207530
  import { z as z4 } from "zod";
207905
207531
  var ProjectFileSchema = z4.object({
207906
207532
  slug: z4.string().min(1)
@@ -207908,23 +207534,23 @@ var ProjectFileSchema = z4.object({
207908
207534
  var FILENAME = "project";
207909
207535
  var DIRNAME = ".secondlayer";
207910
207536
  async function readActiveProject(cwd, globalDefault) {
207911
- let dir = resolve9(cwd);
207912
- const home = resolve9(homedir5());
207537
+ let dir = resolve8(cwd);
207538
+ const home = resolve8(homedir5());
207913
207539
  const fsRoot = parsePath2(dir).root;
207914
207540
  while (true) {
207915
- const candidate = join14(dir, DIRNAME, FILENAME);
207916
- if (existsSync8(candidate)) {
207541
+ const candidate = join13(dir, DIRNAME, FILENAME);
207542
+ if (existsSync7(candidate)) {
207917
207543
  try {
207918
207544
  const raw = await readFile6(candidate, "utf8");
207919
207545
  const parsed = ProjectFileSchema.parse(JSON.parse(raw));
207920
207546
  return { slug: parsed.slug, resolvedFrom: candidate };
207921
207547
  } catch {}
207922
207548
  }
207923
- if (existsSync8(join14(dir, ".git")))
207549
+ if (existsSync7(join13(dir, ".git")))
207924
207550
  break;
207925
207551
  if (dir === home || dir === fsRoot)
207926
207552
  break;
207927
- const parent = dirname10(dir);
207553
+ const parent = dirname9(dir);
207928
207554
  if (parent === dir)
207929
207555
  break;
207930
207556
  dir = parent;
@@ -207932,7 +207558,7 @@ async function readActiveProject(cwd, globalDefault) {
207932
207558
  if (globalDefault) {
207933
207559
  return {
207934
207560
  slug: globalDefault,
207935
- resolvedFrom: join14(homedir5(), ".secondlayer", "config.json")
207561
+ resolvedFrom: join13(homedir5(), ".secondlayer", "config.json")
207936
207562
  };
207937
207563
  }
207938
207564
  return null;
@@ -208005,7 +207631,7 @@ init_api_url();
208005
207631
  init_http();
208006
207632
  init_output();
208007
207633
  init_session();
208008
- import { confirm as confirm3, input as input2 } from "@inquirer/prompts";
207634
+ import { confirm as confirm3, input } from "@inquirer/prompts";
208009
207635
  function sessionExpiry() {
208010
207636
  return new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString();
208011
207637
  }
@@ -208065,7 +207691,7 @@ async function runLoginFlow(options = {}) {
208065
207691
  }
208066
207692
  }
208067
207693
  }
208068
- const email = await input2({
207694
+ const email = await input({
208069
207695
  message: "Email",
208070
207696
  validate: (v) => /^.+@.+\..+$/.test(v) ? true : "Invalid email"
208071
207697
  });
@@ -208086,7 +207712,7 @@ async function runLoginFlow(options = {}) {
208086
207712
  }
208087
207713
  process.exit(1);
208088
207714
  }
208089
- const code = await input2({
207715
+ const code = await input({
208090
207716
  message: "Enter the 6-digit code",
208091
207717
  validate: (v) => /^\d{6}$/.test(v) ? true : "Expected 6 digits"
208092
207718
  });
@@ -208147,15 +207773,15 @@ function registerLogoutCommand(program) {
208147
207773
  }
208148
207774
  // src/commands/uninstall.ts
208149
207775
  import { spawnSync as spawnSync4 } from "node:child_process";
208150
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
208151
- import { join as join15, resolve as resolve11 } from "node:path";
207776
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
207777
+ import { join as join14, resolve as resolve10 } from "node:path";
208152
207778
  import { planUninstall, uninstallCommand } from "@secondlayer/shared/runtime";
208153
207779
 
208154
207780
  // src/lib/instance-init.ts
208155
207781
  init_output();
208156
207782
  import { randomBytes as randomBytes3 } from "node:crypto";
208157
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "node:fs";
208158
- import { resolve as resolve10 } from "node:path";
207783
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
207784
+ import { resolve as resolve9 } from "node:path";
208159
207785
  import { ARCHIVE_ROOT_PUBLIC_KEY_PEM } from "@secondlayer/shared/archive/root-key";
208160
207786
  import { generateEd25519KeyPair } from "@secondlayer/shared/crypto/ed25519";
208161
207787
  import { INSTANCE_NETWORKS } from "@secondlayer/shared/db/queries/instance";
@@ -208204,7 +207830,7 @@ function unescapeEnvValue(raw) {
208204
207830
  `).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
208205
207831
  }
208206
207832
  function readEnvValue(envPath, key) {
208207
- if (!existsSync9(envPath))
207833
+ if (!existsSync8(envPath))
208208
207834
  return null;
208209
207835
  const match = readFileSync7(envPath, "utf8").match(new RegExp(`^${key}=(.*)$`, "m"));
208210
207836
  return match ? unescapeEnvValue(match[1]) : null;
@@ -208252,12 +207878,12 @@ function renderInstanceEnv(env) {
208252
207878
  `);
208253
207879
  }
208254
207880
  function writeInstanceEnv(cwd, env, file = INSTANCE_ENV_FILE) {
208255
- const path = resolve10(cwd, file);
208256
- writeFileSync7(path, renderInstanceEnv(env), { mode: 384 });
207881
+ const path = resolve9(cwd, file);
207882
+ writeFileSync6(path, renderInstanceEnv(env), { mode: 384 });
208257
207883
  return path;
208258
207884
  }
208259
207885
  function loadExistingInstanceEnv(cwd, file = INSTANCE_ENV_FILE) {
208260
- const path = resolve10(cwd, file);
207886
+ const path = resolve9(cwd, file);
208261
207887
  return {
208262
207888
  INSTANCE_TOKEN: readEnvValue(path, "INSTANCE_TOKEN"),
208263
207889
  SECONDLAYER_SECRETS_KEY: readEnvValue(path, "SECONDLAYER_SECRETS_KEY"),
@@ -208275,8 +207901,8 @@ init_resolve_auth();
208275
207901
  var UNINSTALL_EXIT = { OK: 0, FAILED: 1, REFUSED: 2 };
208276
207902
  var REPO_COMPOSE = "docker/oss/docker-compose.yml";
208277
207903
  function bundleHasKeys(bundleDir) {
208278
- const manifest = join15(bundleDir, "manifest.json");
208279
- if (!existsSync10(manifest))
207904
+ const manifest = join14(bundleDir, "manifest.json");
207905
+ if (!existsSync9(manifest))
208280
207906
  return false;
208281
207907
  try {
208282
207908
  const parsed = JSON.parse(readFileSync8(manifest, "utf8"));
@@ -208286,27 +207912,27 @@ function bundleHasKeys(bundleDir) {
208286
207912
  }
208287
207913
  }
208288
207914
  function resolveUninstallLayout(dir, composeOverride) {
208289
- const setupCompose = resolve11(dir, "docker-compose.yml");
208290
- const setupEnv = resolve11(dir, ".env");
208291
- const initEnv = resolve11(dir, ".env.local");
208292
- const secretsFile = [setupEnv, initEnv].find((file) => readEnvValue(file, "SECONDLAYER_SECRETS_KEY") !== null) ?? [setupEnv, initEnv].find((file) => existsSync10(file));
207915
+ const setupCompose = resolve10(dir, "docker-compose.yml");
207916
+ const setupEnv = resolve10(dir, ".env");
207917
+ const initEnv = resolve10(dir, ".env.local");
207918
+ const secretsFile = [setupEnv, initEnv].find((file) => readEnvValue(file, "SECONDLAYER_SECRETS_KEY") !== null) ?? [setupEnv, initEnv].find((file) => existsSync9(file));
208293
207919
  if (composeOverride) {
208294
- const composeFile = resolve11(dir, composeOverride);
208295
- const sibling = resolve11(composeFile, "..", ".env");
207920
+ const composeFile = resolve10(dir, composeOverride);
207921
+ const sibling = resolve10(composeFile, "..", ".env");
208296
207922
  return {
208297
207923
  composeFile,
208298
- envFile: existsSync10(sibling) ? sibling : undefined,
207924
+ envFile: existsSync9(sibling) ? sibling : undefined,
208299
207925
  secretsFile
208300
207926
  };
208301
207927
  }
208302
- if (existsSync10(setupCompose)) {
207928
+ if (existsSync9(setupCompose)) {
208303
207929
  return {
208304
207930
  composeFile: setupCompose,
208305
- envFile: existsSync10(setupEnv) ? setupEnv : undefined,
207931
+ envFile: existsSync9(setupEnv) ? setupEnv : undefined,
208306
207932
  secretsFile
208307
207933
  };
208308
207934
  }
208309
- return { composeFile: resolve11(dir, REPO_COMPOSE), secretsFile };
207935
+ return { composeFile: resolve10(dir, REPO_COMPOSE), secretsFile };
208310
207936
  }
208311
207937
  function composeDownArgs(plan, layout) {
208312
207938
  const base = uninstallCommand(plan, layout.composeFile);
@@ -208326,7 +207952,7 @@ function registerUninstallCommand(program) {
208326
207952
  const dataDir = process.env.DATA_DIR ?? "./data";
208327
207953
  const layout = resolveUninstallLayout(process.cwd(), opts.compose);
208328
207954
  const secretsPresent = !!process.env.SECONDLAYER_SECRETS_KEY || !!layout.secretsFile;
208329
- const keysBackedUp = opts.backup ? bundleHasKeys(resolve11(opts.backup)) : false;
207955
+ const keysBackedUp = opts.backup ? bundleHasKeys(resolve10(opts.backup)) : false;
208330
207956
  const decision = planUninstall({
208331
207957
  purge: opts.purge === true,
208332
207958
  confirmed: opts.yes === true,
@@ -208399,14 +208025,14 @@ init_fs();
208399
208025
  init_output();
208400
208026
  init_resolve_auth();
208401
208027
  import {
208402
- chmodSync as chmodSync2,
208403
- existsSync as existsSync11,
208404
- mkdirSync as mkdirSync5,
208028
+ chmodSync,
208029
+ existsSync as existsSync10,
208030
+ mkdirSync as mkdirSync4,
208405
208031
  readFileSync as readFileSync9,
208406
- statSync as statSync3,
208407
- writeFileSync as writeFileSync8
208032
+ statSync as statSync2,
208033
+ writeFileSync as writeFileSync7
208408
208034
  } from "node:fs";
208409
- import { join as join16, resolve as resolve12 } from "node:path";
208035
+ import { join as join15, resolve as resolve11 } from "node:path";
208410
208036
  import { closeDb, getDb as getDb4, sql as sql2 } from "@secondlayer/shared/db";
208411
208037
  import {
208412
208038
  decryptBundle,
@@ -208555,10 +208181,10 @@ async function runBackup(opts) {
208555
208181
  printError(plan.reason);
208556
208182
  process.exit(BACKUP_EXIT.REFUSED);
208557
208183
  }
208558
- const outDir = resolve12(opts.out);
208559
- mkdirSync5(outDir, { recursive: true });
208184
+ const outDir = resolve11(opts.out);
208185
+ mkdirSync4(outDir, { recursive: true });
208560
208186
  console.error("dumping database…");
208561
- const dumpPath = join16(outDir, DB_FILE);
208187
+ const dumpPath = join15(outDir, DB_FILE);
208562
208188
  const dumpCmd = pgDumpInvocation(databaseUrl, dumpPath);
208563
208189
  const dump = await runProcess(dumpCmd.cmd, "pg_dump", dumpCmd.env);
208564
208190
  if (!dump.ok) {
@@ -208570,7 +208196,7 @@ async function runBackup(opts) {
208570
208196
  db: {
208571
208197
  file: DB_FILE,
208572
208198
  sha256: await sha256File(dumpPath),
208573
- bytes: statSync3(dumpPath).size,
208199
+ bytes: statSync2(dumpPath).size,
208574
208200
  format: "pg_dump-custom"
208575
208201
  }
208576
208202
  };
@@ -208578,16 +208204,16 @@ async function runBackup(opts) {
208578
208204
  const lines = SECRET_ENV_KEYS.filter((k) => process.env[k]).map((k) => `${k}=${process.env[k]}`);
208579
208205
  const sealed = encryptBundle(lines.join(`
208580
208206
  `), passphrase);
208581
- const secretsPath = join16(outDir, SECRETS_FILE);
208582
- writeFileSync8(secretsPath, sealed);
208583
- chmodSync2(secretsPath, 384);
208207
+ const secretsPath = join15(outDir, SECRETS_FILE);
208208
+ writeFileSync7(secretsPath, sealed);
208209
+ chmodSync(secretsPath, 384);
208584
208210
  manifest.secrets = {
208585
208211
  file: SECRETS_FILE,
208586
208212
  encrypted: true,
208587
208213
  canary: sealKeyCanary(secretsKey)
208588
208214
  };
208589
208215
  }
208590
- writeFileSync8(join16(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
208216
+ writeFileSync7(join15(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
208591
208217
  `);
208592
208218
  output({
208593
208219
  json: opts.json,
@@ -208616,14 +208242,14 @@ function attachRestoreCommand(cmd) {
208616
208242
  }
208617
208243
  async function runRestore(opts) {
208618
208244
  const databaseUrl = requireDatabaseUrl();
208619
- const dir = resolve12(opts.from);
208620
- const manifestPath = join16(dir, MANIFEST_FILE);
208621
- if (!existsSync11(manifestPath)) {
208245
+ const dir = resolve11(opts.from);
208246
+ const manifestPath = join15(dir, MANIFEST_FILE);
208247
+ if (!existsSync10(manifestPath)) {
208622
208248
  printError(`no ${MANIFEST_FILE} in ${dir}`);
208623
208249
  process.exit(BACKUP_EXIT.REFUSED);
208624
208250
  }
208625
208251
  const manifest = JSON.parse(readFileSync9(manifestPath, "utf8"));
208626
- const dumpPath = join16(dir, manifest.db?.file ?? DB_FILE);
208252
+ const dumpPath = join15(dir, manifest.db?.file ?? DB_FILE);
208627
208253
  if (manifest.db && await sha256File(dumpPath) !== manifest.db.sha256) {
208628
208254
  printError("the database dump does not match the digest in the manifest; this bundle is corrupt or truncated");
208629
208255
  process.exit(BACKUP_EXIT.REFUSED);
@@ -208637,7 +208263,7 @@ async function runRestore(opts) {
208637
208263
  process.exit(BACKUP_EXIT.REFUSED);
208638
208264
  }
208639
208265
  try {
208640
- const env = decryptBundle(readFileSync9(join16(dir, manifest.secrets.file)), passphrase);
208266
+ const env = decryptBundle(readFileSync9(join15(dir, manifest.secrets.file)), passphrase);
208641
208267
  bundleKey = env.split(`
208642
208268
  `).find((l) => l.startsWith("SECONDLAYER_SECRETS_KEY="))?.slice("SECONDLAYER_SECRETS_KEY=".length).trim();
208643
208269
  } catch {
@@ -208827,7 +208453,7 @@ init_resolve_auth();
208827
208453
 
208828
208454
  // src/lib/setup-prompts.ts
208829
208455
  import { resolve as resolvePath3 } from "node:path";
208830
- import { confirm as confirm4, input as input3, select as select4 } from "@inquirer/prompts";
208456
+ import { confirm as confirm4, input as input2, select as select3 } from "@inquirer/prompts";
208831
208457
 
208832
208458
  // src/lib/oss-compose.ts
208833
208459
  function buildOssCompose(opts = {}) {
@@ -209005,10 +208631,10 @@ dbcache=4096
209005
208631
  // src/lib/setup-wizard.ts
209006
208632
  import { spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
209007
208633
  import { randomBytes as randomBytes4 } from "node:crypto";
209008
- import { existsSync as existsSync12 } from "node:fs";
208634
+ import { existsSync as existsSync11 } from "node:fs";
209009
208635
  import { writeFile as writeFile6 } from "node:fs/promises";
209010
208636
  import { createServer } from "node:net";
209011
- import { join as join17, resolve as resolvePath2 } from "node:path";
208637
+ import { join as join16, resolve as resolvePath2 } from "node:path";
209012
208638
  import { closeDb as closeDb2, getRawClientFor } from "@secondlayer/shared/db";
209013
208639
  import { FLOORS, diskFloorGb } from "@secondlayer/shared/runtime";
209014
208640
  init_resolve_auth();
@@ -209108,8 +208734,8 @@ function randomHex(bytes) {
209108
208734
  return randomBytes4(bytes).toString("hex");
209109
208735
  }
209110
208736
  function resolveSecrets(config) {
209111
- const envPath = join17(config.dir, ".env");
209112
- const existing = config.force || !existsSync12(envPath) ? {} : readEnvFile(config.dir, envPath);
208737
+ const envPath = join16(config.dir, ".env");
208738
+ const existing = config.force || !existsSync11(envPath) ? {} : readEnvFile(config.dir, envPath);
209113
208739
  const instance = buildInstanceEnv({
209114
208740
  network: config.network,
209115
208741
  existing: {
@@ -209201,13 +208827,13 @@ function renderSetupEnv(config, secrets) {
209201
208827
  `);
209202
208828
  }
209203
208829
  async function writeSetupFiles(config, secrets) {
209204
- const composePath = join17(config.dir, "docker-compose.yml");
209205
- const envPath = join17(config.dir, ".env");
208830
+ const composePath = join16(config.dir, "docker-compose.yml");
208831
+ const envPath = join16(config.dir, ".env");
209206
208832
  await writeFile6(composePath, buildOssCompose({ owner: config.owner, imageTag: config.imageTag }));
209207
208833
  await writeFile6(envPath, renderSetupEnv(config, secrets), { mode: 384 });
209208
208834
  const result = { composePath, envPath };
209209
208835
  if (config.nodeMode === "full") {
209210
- const configTomlPath = join17(config.dir, "Config.toml");
208836
+ const configTomlPath = join16(config.dir, "Config.toml");
209211
208837
  await writeFile6(configTomlPath, buildOssStacksConfigToml({
209212
208838
  network: config.network,
209213
208839
  bitcoinRpcPassword: secrets.bitcoinRpcPassword ?? ""
@@ -209215,7 +208841,7 @@ async function writeSetupFiles(config, secrets) {
209215
208841
  result.configTomlPath = configTomlPath;
209216
208842
  }
209217
208843
  if (config.nodeMode === "full") {
209218
- const bitcoinConfPath = join17(config.dir, "bitcoin.conf");
208844
+ const bitcoinConfPath = join16(config.dir, "bitcoin.conf");
209219
208845
  await writeFile6(bitcoinConfPath, buildOssBitcoinConf({ rpcPassword: secrets.bitcoinRpcPassword ?? "" }));
209220
208846
  result.bitcoinConfPath = bitcoinConfPath;
209221
208847
  }
@@ -209593,7 +209219,7 @@ var NODE_MODE_DESCRIPTIONS = {
209593
209219
  full: "Bundled Stacks node + bitcoind."
209594
209220
  };
209595
209221
  async function promptSetupConfig(flags) {
209596
- const network = safeParse(flags.network, parseInstanceNetwork) ?? await select4({
209222
+ const network = safeParse(flags.network, parseInstanceNetwork) ?? await select3({
209597
209223
  message: "Network",
209598
209224
  choices: [
209599
209225
  {
@@ -209613,7 +209239,7 @@ async function promptSetupConfig(flags) {
209613
209239
  }
209614
209240
  ]
209615
209241
  });
209616
- const nodeMode = safeParse(flags.nodeMode, parseSetupNodeMode) ?? await select4({
209242
+ const nodeMode = safeParse(flags.nodeMode, parseSetupNodeMode) ?? await select3({
209617
209243
  message: "Node mode",
209618
209244
  choices: SETUP_NODE_MODES.map((mode) => {
209619
209245
  const floor = guardrailPreview(mode, network);
@@ -209627,7 +209253,7 @@ async function promptSetupConfig(flags) {
209627
209253
  let against = flags.against;
209628
209254
  let skipBootstrap = !!flags.skipBootstrap;
209629
209255
  if (!skipBootstrap && !against) {
209630
- const choice = await select4({
209256
+ const choice = await select3({
209631
209257
  message: "Bootstrap from",
209632
209258
  choices: [
209633
209259
  {
@@ -209652,7 +209278,7 @@ async function promptSetupConfig(flags) {
209652
209278
  } else if (choice === "skip") {
209653
209279
  skipBootstrap = true;
209654
209280
  } else {
209655
- against = (await input3({
209281
+ against = (await input2({
209656
209282
  message: "Manifest URL or local path",
209657
209283
  default: DEFAULT_ARCHIVE_MANIFEST
209658
209284
  })).trim();
@@ -209840,5 +209466,5 @@ registerCreditsCommand(program);
209840
209466
  registerArchiveCommand(program);
209841
209467
  program.parse();
209842
209468
 
209843
- //# debugId=BC7D717F23E4321C64756E2164756E21
209469
+ //# debugId=DA489CE32ABB5ED564756E2164756E21
209844
209470
  //# sourceMappingURL=cli.js.map