Skip to content

RocketChat/Pexip.External.Chat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pexip External Chat Plugin

A Pexip Web App 3 plugin that adds a Chat toolbar button and bridges the meeting to an external chat experience hosted by the page that embeds Web App 3 (the top window).

The plugin and the top window communicate over window.postMessage. The plugin also exposes the Web App 3 conference.dialOut capability so the top window can dial participants into the meeting.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Top window (embedding page)  β”‚
β”‚                              β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   postMessage (both directions)
β”‚   β”‚ Web App 3 (iframe)    β”‚  β”‚
β”‚   β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  │◄─┼────────────────────────────────┐
β”‚   β”‚   β”‚ external-chat  β”‚β”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚   β”‚   β”‚   plugin       β”‚  β”‚  β”‚
β”‚   β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Repository layout

.
β”œβ”€β”€ Makefile                       # build + package pipeline (run from repo root)
β”œβ”€β”€ external-chat/                 # the plugin source (Vite + TypeScript)
β”‚   β”œβ”€β”€ src/index.ts               # plugin entry point
β”‚   └── package.json               # version is the source of truth for releases
└── webapp3/
    └── branding/
        β”œβ”€β”€ manifest.json          # Web App 3 branding manifest (registers the plugin)
        └── plugins/external-chat/ # built plugin is copied here by `make deploy`

The plugin id in external-chat/src/index.ts (registerPlugin({ id: 'external-chat' })) must match the plugin id in webapp3/branding/manifest.json (plugins[].id). A mismatch causes Web App 3 to reject the plugin at load time.


postMessage API

All messages β€” in both directions β€” share a single envelope: a flat object with an action string plus any payload fields alongside it.

{ action: 'pexip:plugin:external-chat/<name>', ...payloadFields }

Every action is namespaced with the pexip:plugin:external-chat/ prefix. Messages without that prefix are ignored (and logged as a warning).

Security

The plugin only reacts to messages whose event.source is the top window. Messages originating from the plugin's own iframe or sibling frames are dropped. If your deployment has a fixed host origin, you should additionally gate on event.origin in src/index.ts for defense in depth.


Messages sent BY the plugin (plugin β†’ top window)

Listen for these in the top window:

window.addEventListener('message', (event) => {
  if (event.source !== document.querySelector('iframe#webapp3')?.contentWindow) return;
  const { action, ...data } = event.data ?? {};
  switch (action) {
    case 'pexip:plugin:external-chat/ready':            /* plugin is loaded */ break;
    case 'pexip:plugin:external-chat/connected':        /* user joined the call */ break;
    case 'pexip:plugin:external-chat/disconnected':     /* data.userInitiated, data.error, data.errorCode */ break;
    case 'pexip:plugin:external-chat/toggle-chat':      /* data.active */      break;
    case 'pexip:plugin:external-chat/dial-out-success': /* data.uuid, data.displayName */ break;
    case 'pexip:plugin:external-chat/dial-out-error':   /* data.message */     break;
  }
});
Action Payload When
pexip:plugin:external-chat/ready (none) Plugin finished loading and registering (before the user joins).
pexip:plugin:external-chat/connected (none) User joined the call (passed preflight); the in-meeting toolbar and Chat button are now visible/accessible.
pexip:plugin:external-chat/disconnected { userInitiated: boolean, error?: string, errorCode?: string } User left or lost the call; the toolbar is no longer available. userInitiated is true when the user clicked Leave, false for an involuntary drop (in which case error/errorCode are set).
pexip:plugin:external-chat/toggle-chat { active: boolean } User clicked the Chat toolbar button. active is the requested state (the opposite of the current one).
pexip:plugin:external-chat/dial-out-success { uuid: string, displayName?: string } A dial-out request succeeded; the dialed participant joined.
pexip:plugin:external-chat/dial-out-error { message: string } A dial-out request failed.

Note: Clicking the toolbar button only notifies the top window via toggle-chat. The button's active/tooltip state does not change on its own β€” the top window is the source of truth and must echo back toggle-chat-button-state (below) to update the button.


Messages handled BY the plugin (top window β†’ plugin)

Send these from the top window to the Web App 3 iframe:

const iframe = document.querySelector('iframe#webapp3');
iframe.contentWindow.postMessage({
  action: 'pexip:plugin:external-chat/toggle-chat-badge',
  visible: true,
}, '*'); // use the Web App 3 origin instead of '*' in production
Action Payload Effect
pexip:plugin:external-chat/toggle-chat-button-state { active: boolean } Sets the Chat button's active state and tooltip (Close Chat / Open Chat).
pexip:plugin:external-chat/toggle-chat-badge { visible: boolean } Shows or hides the unread badge on the Chat button.
pexip:plugin:external-chat/dial-out dial parameters (see below) Dials a destination into the conference via conference.dialOut. Replies with dial-out-success / dial-out-error.

dial-out parameters

These map directly to the Pexip Infinity dial request body.

Field Type Required Description
role 'HOST' | 'GUEST' βœ… Privilege level of the dialed participant.
destination string βœ… The target address to call.
protocol 'sip' | 'h323' | 'rtmp' | 'mssip' | 'auto' βœ… Protocol used to place the call.
call_type 'video' | 'video-only' | 'audio' β€” Limits the media content of the call.
presentation_url string β€” For RTMP calls, sends presentation to a separate destination.
streaming 'yes' | 'no' β€” Marks the participant as a streaming/recording device.
dtmf_sequence string β€” DTMF tones to send once the call connects.
source string β€” Source URI (must be valid for the conference).
source_display_name string β€” Calling display name.
remote_display_name string β€” Friendly name shown in participant lists / overlays.
text string β€” Overlay text used instead of remote_display_name.
keep_conference_alive 'keep_conference_alive' | 'keep_conference_alive_if_multiple' | 'keep_conference_alive_never' β€” Whether the conference continues after others leave.

Example:

iframe.contentWindow.postMessage({
  action: 'pexip:plugin:external-chat/dial-out',
  role: 'GUEST',
  destination: 'alice@example.com',
  protocol: 'sip',
  call_type: 'video',
  remote_display_name: 'Alice',
}, '*');

conference.dialOut resolves only once the dialed participant actually joins. Hard failures (e.g. an invalid URI) reject and produce dial-out-error, but a destination that simply never answers will neither resolve nor error.


Setup

Prerequisites: Node.js 18+ (developed on Node 22) and npm.

cd external-chat
npm install

Develop

npm start

Vite serves the plugin from https://localhost:5173 (self-signed cert via vite-plugin-mkcert β€” accept it in the browser once). You access it through your Web App 3 URL configured to load the plugin from this dev server. See the Pexip setup guide.

Build (standalone)

npm run build   # outputs to external-chat/dist/

The current version is read from external-chat/package.json and is logged by the plugin at runtime (plugin: external-chat loaded v<version>).


Building & packaging with the Makefile

Run all make commands from the repository root.

make            # full release: bump the minor version, build, then package
make package    # build & package using the CURRENT version (no bump)

Targets

Target What it does Bumps version?
make release Bumps the version, then runs package. βœ…
make all Alias for make release (the default target). βœ…
make bump Bumps the minor version in external-chat/package.json (npm version minor --no-git-tag-version β€” no git commit or tag). βœ…
make build Runs npm run build. β€”
make deploy Runs build, then copies external-chat/dist/ into webapp3/branding/plugins/external-chat/. β€”
make package Runs deploy, then zips the webapp3/ folder into external-chat-v<version>.zip at the repo root, using the current package.json version. β€”
make clean Removes external-chat/dist/ and the deployed plugin folder. β€”

Dependency chains: release β†’ bump β†’ package β†’ deploy β†’ build. Only release, all, and bump change the version β€” build/deploy/package use the current one, so CI and one-off packaging never bump (CI runs make package).

Output

make produces external-chat-v<version>.zip in the repo root, where <version> is the value in package.json (e.g. external-chat-v1.4.0.zip) β€” freshly bumped by make/make release, or unchanged by make package. The zip contains the full webapp3/ branding bundle, ready to upload.

Continuous integration

.github/workflows/ci.yml runs on pushes to main, on pull requests, and on manual dispatch. It installs dependencies (npm ci), then runs lint, typecheck (tsc --noEmit), and make package (build + zip, no version bump). The resulting external-chat-v<version>.zip is uploaded as a downloadable workflow artifact named external-chat-v<version>.

Releasing

.github/workflows/release.yml is a manually triggered workflow (Actions β†’ Release β†’ Run workflow). It reads the current version from external-chat/package.json, builds the zip (make package, no bump), then creates a v<version> git tag and a GitHub release with external-chat-v<version>.zip attached as an asset. Release notes are auto-generated from the changes since the previous release.

Typical flow:

make bump                 # 1. bump the minor version in package.json
git commit -am "release"  # 2. commit the bump (and push)
# 3. run the "Release" workflow from the Actions tab

If a release for the current version already exists, the workflow fails with a reminder to bump first (it never overwrites an existing tag/release).

About

Pexip External Chat integration for embedded experience

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors