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

@belonguniverseai/react-sdk

v0.6.28

Published

Belong — embeddable React AI assistant dock. Mount <BelongWidget> in your app tree with getToken dependency-injection auth.

Readme

@belonguniverseai/react-sdk

Embeddable Belong AI assistant dock as a React component. Mount <BelongWidget> inside your own React tree — no <script> tag, no globals. Authentication is dependency-injected via a getToken callback (called per request; Belong never caches your token).

Install

npm install @belonguniverseai/react-sdk

react and react-dom (>= 18.2) are peer dependencies — the component mounts on your app's single React copy.

Usage

import { BelongWidget } from "@belonguniverseai/react-sdk";

export function App() {
  return (
    <BelongWidget
      getToken={async () => {
        // Return a fresh Belong-audience JWT. Called per request.
        return await getBelongToken();
      }}
      backend="https://your-belong-backend.example.com"
      tenant="your-tenant-id-or-slug"
    />
  );
}

Props

| Prop | Type | Required | Description | | ---------------- | ------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | getToken | () => Promise<string> | yes | Resolves a bearer token per request (DI auth; never cached). | | backend | string | yes | Belong backend base URL. | | tenant | string | no | Public tenant ID or slug for branding. Required when the API hosts multiple tenants; omit on a single-tenant API. Auth still comes from the JWT. | | universeOrigin | string | no | Deprecated, ignored. Cross-origin navigation keys off window.location; safe to remove. | | agentId | string | no | Sent as X-Belong-Agent-Id on every request. | | locale | BelongLocale | no | Host/tenant default language (user choice still wins). | | panelEnabled | boolean | no | Whether the active workspace shows the assistant panel. | | agentGrant | { provider?: string; scopeExternalId?: string; scopeUrlParam?: string } | no | Optional CLI agent-grant overrides. Most hosts need none of this — a scoped workspace already offers the default grant. | | workspace | string \| null | no | Active workspace id — re-scopes sessions, files, chat, and the CLI grant on switch. null disables scoped surfaces while resolving; omit if unused. |

The dock renders into its own shadow root, so its styles never leak into (or inherit from) your app.

Tenant default theme

Both the React component and window.belong.init({ apiBaseUrl, tenant }) load GET /v1/config/theme?tenant=<id-or-slug> before rendering the dock. The API resolves the active tenant and reads tenants/<tenantId>/config/theme.json from its private asset store, with the existing knowledge-domain theme as a fallback. The browser needs no bucket credentials or direct bucket access.

The published tenant theme is the default. Appearance settings offer Company default, Belong, Simetrik, and Custom. Explicit style choices are stored per API endpoint and tenant. Selecting Company default restores the latest published branding; old unscoped style preferences cannot silently replace it. The SDK refreshes the baseline on page focus or when the tab becomes visible, while preserving an explicit style and personal color-mode/position preferences. The script embed can also restore it with belong.applyPreset("tenant").

Theme reads bypass HTTP caches. API instances refresh their tenant registry and asset cache using the existing assets_revision signal, so publishing must advance that revision. A first read also syncs revision-0 tenants added after boot. Network failures retain the last good theme or built-in/inline fallback; initial theme reads time out after five seconds so an unavailable API cannot block the dock.

Rollout requires releasing the API and both SDK bundles, then upgrading the SDK installed in each host application. No admin-page change or public bucket access is required. Configure each deployment with the intended environment/region's tenant bucket and backend read permissions.

Host context (window.belong.init)

The script-tag embed's init takes two optional host-context props that personalise what the dock shows before the first message:

| Prop | Type | Required | Description | | ------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------- | | user | { displayName?: string } | no | Signed-in user; personalises the first message and the avatar menu. | | pageContext | { label?: string; fromDocumentTitle?: boolean } | no | Page label for the first message; defaults to the tab title. |

Both have runtime setters on window.belong, alongside setLocale and setWorkspace:

  • belong.setUser({ displayName }) — wins over init({ user }). setUser(null) drops the override back to the init value; setUser({ displayName: null }) means "no name for this user" and shows none even when init seeded one.
  • belong.setPageContext(label) — wins over init({ pageContext }) and the tab title; setPageContext(null) drops the override. With no label anywhere, the dock reads document.title live (SPA navigation updates it), unless the host passed pageContext: { fromDocumentTitle: false }.

A re-init states the host's context in full: omitting user or pageContext CLEARS what a previous init seeded (the config is replaced wholesale, not merged). A live setUser / setPageContext override outranks init and survives a later one — clear it with null to hand control back to the init values.

Neither value is persisted — a reload re-derives both from the host's next init.

Opening the dock from the host (window.belong.open)

belong.open({ size?, draft? }) shows the chat view at the requested size: "fullscreen" covers the viewport on desktop (a phone resolves it to the open sheet, like the rail's own toggle), "expanded" docks it beside the page, and omitting size keeps the current size (a collapsed dock expands). draft prefills the composer — never sends it, only when the composer is empty, at most 4,000 characters — and focuses it. The user can always leave fullscreen.

It is safe to call BEFORE init resolves: a request made before the dock mounts is applied at mount, so open({ size: "fullscreen" }) followed by init(...) mounts straight into fullscreen with no flash of the docked size.

Host-bridged MCP (init({ hostMcp }))

Some tools can only be reached from the signed-in user's own page — an MCP server behind an identity-aware proxy, an intranet, a cookie session. A tenant publishes such a server as an MCP plugin entry with transport: "host" and a same-origin mcpUri path (see docs/guides/009-manual-agent-integration.md); the agent's calls then travel to the dock, which POSTs each JSON-RPC tools/call to that path on the page's own origin with credentials: "same-origin" and relays the raw answer back.

The host must opt in, per path:

window.belong.init({
  // …
  hostMcp: { allowedPaths: ["/mcp"] }, // root-relative, exact match, at most 8
});

A path not listed is refused in the page (mcp_not_allowed) whatever the tenant publishes; omitting hostMcp disables the feature. Requests carry x-belong-source: dock so the host can label its own audit logs; they follow no redirects (an expired proxy session reads as "sign-in expired", not as a login page), abort after 55 s, and relay at most 1,000,000 characters of body.

Restricting what the agent can do on the page (init({ browserControl }))

By default the dock runs every browser-control op the agent sends: reading the page (snapshot, read), driving it (click, type, select, press, navigate), running JavaScript in it (eval) and host MCP calls (mcp_call). All of them act with the signed-in user's own session on your origin.

A host can limit that to the ops it wants:

window.belong.init({
  // …
  hostMcp: { allowedPaths: ["/mcp"] },
  browserControl: { allowedOps: ["mcp_call"] }, // only the bridged MCP calls
});

Every other op is refused in the page before it runs (op_not_allowed), and the agent is told the page does not allow it. allowedOps: [] refuses everything. Omitting browserControl keeps every op, as before. A value that is present but invalid (an unknown op name, a misspelt key) refuses everything and logs a console warning, because a host that passed one meant to restrict the page. Like hostMcp, it is restated on every init.

If your page only bridges MCP, pass allowedOps: ["mcp_call"]. Otherwise the agent can also script and click through the page with the viewer's session, which reaches everything hostMcp.allowedPaths was meant to fence off. That matters most when the agent reads text written by other people (customer conversations, tickets, email), since such text can carry instructions aimed at the agent.

Account authorization and Content Security Policy

Browser-bound account authorization opens an about:blank popup, clears its opener, and submits a form POST to the configured API's browserBindingUrl. The popup inherits the embedding document's CSP even after its opener is cleared. If that document restricts form-action, allow both the API bootstrap origin and the authorization provider's origin in every enforced policy. Chromium also checks the bootstrap's 303 redirect against this policy; allowing only the API is not enough.

For example, a deployment using the public Microsoft login service could use:

Content-Security-Policy: form-action 'self' https://your-belong-backend.example.com https://login.microsoftonline.com

Merge those hosts into your existing policy, using your actual API and configured provider origins (including any required redirect destinations). A same-origin API proxy is covered by 'self'; the external provider still needs permission. Existing connect-src and API allowed-origin requirements continue to apply independently.

An enforced form-action violation closes the popup and shows the existing authorization failure UI. Users can retry with the Connect/Reconnect action after the host policy is fixed. The SDK does not bypass CSP or offer direct provider navigation for bound responses. Proofs travel only in the POST body, never in URLs. The popup uses referrer policy origin so bootstrap POSTs retain a trustworthy Origin header; the backend redirect should send Referrer-Policy: no-referrer.

Run the SDK's real Chromium checks (including cross-origin CSP and manual fallback) from this package with node --test tests/browser/authorization-popup.mjs.

Voice calls (new in 0.2.0)

The dock's rail now carries a phone button: a real two-way voice call with a GPT-realtime voice operator that delegates work to Belong agents. The operator runs a team of up to 3 Belong agents at once ("Main agent" + background agents 2–3), routes same-scope follow-ups onto the agent already doing that work, spawns a new agent for unrelated asks — and says which it chose. Files the agents publish open on screen automatically; approvals and scheduling work by voice.

Voice calls require the backend to be configured with an OPENAI_API_KEY (model/voice are tuned via OPENAI_REALTIME_MODEL / OPENAI_REALTIME_VOICE); on an unconfigured deployment the call button shows "Call mode is not enabled on this deployment." when tapped. Embedding hosts need no CSP changes: the WebRTC handshake (SDP offer/answer) relays through the Belong backend — already in your connect-src if the dock works at all — and the call audio itself is a direct browser↔OpenAI WebRTC media stream, which connect-src does not govern (audio never relays through the Belong backend).

Interactive HTML artifacts

Registered HTML reports receive the versioned window.belongArtifact helper. The parent SDK owns authentication and approval; the opaque iframe submits named actions and observes durable operation results without a sandbox port or tokens. See the authoring contract and demo.