@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 +12 -59
- package/dist/cli.js +136 -9
- package/dist/cli.js.map +8 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,51 +10,27 @@ sl --version
|
|
|
10
10
|
|
|
11
11
|
## Auth
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Default API is `http://127.0.0.1:3800`. Override with `SL_API_URL`.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
|
44
|
-
sl
|
|
45
|
-
|
|
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` |
|
|
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` |
|
|
167
|
-
| `SL_API_URL` |
|
|
168
|
-
| `SL_PLATFORM_API_URL` |
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
["
|
|
34883
|
-
["
|
|
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=
|
|
39967
|
+
//# debugId=F9D9C4C9412258E564756E2164756E21
|
|
39841
39968
|
//# sourceMappingURL=cli.js.map
|