@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 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, trial days left |
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, trial days left |
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 + trial status check |
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.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": "^2.0.0",
32457
- "@secondlayer/shared": "^2.1.0",
32458
- "@secondlayer/stacks": "^0.3.0",
32459
- "@secondlayer/subgraphs": "^0.11.8",
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", "launch").action(async (opts) => {
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(`Next: sl instance create --plan launch`));
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=93095DDF734A3A2E64756E2164756E21
35439
+ //# debugId=2929270B62E4733C64756E2164756E21
35453
35440
  //# sourceMappingURL=cli.js.map