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

@tokenflight/widget

v0.2.0

Published

Embed the TokenFlight conversion page in your site: an iframe host that relays wallet requests.

Readme

@tokenflight/widget

Put the TokenFlight conversion page on your site. The page does all the work; this package hosts its iframe, relays the few wallet calls it needs to your wallet, and reports what happens to the order. It has no runtime dependencies and never sees an API key.

This is the conversion widget (Hyperstream v2 orders). It is separate from @tokenflight/swap, uses a different message prefix (tfw:), and can sit on the same page.

Install

npm install @tokenflight/widget

The package has no runtime dependencies and ships its own types. If the page speaks a different protocol version than the installed SDK, the widget reports PROTOCOL_MISMATCH (see Protocol); update the package or ask for the page to be redeployed.

Use

The page has to be deployed somewhere that allows your site's origin; its address is your pageUrl. Then:

import { TokenFlightWidget } from "@tokenflight/widget";

new TokenFlightWidget({
  pageUrl: "https://fly.tokenflight.ai", // the page address you use
  walletAdapter, // your site's wallet (see Wallet)
  container: "#convert",
}).initialize();

That is a working widget. Everything else is optional:

const widget = new TokenFlightWidget({
  /* ...as above... */
  config: {
    fromToken: "eip155:8453:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // start from a pair
    toToken: "eip155:42161:0xaf88d065e77c8cc2239327c5edb3a432268e5831",
    amount: "10.50",
    customColors: { "--tf-primary": "#2563eb" }, // your brand colour
  },
}).initialize();

widget.on("orderCreated", ({ orderId }) => saveForLater(orderId));
widget.on("orderCompleted", ({ orderId, outcome }) => console.log(orderId, outcome)); // filled | partial | unfilled
widget.update({ config: { amount: "25", theme: "dark" } });
widget.destroy();

Wallet

wallet is the same kind of object the swap widget takes, and the @tokenflight/swap adapters work as they are (checked against the published 0.4.10 adapters, see below). Pick the one for the wallet library your site already uses:

// wagmi
import { createWagmiAdapter } from "@tokenflight/adapter-wagmi";
const wallet = await createWagmiAdapter({ wagmiConfig });

// Reown AppKit
import { createAppKitAdapter } from "@tokenflight/adapter-appkit";
const wallet = await createAppKitAdapter({ appKit });

// ethers (any EIP-1193 provider)
import { EthersWalletAdapter } from "@tokenflight/adapter-ethers";
const wallet = new EthersWalletAdapter(window.ethereum);

// no library: a bare EIP-1193 provider, with the adapter this package ships
import { eip1193Adapter } from "@tokenflight/widget";
const wallet = eip1193Adapter(window.ethereum, { supportedChainIds: [1, 8453, 42161] });

Or write your own: it needs connect, disconnect, isConnected, getAddress, executeWalletAction, on/off and, optionally, getCurrentChainId, name and supportedChainIds (see WalletAdapterLike).

What the page may ask of it is only four EIP-1193 requests, each sent through executeWalletAction({ type: "eip1193_request", chainId, method, params }): wallet_switchEthereumChain, wallet_addEthereumChain, eth_sendTransaction (from the connected account only) and eth_chainId. Anything else is dropped. Chain-changing requests are addressed to the chain the wallet is on, because the ethers and wagmi adapters switch to chainId before running any request, which would otherwise stop a chain from ever being added.

If the adapter has supportedChainIds (the wagmi adapter derives it from the config's chains, the AppKit adapter from its networks), the page only offers source tokens on those chains.

The wallet-adapter contract

The contract is tokenflight-embed's IWalletAdapter (@tokenflight/swap), exported here as a type from src/wallet-adapter.ts, copied as it is so this package has no dependency on the swap widget. The adapters written for it (@tokenflight/adapter-wagmi, -appkit, -ethers) are therefore adapters for this widget, and AppKit is one implementation among them, not a special case. The bridge itself uses only part of it (WalletAdapterLike in src/host-bridge.ts), which every IWalletAdapter satisfies.

Options and events

Names follow tokenflight-embed's TokenFlightWidgetOptions where it has the same thing.

| Option | | |---|---| | container | Element or selector. | | walletAdapter | See above. A wallet adapter that limits chains limits the source tokens. | | pageUrl | Your deployment. https, or http on localhost. | | config | See below. Optional. | | readyTimeoutMs | How long to wait for the page (default 15 000). | | lazy | true creates the frame only when the container is about to scroll into view (default: at once). For a widget below the first screen. | | minHeight, maxHeight | Bounds for the frame's height in px. Above maxHeight the page scrolls inside the frame. Dialogs open inside the frame too, so keep maxHeight at 400 or more. |

| config | | |---|---| | fromToken, toToken | { chainId, address }, a CAIP-10 string (eip155:8453:0x…) or that object as JSON. EVM tokens only; anything else throws. | | tradeType | EXACT_INPUT (amount is what is paid) or EXACT_OUTPUT (amount is what is received). | | amount | Decimal text. With EXACT_INPUT it is a starting value the user can change; with EXACT_OUTPUT a preset amount is fixed. | | recipient | Where the converted funds go (default: the connected wallet). Once set, the user cannot change it. | | recipientEditable | true lets the user change a preset recipient. | | refundTo | Where a refund goes (default: the connected wallet). Once set, the user cannot change it. | | refundToEditable | true lets the user change a preset refundTo. | | orderId | Open this order's tracking view instead of the form. | | theme | auto, light or dark. | | customColors | Colours, radii and font by name; see Customizing the look. A flat map, or { light, dark }. Updating replaces the whole look. | | lockFromToken, lockToToken | Keep fromToken / toToken as given: that picker is closed and the direction cannot be swapped. | | hidePoweredBy | Hide the "Powered by TokenFlight" line at the foot of the card. Shown by default. | | noBackground, noBorder | Drop the card's fill / its 1px edge so your own background shows through. | | showWallet | The page shows a connect / account control on its From card (default true). Pass false when your site already has one. Read at initialize(). | | locale | Accepted and forwarded; the page is English only for now, and any other language logs a console warning. Read at initialize(); update() warns if you change it. |

update({ config }) changes only the keys you pass. initialize() can also be called as mount().

Events: ready, quote, orderCreated, depositSubmitted, orderState, orderCompleted, orderFailed, error. Payloads carry ids, states, tokens and amounts ({ chainId, token, symbol, decimals, amount }, amounts in the token's smallest unit), never keys or signatures:

| Event | Data | |---|---| | quote | spend, receive | | orderCreated | orderId, spend, receive, depositor, payout, refund | | depositSubmitted | orderId, txHash, chainId (the source chain's transaction) | | orderState | orderId, state | | orderCompleted | orderId, outcome, spend, received, refunded | | orderFailed | orderId | | error | code, message |

Error codes from the SDK: PROTOCOL_MISMATCH means the page and the SDK need to be upgraded together; READY_TIMEOUT means the page did not answer in time (wrong address, or your origin is not in its ALLOWED_HOST_ORIGINS); PAGE_CRASH means the page hit an error and is showing its own message; TOKEN_NOT_SUPPORTED means a fromToken or toToken you passed is not offered by this deployment, so that side was left empty. On the first two the SDK also puts a short message (with a "Try again" button for a timeout) in your container, so the user never sees an empty frame. A page that answers after the timeout is still accepted. widget.reload() loads the page again and restarts the handshake.

Customizing the look

customColors uses the names of tokenflight-embed's customColors, so a host that has styled the swap widget can reuse its map. A flat map applies in light and dark alike. For two palettes, give a table per theme; the page uses the one for the theme on screen (including auto, which follows the visitor's system) and switches by itself:

customColors: {
  light: { "--tf-primary": "#2563eb", "--tf-text-on-primary": "#ffffff" },
  dark: { "--tf-primary": "#a3e635", "--tf-text-on-primary": "#0b0d12" },
}

Either table may be left out, and a theme without one keeps the page's own colours. A map cannot mix the two forms.

| Key | Sets | |---|---| | --tf-surface | the card, its pills and buttons (follows into dialogs unless --tf-bg-elevated is set) | | --tf-bg-elevated | dialogs. Set it solid when --tf-surface is see-through | | --tf-bg-secondary | quiet fills inside the card | | --tf-surface-hover | pills and rows under the pointer (follows --tf-bg-secondary unless set) | | --tf-input-bg | amount and address fields | | --tf-text, --tf-text-secondary, --tf-text-tertiary | text | | --tf-border, --tf-border-light | lines | | --tf-primary, --tf-text-on-primary | the main button, focus ring, and the text on it | | --tf-success, --tf-error, --tf-warning | state colours; their tinted backgrounds are derived | | --tf-radius-xs, -sm, --tf-radius, -lg, -xl | corner radii (0 to 48px or 3rem) | | --tf-shadow, --tf-shadow-lg | the shadow of floating parts and of dialogs: none, or up to four layers like 0 8px 40px rgba(0,0,0,0.08) | | --tf-font-family | system (the default is the page's own font) | | --tf-bg | the page floor; the frame is transparent, so this is rarely visible |

A map written for the swap widget can be passed as it is: keys this page does not use (--tf-glass, --tf-skeleton, --tf-primary-glow, --tf-control-*, --tf-focus-ring-*, the --tf-font-* sizes, ...) are ignored without an error. Any other unknown key is refused. The strong edge (focus ring, outlines) is derived from --tf-text when you set it.

Values are a hex colour, rgb(), hsl(), oklch() (or oklab, lab, lch) or transparent, at most 64 characters, at most 40 keys. The SDK throws on a key or value outside this, so a typo shows in development; the page drops such an entry on its own, so a value from elsewhere cannot add CSS to it. Anything beyond this (arbitrary CSS, a stylesheet URL) is deliberately not offered: the page is in your visitors' trust, and a host-supplied stylesheet could restyle or hide what it shows.

Protocol

@tokenflight/widget/protocol exports the message types and parsers. Protocol version: 1. Messages are { type: "tfw:<name>", protocolVersion, seq, payload }. The page announces itself with ready to each allowed origin, the host replies init; wallet calls are walletRequest / walletResult by request id; the page reports resize (with a minHeight while a dialog that cannot open inside the card is shown) and event.

Develop

pnpm --filter @tokenflight/widget check-types
pnpm --filter @tokenflight/widget build   # tsc → dist
pnpm --filter @tokenflight/widget demo    # host page on http://localhost:5174

Limits

  • EVM only. The wallet bridge connects and signs on EVM chains; a non-EVM token can be a destination (with a payout address) but not a source.
  • locale, showWallet and the wallet adapter are fixed at initialize().
  • Referrer and fee attribution are set by the page's own deployment, not by the host.