@viadialog/viaflow-sdk
v0.0.9
Published
Browser SDK to embed the Viaflow webphone in any host page via an iframe and a typed postMessage bridge. Voice, SMS, agent status, CTI screen pop.
Readme
@viadialog/viaflow-sdk
Browser SDK that embeds the Viaflow web app into any host page via an iframe and exposes a typed JavaScript API for click-to-call, SMS, navigation and call lifecycle events.
Status: scaffold. The Viaflow web app does not yet implement the matching
postMessageprotocol — until that lands, only the iframe lifecycle (mount / show / hide / destroy) is functional. Action calls and event subscriptions will be silently no-ops on the app side.
Install
The SDK is currently distributed via the internal Viadialog MinIO CDN. npm publish is wired but disabled — see docs/release.md §8 for how to re-enable it.
<script
src="http://minio-viaflow-prod.in.viadialog.com:8001/cdnstorage/viaflow-sdk/0.0.8/index.global.min.js"
integrity="sha384-REPLACE_WITH_RELEASE_NOTES_HASH"
crossorigin="anonymous"></script>
<script>
// appUrl defaults to https://viaflow-app.viadialog.com/embedded-banner
const sdk = new ViaflowSDK.ViaflowSDK();
sdk.generate();
</script>The CDN serves two flavours of the IIFE bundle at every versioned URL:
| File | Size | Use for |
|---|---|---|
| index.global.min.js | ~12 KB | Production. Default. |
| index.global.js | ~22 KB | Debugging — readable identifiers and stack traces. |
Each release publishes both SRI hashes in the CHANGELOG entry and in the GitLab CI release log. URLs are immutable: 0.0.8/index.global.min.js always serves the same bytes.
The current endpoint is HTTP and reachable only from the Viadialog network. SRI requires HTTPS for browsers to accept the
integrity=attribute on cross-origin scripts loaded from the public internet — fine internally, not yet usable for external integrators.
Usage
import { ViaflowSDK } from "@viadialog/viaflow-sdk";
const sdk = new ViaflowSDK({
// appUrl defaults to https://viaflow-app.viadialog.com/embedded-banner
size: "medium",
position: { bottom: "0", right: "64px" },
trayicon: true,
});
sdk.generate();
sdk.on("ringingCall", (call) => {
console.log("incoming call from", call.number);
});
document.querySelector("#call-btn")?.addEventListener("click", () => {
sdk.dial("+33612345678");
});Constructor options
| Option | Type | Default | |
|--------|------|---------|---|
| appUrl | string | https://viaflow-app.viadialog.com/embedded-banner | URL of the Viaflow banner to embed. Override only for staging/dev environments. |
| container | string | document.body | DOM id of the parent element. |
| type | "fixed" \| "relative" \| "absolute" | "fixed" (or "relative" if container is set) | CSS positioning of the iframe wrapper. |
| size | "small" \| "medium" \| "big" \| "auto" | "medium" | Preset width/height. |
| position | { top?, bottom?, left?, right? } | { right: "64px", bottom: "0" } | Manual position. |
| border | boolean | true | Drop shadow around the iframe. |
| animation | boolean | true | Fade-in/out on show/hide. |
| backgroundColor | string | — | Background of the iframe wrapper. |
| trayicon | boolean | true | Render a tray bubble when the iframe is hidden. |
| trayposition | { top?, bottom?, left?, right? } | { bottom: "10px", right: "10px" } | Tray bubble position. |
| trayIconUrl | string | placeholder | Override the tray bubble image. |
Methods
Lifecycle
sdk.generate()— mount the iframe in the DOM and show it. Returns theHTMLIFrameElementon success.sdk.destroy()— unmount and tear down event listeners.sdk.show()/sdk.hide()/sdk.toggle(force?)— visibility.sdk.isDisplayed()— current visibility.
Actions (host → app)
These all auto-show the iframe except changePage / reload / logout.
sdk.dial(number, fromNumber?)sdk.sendSMS(toNumber, message, fromNumber?)sdk.openCallLog(callId)sdk.changePage(page)sdk.reload()sdk.logout()sdk.getCurrentPage()
CTI screen pop
When a call event fires, automatically navigate the host page to a relevant record (case detail, contact lookup, etc.).
sdk.screenPop({
url: "/cases/{{case_id}}",
required: ["case_id"],
on: ["ringingCall"],
});
sdk.screenPop({
url: "/contacts/lookup?phone={{number}}",
on: ["ringingCall"],
});Multiple registrations are evaluated in order — the first one that produces a non-null URL pops, the rest are skipped for that call_id. Useful to express "if there's a case, open it; otherwise fall back to phone lookup".
Template syntax: {{var}} with fallback chain {{var_a|var_b|"literal default"}}. Substitutions are URI-encoded.
Filters:
required: ["case_id"]— skip unless the call carries all listed keyswhenInbound(defaulttrue),whenOutbound(defaultfalse),whenTransferred(defaultfalse)
SPA hosts: provide a navigate callback to drive your router instead of window.location:
sdk.screenPop({
url: "/cases/{{case_id}}",
navigate: (url, call) => router.push(url),
});Custom logic: use resolve for async CRM lookups, and beforePop to cancel:
sdk.screenPop({
on: ["ringingCall"],
resolve: async (call) => {
const match = await crm.searchByPhone(call.number);
return match ? `/contacts/${match.id}` : null;
},
beforePop: (call) => !document.body.classList.contains("editing"),
});See examples/screenpop.html for a working mini-CRM with hash routing.
Events (app → host)
const unsubscribe = sdk.on("ringingCall", (call) => { /* ... */ });
unsubscribe();
// or
sdk.off("ringingCall", listener); // remove one
sdk.off("ringingCall"); // remove all listeners for this event
sdk.offAll(); // remove every listenerAvailable events: dialerReady, login, logout, changePage, ringingCall, answeredCall, hangupCall, smsSent, smsReceived. See PROTOCOL.md for payload shapes.
Development
npm install
npm run build # produces dist/index.{js,cjs,global.js} + .d.ts
npm run typecheck
npm run dev # build:watch + host server (:3000) + mock server (:3002)Releasing
See docs/release.md for the full release guide — one-time setup (npm scope, GitLab variables, MinIO bucket, CDN/DNS), the standard release workflow, pre-release (alpha/beta/rc), versioning policy, and pipeline troubleshooting.
Local end-to-end test with the mock app
Until the real Viaflow web app ships the matching postMessage protocol (see PROTOCOL.md), mock/index.html simulates it. It speaks the full protocol: handshake, every event, and auto-responds to dial / sendSMS / changePage with realistic event sequences.
npm run devThen open:
- Host page (loads the SDK): http://localhost:3000/examples/vanilla.html
- Mock app (rendered inside the iframe): http://localhost:3002/
The host's appUrl defaults to http://localhost:3001 but can be overridden via ?appUrl=… in the URL. Click dial on the host → the mock auto-emits ringingCall → answeredCall → hangupCall over 5 seconds.
