@secondlayer/cli 3.0.0 → 3.1.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
@@ -32410,7 +32410,7 @@ var {
32410
32410
  // package.json
32411
32411
  var package_default = {
32412
32412
  name: "@secondlayer/cli",
32413
- version: "3.0.0",
32413
+ version: "3.1.0",
32414
32414
  description: "CLI for subgraphs and blockchain indexing on Stacks",
32415
32415
  type: "module",
32416
32416
  bin: {
@@ -32452,8 +32452,8 @@ var package_default = {
32452
32452
  dependencies: {
32453
32453
  "@inquirer/prompts": "^8.2.0",
32454
32454
  "@secondlayer/bundler": "^0.3.0",
32455
- "@secondlayer/sdk": "^1.0.1",
32456
- "@secondlayer/shared": "^2.0.0",
32455
+ "@secondlayer/sdk": "^2.0.0",
32456
+ "@secondlayer/shared": "^2.1.0",
32457
32457
  "@secondlayer/stacks": "^0.3.0",
32458
32458
  "@secondlayer/subgraphs": "^0.11.8",
32459
32459
  "@secondlayer/workflows": "^1.1.0",
@@ -32521,20 +32521,6 @@ function withErrorHandling(fn, options) {
32521
32521
  }
32522
32522
  };
32523
32523
  }
32524
- async function assertOk(res) {
32525
- if (res.ok)
32526
- return;
32527
- const body = await res.text();
32528
- try {
32529
- const parsed = JSON.parse(body);
32530
- if (typeof parsed.error === "string" && parsed.error)
32531
- throw new Error(parsed.error);
32532
- } catch (e) {
32533
- if (e instanceof Error && e.message !== body)
32534
- throw e;
32535
- }
32536
- throw new Error(`HTTP ${res.status}`);
32537
- }
32538
32524
  async function getTenantClient() {
32539
32525
  const { apiUrl, ephemeralKey } = await resolveActiveTenant();
32540
32526
  return new SecondLayer({ baseUrl: apiUrl, apiKey: ephemeralKey });
@@ -32569,51 +32555,12 @@ async function querySubgraphTableCount(name, table, params = {}) {
32569
32555
  async function getSubgraphGaps(name, opts) {
32570
32556
  return (await getTenantClient()).subgraphs.gaps(name, opts);
32571
32557
  }
32572
- async function publishSubgraphApi(name, opts) {
32573
- const { apiUrl, ephemeralKey } = await resolveActiveTenant();
32574
- const res = await fetch(`${apiUrl}/api/subgraphs/${name}/publish`, {
32575
- method: "POST",
32576
- headers: {
32577
- "content-type": "application/json",
32578
- authorization: `Bearer ${ephemeralKey}`
32579
- },
32580
- body: JSON.stringify(opts ?? {})
32581
- });
32582
- await assertOk(res);
32583
- return res.json();
32584
- }
32585
- async function unpublishSubgraphApi(name) {
32586
- const { apiUrl, ephemeralKey } = await resolveActiveTenant();
32587
- const res = await fetch(`${apiUrl}/api/subgraphs/${name}/unpublish`, {
32588
- method: "POST",
32589
- headers: {
32590
- "content-type": "application/json",
32591
- authorization: `Bearer ${ephemeralKey}`
32592
- },
32593
- body: JSON.stringify({})
32594
- });
32595
- await assertOk(res);
32596
- return res.json();
32597
- }
32598
32558
  async function getAccountProfile() {
32599
32559
  return httpPlatform("/api/accounts/me");
32600
32560
  }
32601
32561
  async function updateAccountProfile(data) {
32602
32562
  return httpPlatform("/api/accounts/me", { method: "PATCH", body: data });
32603
32563
  }
32604
- async function getPlatformClient() {
32605
- const base = process.env.SL_PLATFORM_API_URL ?? "https://api.secondlayer.tools";
32606
- return new SecondLayer({ baseUrl: base });
32607
- }
32608
- async function browseMarketplace(opts = {}) {
32609
- return (await getPlatformClient()).marketplace.browse(opts);
32610
- }
32611
- async function getMarketplaceSubgraph(name) {
32612
- return (await getPlatformClient()).marketplace.get(name);
32613
- }
32614
- async function forkMarketplaceSubgraph(name, newName) {
32615
- return (await getPlatformClient()).marketplace.fork(name, newName);
32616
- }
32617
32564
 
32618
32565
  // src/commands/account.ts
32619
32566
  init_output();
@@ -34103,37 +34050,6 @@ ${rows.length} row(s)`));
34103
34050
  handleApiError(err, "delete subgraph");
34104
34051
  }
34105
34052
  });
34106
- subgraphs.command("publish <name>").description("Publish a subgraph to the marketplace").option("--tags <tags>", "Tags (comma-separated, max 5)").option("--description <desc>", "Public description (max 500 chars)").option("--json", "Output as JSON").action(async (name, options2) => {
34107
- try {
34108
- const opts = {};
34109
- if (options2.tags) {
34110
- opts.tags = options2.tags.split(",").map((t) => t.trim());
34111
- }
34112
- if (options2.description) {
34113
- opts.description = options2.description;
34114
- }
34115
- const result = await publishSubgraphApi(name, opts);
34116
- if (options2.json) {
34117
- console.log(JSON.stringify(result, null, 2));
34118
- return;
34119
- }
34120
- success(result.message);
34121
- } catch (err) {
34122
- handleApiError(err, "publish subgraph");
34123
- }
34124
- });
34125
- subgraphs.command("unpublish <name>").description("Remove a subgraph from the marketplace").option("--json", "Output as JSON").action(async (name, options2) => {
34126
- try {
34127
- const result = await unpublishSubgraphApi(name);
34128
- if (options2.json) {
34129
- console.log(JSON.stringify(result, null, 2));
34130
- return;
34131
- }
34132
- success(result.message);
34133
- } catch (err) {
34134
- handleApiError(err, "unpublish subgraph");
34135
- }
34136
- });
34137
34053
  subgraphs.command("scaffold <contractAddress>").description("Scaffold a defineSubgraph() file from a contract ABI").option("-o, --output <path>", "Output file path (required)").option("--api-key <key>", "Hiro API key").action(async (contractAddress, options2) => {
34138
34054
  try {
34139
34055
  if (!options2.output) {
@@ -34981,89 +34897,6 @@ function formatLogLine3(service, line) {
34981
34897
  }
34982
34898
  return `${prefix} ${line}`;
34983
34899
  }
34984
- // src/commands/marketplace.ts
34985
- init_output();
34986
- function registerMarketplaceCommand(program2) {
34987
- const marketplace = program2.command("marketplace").alias("mp").description("Browse the public subgraph marketplace");
34988
- marketplace.command("browse").description("List public subgraphs").option("--tags <tags>", "Filter by tags (comma-separated)").option("--search <query>", "Search by name or description").option("--sort <field>", "Sort by: recent, popular, name", "recent").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(async (options2) => {
34989
- try {
34990
- const result = await browseMarketplace({
34991
- tags: options2.tags ? options2.tags.split(",").map((t) => t.trim()) : undefined,
34992
- search: options2.search,
34993
- sort: options2.sort,
34994
- limit: Number.parseInt(options2.limit ?? "20", 10)
34995
- });
34996
- if (options2.json) {
34997
- console.log(JSON.stringify(result, null, 2));
34998
- return;
34999
- }
35000
- if (result.data.length === 0) {
35001
- console.log(dim("No public subgraphs found"));
35002
- return;
35003
- }
35004
- const rows = result.data.map((s) => [
35005
- s.name,
35006
- s.creator?.displayName ?? s.creator?.slug ?? dim("—"),
35007
- (s.tags ?? []).join(", ") || dim("—"),
35008
- s.status
35009
- ]);
35010
- console.log(formatTable(["Name", "Creator", "Tags", "Status"], rows));
35011
- console.log(dim(`
35012
- ${result.meta.total} subgraph(s) total`));
35013
- } catch (err) {
35014
- handleApiError(err, "browse marketplace");
35015
- }
35016
- });
35017
- marketplace.command("view <name>").description("View a public subgraph's details").option("--json", "Output as JSON").action(async (name, options2) => {
35018
- try {
35019
- const detail = await getMarketplaceSubgraph(name);
35020
- if (options2.json) {
35021
- console.log(JSON.stringify(detail, null, 2));
35022
- return;
35023
- }
35024
- console.log(formatKeyValue([
35025
- ["Name", detail.name],
35026
- ["Description", detail.description ?? dim("—")],
35027
- [
35028
- "Creator",
35029
- detail.creator?.displayName ?? detail.creator?.slug ?? dim("—")
35030
- ],
35031
- ["Status", detail.status],
35032
- ["Version", detail.version],
35033
- ["Tags", (detail.tags ?? []).join(", ") || dim("—")],
35034
- ["Tables", detail.tables?.join(", ") ?? dim("—")],
35035
- ["Start Block", String(detail.startBlock)],
35036
- ["Last Processed", String(detail.lastProcessedBlock)],
35037
- ["Queries (7d)", String(detail.usage?.totalQueries7d ?? 0)],
35038
- ["Queries (30d)", String(detail.usage?.totalQueries30d ?? 0)],
35039
- ["Created", detail.createdAt]
35040
- ]));
35041
- if (detail.tableSchemas) {
35042
- console.log(dim(`
35043
- Endpoints:`));
35044
- for (const [table, schema] of Object.entries(detail.tableSchemas)) {
35045
- console.log(` ${cyan(table)} — ${schema.rowCount} rows — ${schema.endpoint}`);
35046
- }
35047
- }
35048
- } catch (err) {
35049
- handleApiError(err, "view subgraph");
35050
- }
35051
- });
35052
- marketplace.command("fork <name>").description("Fork a public subgraph into your account").option("--name <newName>", "Name for the forked subgraph").option("--json", "Output as JSON").action(async (name, options2) => {
35053
- try {
35054
- const result = await forkMarketplaceSubgraph(name, options2.name);
35055
- if (options2.json) {
35056
- console.log(JSON.stringify(result, null, 2));
35057
- return;
35058
- }
35059
- success(`Forked ${result.forkedFrom} as ${result.name}`);
35060
- console.log(dim(`Subgraph ID: ${result.subgraphId}`));
35061
- console.log(dim("Indexing will start automatically from the source's start block."));
35062
- } catch (err) {
35063
- handleApiError(err, "fork subgraph");
35064
- }
35065
- });
35066
- }
35067
34900
  // src/commands/whoami.ts
35068
34901
  init_config();
35069
34902
  init_http();
@@ -35355,6 +35188,62 @@ function registerInstanceCommand(program2) {
35355
35188
  handleInstanceError(err, "rotate keys");
35356
35189
  }
35357
35190
  });
35191
+ const db = instance.command("db").description("Get a DATABASE_URL for direct Postgres access (via SSH tunnel)");
35192
+ db.command("info", { isDefault: true }).description("Print SSH tunnel command + DATABASE_URL for the instance").action(async () => {
35193
+ guardOssMode();
35194
+ try {
35195
+ const res = await httpPlatform("/api/tenants/me/db-access");
35196
+ console.log("");
35197
+ console.log(dim("1. Upload your public key (one time):"));
35198
+ console.log(dim(" sl instance db add-key ~/.ssh/id_ed25519.pub"));
35199
+ console.log("");
35200
+ console.log(dim("2. Open the SSH tunnel in a separate terminal:"));
35201
+ console.log(green(` ${res.sshCommand}`));
35202
+ console.log("");
35203
+ console.log(dim("3. Use this DATABASE_URL while the tunnel is open:"));
35204
+ console.log(green(` ${res.databaseUrl}`));
35205
+ console.log("");
35206
+ } catch (err) {
35207
+ handleInstanceError(err, "fetch db access info");
35208
+ }
35209
+ });
35210
+ db.command("add-key <path>").description("Upload an SSH public key to the bastion for this instance").action(async (path) => {
35211
+ guardOssMode();
35212
+ let publicKey;
35213
+ try {
35214
+ publicKey = (await Bun.file(path).text()).trim();
35215
+ } catch (err) {
35216
+ error(`Could not read ${path}: ${err instanceof Error ? err.message : String(err)}`);
35217
+ process.exit(1);
35218
+ }
35219
+ if (!publicKey) {
35220
+ error(`${path} is empty`);
35221
+ process.exit(1);
35222
+ }
35223
+ try {
35224
+ await httpPlatform("/api/tenants/me/db-access/key", { method: "POST", body: { publicKey } });
35225
+ success("Bastion key installed. You can now open the SSH tunnel.");
35226
+ } catch (err) {
35227
+ handleInstanceError(err, "upload bastion key");
35228
+ }
35229
+ });
35230
+ db.command("revoke-key").description("Revoke bastion access for this instance").option("-y, --yes", "Skip confirmation").action(async (opts) => {
35231
+ guardOssMode();
35232
+ if (!opts.yes) {
35233
+ const ok = await confirm4({
35234
+ message: "Revoke bastion access for this instance?",
35235
+ default: false
35236
+ });
35237
+ if (!ok)
35238
+ return;
35239
+ }
35240
+ try {
35241
+ await httpPlatform("/api/tenants/me/db-access/key", { method: "DELETE" });
35242
+ success("Bastion access revoked.");
35243
+ } catch (err) {
35244
+ handleInstanceError(err, "revoke bastion key");
35245
+ }
35246
+ });
35358
35247
  }
35359
35248
  function guardOssMode() {
35360
35249
  if (isOssMode()) {
@@ -35550,7 +35439,6 @@ registerWhoamiCommand(program);
35550
35439
  registerProjectCommand(program);
35551
35440
  registerInstanceCommand(program);
35552
35441
  registerSubgraphsCommand(program);
35553
- registerMarketplaceCommand(program);
35554
35442
  registerStatusCommand(program);
35555
35443
  registerStackCommand(program);
35556
35444
  registerDbCommand(program);
@@ -35560,5 +35448,5 @@ registerLocalCommand(program);
35560
35448
  registerAccountCommand(program);
35561
35449
  program.parse();
35562
35450
 
35563
- //# debugId=E8F09B3E58038C8F64756E2164756E21
35451
+ //# debugId=395566BC0854202D64756E2164756E21
35564
35452
  //# sourceMappingURL=cli.js.map