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

@nevermined-io/ui-widgets

v0.5.21

Published

Browser SDK for embedding Nevermined flows (checkout, card enrollment, card management, delegations) into your own website via secure iframes.

Downloads

3,263

Readme

@nevermined-io/ui-widgets

Browser SDK for embedding Nevermined flows (checkout, card enrollment, card management, delegations) into your own website via secure iframes.

Pairs with @nevermined-io/ui-widgets-server, which mints widget sessions server-to-server from your backend and hands the response to this SDK.

Install

npm install @nevermined-io/ui-widgets
# or
pnpm add @nevermined-io/ui-widgets

ESM-only. Works in any modern browser bundler (Vite, webpack 5, Rspack, esbuild, etc.).

Quick start

import { NeverminedWidgets } from '@nevermined-io/ui-widgets'

// 1. Get a widget session from your backend (see ui-widgets-server). The
//    backend calls Nevermined with your widget key `rawSecret` and forwards
//    the response — the secret never reaches the browser.
const session = await fetch('/api/widget-session').then((r) => r.json())

// 2. Initialize the SDK
const nvm = await NeverminedWidgets.initialize({
  session,
  environment: 'sandbox',
})

// 3. Mount a widget
nvm.checkout.start({
  did: 'did:nv:abc...',
  container: document.getElementById('checkout')!,
  onReady: () => console.log('iframe ready'),
  onSuccess: (result) => console.log('purchase complete', result),
  onError: (error) => console.error('checkout error', error),
  onClose: () => console.log('user closed the iframe'),
})

The widget renders inside container as an iframe. The host page never sees Stripe details, the user's NVM API key, or the underlying blockchain transactions — those stay inside the iframe and the Nevermined backend.

Environments

| Value | API base URL | Webapp URL | | ----------------- | ------------------------------------ | ------------------------ | | live | https://api.live.nevermined.app | https://nevermined.app | | sandbox | https://api.sandbox.nevermined.app | https://nevermined.app | | staging_live | https://api.live.nevermined.dev | https://nevermined.dev | | staging_sandbox | https://api.sandbox.nevermined.dev | https://nevermined.dev | | local | http://localhost:3001 | http://localhost:4200 |

local is for developing against a self-hosted stack. Production integrations should use live or sandbox.

API

NeverminedWidgets.initialize(config)

Accepts a widget session minted server-to-server by your backend (typically via @nevermined-io/ui-widgets-server.createWidgetSession) and returns a NeverminedWidgets instance you keep around for the lifetime of the page (or until logout). The SDK does not mint sessions itself; the widget key rawSecret stays on your backend.

const nvm = await NeverminedWidgets.initialize({
  session, // WidgetSession returned by your backend
  environment: 'live',
})

The session refreshes itself automatically in the background. If a refresh fails (revoked widget key, expired session, network outage), the SDK emits 'session-expired':

nvm.on('session-expired', () => {
  // Fetch a fresh widget session from your backend and re-initialize.
})

nvm.checkout.start(options)

Mounts the checkout iframe so the user can purchase a plan for a given agent DID.

nvm.checkout.start({
  did: 'did:nv:...',
  planId: '...',                 // optional: skip plan selection
  container: HTMLElement,        // optional: defaults to document.body
  onBooted: () => void,          // iframe DOM mounted, before auth
  onReady: () => void,           // iframe authenticated and rendered
  onSuccess: ({ did, planId, txHash }) => void,
  onError: (error: EmbedError) => void,
  onClose: () => void,           // iframe was dismissed; instance is now terminal
})

After onClose the widget instance is terminal — call nvm.checkout.start() again on a fresh instance via nvm.checkout to mount another checkout.

nvm.delegations

Card and delegation management. Three iframe-based flows + two SDK-direct revocations:

// Iframe flows
nvm.delegations.enrollCard({ container, onSuccess, onError, onClose })
nvm.delegations.listCards({ container, onCardAction, onError, onClose })
nvm.delegations.createDelegation({ paymentMethodId, container, onSuccess, onError })

// Direct API calls (no iframe) — use the widget session token under the hood
await nvm.delegations.revokeCard(paymentMethodId)
await nvm.delegations.revokeDelegation(delegationId)

listCards emits per-row actions through onCardAction so the host can react (e.g. mount createDelegation for the selected card):

nvm.delegations.listCards({
  container,
  onCardAction: ({ action, paymentMethodId }) => {
    if (action === 'delegate') {
      nvm.delegations.createDelegation({ paymentMethodId, container })
    }
  },
})

The two iframe flows and listCards share a single iframe slot — calling any of them dismounts the previous iframe.

nvm.account

const { userId, userWallet } = nvm.account

The user identity backed by the widget session. userWallet is the user's smart account address.

nvm.destroy()

Tears down any active iframe, stops the session refresh timer, and clears event listeners. Call this when the user logs out or you no longer need any widget on the page.

Errors

WidgetInitError

Thrown by NeverminedWidgets.initialize() when the session is missing or malformed, or the refresh network call fails later.

try {
  await NeverminedWidgets.initialize({ session, environment: 'live' })
} catch (err) {
  if (err instanceof WidgetInitError) {
    // err.code: MISSING_SESSION | INVALID_SESSION | INVALID_ENVIRONMENT
    //         | NETWORK_ERROR
  }
}

WidgetSessionExpiredError

Thrown by nvm.getSessionToken() when the cached session has expired and was not refreshed in time.

WidgetApiError

Thrown by revokeCard() and revokeDelegation() on non-2xx responses or network failures. Carries status and the optional apiCode (BCK error code) so consumers can branch on 401/403 without parsing the message.

EmbedError (callback payload)

Errors surfaced through onError callbacks have a normalized shape:

type EmbedError = {
  code: 'UNAUTHORIZED' | 'NETWORK' | 'PAYMENT_NOT_CONFIRMED' | 'UNKNOWN'
  message: string
  status?: number // HTTP status when applicable
  apiCode?: string // BCK.* error code when the iframe surfaces one
}

postMessage protocol

The SDK and the embedded iframes communicate over window.postMessage with a versioned message envelope. Most consumers never need to deal with this directly, but the types are exported in case you want to inspect frames or build a custom integration:

import {
  WidgetMessageType,
  parseMessage,
  createMessage,
  WIDGET_MESSAGE_VERSION,
} from '@nevermined-io/ui-widgets'

Message types:

| Type | Direction | When | | ----------------- | --------------- | --------------------------------------------------------- | | nvm:booted | iframe → parent | DOM mounted, before the iframe knows the session token | | nvm:init | parent → iframe | SDK responds to booted with the session token | | nvm:ready | iframe → parent | Auth validated, iframe rendered | | nvm:resize | iframe → parent | Iframe content height changed | | nvm:success | iframe → parent | Terminal success (purchase complete, card enrolled, etc.) | | nvm:error | iframe → parent | Error (terminal or recoverable; check EmbedError.code) | | nvm:card-action | iframe → parent | Per-row action inside listCards (e.g. delegate) | | nvm:close | iframe ↔ parent | Iframe is being dismissed |

All frames carry version: '1'. The SDK rejects frames with mismatched versions to keep upgrades safe.

Security model

  • Origin allowlist: every widget key has an allowedOrigins list. The webapp validates that the host's parentOrigin is on that list before responding to the handshake. A leaked widget key cannot mount widgets on an unrecognized origin.
  • Session token never in URL: the SDK delivers the session token to the iframe via postMessage after a nvm:booted handshake. The token is not visible in the iframe src, browser history, or referer headers.
  • Wildcard origin rejected: IframeManager refuses to construct with '*'.
  • Sandboxed iframe: the embed routes run in a no-chrome layout that excludes navigation, links to other dashboard areas, and persistent cookies for cross-origin contexts.

License

Apache-2.0 © Nevermined