@secondlayer/cli 10.2.1 → 10.3.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/README.md CHANGED
@@ -10,51 +10,27 @@ sl --version
10
10
 
11
11
  ## Auth
12
12
 
13
- Two ways to authenticate:
13
+ Default API is `http://127.0.0.1:3800`. Override with `SL_API_URL`.
14
14
 
15
- - **Interactive (`sl login`)** — magic-link email → 6-digit code → session
16
- written to `~/.secondlayer/session.json`. Used for day-to-day CLI work.
17
- - **Machine / CI** — set `SL_API_KEY` to an API key created in the platform
18
- console at https://secondlayer.tools/platform/api-keys. Keys are prefixed
19
- `sk-sl_`. For a persisted headless login: `echo "$SL_API_KEY" | sl login --with-token`.
15
+ Writes against a published bind use `INSTANCE_TOKEN` from `sl init` as
16
+ `SL_API_KEY`. Loopback reads need no token.
20
17
 
21
18
  ```bash
22
- # interactive
23
- sl login
24
-
25
- # machine / CI
26
- export SL_API_KEY=sk-sl_xxxxxxxx
19
+ export SL_API_URL=http://127.0.0.1:3800
20
+ export SL_API_KEY=<INSTANCE_TOKEN>
27
21
  ```
28
22
 
29
- `sl whoami` shows the active account, the effective API URL, and the credential
30
- source (and exits non-zero when not logged in). The global `--api-key` /
31
- `--api-url` flags (and `SL_API_KEY` / `SL_API_URL`) apply to every command.
32
-
33
- During open beta, reads are public (no key needed) — for subgraphs that means
34
- **public** subgraphs only (managed deploys default public; BYO deploys and all
35
- pre-existing subgraphs are private, readable with your key). Writes — deploying,
36
- publishing, or managing subgraphs and subscriptions — require a session or an
37
- `sk-sl_` key.
38
-
39
23
  ## Quickstart
40
24
 
41
25
  ```bash
42
26
  bun add -g @secondlayer/cli
43
- sl login
44
- sl projects create my-app
45
- sl projects use my-app
27
+ sl init --network mainnet
28
+ sl start --print
29
+ # docker compose -f docker/oss/docker-compose.yml up -d
46
30
 
47
- # scaffold + deploy a subgraph from a deployed contract
48
31
  sl subgraphs scaffold SP1234ABCD.my-contract -o subgraphs/my-contract.ts
49
32
  sl subgraphs deploy subgraphs/my-contract.ts --start-block <recent-block>
50
33
  sl subgraphs query my-contract <table> --sort _block_height --order desc
51
-
52
- # wire a webhook receiver
53
- sl subscriptions create my-hook \
54
- --runtime node \
55
- --subgraph my-contract \
56
- --table <table> \
57
- --url https://<receiver-host>/webhook
58
34
  ```
59
35
 
60
36
  `sl subgraphs scaffold` writes the definition file, creates/updates
@@ -75,27 +51,6 @@ No account. Writes `.env.local`, restores history, prints the Stacks observer st
75
51
  | `sl verify [all\|raw\|decode:<name>\|subgraph:<name>] --against <manifest> [--quick\|--deep\|--anchor]` | Compare local data to a signed archive. Default target `raw`. Exit `0` clean, `1` diverged, `2` unanchored |
76
52
  | `sl repair --against <archive> [--apply]` | Plan (default) or apply an archive repair |
77
53
 
78
- ### Auth & project
79
-
80
- | Command | What it does |
81
- |---|---|
82
- | `sl login` / `sl logout` | Start or revoke a session |
83
- | `sl whoami` | Print account, credential source, and active project |
84
- | `sl keys create --product streams [--name <name>]` | Mint a scoped `streams`/`index` read key; prints the `sk-sl_` key **once**. Needs an account key in `SL_API_KEY` |
85
- | `sl projects create [name]` | Create a project |
86
- | `sl projects list` | List projects |
87
- | `sl projects use <slug>` | Bind cwd to a project (writes `./.secondlayer/project`) |
88
- | `sl projects get` | Show resolved project + source file |
89
- | `sl projects delete <slug>` (alias `rm`) | Delete a project (`-y` to skip confirm) |
90
-
91
- Project binding is per-directory: `.secondlayer/project` in cwd takes
92
- precedence over `~/.secondlayer/config.json:defaultProject`. The walk-up stops
93
- at `.git`.
94
-
95
- **Key products:** an `account` key (dashboard default) grants both `streams:read`
96
- and `index:read` and is the only key that can mint; `streams`/`index` keys are
97
- scoped reads and cannot mint (403). Minted keys inherit your plan's tier.
98
-
99
54
  ### Subgraphs
100
55
 
101
56
  | Command | What it does |
@@ -153,19 +108,17 @@ deliveries/...) operates on both kinds.
153
108
  | Command | What it does |
154
109
  |---|---|
155
110
  | `sl contracts generate [files...]` (alias `gen`) | Generate TS interfaces from Clarity contracts |
156
- | `sl context` | Print a headless orientation snapshot — account, Streams + Index tips, your subgraphs, subscriptions, and in-flight reindex operations. CLI counterpart to the MCP `secondlayer://context` resource |
111
+ | `sl context` | Instance snapshot — Streams + Index tips, subgraphs, subscriptions |
157
112
  | `sl doctor` / `sl status` | Reachability + health checks |
158
- | `sl account get` / `sl account update` | Show or update display name / bio / slug |
159
- | `sl account billing` | Show plan, subscription, trial, discounts |
160
113
  | `sl config get/set/reset/delete` | Inspect or reset local config |
161
114
 
162
115
  ## Environment variables
163
116
 
164
117
  | Var | Purpose |
165
118
  |---|---|
166
- | `SL_API_KEY` | An `sk-sl_` API key (or session token) for machine/CI use; bypasses platform resolution |
167
- | `SL_API_URL` | Point at an OSS or internal API directly, bypassing the platform |
168
- | `SL_PLATFORM_API_URL` | Override the platform API base (default `https://api.secondlayer.tools`) |
119
+ | `SL_API_KEY` | `INSTANCE_TOKEN` from `sl init` for writes. Loopback reads need no token |
120
+ | `SL_API_URL` | Instance API. Default `http://127.0.0.1:3800` |
121
+ | `SL_PLATFORM_API_URL` | Alias of `SL_API_URL` |
169
122
  | `STACKS_NETWORK` | Default network (also via `--network <local\|testnet\|mainnet>`) |
170
123
  | `HIRO_API_KEY` | Used by `sl contracts generate` for remote contract fetches |
171
124
 
package/dist/cli.js CHANGED
@@ -2580,7 +2580,7 @@ function isOssMode() {
2580
2580
  return true;
2581
2581
  }
2582
2582
  }
2583
- var LOCAL_API_URL = "http://127.0.0.1:3800";
2583
+ var LOCAL_API_URL = "http://127.0.0.1:3800", ARCHIVE_OPS_API_URL = "https://api.secondlayer.tools";
2584
2584
  var init_resolve_auth = __esm(() => {
2585
2585
  init_session();
2586
2586
  });
@@ -2629,9 +2629,28 @@ async function httpPlatform(path2, opts = {}) {
2629
2629
  async function httpPlatformAnon(path2, opts = {}) {
2630
2630
  return request(`${resolveApiUrl()}${path2}`, opts);
2631
2631
  }
2632
+ function resolveArchiveOpsUrl() {
2633
+ return (process.env.SL_CREDITS_API_URL ?? ARCHIVE_OPS_API_URL).replace(/\/+$/, "");
2634
+ }
2635
+ async function httpArchiveOpsAnon(path2, opts = {}) {
2636
+ return request(`${resolveArchiveOpsUrl()}${path2}`, opts);
2637
+ }
2638
+ async function httpArchiveOps(path2, opts = {}) {
2639
+ const envKey = resolveEnvKey();
2640
+ const session = envKey ? null : await readSession();
2641
+ const bearer = envKey ?? session?.token;
2642
+ if (!bearer) {
2643
+ throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, "Not logged in — run `SL_API_URL=https://api.secondlayer.tools sl login`");
2644
+ }
2645
+ return request(`${resolveArchiveOpsUrl()}${path2}`, {
2646
+ ...opts,
2647
+ bearer
2648
+ });
2649
+ }
2632
2650
  var CliHttpError, REQUEST_TIMEOUT_MS = 30000;
2633
2651
  var init_http = __esm(() => {
2634
2652
  init_resolve_auth();
2653
+ init_session();
2635
2654
  CliHttpError = class CliHttpError extends Error {
2636
2655
  status;
2637
2656
  code;
@@ -34787,7 +34806,7 @@ init_esm();
34787
34806
  // package.json
34788
34807
  var package_default = {
34789
34808
  name: "@secondlayer/cli",
34790
- version: "10.2.1",
34809
+ version: "10.3.0",
34791
34810
  repository: {
34792
34811
  type: "git",
34793
34812
  url: "git+https://github.com/ryanwaits/secondlayer.git",
@@ -34831,7 +34850,7 @@ var package_default = {
34831
34850
  "@secondlayer/bundler": "^0.5.0",
34832
34851
  "@secondlayer/scaffold": "^1.5.1",
34833
34852
  "@secondlayer/sdk": "^6.54.0",
34834
- "@secondlayer/shared": "^7.11.0",
34853
+ "@secondlayer/shared": "^7.11.1",
34835
34854
  "@secondlayer/stacks": "^3.3.1",
34836
34855
  "@secondlayer/subgraphs": "^3.26.4",
34837
34856
  esbuild: "^0.27.4",
@@ -34874,15 +34893,13 @@ async function runBillingStatus(json) {
34874
34893
  output({ json, data: res, human: () => renderBillingStatus(res) });
34875
34894
  }
34876
34895
  function addBillingCommand(parent) {
34877
- parent.command("billing").description("Show your plan, Stripe subscription, trial, and discounts").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
34896
+ parent.command("billing").description("Show archive credit balance (hidden; use sl credits)").option("--json", "Output as JSON").action((options) => runBillingStatus(options.json));
34878
34897
  }
34879
34898
  function renderBillingStatus(res) {
34880
34899
  if (!res.subscription) {
34881
34900
  console.log(formatKeyValue([
34882
- ["Plan", "Free"],
34883
- ["Reads", dim("10 req/s · last ~24h window")],
34884
- ["Subgraphs", dim("upgrade to deploy / go private")],
34885
- ["Upgrade", dim("https://secondlayer.tools/platform/billing")]
34901
+ ["Credits", dim("sl credits balance")],
34902
+ ["Buy", dim("sl credits buy --email you@example.com --pack 25")]
34886
34903
  ]));
34887
34904
  return;
34888
34905
  }
@@ -34980,6 +34997,115 @@ function registerAccountCommand(program2) {
34980
34997
  action: "update profile"
34981
34998
  }));
34982
34999
  }
35000
+ // src/commands/credits.ts
35001
+ init_http();
35002
+ init_output();
35003
+ var PACKS = [10, 25, 50, 100];
35004
+ function parsePack(raw) {
35005
+ const n = Number(raw);
35006
+ if (!PACKS.includes(n)) {
35007
+ error(`--pack must be one of ${PACKS.join(", ")}`);
35008
+ process.exit(1);
35009
+ }
35010
+ return n;
35011
+ }
35012
+ async function runBuy(opts) {
35013
+ const email = opts.email.trim().toLowerCase();
35014
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
35015
+ error("--email must be a valid address");
35016
+ process.exit(1);
35017
+ }
35018
+ const amount = parsePack(opts.pack);
35019
+ let res;
35020
+ try {
35021
+ res = await httpArchiveOpsAnon("/api/public/credits/checkout", { method: "POST", body: { email, amount } });
35022
+ } catch (err) {
35023
+ if (err instanceof CliHttpError) {
35024
+ error(err.message);
35025
+ process.exit(1);
35026
+ }
35027
+ throw err;
35028
+ }
35029
+ output({
35030
+ json: opts.json,
35031
+ data: res,
35032
+ human: () => {
35033
+ success(`Checkout for $${amount} → ${email}`);
35034
+ console.log(res.url);
35035
+ console.log(dim("After payment: SL_API_URL=https://api.secondlayer.tools sl login && sl credits balance"));
35036
+ }
35037
+ });
35038
+ }
35039
+ async function runBalance(opts) {
35040
+ let res;
35041
+ try {
35042
+ res = await httpArchiveOps("/api/billing/status");
35043
+ } catch (err) {
35044
+ if (err instanceof CliHttpError) {
35045
+ error(err.message);
35046
+ process.exit(1);
35047
+ }
35048
+ throw err;
35049
+ }
35050
+ const micros = BigInt(res.creditsUsdMicros ?? "0");
35051
+ const usd = Number(micros) / 1e6;
35052
+ output({
35053
+ json: opts.json,
35054
+ data: { creditsUsd: usd, creditsUsdMicros: micros.toString() },
35055
+ human: () => {
35056
+ const refill = res.refill;
35057
+ console.log(formatKeyValue([
35058
+ ["Balance", `$${usd.toFixed(2)}`],
35059
+ [
35060
+ "Refill",
35061
+ refill?.belowUsd != null ? `on — below $${refill.belowUsd} buy $${refill.packUsd}` : dim("off")
35062
+ ],
35063
+ ["Buy", dim("sl credits buy --email you@example.com --pack 25")]
35064
+ ]));
35065
+ }
35066
+ });
35067
+ }
35068
+ function registerCreditsCommand(program2) {
35069
+ const credits = program2.command("credits").description("Buy and check archive credits");
35070
+ credits.command("buy").description("Open a one-time Stripe checkout for archive credits").requiredOption("--email <email>", "Receipt email; becomes the account").option("--pack <usd>", `One of ${PACKS.join(", ")}`, "25").option("--json", "Output as JSON").action((opts) => runBuy(opts));
35071
+ credits.command("balance").description("Show prepaid archive credit balance").option("--json", "Output as JSON").action((opts) => runBalance(opts));
35072
+ credits.command("refill").description("Opt-in auto-refill when the balance drops under a threshold").option("--below <usd>", "Trigger when balance is under this USD amount").option("--pack <usd>", `Pack to buy (${PACKS.join(", ")})`, "25").option("--off", "Turn auto-refill off").option("--json", "Output as JSON").action((opts) => runRefill(opts));
35073
+ }
35074
+ async function runRefill(opts) {
35075
+ if (!opts.off && opts.below === undefined) {
35076
+ await runBalance(opts);
35077
+ return;
35078
+ }
35079
+ const body = opts.off ? { belowUsd: null } : { belowUsd: Number(opts.below), packUsd: parsePack(opts.pack) };
35080
+ if (!opts.off && (!Number.isFinite(body.belowUsd) || (body.belowUsd ?? 0) < 1)) {
35081
+ error("--below must be at least 1");
35082
+ process.exit(1);
35083
+ }
35084
+ let res;
35085
+ try {
35086
+ res = await httpArchiveOps("/api/billing/refill", {
35087
+ method: "POST",
35088
+ body
35089
+ });
35090
+ } catch (err) {
35091
+ if (err instanceof CliHttpError) {
35092
+ error(err.message);
35093
+ process.exit(1);
35094
+ }
35095
+ throw err;
35096
+ }
35097
+ output({
35098
+ json: opts.json,
35099
+ data: res,
35100
+ human: () => {
35101
+ if (res.belowUsd == null) {
35102
+ success("Auto-refill off");
35103
+ return;
35104
+ }
35105
+ success(`Auto-refill on — below $${res.belowUsd} buy $${res.packUsd}`);
35106
+ }
35107
+ });
35108
+ }
34983
35109
 
34984
35110
  // src/commands/index.ts
34985
35111
  init_codegen();
@@ -39833,9 +39959,10 @@ registerContextCommand(program);
39833
39959
  registerVerifyCommand(program);
39834
39960
  registerRepairCommand(program);
39835
39961
  program.commandsGroup("Account:");
39962
+ registerCreditsCommand(program);
39836
39963
  registerAccountCommand(program);
39837
39964
  registerKeysCommand(program);
39838
39965
  program.parse();
39839
39966
 
39840
- //# debugId=60FAFC7C2FFCA95764756E2164756E21
39967
+ //# debugId=F9D9C4C9412258E564756E2164756E21
39841
39968
  //# sourceMappingURL=cli.js.map