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

@xapps-platform/widget-sdk

v0.2.1

Published

Typed browser bridge SDK for Xapps publisher widgets

Readme

@xapps-platform/widget-sdk

Browser bridge SDK for publisher widgets running inside Xapps iframes.

Install

npm install @xapps-platform/widget-sdk

Exports

  • createBridge from @xapps-platform/widget-sdk
  • useXappsBridge, useToolRequest from @xapps-platform/widget-sdk/react
  • XappsAdapter/init from @xapps-platform/widget-sdk/adapter

Minimal usage

import { createBridge } from "@xapps-platform/widget-sdk";

const bridge = createBridge();
const context = await bridge.getContext();
const tools = await bridge.listTools();
const result = await bridge.createRequest({
  toolName: "example_tool",
  payload: { hello: "world" },
});
const guard = await bridge.requestGuard({
  guardSlug: "platform.confirmation",
  trigger: "before:tool_run",
  context: { requestId: "req_123" },
});

Bridge API Surface

Request lifecycle:

  • createRequest(...)
  • createMultipartRequest(...)
  • getRequest(...)
  • getResponse(...)
  • getRequestEvents(...)
  • getRequestArtifacts(...)
  • attachRequestArtifact(...)
  • subscribeRequest(...)
  • unsubscribeRequest(...)

Upload lifecycle:

  • createUpload(...)
  • createMultipartUpload(...)
  • putMultipartUploadPart(...)
  • listMultipartUploadParts(...)
  • completeMultipartUpload(...)
  • getMultipartUpload(...)

Guard/session/identity:

  • requestGuard(...)
  • getVendorAssertion(...)
  • signAction(...)
  • requestTokenRefresh(...)
  • getTools(...) / listTools(...)

Bridge listeners:

  • onTokenRefresh(...)
  • onSessionExpired(...)
  • onRequestStatusUpdate(...)
  • onGuardStatus(...)
  • onExpandResult(...)
  • onThemeChanged(...)
  • onFocusRequest(...)
  • onFocusTrap(...)

Operational surfaces:

  • openOperationalSurface(...)

Bootstrap verification helper:

  • verifyWidgetBootstrap(...)

Expand / Focus / Fullscreen (Widget -> Host)

Widgets can request a larger host-managed presentation mode (for example overlay/focus mode, then fullscreen).

import { createBridge } from "@xapps-platform/widget-sdk";

const bridge = createBridge();

bridge.onExpandResult((result) => {
  // result.hostManaged, result.stage, result.nativeFullscreen
  console.log("expand result", result);
});

// First step: request focus mode (host overlay if supported).
bridge.requestExpand({
  expanded: true,
  stage: "focus",
  source: "jsonforms",
});

// Optional second step: request fullscreen.
bridge.requestExpand({
  expanded: true,
  stage: "fullscreen",
  source: "jsonforms",
});

// Exit back to inline.
bridge.requestExpand({
  expanded: false,
  stage: "inline",
  source: "jsonforms",
});

Notes:

  • If the host does not support the expand bridge, widgets should keep a local fallback (inside iframe bounds).
  • Host support is documented in xapps-embed-sdk and the expansion spec.

Operational surface opens (Widget -> Host)

Widgets can ask the host to open user-facing operational surfaces for the current xapp context.

import { createBridge } from "@xapps-platform/widget-sdk";

const bridge = createBridge();

bridge.openOperationalSurface({
  surface: "payments",
  installationId: "inst_123",
  paymentSessionId: "pay_123",
  placement: "in_router",
});

Supported surfaces:

  • requests
  • payments
  • invoices
  • notifications

Optional focused record ids:

  • requestId
  • paymentSessionId
  • invoiceId
  • notificationId

Placement hints:

  • in_router
  • side_panel
  • full_page

Current platform behavior still defaults to in_router. Additional placements are declared now so hosts can evolve later without changing widget-side API usage.

Publisher-rendered widget shell helper (recommended):

import { createBridge, createExpandController } from "@xapps-platform/widget-sdk";

const bridge = createBridge();
const expand = createExpandController(bridge, {
  source: "publisher-shell",
  widgetId: "wid_123",
  suggested: { renderer: "publisher", layout: "app" },
});

// Icon-only button: inline -> focus -> fullscreen -> inline
document.getElementById("expandBtn")?.addEventListener("click", () => {
  expand.toggle();
});

expand.onChange((state) => {
  // Hide local overlay chrome while host is managing focus/fullscreen.
  document.body.classList.toggle("host-overlay-active", state.hostManaged && state.expanded);
});

Request-widget bootstrap verification helper:

import { createBridge, verifyWidgetBootstrap } from "@xapps-platform/widget-sdk";

const bridge = createBridge();

const verified = await verifyWidgetBootstrap({
  bridge,
  endpoint: "/widgets/my-private-widget/bootstrap-verify",
  body: {
    widgetKind: "request_capable",
  },
});

console.log(verified.context.hostOrigin);
console.log(verified.payload);

Recommended contract:

  • load public iframe_url bootstrap without secrets
  • use verifyWidgetBootstrap(...) to send current widget context to your backend
  • let your backend verify the short-lived widget token against the gateway before exposing private request-capable runtime state
  • if the page is opened directly outside an Xapps host/embed, keep private runtime blocked and show a clear "open from Xapps" message instead of treating direct access as a valid request-capable session

Optional stronger bootstrap transport already supported:

  • set widgets[].config.xapps.bootstrap_transport = "signed_ticket"
  • the publisher wrapper will append xapps_bootstrap_ticket=... to the iframe URL hash
  • verifyWidgetBootstrap(...) will consume that ticket from the URL and forward it as bootstrapTicket to your backend verify endpoint
  • this stays additive; the current default remains a public bootstrap shell

Guard helpers

import {
  getGuardBlockedDetails,
  getPaymentGuardRefResolution,
  isGuardBlockedError,
  isPaymentGuardGovernanceReason,
} from "@xapps-platform/widget-sdk";

try {
  await bridge.createRequest({ toolName: "generate_report", payload: {} });
} catch (err) {
  if (isGuardBlockedError(err)) {
    const guard = getGuardBlockedDetails(err);
    const refResolution = getPaymentGuardRefResolution(err);
    // guard?.guardSlug, guard?.reason, guard?.action, refResolution?.source
    if (isPaymentGuardGovernanceReason(guard?.reason)) {
      // reason is payment_guard_override_not_allowed or payment_guard_pricing_floor_violation
    }
  }
}

Payment Guard UX Helpers

Use payment helpers so Pay/Submit state stays correct after replay/consume outcomes:

import {
  attachPaymentEvidenceToGuardOrchestration,
  resolveGuardPrimaryActionLabel,
  reconcilePaymentEvidenceFromGuardBlocked,
} from "@xapps-platform/widget-sdk";

try {
  await bridge.createRequest({ toolName: "submit_wizard_application", payload });
} catch (err) {
  // Marks current payment evidence as consumed when reason is payment_receipt_already_used.
  reconcilePaymentEvidenceFromGuardBlocked({ error: err });
}

const ctaLabel = resolveGuardPrimaryActionLabel({
  guard: activeGuard,
  submitLabel: "Submit",
  payLabel: "Pay",
});

Integration note:

  • Host pages should use @xapps-platform/embed-sdk payment return helpers (resolvePaymentReturnContext preferred) and pass payment params once on resume.
  • Widget pages should use @xapps-platform/widget-sdk helpers above to avoid stale submit state after replay-rejected evidence.
  • @xapps-platform/marketplace-ui can carry host/payment context across marketplace routes; widget-sdk remains the widget-side API surface.
  • Canonical payment evidence requires xapps_payment_issuer to be present in forwarded xapps_payment_* params.

Notes

  • Runtime: browser iframe context.
  • React hooks are provided via @xapps-platform/widget-sdk/react.
  • Guard bridge helpers: requestGuard(...) and onGuardStatus(...).
  • See package/runtime ownership: docs/guides/12-package-usage-and-ownership.md.