@_solaris/messenger-widget
v0.5.4
Published
Embeddable chat messenger widget — Vue 3 library + iframe-hosted UI + snippet drop-in. Wired to messenger-server (cookie-based session).
Readme
messenger-widget
Embeddable chat messenger widget. Same UI as the former ww-messenger WeWeb
plugin, repackaged as a framework-agnostic npm package.
Published as @_solaris/messenger-widget.
Two ways to use it
1. Vue 3 library
npm i @_solaris/messenger-widget vueimport { Messenger } from '@_solaris/messenger-widget';
import '@_solaris/messenger-widget/style.css';
// Linked mode (merchant identifies the user):
// <Messenger :base-url="..." :widget-id="..." :token="merchantJwt" display-mode="floating" />
//
// Visitor mode (anonymous): omit `:token` — the widget calls POST /client/session
// on boot and persists a brispr-issued JWT in localStorage. Requires the widget's
// `security.allow_unauthenticated=true` server-side.
// <Messenger :base-url="..." :widget-id="..." display-mode="floating" />
//
// UI language: pass `language` ('fr' | 'en'). When omitted, it falls back to
// the authenticated customer's `language`, then the widget config's
// `default_language`, then French:
// <Messenger ... language="en" />
//
// Optionally pass agent context. `context.customer` is a flat object —
// pushed once to PATCH /customers/me on boot so the agent has it as context.
// `name` and `email` map to the customer's columns; any other key is a named
// variable value (server does a partial set, keeping ones you don't pass):
// :context="{ customer: { name: 'Jane', email: '[email protected]', plan: 'pro', seats: 12 } }"Auth model
The widget sends Authorization: Bearer <jwt> on every call. The JWT comes
from one of two sources, depending on whether token is passed:
- linked (merchant backend signs): sign a JWT HS256 with the widget secret,
claims
{ sub: <external_id>, wid: <widget_id>, kind: "linked", exp }. Pass the resulting JWT astoken. Typical TTL 1h. For long-lived SPAs that outlive the token, push a fresh one without tear-down via the rotation hook below — same pattern as Intercom'sIntercom('update', { ... }). - visitor (omit
token): the widget callsPOST /client/sessiononce, the server creates acustomersrow (identity_type='visitor') and returns a 30-day JWT. The widget persists it inlocalStorage[brispr_token_<wid>]for cross-reload continuity. Server-side opt-in viawidgets.security.allow_unauthenticated.
It also exports the individual presentational components, the design tokens and helpers — used by the WeWeb "conversation admin" plugin which supplies its own WeWeb-managed data instead of the built-in JWT/SSE transport:
import {
MessageList,
Bubble,
Composer,
ApprovalCard,
FormCard,
ArtifactRenderer,
AIAvatar,
HumanAvatar,
TeamAvatars,
AttachmentPreview,
tokens,
renderMarkdown,
uuid,
createStore,
createTransport,
} from '@_solaris/messenger-widget';2. Standalone embed (any site, no build step)
<script src="https://your-cdn/messenger.embed.js"></script>
<script>
Messenger.init({
baseUrl: 'https://messenger.your-saas.com',
widgetId: '…',
token: '…', // optional — JWT HS256 signed by your backend with
// the widget secret. Omit to run in visitor mode
// (anonymous, brispr-issued token persisted in
// localStorage, server-side opt-in required).
displayMode: 'floating', // 'floating' | 'sheet' | 'embedded'
language: 'en', // optional — 'fr' | 'en'; else customer.language / widget.default_language
// Optional agent context. `context.customer` is a flat object pushed
// once to PATCH /customers/me on boot so the agent has it as context.
// `name`/`email` map to the customer's columns; any other key is a
// named variable value (server keeps variables you don't pass):
context: {
customer: {
name: 'Jane Doe',
email: '[email protected]',
plan: 'pro',
seats: 12,
},
},
});
// Messenger.destroy() to tear it down.
</script>init() is idempotent (no-op if re-called with identical options) and requires
only baseUrl + widgetId to attempt a boot — without token, the widget
falls back to visitor mode automatically. See
examples/weweb-embed.md for the WeWeb integration
(reactive JWT via WeWeb variables + workflow).
Token rotation (linked mode)
When the merchant JWT is about to expire on a long-lived SPA, push a fresh one without tear-down. The widget swaps it in-place and rotates the SSE stream — the open conversation is preserved.
Embed (standalone) — call Messenger.update({ token }):
// Around 5min before expiration, fetch a new token from your backend, then:
Messenger.update({ token: newJwt });Vue lib — just change the token prop. A watcher catches the change and
calls the same rotation under the hood:
<Messenger :base-url="..." :widget-id="..." :token="currentJwt" />When currentJwt updates (e.g. after your auth store fetches a new one), the
widget rotates without re-mounting.
Messenger.update() (or the watcher) is a no-op if called before the widget
boots — the new token will be used on the next boot.
Build
npm install
npm run build # build:lib + build:embed + build:types → dist/| Output | Target | Vue |
| ----------------------------------------------- | ------ | --------------- |
| dist/messenger.js / .cjs + dist/style.css | lib | external (peer) |
| dist/messenger.embed.js | embed | bundled in |
| dist/types/ | types | from JSDoc |
License
Proprietary and source-available. The Software may be embedded in your own application only to interoperate with the Licensor's backend service; no modification, no use with any other backend, no redistribution. Public availability on npm grants no rights beyond the license. See LICENSE.
