@secondlayer/cli 3.1.1 → 3.1.2-alpha.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 +80 -4
- package/dist/cli.js +18 -31
- package/dist/cli.js.map +9 -9
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ sl subgraphs deploy ./x.ts # deploy to your instance
|
|
|
26
26
|
|---|---|
|
|
27
27
|
| `sl login` | Magic-link email → 6-digit code → writes session to `~/.secondlayer/session.json` |
|
|
28
28
|
| `sl logout` | Revokes the session and clears the local file |
|
|
29
|
-
| `sl whoami` | Prints account, active project, instance URL,
|
|
29
|
+
| `sl whoami` | Prints account, active project, instance URL, plan, status |
|
|
30
30
|
|
|
31
31
|
### Project
|
|
32
32
|
|
|
@@ -50,7 +50,7 @@ One instance per project. The platform API spawns a dedicated `sl-pg-{slug}`,
|
|
|
50
50
|
| Command | What it does |
|
|
51
51
|
|---|---|
|
|
52
52
|
| `sl instance create --plan <launch\|grow\|scale>` | Provision containers. Boxed reveal of `serviceKey` + `anonKey` (shown once). |
|
|
53
|
-
| `sl instance info` | Plan, status, resource usage
|
|
53
|
+
| `sl instance info` | Plan, status, resource usage |
|
|
54
54
|
| `sl instance resize --plan <...>` | Recreate containers with new CPU/memory (~30s downtime) |
|
|
55
55
|
| `sl instance suspend` / `resume` | Stop/start containers, volume preserved |
|
|
56
56
|
| `sl instance keys rotate [--service\|--anon\|--both]` | Bump JWT gen, recreate API container, mint replacement key(s) |
|
|
@@ -95,7 +95,7 @@ invocation. No long-lived key on disk.
|
|
|
95
95
|
|---|---|
|
|
96
96
|
| `sl generate [files...]` (aliases: `gen`, `codegen`) | Generate TS interfaces from Clarity contracts |
|
|
97
97
|
| `sl init` | Scaffold `secondlayer.config.ts` |
|
|
98
|
-
| `sl doctor` | Session + project + instance reachability
|
|
98
|
+
| `sl doctor` | Session + project + instance reachability check |
|
|
99
99
|
| `sl status` | Platform/instance health |
|
|
100
100
|
| `sl account profile` | Update display name / bio / slug |
|
|
101
101
|
| `sl config show/set/reset/clear` | Inspect or reset local config |
|
|
@@ -117,12 +117,88 @@ Every tenant-scoped failure surfaces a typed code and an action hint:
|
|
|
117
117
|
| Code | CLI hint |
|
|
118
118
|
|---|---|
|
|
119
119
|
| `SESSION_EXPIRED` | `Session expired. Run: sl login` |
|
|
120
|
-
| `TRIAL_EXPIRED` | `Your trial expired. Run: sl instance resize --plan <...> and add payment` |
|
|
121
120
|
| `TENANT_SUSPENDED` | `Instance is suspended. Run: sl instance resume` |
|
|
122
121
|
| `NO_ACTIVE_PROJECT` | `No project selected. Run: sl project use <slug>` |
|
|
123
122
|
| `NO_TENANT_FOR_PROJECT` | `Project has no instance. Run: sl instance create --plan launch` |
|
|
124
123
|
| `KEY_ROTATED` | Handled transparently — `http.ts` re-mints and retries once |
|
|
125
124
|
|
|
125
|
+
## Code generation (`sl generate`)
|
|
126
|
+
|
|
127
|
+
Generate type-safe interfaces, functions, and optional React hooks from
|
|
128
|
+
Clarity contracts — works against local `.clar` files, deployed contracts
|
|
129
|
+
(network inferred from address prefix), or glob patterns.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Local .clar files
|
|
133
|
+
sl generate ./contracts/token.clar -o ./src/generated.ts
|
|
134
|
+
|
|
135
|
+
# Deployed contracts (SP/SM → mainnet, ST/SN → testnet)
|
|
136
|
+
sl generate SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-vault -o ./src/generated.ts
|
|
137
|
+
|
|
138
|
+
# Glob
|
|
139
|
+
sl generate "./contracts/*.clar" -o ./src/generated.ts
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Config-driven mode:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
sl init # creates secondlayer.config.ts
|
|
146
|
+
sl generate # regenerates from the config
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// secondlayer.config.ts
|
|
151
|
+
import { defineConfig } from "@secondlayer/cli"
|
|
152
|
+
import { clarinet, actions, react } from "@secondlayer/cli/plugins"
|
|
153
|
+
|
|
154
|
+
export default defineConfig({
|
|
155
|
+
out: "src/generated.ts",
|
|
156
|
+
plugins: [clarinet(), actions(), react()],
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Plugins
|
|
161
|
+
|
|
162
|
+
| Plugin | What it adds |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `clarinet()` | Parse local Clarinet project |
|
|
165
|
+
| `actions()` | `read.*` + `write.*` helpers on each contract |
|
|
166
|
+
| `react()` | Typed React Query hooks (`useTokenTransfer`, `useTokenBalance`, etc.) |
|
|
167
|
+
| `testing()` | Clarinet SDK test helpers |
|
|
168
|
+
|
|
169
|
+
### Usage examples
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { token } from "./generated/contracts"
|
|
173
|
+
import { makeContractCall, fetchCallReadOnlyFunction } from "@stacks/transactions"
|
|
174
|
+
|
|
175
|
+
// Works with @stacks/transactions directly:
|
|
176
|
+
await makeContractCall({
|
|
177
|
+
...token.transfer({ amount: 100n, recipient: "SP..." }),
|
|
178
|
+
network: "mainnet",
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// With actions() plugin — read/write helpers:
|
|
182
|
+
const balance = await token.read.getBalance({ account: "SP..." })
|
|
183
|
+
await token.write.transfer({ amount: 100n, recipient: "SP..." })
|
|
184
|
+
|
|
185
|
+
// Maps / vars / constants:
|
|
186
|
+
const supply = await token.vars.totalSupply.get()
|
|
187
|
+
const bal = await token.maps.balances.get("SP...")
|
|
188
|
+
const max = await token.constants.maxSupply.get()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// With react() plugin:
|
|
193
|
+
import { useTokenTransfer, useTokenBalance } from "./generated/hooks"
|
|
194
|
+
|
|
195
|
+
function App() {
|
|
196
|
+
const { transfer, isRequestPending } = useTokenTransfer()
|
|
197
|
+
const { data: balance } = useTokenBalance("SP...")
|
|
198
|
+
// ...
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
126
202
|
## License
|
|
127
203
|
|
|
128
204
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -2583,8 +2583,8 @@ function isOssMode() {
|
|
|
2583
2583
|
return !!process.env.SL_API_URL && !process.env.SL_SERVICE_KEY;
|
|
2584
2584
|
}
|
|
2585
2585
|
var init_resolve_tenant = __esm(() => {
|
|
2586
|
-
init_http();
|
|
2587
2586
|
init_config();
|
|
2587
|
+
init_http();
|
|
2588
2588
|
init_project_file();
|
|
2589
2589
|
});
|
|
2590
2590
|
|
|
@@ -32410,7 +32410,7 @@ var {
|
|
|
32410
32410
|
// package.json
|
|
32411
32411
|
var package_default = {
|
|
32412
32412
|
name: "@secondlayer/cli",
|
|
32413
|
-
version: "3.1.
|
|
32413
|
+
version: "3.1.2-alpha.0",
|
|
32414
32414
|
description: "CLI for subgraphs and blockchain indexing on Stacks",
|
|
32415
32415
|
type: "module",
|
|
32416
32416
|
bin: {
|
|
@@ -32452,12 +32452,11 @@ var package_default = {
|
|
|
32452
32452
|
license: "MIT",
|
|
32453
32453
|
dependencies: {
|
|
32454
32454
|
"@inquirer/prompts": "^8.2.0",
|
|
32455
|
-
"@secondlayer/bundler": "^0.3.0",
|
|
32456
|
-
"@secondlayer/sdk": "^
|
|
32457
|
-
"@secondlayer/shared": "^
|
|
32458
|
-
"@secondlayer/stacks": "^0.
|
|
32459
|
-
"@secondlayer/subgraphs": "^0.
|
|
32460
|
-
"@secondlayer/workflows": "^1.1.0",
|
|
32455
|
+
"@secondlayer/bundler": "^0.3.1-alpha.0",
|
|
32456
|
+
"@secondlayer/sdk": "^3.0.0-alpha.0",
|
|
32457
|
+
"@secondlayer/shared": "^3.0.0-alpha.0",
|
|
32458
|
+
"@secondlayer/stacks": "^1.0.0-alpha.0",
|
|
32459
|
+
"@secondlayer/subgraphs": "^1.0.0-alpha.0",
|
|
32461
32460
|
"@biomejs/js-api": "^0.7.0",
|
|
32462
32461
|
"@biomejs/wasm-nodejs": "^1.9.0",
|
|
32463
32462
|
esbuild: "^0.19.0",
|
|
@@ -32488,11 +32487,6 @@ function handleApiError(err, action) {
|
|
|
32488
32487
|
console.error("Session expired. Run: sl login");
|
|
32489
32488
|
process.exit(1);
|
|
32490
32489
|
}
|
|
32491
|
-
if (err.code === "TRIAL_EXPIRED") {
|
|
32492
|
-
console.error(err.message);
|
|
32493
|
-
console.error("Run: sl instance resize --plan <...> and add payment");
|
|
32494
|
-
process.exit(1);
|
|
32495
|
-
}
|
|
32496
32490
|
if (err.code === "TENANT_SUSPENDED") {
|
|
32497
32491
|
console.error("Tenant is suspended. Run: sl instance resume");
|
|
32498
32492
|
process.exit(1);
|
|
@@ -34934,13 +34928,9 @@ function registerWhoamiCommand(program2) {
|
|
|
34934
34928
|
try {
|
|
34935
34929
|
const tenant = await httpPlatform("/api/tenants/me");
|
|
34936
34930
|
if (tenant.tenant) {
|
|
34937
|
-
const trialDays = Math.max(0, Math.ceil((new Date(tenant.tenant.trialEndsAt).getTime() - Date.now()) / (24 * 60 * 60 * 1000)));
|
|
34938
34931
|
rows.push(["Instance", tenant.tenant.apiUrl]);
|
|
34932
|
+
rows.push(["Plan", tenant.tenant.plan]);
|
|
34939
34933
|
rows.push(["Status", tenant.tenant.status]);
|
|
34940
|
-
rows.push([
|
|
34941
|
-
"Trial",
|
|
34942
|
-
`${trialDays} day${trialDays === 1 ? "" : "s"} left`
|
|
34943
|
-
]);
|
|
34944
34934
|
} else {
|
|
34945
34935
|
rows.push([
|
|
34946
34936
|
"Instance",
|
|
@@ -35038,12 +35028,12 @@ init_resolve_tenant();
|
|
|
35038
35028
|
import { confirm as confirm4, input as input3, select as select3 } from "@inquirer/prompts";
|
|
35039
35029
|
function registerInstanceCommand(program2) {
|
|
35040
35030
|
const instance = program2.command("instance").description("Manage your dedicated Secondlayer instance");
|
|
35041
|
-
instance.command("create").description("Provision a new dedicated instance for the active project").option("--plan <plan>", "Plan: launch | grow | scale", "
|
|
35031
|
+
instance.command("create").description("Provision a new dedicated instance for the active project").option("--plan <plan>", "Plan: hobby (free) | launch | grow | scale", "hobby").action(async (opts) => {
|
|
35042
35032
|
guardOssMode();
|
|
35043
35033
|
const activeSlug = await requireActiveProject();
|
|
35044
35034
|
const plan = opts.plan;
|
|
35045
|
-
if (!["launch", "grow", "scale"].includes(plan)) {
|
|
35046
|
-
error(`Invalid plan: ${plan} (expected launch, grow, or scale)`);
|
|
35035
|
+
if (!["hobby", "launch", "grow", "scale"].includes(plan)) {
|
|
35036
|
+
error(`Invalid plan: ${plan} (expected hobby, launch, grow, or scale)`);
|
|
35047
35037
|
process.exit(1);
|
|
35048
35038
|
}
|
|
35049
35039
|
try {
|
|
@@ -35061,13 +35051,17 @@ function registerInstanceCommand(program2) {
|
|
|
35061
35051
|
guardOssMode();
|
|
35062
35052
|
await renderInstanceInfo();
|
|
35063
35053
|
});
|
|
35064
|
-
instance.command("resize").description("Change your instance plan (brief downtime)").option("--plan <plan>", "Target plan: launch | grow | scale").option("--yes", "Skip confirm").action(async (opts) => {
|
|
35054
|
+
instance.command("resize").description("Change your instance plan (brief downtime)").option("--plan <plan>", "Target plan: hobby | launch | grow | scale").option("--yes", "Skip confirm").action(async (opts) => {
|
|
35065
35055
|
guardOssMode();
|
|
35066
35056
|
let target = opts.plan;
|
|
35067
35057
|
if (!target) {
|
|
35068
35058
|
const answer = await select3({
|
|
35069
35059
|
message: "Target plan",
|
|
35070
35060
|
choices: [
|
|
35061
|
+
{
|
|
35062
|
+
value: "hobby",
|
|
35063
|
+
name: "Hobby — free (0.5 vCPU · 512 MB · 5 GB, auto-pause after 7d idle)"
|
|
35064
|
+
},
|
|
35071
35065
|
{
|
|
35072
35066
|
value: "launch",
|
|
35073
35067
|
name: "Launch — $99/mo (1 vCPU · 2 GB · 10 GB)"
|
|
@@ -35269,12 +35263,10 @@ async function renderInstanceInfo() {
|
|
|
35269
35263
|
return;
|
|
35270
35264
|
}
|
|
35271
35265
|
const t = res.tenant;
|
|
35272
|
-
const trialDays = Math.max(0, Math.ceil((new Date(t.trialEndsAt).getTime() - Date.now()) / (24 * 60 * 60 * 1000)));
|
|
35273
35266
|
console.log(formatKeyValue([
|
|
35274
35267
|
["URL", t.apiUrl],
|
|
35275
35268
|
["Plan", t.plan],
|
|
35276
35269
|
["Status", t.status],
|
|
35277
|
-
["Trial", `${trialDays} day${trialDays === 1 ? "" : "s"} left`],
|
|
35278
35270
|
["Created", new Date(t.createdAt).toLocaleString()]
|
|
35279
35271
|
]));
|
|
35280
35272
|
} catch (err) {
|
|
@@ -35308,11 +35300,6 @@ function handleInstanceError(err, action) {
|
|
|
35308
35300
|
error("Session expired. Run: sl login");
|
|
35309
35301
|
process.exit(1);
|
|
35310
35302
|
}
|
|
35311
|
-
if (err.code === "TRIAL_EXPIRED") {
|
|
35312
|
-
error(err.message);
|
|
35313
|
-
error("Add a payment method at the dashboard to keep your instance running.");
|
|
35314
|
-
process.exit(1);
|
|
35315
|
-
}
|
|
35316
35303
|
if (err.code === "TENANT_SUSPENDED") {
|
|
35317
35304
|
error("Instance is suspended. Run: sl instance resume");
|
|
35318
35305
|
process.exit(1);
|
|
@@ -35345,7 +35332,7 @@ function registerProjectCommand(program2) {
|
|
|
35345
35332
|
success(`Created project ${res.project.name} (${res.project.slug})`);
|
|
35346
35333
|
const path = await writeActiveProject(res.project.slug, process.cwd());
|
|
35347
35334
|
info(dim(`Bound to this directory → ${path}`));
|
|
35348
|
-
info(dim(
|
|
35335
|
+
info(dim("Next: sl instance create --plan launch"));
|
|
35349
35336
|
} catch (err) {
|
|
35350
35337
|
handleProjectError(err);
|
|
35351
35338
|
}
|
|
@@ -35449,5 +35436,5 @@ registerLocalCommand(program);
|
|
|
35449
35436
|
registerAccountCommand(program);
|
|
35450
35437
|
program.parse();
|
|
35451
35438
|
|
|
35452
|
-
//# debugId=
|
|
35439
|
+
//# debugId=2929270B62E4733C64756E2164756E21
|
|
35453
35440
|
//# sourceMappingURL=cli.js.map
|