@secondlayer/cli 10.3.2 → 11.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.
Files changed (3) hide show
  1. package/dist/cli.js +156 -454
  2. package/dist/cli.js.map +12 -15
  3. package/package.json +6 -6
package/dist/cli.js CHANGED
@@ -2772,118 +2772,6 @@ var init_output = __esm(() => {
2772
2772
  ANSI_ESCAPE_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
2773
2773
  });
2774
2774
 
2775
- // src/lib/api-client.ts
2776
- import { ApiError, SecondLayer } from "@secondlayer/sdk";
2777
- function nextStepHint(status) {
2778
- if (status === undefined)
2779
- return;
2780
- if (status === 403)
2781
- return "You may not have access — check your active project with `secondlayer whoami`.";
2782
- if (status === 404)
2783
- return "Check the name/slug — run the matching `list` command to see what exists.";
2784
- if (status === 400 || status === 422)
2785
- return "Check the command arguments and flags — see `--help` for the expected format.";
2786
- if (status === 429)
2787
- return "Rate limited — wait a moment and retry.";
2788
- if (status >= 500)
2789
- return "Server error — retry shortly, or check `secondlayer status`.";
2790
- return;
2791
- }
2792
- function handleApiError(err, action) {
2793
- const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
2794
- if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
2795
- printError("Authentication required.", {
2796
- hint: isOssMode() ? "Set SL_API_KEY / INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
2797
- });
2798
- process.exit(1);
2799
- }
2800
- const detail = err instanceof Error ? err.message : String(err);
2801
- printError(`Failed to ${action}: ${detail}`, { hint: nextStepHint(status) });
2802
- process.exit(1);
2803
- }
2804
- function withErrorHandling(fn, options) {
2805
- return async (...args) => {
2806
- try {
2807
- await fn(...args);
2808
- } catch (err) {
2809
- if (options?.onError) {
2810
- options.onError(err);
2811
- } else {
2812
- handleApiError(err, options?.action ?? "execute command");
2813
- }
2814
- }
2815
- };
2816
- }
2817
- async function getPlatformClient() {
2818
- const { apiUrl, ephemeralKey } = await resolveAuth();
2819
- return new SecondLayer({ baseUrl: apiUrl, apiKey: ephemeralKey });
2820
- }
2821
- async function listSubgraphsApi() {
2822
- return (await getPlatformClient()).subgraphs.list();
2823
- }
2824
- async function getSubgraphApi(name) {
2825
- return (await getPlatformClient()).subgraphs.get(name);
2826
- }
2827
- async function getSubgraphOpenApi(name, options) {
2828
- return (await getPlatformClient()).subgraphs.openapi(name, options);
2829
- }
2830
- async function getSubgraphAgentSchema(name, options) {
2831
- return (await getPlatformClient()).subgraphs.schema(name, options);
2832
- }
2833
- async function getSubgraphMarkdown(name, options) {
2834
- return (await getPlatformClient()).subgraphs.markdown(name, options);
2835
- }
2836
- async function reindexSubgraphApi(name) {
2837
- return (await getPlatformClient()).subgraphs.reindex(name);
2838
- }
2839
- async function backfillSubgraphApi(name, options) {
2840
- return (await getPlatformClient()).subgraphs.backfill(name, options);
2841
- }
2842
- async function stopSubgraphApi(name) {
2843
- return (await getPlatformClient()).subgraphs.stop(name);
2844
- }
2845
- async function deleteSubgraphApi(name, options) {
2846
- return (await getPlatformClient()).subgraphs.delete(name, options);
2847
- }
2848
- async function deploySubgraphApi(data) {
2849
- return (await getPlatformClient()).subgraphs.deploy(data);
2850
- }
2851
- async function publishSubgraphApi(name) {
2852
- return (await getPlatformClient()).subgraphs.publish(name);
2853
- }
2854
- async function unpublishSubgraphApi(name) {
2855
- return (await getPlatformClient()).subgraphs.unpublish(name);
2856
- }
2857
- async function querySubgraphTable(name, table, params = {}) {
2858
- return (await getPlatformClient()).subgraphs.queryTable(name, table, params);
2859
- }
2860
- async function querySubgraphTableCount(name, table, params = {}) {
2861
- return (await getPlatformClient()).subgraphs.queryTableCount(name, table, params);
2862
- }
2863
- async function getSubgraphGaps(name, opts) {
2864
- return (await getPlatformClient()).subgraphs.gaps(name, opts);
2865
- }
2866
- async function getContractPrintSchema(contractId) {
2867
- let client;
2868
- try {
2869
- client = await getPlatformClient();
2870
- } catch {
2871
- client = new SecondLayer({ baseUrl: resolveApiUrl() });
2872
- }
2873
- return client.index.printSchema(contractId);
2874
- }
2875
- async function getAccountProfile() {
2876
- return httpPlatform("/api/accounts/me");
2877
- }
2878
- async function updateAccountProfile(data) {
2879
- return httpPlatform("/api/accounts/me", { method: "PATCH", body: data });
2880
- }
2881
- var init_api_client = __esm(() => {
2882
- init_http();
2883
- init_output();
2884
- init_resolve_auth();
2885
- });
2886
-
2887
2775
  // ../../node_modules/chalk/source/vendor/ansi-styles/index.js
2888
2776
  function assembleStyles() {
2889
2777
  const codes = new Map;
@@ -28400,6 +28288,93 @@ var init_subgraphs = __esm(() => {
28400
28288
  init_format();
28401
28289
  });
28402
28290
 
28291
+ // src/lib/api-client.ts
28292
+ import { ApiError, SecondLayer } from "@secondlayer/sdk";
28293
+ function nextStepHint(status) {
28294
+ if (status === undefined)
28295
+ return;
28296
+ if (status === 403)
28297
+ return "You may not have access — check your active project with `secondlayer whoami`.";
28298
+ if (status === 404)
28299
+ return "Check the name/slug — run the matching `list` command to see what exists.";
28300
+ if (status === 400 || status === 422)
28301
+ return "Check the command arguments and flags — see `--help` for the expected format.";
28302
+ if (status === 429)
28303
+ return "Rate limited — wait a moment and retry.";
28304
+ if (status >= 500)
28305
+ return "Server error — retry shortly, or check `secondlayer status`.";
28306
+ return;
28307
+ }
28308
+ function handleApiError(err, action2) {
28309
+ const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
28310
+ if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
28311
+ printError("Authentication required.", {
28312
+ hint: isOssMode() ? "Set SL_API_KEY / INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
28313
+ });
28314
+ process.exit(1);
28315
+ }
28316
+ const detail = err instanceof Error ? err.message : String(err);
28317
+ printError(`Failed to ${action2}: ${detail}`, { hint: nextStepHint(status) });
28318
+ process.exit(1);
28319
+ }
28320
+ async function getPlatformClient() {
28321
+ const { apiUrl, ephemeralKey } = await resolveAuth();
28322
+ return new SecondLayer({ baseUrl: apiUrl, apiKey: ephemeralKey });
28323
+ }
28324
+ async function listSubgraphsApi() {
28325
+ return (await getPlatformClient()).subgraphs.list();
28326
+ }
28327
+ async function getSubgraphApi(name) {
28328
+ return (await getPlatformClient()).subgraphs.get(name);
28329
+ }
28330
+ async function getSubgraphOpenApi(name, options3) {
28331
+ return (await getPlatformClient()).subgraphs.openapi(name, options3);
28332
+ }
28333
+ async function getSubgraphAgentSchema(name, options3) {
28334
+ return (await getPlatformClient()).subgraphs.schema(name, options3);
28335
+ }
28336
+ async function getSubgraphMarkdown(name, options3) {
28337
+ return (await getPlatformClient()).subgraphs.markdown(name, options3);
28338
+ }
28339
+ async function reindexSubgraphApi(name) {
28340
+ return (await getPlatformClient()).subgraphs.reindex(name);
28341
+ }
28342
+ async function backfillSubgraphApi(name, options3) {
28343
+ return (await getPlatformClient()).subgraphs.backfill(name, options3);
28344
+ }
28345
+ async function stopSubgraphApi(name) {
28346
+ return (await getPlatformClient()).subgraphs.stop(name);
28347
+ }
28348
+ async function deleteSubgraphApi(name, options3) {
28349
+ return (await getPlatformClient()).subgraphs.delete(name, options3);
28350
+ }
28351
+ async function deploySubgraphApi(data) {
28352
+ return (await getPlatformClient()).subgraphs.deploy(data);
28353
+ }
28354
+ async function querySubgraphTable(name, table, params = {}) {
28355
+ return (await getPlatformClient()).subgraphs.queryTable(name, table, params);
28356
+ }
28357
+ async function querySubgraphTableCount(name, table, params = {}) {
28358
+ return (await getPlatformClient()).subgraphs.queryTableCount(name, table, params);
28359
+ }
28360
+ async function getSubgraphGaps(name, opts) {
28361
+ return (await getPlatformClient()).subgraphs.gaps(name, opts);
28362
+ }
28363
+ async function getContractPrintSchema(contractId) {
28364
+ let client;
28365
+ try {
28366
+ client = await getPlatformClient();
28367
+ } catch {
28368
+ client = new SecondLayer({ baseUrl: resolveApiUrl() });
28369
+ }
28370
+ return client.index.printSchema(contractId);
28371
+ }
28372
+ var init_api_client = __esm(() => {
28373
+ init_http();
28374
+ init_output();
28375
+ init_resolve_auth();
28376
+ });
28377
+
28403
28378
  // src/lib/fs.ts
28404
28379
  import { mkdir as mkdir2, readFile as readFile2, stat, unlink, writeFile as writeFile2 } from "node:fs/promises";
28405
28380
  async function readJsonFile(path11) {
@@ -29587,7 +29562,6 @@ import {
29587
29562
  generatePrintPayloadTypes,
29588
29563
  generatePrintSchemaSubgraph
29589
29564
  } from "@secondlayer/scaffold";
29590
- import { ByoBreakingChangeError } from "@secondlayer/sdk";
29591
29565
  import { TRAIT_STANDARDS } from "@secondlayer/stacks/clarity";
29592
29566
  async function loadSubgraphWithDepCheck(absPath) {
29593
29567
  try {
@@ -29940,27 +29914,6 @@ ${dim("Columns")}`);
29940
29914
  const deployTarget = context.bundled ? "tenant API" : "local database";
29941
29915
  info(`Dry run only. No ${deployTarget} changes were made.`);
29942
29916
  }
29943
- function printByoBreakingPlan(details) {
29944
- error("Refusing breaking schema change on BYO subgraph (no data dropped).");
29945
- console.log(`
29946
- Breaking changes:`);
29947
- for (const r2 of details.reasons)
29948
- console.log(` ${red("✗")} ${r2}`);
29949
- console.log(`
29950
- To rebuild manually, run on YOUR database:`);
29951
- console.log(` ${details.plan.dropStatement}`);
29952
- console.log(` ${details.plan.statements.join(`;
29953
- `)}`);
29954
- console.log(`
29955
- Grant (first deploy only):`);
29956
- for (const line of details.plan.grantScript.split(`
29957
- `)) {
29958
- console.log(` ${dim(line)}`);
29959
- }
29960
- console.log(`
29961
- ${yellow("This DROPS all rows in that schema, then rebuilds it. Re-deploy after.")}`);
29962
- console.log(dim("(--force destructive rebuild not yet supported — manual DROP required.)"));
29963
- }
29964
29917
  function formatDuration(seconds2) {
29965
29918
  if (seconds2 < 90)
29966
29919
  return `${Math.max(1, Math.round(seconds2))}s`;
@@ -30140,7 +30093,7 @@ Stopped watching.`);
30140
30093
  });
30141
30094
  await new Promise(() => {});
30142
30095
  });
30143
- subgraphs.command("deploy <file>").alias("update").description("Deploy a subgraph definition file (alias: update — deploy is create-or-update)").option("--start-block <n>", "Override the subgraph definition startBlock for this deploy").option("--tip-first", "Go live at chain tip immediately; history backfills in the background (requires order-tolerant handlers — commutative or insert-only writes)").option("--dry-run", "Validate and preview deploy without writing changes").option("-y, --yes", "Skip the reindex confirmation prompt").option("--database-url <url>", "BYO data plane: write the subgraph's schema/rows to your own Postgres. With --dry-run, prints the DDL + grant script and verifies the connection.").option("--strict", "Run `tsc --noEmit` against the handler before deploy (slower; catches TS type errors)").addOption(new Option("--visibility <visibility>", "Hosted only. Public/private namespace.").hideHelp()).option("--allow-uncommitted", "Deploy even though the source file is not committed to git (the deployed definition will exist only in the database)").action(async (file, options3) => {
30096
+ subgraphs.command("deploy <file>").alias("update").description("Deploy a subgraph definition file (alias: update — deploy is create-or-update)").option("--start-block <n>", "Override the subgraph definition startBlock for this deploy").option("--tip-first", "Go live at chain tip immediately; history backfills in the background (requires order-tolerant handlers — commutative or insert-only writes)").option("--dry-run", "Validate and preview deploy without writing changes").option("-y, --yes", "Skip the reindex confirmation prompt").option("--strict", "Run `tsc --noEmit` against the handler before deploy (slower; catches TS type errors)").addOption(new Option("--visibility <visibility>", "Hosted only. Public/private namespace.").hideHelp()).option("--allow-uncommitted", "Deploy even though the source file is not committed to git (the deployed definition will exist only in the database)").action(async (file, options3) => {
30144
30097
  try {
30145
30098
  const absPath = resolve3(file);
30146
30099
  if (!options3.dryRun) {
@@ -30173,15 +30126,6 @@ Stopped watching.`);
30173
30126
  }
30174
30127
  const dryRun = options3.dryRun;
30175
30128
  const visibility = parseVisibilityOption(options3.visibility);
30176
- if (visibility === "public" && options3.databaseUrl && !options3.yes) {
30177
- const confirmed = await confirm3({
30178
- message: "⚠ Public BYO subgraph: anonymous reads will query YOUR database. Continue?"
30179
- });
30180
- if (!confirmed) {
30181
- info("Aborted.");
30182
- process.exit(0);
30183
- }
30184
- }
30185
30129
  const startBlock = parseStartBlockOption(options3.startBlock);
30186
30130
  if (startBlock !== undefined) {
30187
30131
  warn(`--start-block ${startBlock} overrides the definition's startBlock for this deploy.`);
@@ -30246,9 +30190,6 @@ Stopped watching.`);
30246
30190
  }
30247
30191
  }
30248
30192
  }
30249
- if (options3.databaseUrl) {
30250
- info("BYO data plane: schema + rows will live in your database. The server verifies the connection before deploying.");
30251
- }
30252
30193
  const result = await deploySubgraphApi({
30253
30194
  name: effectiveDef.name,
30254
30195
  version: undefined,
@@ -30258,12 +30199,8 @@ Stopped watching.`);
30258
30199
  handlerCode,
30259
30200
  sourceCode: source,
30260
30201
  ...deployStartBlock !== undefined ? { startBlock: deployStartBlock } : {},
30261
- ...options3.databaseUrl ? { databaseUrl: options3.databaseUrl } : {},
30262
30202
  ...visibility ? { visibility } : {}
30263
30203
  });
30264
- if (result.start_block_clamped) {
30265
- info(` Free tier indexes forward from deploy (start block ${result.start_block}) — upgrade for genesis backfill.`);
30266
- }
30267
30204
  for (const w2 of result.warnings ?? [])
30268
30205
  warn(w2);
30269
30206
  const printDeployFooter = async () => {
@@ -30276,7 +30213,6 @@ Stopped watching.`);
30276
30213
  info(` Share: ${apiUrl}/v1/subgraphs/${effectiveDef.name} (public — no key needed)`);
30277
30214
  } else if (firstTable) {
30278
30215
  info(` REST: ${apiUrl}/api/subgraphs/${effectiveDef.name}/${firstTable}`);
30279
- info(` Publish: secondlayer subgraphs publish ${effectiveDef.name} (open anon /v1 reads)`);
30280
30216
  }
30281
30217
  if (result.reindexStarted) {
30282
30218
  const denom = result.estimatedEvents != null ? ` ~${result.estimatedEvents.toLocaleString()} events —` : "";
@@ -30356,14 +30292,6 @@ Stopped watching.`);
30356
30292
  await closeDb();
30357
30293
  }
30358
30294
  } catch (err) {
30359
- if (err instanceof ByoBreakingChangeError) {
30360
- printByoBreakingPlan(err.details);
30361
- process.exit(1);
30362
- }
30363
- if (err && typeof err === "object" && err.code === "BYO_BREAKING_CHANGE" && err.details) {
30364
- printByoBreakingPlan(err.details);
30365
- process.exit(1);
30366
- }
30367
30295
  error(`Failed to deploy subgraph: ${err}`);
30368
30296
  process.exit(1);
30369
30297
  }
@@ -30700,33 +30628,6 @@ ${rows.length} row(s)`));
30700
30628
  handleApiError(err, "delete subgraph");
30701
30629
  }
30702
30630
  });
30703
- subgraphs.command("publish <name>", { hidden: true }).description("Make a subgraph publicly readable on /v1/subgraphs/<name> (claims the name globally, no key needed to read)").action(async (name) => {
30704
- try {
30705
- await requireAuth();
30706
- const result = await publishSubgraphApi(name);
30707
- success(`Subgraph "${name}" is now public`);
30708
- try {
30709
- const { apiUrl } = await resolveAuth();
30710
- info(` Share: ${apiUrl}${result.url} (no key needed)`);
30711
- } catch {}
30712
- } catch (err) {
30713
- const status = err?.status;
30714
- if (status === 409) {
30715
- error(`Public name "${name}" is already taken by another account. Rename the subgraph (redeploy under a new name) or keep it private.`);
30716
- process.exit(1);
30717
- }
30718
- handleApiError(err, "publish subgraph");
30719
- }
30720
- });
30721
- subgraphs.command("unpublish <name>", { hidden: true }).description("Make a subgraph private again — reads require your API key, the public name claim is released").action(async (name) => {
30722
- try {
30723
- await requireAuth();
30724
- await unpublishSubgraphApi(name);
30725
- success(`Subgraph "${name}" is now private (reads need your key)`);
30726
- } catch (err) {
30727
- handleApiError(err, "unpublish subgraph");
30728
- }
30729
- });
30730
30631
  subgraphs.command("scaffold [contractAddress]").description("Scaffold a defineSubgraph() file from a contract or trait").option("-o, --output <path>", "Output file path (required)").option("-k, --api-key <key>", "Stacks node API key for direct RPC URLs").option("--functions <names>", "Comma-separated public functions to index as typed contract_call tables").option("--trait <std>", "Scaffold a trait-scoped source (sip-009|sip-010|sip-013) — no contract needed").option("--no-install", "Skip bun install after writing package.json").addHelpText("after", `
30731
30632
  Examples:
30732
30633
  $ secondlayer subgraphs scaffold SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft -o subgraphs/apes.ts
@@ -34789,7 +34690,7 @@ init_esm();
34789
34690
  // package.json
34790
34691
  var package_default = {
34791
34692
  name: "@secondlayer/cli",
34792
- version: "10.3.2",
34693
+ version: "11.0.0",
34793
34694
  repository: {
34794
34695
  type: "git",
34795
34696
  url: "git+https://github.com/ryanwaits/secondlayer.git",
@@ -34830,12 +34731,12 @@ var package_default = {
34830
34731
  "@biomejs/wasm-nodejs": "^1.9.0",
34831
34732
  "@dsnp/parquetjs": "^1.8.8",
34832
34733
  "@inquirer/prompts": "^8.2.0",
34833
- "@secondlayer/bundler": "^0.5.0",
34834
- "@secondlayer/scaffold": "^1.5.1",
34835
- "@secondlayer/sdk": "^6.54.1",
34836
- "@secondlayer/shared": "^7.11.1",
34734
+ "@secondlayer/bundler": "^0.5.1",
34735
+ "@secondlayer/scaffold": "^1.5.3",
34736
+ "@secondlayer/sdk": "^7.0.0",
34737
+ "@secondlayer/shared": "^8.0.0",
34837
34738
  "@secondlayer/stacks": "^3.3.1",
34838
- "@secondlayer/subgraphs": "^3.26.4",
34739
+ "@secondlayer/subgraphs": "^4.0.0",
34839
34740
  esbuild: "^0.27.4",
34840
34741
  "smol-toml": "^1.6.1",
34841
34742
  zod: "^4.3.6"
@@ -34855,134 +34756,6 @@ var package_default = {
34855
34756
  }
34856
34757
  };
34857
34758
 
34858
- // src/commands/account.ts
34859
- init_api_client();
34860
- init_output();
34861
-
34862
- // src/commands/billing.ts
34863
- init_http();
34864
- init_output();
34865
- async function runBillingStatus(json) {
34866
- let res;
34867
- try {
34868
- res = await httpPlatform("/api/billing/status");
34869
- } catch (err) {
34870
- if (err instanceof CliHttpError) {
34871
- error(err.message);
34872
- process.exit(1);
34873
- }
34874
- throw err;
34875
- }
34876
- output({ json, data: res, human: () => renderBillingStatus(res) });
34877
- }
34878
- function addBillingCommand(parent) {
34879
- parent.command("billing").description("Show archive credit balance (hidden; use secondlayer credits)").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
34880
- }
34881
- function renderBillingStatus(res) {
34882
- if (!res.subscription) {
34883
- console.log(formatKeyValue([
34884
- ["Credits", dim("secondlayer credits balance")],
34885
- [
34886
- "Buy",
34887
- dim("secondlayer credits buy --email you@example.com --pack 25")
34888
- ]
34889
- ]));
34890
- return;
34891
- }
34892
- const rows = [];
34893
- rows.push(["Plan", res.plan]);
34894
- rows.push([
34895
- "Customer",
34896
- res.stripeCustomerId ?? dim("(none — no subscription yet)")
34897
- ]);
34898
- const sub = res.subscription;
34899
- rows.push(["Subscription", `${sub.id} (${sub.status})`]);
34900
- if (sub.tier)
34901
- rows.push(["Tier", sub.tier]);
34902
- if (sub.amountCents !== null && sub.interval) {
34903
- const dollars = (sub.amountCents / 100).toFixed(2);
34904
- rows.push(["Price", `$${dollars} / ${sub.interval}`]);
34905
- }
34906
- if (sub.trialEnd) {
34907
- const days = Math.max(0, Math.round((new Date(sub.trialEnd).getTime() - Date.now()) / 86400000));
34908
- rows.push([
34909
- "Trial ends",
34910
- `${formatDate(sub.trialEnd)} (${days}d remaining)`
34911
- ]);
34912
- }
34913
- if (sub.currentPeriodEnd) {
34914
- rows.push(["Renews", formatDate(sub.currentPeriodEnd)]);
34915
- }
34916
- if (sub.cancelAtPeriodEnd) {
34917
- rows.push(["Cancels at period end", "yes"]);
34918
- }
34919
- if (sub.discount) {
34920
- const off = sub.discount.percentOff !== null ? `${sub.discount.percentOff}% off` : sub.discount.amountOff !== null ? `$${(sub.discount.amountOff / 100).toFixed(2)} off` : "discount";
34921
- const label = sub.discount.code ? `${sub.discount.code} (${sub.discount.name ?? "coupon"})` : sub.discount.name ?? "applied";
34922
- rows.push(["Discount", `${label} — ${off}, ${sub.discount.duration}`]);
34923
- }
34924
- console.log(formatKeyValue(rows));
34925
- }
34926
- function formatDate(iso) {
34927
- return new Date(iso).toISOString().slice(0, 10);
34928
- }
34929
-
34930
- // src/commands/account.ts
34931
- async function showProfile(json) {
34932
- const profile = await getAccountProfile();
34933
- output({
34934
- json,
34935
- data: profile,
34936
- human: () => console.log(formatKeyValue([
34937
- ["Email", profile.email],
34938
- ["Plan", profile.plan],
34939
- ["Display Name", profile.displayName ?? dim("—")],
34940
- ["Bio", profile.bio ?? dim("—")],
34941
- ["Slug", profile.slug ?? dim("—")],
34942
- [
34943
- "Notify on reindex complete",
34944
- profile.notifyReindexComplete ? "on" : "off"
34945
- ]
34946
- ]))
34947
- });
34948
- }
34949
- async function applyProfileUpdate(options, getOptionValueSource) {
34950
- const data = {};
34951
- if (options.name)
34952
- data.display_name = options.name;
34953
- if (options.bio)
34954
- data.bio = options.bio;
34955
- if (options.slug)
34956
- data.slug = options.slug;
34957
- if (getOptionValueSource("notifyReindexComplete") === "cli") {
34958
- data.notify_reindex_complete = options.notifyReindexComplete;
34959
- }
34960
- const updated = await updateAccountProfile(data);
34961
- output({
34962
- json: options.json,
34963
- data: updated,
34964
- human: () => {
34965
- success("Profile updated");
34966
- console.log(formatKeyValue([
34967
- ["Display Name", updated.displayName ?? dim("—")],
34968
- ["Bio", updated.bio ?? dim("—")],
34969
- ["Slug", updated.slug ?? dim("—")],
34970
- [
34971
- "Notify on reindex complete",
34972
- updated.notifyReindexComplete ? "on" : "off"
34973
- ]
34974
- ]));
34975
- }
34976
- });
34977
- }
34978
- function registerAccountCommand(program2) {
34979
- const account = program2.command("account", { hidden: true }).description("Manage your account profile");
34980
- addBillingCommand(account);
34981
- account.command("get").description("Show your account profile").option("--json", "Output as JSON").action(withErrorHandling(async (options) => showProfile(options.json), { action: "show profile" }));
34982
- account.command("update").description("Update your public profile").option("--name <name>", "Set display name").option("--bio <bio>", "Set bio").option("--slug <slug>", "Set public URL slug").option("--notify-reindex-complete", "Email me when a subgraph reindex finishes").option("--no-notify-reindex-complete", "Don't email me when a subgraph reindex finishes").option("--json", "Output as JSON").action(withErrorHandling(async (options, command) => applyProfileUpdate(options, (key) => command.getOptionValueSource(key)), {
34983
- action: "update profile"
34984
- }));
34985
- }
34986
34759
  // src/commands/credits.ts
34987
34760
  init_http();
34988
34761
  init_output();
@@ -35497,6 +35270,65 @@ async function validateDatabaseConnection(url) {
35497
35270
  console.log(dim("The URL was saved but connection failed. Check your database settings."));
35498
35271
  }
35499
35272
  }
35273
+ // src/commands/console.ts
35274
+ init_output();
35275
+ init_resolve_auth();
35276
+ import { spawn as spawn3 } from "node:child_process";
35277
+ var DEFAULT_CONSOLE_URL = "http://localhost:3801/console";
35278
+ var CONSOLE_PORT = 3801;
35279
+ function resolveConsoleUrl(override) {
35280
+ if (override)
35281
+ return override.replace(/\/+$/, "");
35282
+ const apiUrl = process.env.SL_API_URL;
35283
+ if (apiUrl && isOssMode()) {
35284
+ try {
35285
+ const { protocol, hostname } = new URL(apiUrl);
35286
+ return `${protocol}//${hostname}:${CONSOLE_PORT}/console`;
35287
+ } catch {}
35288
+ }
35289
+ return DEFAULT_CONSOLE_URL;
35290
+ }
35291
+ async function isReachable(url) {
35292
+ try {
35293
+ await fetch(url, { signal: AbortSignal.timeout(2000) });
35294
+ return true;
35295
+ } catch {
35296
+ return false;
35297
+ }
35298
+ }
35299
+ function openBrowser(url) {
35300
+ const opener = process.platform === "darwin" ? "open" : process.platform === "linux" ? "xdg-open" : undefined;
35301
+ if (!opener)
35302
+ return Promise.resolve(false);
35303
+ return new Promise((resolve5) => {
35304
+ const child = spawn3(opener, [url], { stdio: "ignore", detached: true });
35305
+ child.once("error", () => resolve5(false));
35306
+ child.once("spawn", () => {
35307
+ child.unref();
35308
+ resolve5(true);
35309
+ });
35310
+ });
35311
+ }
35312
+ function registerConsoleCommand(program2) {
35313
+ program2.command("console").description("Open the console UI in a browser").option("--url <url>", `Console URL (default ${DEFAULT_CONSOLE_URL})`).option("--no-open", "Print the console URL instead of opening a browser").action(async (options3) => {
35314
+ const url = resolveConsoleUrl(options3.url);
35315
+ if (options3.open === false) {
35316
+ writeData(url);
35317
+ return;
35318
+ }
35319
+ if (!await isReachable(url)) {
35320
+ printError(`Console not reachable at ${url}`, {
35321
+ hint: "docker compose --profile console up -d"
35322
+ });
35323
+ process.exit(1);
35324
+ }
35325
+ if (await openBrowser(url)) {
35326
+ success(`console: ${url}`);
35327
+ } else {
35328
+ writeData(url);
35329
+ }
35330
+ });
35331
+ }
35500
35332
  // src/commands/context.ts
35501
35333
  init_output();
35502
35334
  init_resolve_auth();
@@ -37350,46 +37182,6 @@ Examples:
37350
37182
  // src/commands/index.ts
37351
37183
  init_index_api();
37352
37184
 
37353
- // src/commands/keys.ts
37354
- init_output();
37355
- init_resolve_auth();
37356
- import { SecondLayer as SecondLayer4 } from "@secondlayer/sdk";
37357
- function registerKeysCommand(program2) {
37358
- const keys = program2.command("keys", { hidden: true }).description("Manage API keys");
37359
- keys.command("create").description("Mint a scoped streams/index read key (requires an account-level key)").option("--product <product>", "Key scope: streams or index", "streams").option("--name <name>", "Optional label for the key").option("--json", "Print the full response as JSON").action(async (o3) => {
37360
- if (o3.product && o3.product !== "streams" && o3.product !== "index") {
37361
- error("--product must be 'streams' or 'index'");
37362
- process.exit(1);
37363
- }
37364
- const apiKey = resolveEnvKey();
37365
- if (!apiKey) {
37366
- error("No API key set. Export SL_API_KEY with an account-level key (issue one at https://www.secondlayer.tools/platform/api-keys).");
37367
- process.exit(1);
37368
- }
37369
- try {
37370
- const sl = new SecondLayer4({
37371
- baseUrl: resolveApiUrl(),
37372
- apiKey
37373
- });
37374
- const minted = await sl.apiKeys.create({
37375
- product: o3.product === "index" ? "index" : "streams",
37376
- name: o3.name
37377
- });
37378
- output({
37379
- json: o3.json,
37380
- data: minted,
37381
- human: () => {
37382
- success(`Created ${minted.product} key (${minted.prefix}…)`);
37383
- note("This key is shown once — store it now:");
37384
- writeData(minted.key);
37385
- }
37386
- });
37387
- } catch (err) {
37388
- error(err instanceof Error ? err.message : String(err));
37389
- process.exit(1);
37390
- }
37391
- });
37392
- }
37393
37185
  // src/commands/doctor.ts
37394
37186
  init_config2();
37395
37187
 
@@ -38603,14 +38395,6 @@ async function readActiveProject(cwd, globalDefault) {
38603
38395
  }
38604
38396
  return null;
38605
38397
  }
38606
- async function writeActiveProject(slug, cwd) {
38607
- const dir = join13(resolve11(cwd), DIRNAME);
38608
- await mkdir4(dir, { recursive: true });
38609
- const file = join13(dir, FILENAME);
38610
- await writeFile4(file, `${JSON.stringify({ slug }, null, 2)}
38611
- `, "utf8");
38612
- return file;
38613
- }
38614
38398
 
38615
38399
  // src/commands/whoami.ts
38616
38400
  init_resolve_auth();
@@ -38640,7 +38424,6 @@ function registerWhoamiCommand(program2) {
38640
38424
  json: options3.json,
38641
38425
  data: {
38642
38426
  email: account.email,
38643
- plan: account.plan,
38644
38427
  apiUrl: auth.apiUrl,
38645
38428
  authSource,
38646
38429
  project: active ? { slug: active.slug, source: active.resolvedFrom } : null
@@ -38648,7 +38431,6 @@ function registerWhoamiCommand(program2) {
38648
38431
  human: () => {
38649
38432
  const rows = [];
38650
38433
  rows.push(["Email", account.email]);
38651
- rows.push(["Plan", account.plan]);
38652
38434
  rows.push(["API URL", auth.apiUrl]);
38653
38435
  rows.push(["Auth", dim(authSource)]);
38654
38436
  if (active) {
@@ -38691,85 +38473,6 @@ function registerLogoutCommand(program2) {
38691
38473
  success("Logged out.");
38692
38474
  });
38693
38475
  }
38694
- // src/commands/project.ts
38695
- init_config2();
38696
- init_http();
38697
- init_output();
38698
- function registerProjectCommand(program2) {
38699
- const project = program2.command("projects", { hidden: true }).alias("project").description("Manage your Secondlayer project");
38700
- project.command("list").alias("ls").description("List projects in your account").option("--json", "Output as JSON").action(async (options3) => {
38701
- try {
38702
- const res = await httpPlatform("/api/projects");
38703
- const active = await readActiveProject(process.cwd(), (await loadConfig2()).defaultProject);
38704
- output({
38705
- json: options3.json,
38706
- data: { projects: res.projects, active: active?.slug ?? null },
38707
- human: () => {
38708
- if (res.projects.length === 0) {
38709
- info("No project found.");
38710
- return;
38711
- }
38712
- const rows = res.projects.map((p2) => [
38713
- p2.slug === active?.slug ? `* ${p2.slug}` : ` ${p2.slug}`,
38714
- p2.name,
38715
- p2.network,
38716
- new Date(p2.createdAt).toLocaleDateString()
38717
- ]);
38718
- console.log(formatTable(["", "Name", "Network", "Created"], rows));
38719
- if (active) {
38720
- console.log(dim(`Active: ${active.slug} (from ${active.resolvedFrom})`));
38721
- }
38722
- }
38723
- });
38724
- } catch (err) {
38725
- handleProjectError(err);
38726
- }
38727
- });
38728
- project.command("use <slug>").description("Bind this directory to a project (writes ./.secondlayer/project)").action(async (slug) => {
38729
- try {
38730
- await httpPlatform(`/api/projects/${encodeURIComponent(slug)}`);
38731
- } catch (err) {
38732
- if (err instanceof CliHttpError && err.status === 404) {
38733
- error(`Project "${slug}" not found — run 'secondlayer project list' to see available projects`);
38734
- process.exit(1);
38735
- }
38736
- handleProjectError(err);
38737
- }
38738
- const path11 = await writeActiveProject(slug, process.cwd());
38739
- success(`Bound to project "${slug}"`);
38740
- info(dim(`Written to ${path11}`));
38741
- info(dim("Tip: add `.secondlayer/` to .gitignore — it's account-personal."));
38742
- });
38743
- project.command("get").description("Show the active project for this directory").option("--json", "Output as JSON").action(async (options3) => {
38744
- const config = await loadConfig2();
38745
- const active = await readActiveProject(process.cwd(), config.defaultProject);
38746
- output({
38747
- json: options3.json,
38748
- data: active ? { slug: active.slug, source: active.resolvedFrom } : null,
38749
- human: () => {
38750
- if (!active) {
38751
- info("No active project.");
38752
- info(dim("Run 'secondlayer project use <slug>' to bind this directory."));
38753
- return;
38754
- }
38755
- console.log(active.slug);
38756
- console.log(dim(`(from ${active.resolvedFrom})`));
38757
- }
38758
- });
38759
- });
38760
- }
38761
- function handleProjectError(err) {
38762
- if (err instanceof CliHttpError) {
38763
- if (err.code === "SESSION_EXPIRED") {
38764
- error("Session expired. Run: secondlayer login");
38765
- process.exit(1);
38766
- }
38767
- error(err.message);
38768
- process.exit(1);
38769
- }
38770
- error(err instanceof Error ? err.message : String(err));
38771
- process.exit(1);
38772
- }
38773
38476
  // src/commands/verify.ts
38774
38477
  import {
38775
38478
  compareRangeDigests,
@@ -39873,6 +39576,7 @@ function registerStartCommand(program2) {
39873
39576
  }
39874
39577
  success(`config ok (${parsed.config.NETWORK}, ${parsed.config.NODE_MODE})`);
39875
39578
  console.log(cmd);
39579
+ note(" console UI (optional): add --profile console, then `secondlayer console`");
39876
39580
  });
39877
39581
  }
39878
39582
  // src/cli.ts
@@ -39899,6 +39603,7 @@ registerInitCommand(program);
39899
39603
  registerBootstrapCommand(program);
39900
39604
  registerObserverCommand(program);
39901
39605
  registerStartCommand(program);
39606
+ registerConsoleCommand(program);
39902
39607
  registerLoginCommand(program);
39903
39608
  registerLogoutCommand(program);
39904
39609
  registerWhoamiCommand(program);
@@ -39908,7 +39613,6 @@ registerSubscriptionsCommand(program);
39908
39613
  registerStreamsCommand(program);
39909
39614
  registerIndexCommand(program);
39910
39615
  program.commandsGroup("Project & codegen:");
39911
- registerProjectCommand(program);
39912
39616
  registerCodegenCommand(program);
39913
39617
  var configureGenerate = (cmd) => cmd.option("-c, --config <path>", "Path to config file").option("-o, --output <path>", "Output file path (required when using direct files)").option("-k, --api-key <key>", "Stacks node API key for direct RPC URLs").option("-w, --watch", "Watch for changes").action(async (files, options3) => {
39914
39618
  const { deprecatedCodegenNotice: deprecatedCodegenNotice2 } = await Promise.resolve().then(() => (init_codegen(), exports_codegen));
@@ -39935,9 +39639,7 @@ registerVerifyCommand(program);
39935
39639
  registerRepairCommand(program);
39936
39640
  program.commandsGroup("Account:");
39937
39641
  registerCreditsCommand(program);
39938
- registerAccountCommand(program);
39939
- registerKeysCommand(program);
39940
39642
  program.parse();
39941
39643
 
39942
- //# debugId=0D2E887299BDADAE64756E2164756E21
39644
+ //# debugId=3107CF5F3E1F73F364756E2164756E21
39943
39645
  //# sourceMappingURL=cli.js.map