Widget

TypeScript
interface SiteWidget<TApi extends object = {}> {
  readonly widgetId: string;      // unique; prefix it with your product, e.g. 'acme-counter'
  readonly widgetTitle: string;   // tile and window title
  readonly widgetIcon: string;    // a Material Symbols icon name
  readonly optional: boolean;     // false: opened automatically and cannot be closed
  readonly backgroundConnectors: Array<new () => SiteConnector>;
  windowed?: boolean;             // show the roots in a movable window
  styles?: string;                // CSS added while the widget is open
  api?: TApi;                     // returned by widgetsApi.get(widgetId) while open

  mount(app: WeeiApp): HTMLElement | HTMLElement[] | void;
  destroy(): void;
  configureBackground?(app: WeeiApp, allowed: boolean): void;
  createBackgroundApi?(app: WeeiApp): TApi;   // an API available while the widget is closed
}
MemberWhen it runs
mount(app)Each time the widget opens. Return the root element(s); Weei places them and removes them on close.
destroy()Each time the widget closes. Stop timers and subscriptions. A new instance is created for the next opening.
configureBackground(app, allowed)When the widget is added and when its availability changes, whether open or not.
createBackgroundApi(app)Once, when the widget is added. widgetsApi.get() prefers this API.

Connector

TypeScript
interface SiteConnector {
  // static connectorName: string  — required; must not contain '::'
  initListeners(gateway: Gateway): void;
}

interface Gateway {
  readonly myID: string;                     // this participant's peer ID
  readonly reachablePeers$: Observable<string[]>;
  createEvent<T>(name: string): Channel<T>;
}

interface Channel<T> extends Observable<T> {   // subscribe to receive
  next(value: T, toPeerId?: string): void;     // send to everyone or to one peer
  readonly lastMessageFrom: string;            // sender of the message being handled
}

One connector instance exists per class and is shared by every widget that requests it. Declare static connectorName: Weei addresses messages by this name, and a bundler may rename your class.

The app object

MemberUse
app.rtcService.getOrCreateConnector(Class)Observable of the connector instance, created on first use.
app.rtcService.myIDThis participant's peer ID.
app.snackbar.show(notice)Shows a notification: { message, type?, duration?, key?, actionLabel?, onAction? }. type is info, success or error.
app.widgetsApiThe same widgetsApi as on the client.
app.initializedElements.add(widgetId, element)Places an element created after mount() has returned; it is removed when the widget closes.

weei.sdk

MemberContents
rxjsThe RxJS of the loaded release. Use it instead of your own copy.
connectorsCore connectors, shared with Weei itself. See Core connectors.
version, moduleApiVersionRelease version and widget module API version.

See Core connectors for what each connector provides.

Load a widget from a URL

addWidget(url) imports an ES module with these exports:

JavaScript module
export const widgetId = 'acme-counter';
export const apiVersion = 1; // weei.sdk.moduleApiVersion
export const createWidget = () => new CounterWidget();

Rules

  • widgetId must not be the ID of a built-in widget; addWidget() rejects it.
  • Treat every received message as untrusted: check its shape and take the sender from lastMessageFrom, not from the message.
  • Render peer data as text (textContent), never as HTML.
  • Site widgets run with the same access as your page; they are not sandboxed.