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

@utexo/webrgb

v0.1.0

Published

WebRGB: TypeScript declarations, discovery, a mock wallet and a conformance suite for the window.rgb provider injected by RGB wallets such as the KaleidoSwap extension.

Readme

@utexo/webrgb

WebRGB is the window.rgb provider a wallet injects into web pages so a dApp can issue, receive, send and track RGB assets, and pay or receive them over Lightning, without running its own RGB backend. It sits next to WebLN (window.webln) and WebBTC (window.webbtc) and follows the same conventions: one enable() consent per origin, a confirmation in the wallet for every funds-touching call, and errors that carry a code.

SPEC.md is the interface contract. The reference implementation is the KaleidoSwap browser extension from 0.3.0 on. This package ships the TypeScript declarations, discovery, an in-memory mock wallet and a conformance suite.

This is the UTEXO fork of KaleidoSwap WebRGB, renamed to @utexo/webrgb. See INTEGRATION.md for dApp and wallet integration, including mint/burn examples. WalletConnect lives in the separate @utexo/webrgb-walletconnect project.

Try it

The upstream playground imports the upstream module and exercises every window.rgb method, with a live log of calls, results and error codes. Drive it against the extension with a signet or regtest wallet — or press install mock wallet and use it with nothing installed at all.

Install

npm install @utexo/webrgb

Importing anything from the package augments Window, so window.rgb is typed everywhere. For WebLN typings use @webbtc/webln-types; for NIP-07 use nostr-tools.

Usage

import { requestProvider, isProviderError, supports, toAssetArray } from "@utexo/webrgb";

try {
  // Waits for the wallet if the page ran first; `enable` connects the origin.
  const rgb = await requestProvider({ enable: true });

  const info = await rgb.getInfo();
  // { ready, network, protocol: "RGB_L1" | "RGB_LN", methods: [...] }

  const assets = toAssetArray(await rgb.listAssets());
  const { invoice } = await rgb.blindReceive({ assetId: assets[0].id!, amount: 1 });

  if (supports(info, "makeLnInvoice")) {
    const ln = await rgb.makeLnInvoice({ assetId: assets[0].id!, assetAmount: 5 });
    console.log("pay me over Lightning:", ln.invoice);
  }

  rgb.on("transferSettled", (t) => console.log("settled", t.transferId));
} catch (err) {
  if (isProviderError(err) && err.code === "USER_REJECTED") return; // the user said no
  throw err;
}

Surface

| Method | Purpose | |--------|---------| | enable() / getInfo() | Connect the origin; learn network, runtime and served methods | | getAddress() | Bitcoin address that anchors the wallet's RGB state | | blindReceive(args?) | Blinded-UTXO receive invoice; omit assetId for any asset, including one the wallet has never held | | issueAsset(args) | Mint a new asset (gated by its own wallet capability) | | listAssets() / getAssetBalance(id) | Holdings | | sendAsset(args) | Send against an RGB invoice, or explicitly | | burnAsset(args) / getConsignment(args) | Optional BFA burn and consignment sharing for third-party proof verification (UTEXO proposal) | | listTransfers(id?) / getTransferStatus(id) | Transfer history and status | | decodeRgbInvoice(invoice) | What an invoice asks for, before you pay it — read-only, no prompt | | makeLnInvoice(args) / payLnInvoice(args) | RGB over Lightning; listed in methods only when the wallet has a Lightning node | | on / off | transferReceived and transferSettled events |

Feature-detect with supports(info, method) rather than assuming a method exists: a node-less wallet rejects the Lightning methods with METHOD_NOT_SUPPORTED.

listAssets() and listTransfers() are typed wide because wallets differ on whether they wrap the array — pass them through toAssetArray() / toTransferArray().

Discovery

window.rgb is a single slot, so two installed wallets cannot both own it. Wallets also announce themselves, EIP-6963 style, and listProviders() collects the answers:

import { listProviders } from "@utexo/webrgb";

for (const { info, provider } of await listProviders()) {
  console.log(info.name, info.rdns); // show a picker, then use `provider`
}

requestProvider() resolves whichever comes first — an installed window.rgb, an announcement, or the legacy rgb:ready event — so a dApp that wants one wallet needs nothing else.

Wallet side, one call joins discovery:

import { announceProvider } from "@utexo/webrgb";

announceProvider({
  info: { uuid: crypto.randomUUID(), name: "Example", rdns: "com.example.wallet" },
  provider,
});

Building without a wallet

@utexo/webrgb/mock is an in-memory provider that enforces the same rules a real one does — NOT_ENABLED before enable(), METHOD_NOT_SUPPORTED for anything absent from getInfo().methods, a confirmation step you can make refuse:

import { createMockProvider, installMockProvider } from "@utexo/webrgb/mock";

// In a test:
const rgb = createMockProvider({ protocol: "RGB_LN", assets: [{ id: "rgb:x", balance: 100 }] });
await rgb.enable();
const sent = await rgb.sendAsset({ assetId: "rgb:x", amount: 1, recipientId: "utxob:y" });
rgb.settle(sent.transferId!); // fires transferSettled
expect(rgb.calls.map((c) => c.method)).toContain("sendAsset");

// In a dev build: put it on window.rgb and let the app find it as usual.
const { uninstall } = installMockProvider();

Conformance

@utexo/webrgb/conformance checks a live wallet against SPEC.md using read-only calls only, so it raises no confirmation:

import { runConformance, formatReport } from "@utexo/webrgb/conformance";

console.log(formatReport(await runConformance(window.rgb!)));

Errors

| Code | Meaning | |------|---------| | USER_REJECTED | The user declined the connection or the confirmation prompt | | NOT_ENABLED | Called before enable() resolved for this origin | | METHOD_NOT_SUPPORTED | The connected wallet cannot serve this method, or no provider was found | | INVALID_PARAMS | An argument is malformed or out of range; error.message names it | | ASSET_NOT_FOUND | The call names an asset the wallet does not know — for blindReceive, omit assetId | | INTERNAL_ERROR | Anything else; see error.message |

The error crosses a postMessage boundary on its way out of the wallet, so what you catch is a plain Error carrying code — instanceof will not help. Use isProviderError(err), or providerErrorCode(err) for a switch that must be total.

Versioning

@utexo/webrgb starts at 0.1.0 and is versioned independently of the upstream package.

The declarations mirror SPEC.md and the extension's src/injected.ts. A method added to the provider lands here as a minor bump; a changed signature as a major bump. If the two disagree, trust the wallet and open an issue.

Development

npm install
npm test           # tsc over the declarations and index.js, plus the runtime tests
npm run test:package   # are-the-types-wrong + publint against the packed tarball

License

MIT