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

@qntx/spark

v0.5.2

Published

Spark Bitcoin L2 protocol for TypeScript: platform-neutral client, signer and crypto-backend interfaces.

Readme

@qntx/spark

Platform-neutral TypeScript implementation of the Spark Bitcoin L2 protocol. Cryptographic backends (@qntx/spark-wasm, @qntx/spark-native) plug into the SparkCrypto interface exported from @qntx/spark/crypto.

Status: pre-release. See the repository and CHANGELOG.

Security

Trust model: a leaf is spendable only with the signing-operator threshold plus the wallet's key — no single operator can move funds. The wallet verifies locally every transaction it signs (refunds and exit transactions), that every stored exit chain's refunds pay the wallet's own leaf key, that a deposit address's proof of possession is valid, and that every operator reports a leaf identically — and token outputs and committed transfers likewise count only when every operator reports them identically, so a single operator cannot inflate a balance or forge a spend. Lightning sends and receives, leaves swaps, cooperative exits and static-deposit claims go through the SSP; the client validates the SSP responses it acts on (invoice and transfer-id echoes, payment-hash↔preimage proofs, connector and payout transactions, fee bounds).

Leaf quarantine: a leaf the operators report differently, or whose served exit chain fails verification, is excluded from balance and spending; a previously stored (verified) exit chain is kept, and withdrawals.unilateralExit on that leaf reports the precise failure.

Key custody: private keys never leave the SparkSigner — the client only ever sees protocol values (public keys, signatures, ciphertexts).

Outflow verification: createSparkSigner accepts an optional authorize?: (outflow: SparkOutflow) => Promise<void> gate. Before every signature that sends value out, the signer independently derives the outflow — it never trusts caller-supplied amounts or receivers. Authorization happens at two points, each backed by what the SO enforces:

  • signFrost checks every job before producing any share. A target spending a foreign input (connector refund) is an exit candidate: the job must carry exit: { connectorTx, exitTx }, the signer checks that the connector spends exitTx and matches the foreign input, and the outflow reports the payout's exitOutputs. Every other output must be an ephemeral anchor, the spent prevout's own script, the signer's identity, a pending transfer's recorded receiver, or — for leaf/static-deposit keys only — the job's own key. A single-input target with any other output is a lightning candidate carrying that output script (lightningSendHtlcScript reproduces it for an invoice's payment hash); a multi-input one is rejected, as is a batch mixing candidates. Candidates are authorized before any share is produced, since a signed package can later be paired with any shares the signer issued.
  • signIdentity on transfer-package signs only when the package's key_tweak_package is byte-equal to what prepareTransfer sealed this session and every leaf has a recorded refund signature (the amount is the per-key maximum the SO verifies end-to-end). Receivers equal to the bound SSP report swap — or nothing when signFrost already authorized every leaf (a partially authorized SSP transfer is rejected); any other receiver reports transfer with per-receiver totals.

signKeySpend, signHtlcTimeout and the static-deposit-refund/watchtower-recovery statements report onchain outputs decoded from the transaction being signed plus inputSats (the spent prevout total, so callers derive the fee); token-transaction reports token outputs with u128 amounts as bigint. A throwing authorize aborts the signature; records stay for retry. Session records are bounded (4,096 signing keys, 256 prepared transfers, oldest evicted) and wiped on dispose().

Idempotent retries: transfers.send/sendMany, lightning.pay and withdrawals.cooperativeExit accept a transferId — reuse the same id to retry a call whose response may have committed; the same id with different terms fails rather than paying twice. tokens.transfer/tokens.consolidate throw SparkTokenBroadcastError when the broadcast outcome is uncertain — retry with inputOutputIds: error.inputOutputIds and the same receiver and amount; that retry either returns the committed transaction's hash or broadcasts exactly those inputs once. Retrying without it would select different outputs and pay twice.

Offline receive: once a transfer commits, the sender cannot cancel it and its expiry does not return it — transfers.claim(transferId)/claimPending can pick it up at any later time.

Transaction history: transfers.history({ limit?, offset? }) pages transfers newest-first (TRANSFER, PREIMAGE_SWAP, COOPERATIVE_EXIT, UTXO_SWAP), folding each entry with its SSP user_request when the counterparty is the SSP — lightning invoices, payment hashes and preimages, coop-exit fees and payout txids, static-deposit credits. Entries surface as SparkPayment (send/receive, pending/completed/failed, spark/lightning/deposit/ withdraw); nextOffset is undefined at the end.

Unilateral exit: each pre-signed transaction carries a hard deadline — once its parent confirms and its relative timelock passes, it must confirm within 50 blocks; otherwise the operators' watchtower may publish a self-fee variant instead. For intermediate nodes this strands descendants as WATCHTOWER_EXITED (recover with recoverWatchtowerExit while the SO is online); for refunds the watchtower publishes direct_from_cpfp_refund_tx, which pays the leaf key (sweep with sweepRefund). Keep each exit package confirming promptly. Exit chains persist in the SparkStore passed to createSparkClient (required — createMemorySparkStore() for ephemeral wallets); a chain is deleted only when every operator endorses it as no longer exitable by this wallet, so a withheld or fabricated coordinator response cannot erase the offline exit path.

LNURL server (apps/lnurl-server): put per-IP rate limiting in front of the endpoints — invoice creation is unauthenticated. Zap receipt relays are payer-controlled URLs that can resolve to internal addresses (DNS rebinding): run the service where outbound connections to internal ranges are denied at the network layer.

Status: multiple internal review rounds plus two external audit rounds scoped by AUDIT.md; not yet run on mainnet.

Licensed under the Apache License, Version 2.0; see LICENSE and NOTICE.