npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@secondlayer/cli

v15.0.1

Published

Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.

Downloads

2,656

Readme

@secondlayer/cli

The Secondlayer CLI — one binary for Stacks indexing, real-time subgraphs, webhooks, and Clarity code generation.

bun add -g @secondlayer/cli
secondlayer --version

sl is a short alias of secondlayer.

Auth

Default API is http://127.0.0.1:3800. Override with SL_API_URL.

Writes against a published bind use INSTANCE_TOKEN from secondlayer init. Loopback reads need no token. Hosted API and archive credits use SECONDLAYER_API_KEY (sk-sl_*).

export SL_API_URL=http://127.0.0.1:3800
export INSTANCE_TOKEN=<from secondlayer init>

Quickstart

bun add -g @secondlayer/cli
secondlayer setup

secondlayer subgraphs scaffold SP1234ABCD.my-contract -o subgraphs/my-contract.ts
git add subgraphs/my-contract.ts   # deploy refuses an unstaged file; or pass --allow-uncommitted
secondlayer subgraphs deploy subgraphs/my-contract.ts --start-block <recent-block>
secondlayer subgraphs query my-contract <table> --sort _block_height --order desc

secondlayer setup is a guided wizard: it picks network + node mode (with the RAM/disk floor shown live), generates secrets, writes docker-compose.yml and .env (including the DATABASE_URL every later bootstrap/verify/repair in that directory connects with) into a target directory, brings the stack up, prints the observer stanza for an external node, and restores + verifies history from the archive: the one-command replacement for init → hand-copy secrets → docker compose upobserverbootstrapverify. setup is also the only way to bring the stack up: the old secondlayer start, which printed a compose line for a monorepo checkout, is gone. Without a TTY (or with --yes), it skips the interactive prompts and runs from flags instead; --network and --node-mode are then required, and --against is required unless you pass --skip-bootstrap:

secondlayer setup --yes \
  --network mainnet --node-mode external \
  --against https://archive.secondlayer.tools/latest.json

secondlayer subgraphs scaffold writes the definition file, creates/updates package.json, and runs bun install (pass --no-install to skip).

Archive

secondlayer archive groups the history-plane verbs. archive bootstrap, archive verify, and archive repair are the same commands as the top-level bootstrap / verify / repair (golden-path aliases stay). archive latest shows the official tip; archive quote --against <manifest> prices a fetch without charging.

secondlayer archive latest
secondlayer archive quote --against https://archive.secondlayer.tools/latest.json
secondlayer archive bootstrap --against https://archive.secondlayer.tools/latest.json

Commands

Local runtime

No account. Writes .env.local, restores history, prints the Stacks observer stanza.

| Command | What it does | |---|---| | secondlayer setup [--network …] [--node-mode external\|stacks\|full] [--api-port <spec>] [--dir <path>] [--against <manifest>] [--skip-bootstrap] [--skip-verify] [--yes] [--force] | Guided self-host onboarding — secrets, compose + .env, docker up, observer stanza, bootstrap, verify. TUI when interactive; flags-only (no prompts) with --yes or no TTY | | secondlayer init [--network mainnet\|testnet\|devnet] [--api-url <url>] [--force] | Write .env.local (token, secrets key, webhook signing key). --network and --api-url are the global flags. Idempotent | | secondlayer bootstrap --against <manifest> [--from-block <n>] [--to-block <n>] [--verify all\|blocks] [--public-key <pem>] [-y] [--json] | Restore chain history from a verified archive into an empty database. A run that died mid-way resumes per dataset on re-run. After the load, digests for blocks, transactions, and events are checked over the restored range (--verify blocks skips the child datasets and the minutes they cost). Partition fetches retry three times with backoff on resets, timeouts, 429 (honoring Retry-After) and 5xx; a link that stays down exits 1 with a re-run hint, and the re-run resumes. Exit 0 restored, 1 diverged or interrupted, 2 refused | | secondlayer observer [--mode indexer\|signer-shared] [--endpoint host:port] [--recovery journal\|archive] [--network …] | Print the [[events_observer]] stanza. Signer-shared requires --recovery | | secondlayer 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 | | secondlayer repair --against <archive> [--apply] [-y] | Plan (default) or apply an archive repair. A fixed block is rewritten with its transactions and events from the archive; when the reference has no child partition for a height, the block is rewritten alone, the height is named with a bootstrap --from-block H --to-block H remedy, and the exit is 1. Partition fetches retry like bootstrap; a link that stays down exits 1 with a re-run hint, and heights already repaired are kept |

Bootstrap and repair against the official hosted archive (archive.secondlayer.tools) are metered per partition; against any other manifest (a mirror, a teammate's box, a local file) they are free. See Metered fetches.

Metered fetches

secondlayer bootstrap and secondlayer repair pull partitions from the signed archive instead of replaying the chain, and that pull costs money only when it targets the official hosted archive. Point --against at a mirror or a local manifest and nothing is charged, nothing is even contacted beyond that manifest, because self-hosting the archive is a supported way to use these commands, not a workaround.

Against the official host, both commands quote before they charge:

  1. The manifest's partition list is priced with a free, no-write call (POST /api/archive/quote).
  2. The quote prints into the existing plan output, for example metered: 528 partitions ≈ $44.00 · balance $50.00, or for repair inside its monthly allowance, metered: free (4 of 6 monthly repair fetches remaining).
  3. You confirm, or pass -y to skip the prompt. -y never skips the quote or the balance check: if the balance is short, the command exits before any partition is fetched and prints the shortfall and secondlayer credits buy. --json never stands in for -y: without -y it prints {"code":"CONFIRMATION_REQUIRED","quote":…} to stdout and exits 2 so a script can read the price, then re-run with -y. Without a TTY on stdin every confirmation exits 1 rather than letting an empty pipe answer it.
  4. Only then does the command fetch, and only the partitions it actually reads are charged.

A partition already charged in the last 24 hours re-presigns for free, so a resumed or retried bootstrap never pays twice for the same bytes. repair gets 6 free range-bundles a month; bootstrap does not, since it is the whole-chain operation the free tier exists to not subsidize.

secondlayer verify is unaffected: it reads manifests and digests, never partition bytes, and stays free and anonymous no matter which archive it points at.

Subgraphs

| Command | What it does | |---|---| | secondlayer subgraphs create <name> | Scaffold a definition file | | secondlayer subgraphs scaffold <SP...::contract> [-o <path>] [--no-install] | Generate a subgraph from a deployed contract | | secondlayer subgraphs deploy <file> [--start-block <n>] [-y] [--allow-uncommitted] | Deploy; --start-block overrides the definition. The file must be staged or committed (git add), or pass --allow-uncommitted | | secondlayer subgraphs list | List deployments (ls alias) | | secondlayer subgraphs dev <file> | Watch + hot-redeploy | | secondlayer subgraphs query <name> <table> | Query a table with filters, sort, pagination | | secondlayer subgraphs status <name> / gaps <name> | Inspect a deployment | | secondlayer subgraphs spec <nameOrFile> [--format openapi\|agent\|markdown] | Export API docs for a deployed subgraph or a local definition file | | secondlayer codegen subgraph <file> --target kysely\|prisma\|drizzle [-o <path>] | Generate a typed ORM schema for the subgraph's tables | | secondlayer codegen client <name> -o <path> | Generate a typed query client for a deployed subgraph | | secondlayer subgraphs reindex/backfill/stop/delete <name> | Manage processing |

Data products (reads)

| Command | What it does | |---|---| | secondlayer index ft-transfers / nft-transfers / events --event-type <t> / contract-calls | Decoded Index layer. Anonymous reads OK | | secondlayer streams tip / events / consume / reorgs / canonical <h> / dumps | Raw chain event firehose. consume emits one event per line; a reorg appears inline as {"kind":"reorg","fork_point_height":…} and the loop rewinds to re-deliver the canonical run, so a reader drops rows at or above the fork point when it sees one. --max-pages must be a positive integer. Requires INSTANCE_TOKEN past loopback |

Reads emit JSON to stdout (--json accepted across all read commands); -o/--output is a file path, not a format.

Webhooks

| Command | What it does | |---|---| | secondlayer webhooks create <name> --subgraph <name> --table <name> [--runtime <inngest\|trigger\|cloudflare\|node>] [--url <url>] | Subgraph webhook (optional local receiver scaffold). Runtime defaults to node once any of -s/-t/-u or --no-scaffold is given; the menu only appears in a terminal with no flags | | secondlayer webhooks create <name> --url <url> --trigger '<json>' | Chain webhook (repeat --trigger or pass --triggers-file) | | secondlayer webhooks list / get <id\|name> | List or show config + delivery state | | secondlayer webhooks update <id\|name> --url <url> [--filter key.gte=value] | Patch URL, filter, format, retry, etc. | | secondlayer webhooks pause/resume <id\|name> | Stop or restart delivery | | secondlayer webhooks rotate-secret <id\|name> | Rotate signing secret (printed once) | | secondlayer webhooks deliveries/dead <id\|name> | Recent attempts / dead-letter rows | | secondlayer webhooks requeue <id\|name> <outboxId> | Requeue one dead-letter row | | secondlayer webhooks replay <id\|name> --from-block <n> --to-block <n> | Enqueue a historical block range | | secondlayer webhooks doctor/test <id\|name> | Health check / signed fixture |

Read/action commands support --json. Destructive commands prompt unless -y / --yes, default to no, and exit 1 when stdin is not a TTY. Filters are schema-aware: unknown tables/columns, bad operators, and non-scalar columns are rejected before the API call.

Webhooks are subgraph (a table's rows) or chain (raw events, no subgraph). secondlayer webhooks create with --subgraph/--table makes the first. Pass --trigger or --triggers-file for the second. SDK, REST, and MCP take the same triggers array. Every other secondlayer webhooks command operates on both kinds.

Other

| Command | What it does | |---|---| | secondlayer codegen contracts [files...] | Generate TS interfaces from Clarity contracts | | secondlayer context | Instance snapshot — Streams + Index tips, subgraphs, webhooks | | secondlayer doctor / secondlayer status | Reachability + health checks | | secondlayer config get/set/reset/delete | Inspect or reset local config |

Environment variables

| Var | Purpose | |---|---| | INSTANCE_TOKEN | From secondlayer init for writes. Loopback reads need no token | | SECONDLAYER_API_KEY | Hosted account key (sk-sl_*). SL_API_KEY is a one-release hosted fallback | | SL_API_URL | Instance API. Default http://127.0.0.1:3800 | | SL_PLATFORM_API_URL | Alias of SL_API_URL | | STACKS_NETWORK | Default network (also via --network <mainnet\|testnet\|devnet>) | | DATABASE_URL | Postgres that bootstrap, verify, repair, and backup connect to. secondlayer setup writes it into .env pointing at the compose Postgres; unset, the shared dev URL postgres://postgres:postgres@localhost:5432/secondlayer_dev is used | | HIRO_API_KEY | Used by secondlayer codegen contracts for remote contract fetches |

Code generation (secondlayer codegen contracts)

Generate type-safe interfaces, functions, and optional React hooks from Clarity contracts — local .clar files, deployed contracts (network inferred from address prefix), or globs.

secondlayer codegen contracts ./contracts/token.clar -o ./src/generated.ts
secondlayer codegen contracts SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-vault -o ./src/generated.ts
secondlayer codegen contracts "./contracts/*.clar" -o ./src/generated.ts
secondlayer codegen contracts --watch   # regenerate on .clar / config / Clarinet.toml changes

Where the types come from matters. A bare .clar path is read as source, and source only declares argument, map, and data-var types — a function's return type comes out of Clarity's type checker, so it generates as any. A deployed contract id or clarinet: true (below) carries a real ABI, so returns are exact too. Prefer those where you can.

Config-driven:

# write a secondlayer.config.ts, then:
secondlayer codegen contracts  # regenerates from the config
// secondlayer.config.ts
import { defineConfig } from "@secondlayer/cli"

export default defineConfig({
  out: "src/generated.ts",
  clarinet: true, // or { path, include, exclude, includeRequirements }
})

clarinet: true loads ABIs from your Clarinet project via simnet, including [project.requirements] dependency contracts (includeRequirements: false to opt out). Skips silently when Clarinet.toml is missing.

Clarinet tests: getContract with @secondlayer/stacks/simnet.

Generated output includes named per-function type aliases (TokenTransferArgs, TokenTransferResult), a TokenTypes bundle, and a tokenAbi const branded with TypedAbigetContract from @secondlayer/stacks picks up the brand so hovers and type errors show the named aliases instead of expanded inline types.

import { token } from "./generated/contracts"

// Generated call descriptors compose with any tx builder:
await makeContractCall({
  ...token.transfer({ amount: 100n, recipient: "SP..." }),
  network: "mainnet",
})

// Maps/vars/constants accessors are built in:
const supply = await token.vars.totalSupply.get()

Local development

secondlayer setup brings up a self-hosted stack. For Clarinet, use secondlayer devnet connect / status / logs / down (and devnet faucet).

Docs

Full reference: https://secondlayer.tools/docs

License

MIT