@nexafon/vue is a Vue plugin with components and composables around the web SDK. Supported: Vue 3.5.
npm install @nexafon/vue1. Install the plugin
Section titled “1. Install the plugin”createNexafon(options) takes the Nexafon.init options and starts Nexafon once; it stops when the app unmounts.
import { createNexafon } from '@nexafon/vue'import { createApp } from 'vue'import App from './App.vue'
const getUserToken = async () => { const r = await fetch('/api/nexafon-token', { method: 'POST' }) if (!r.ok) throw new Error(`The token endpoint answered ${r.status}`) return r.text()}
createApp(App) .use( createNexafon({ publishableKey: import.meta.env.VITE_NEXAFON_PUBLISHABLE_KEY, getUserToken }), ) .mount('#app')2. Use the components
Section titled “2. Use the components”<script setup lang="ts">import { CallButton, Inbox, Softphone } from '@nexafon/vue'</script>
<template> <main class="support"> <Inbox style="height: 640px" /> <aside> <CallButton phone="+252615550142" /> <Softphone /> </aside> </main></template>
<style>.support { display: grid; gap: 16px; padding: 16px; grid-template-columns: 1fr 340px; }</style>| Component | Renders | Props |
|---|---|---|
<NexafonApp> |
<nexafon-app> |
store? |
<Inbox> |
<nexafon-inbox> |
store? |
<Softphone> |
<nexafon-softphone> |
store? |
<CallButton> |
<nexafon-call-button> |
phone, store? |
class and style fall through to the element. useNexafonEvent(name, listener) listens for the component’s
lifetime; useNexafon() is a ref to the started API (null until it has started).
Writing the raw <nexafon-*> tags in your own templates needs
compilerOptions.isCustomElement: (tag) => tag.startsWith('nexafon-'); the components above do not.
The token endpoint
Section titled “The token endpoint”getUserToken calls your server, which signs a token with a server helper. The example’s
POST /api/nexafon-token handler:
import type { IncomingMessage, ServerResponse } from 'node:http'import { createUserToken } from '@nexafon/node'
interface SignedInUser { id: string name: string role: string email: string emailVerified: boolean isStaff: boolean}
// Your app's own session decides who is signed in, and its own records whether it has confirmed their email. The// example has no sign-in: EXAMPLE_DEMO_USER_EMAIL is a demo user for local runs only, so replace this with your session.function signedInUser(_req: IncomingMessage): SignedInUser | null { const email = process.env.EXAMPLE_DEMO_USER_EMAIL if (!email) return null return { id: 'demo-user-1', name: 'Demo User', role: process.env.EXAMPLE_DEMO_USER_ROLE || 'agent', email, // The demo address is a member you invited, so you have confirmed it. emailVerified: true, isStaff: true, }}
// Everyone who gets a token may reach your workspace's inbox and calls: sign only for your staff, never for customers// who signed up. The example's only user is the demo teammate.function mayUseNexafon(user: SignedInUser): boolean { return user.isStaff}
// POST /api/nexafon-token signs a token for the signed-in user with NEXAFON_SECRET_KEY.export function userToken(req: IncomingMessage, res: ServerResponse): void { if (req.method !== 'POST') { res.writeHead(405).end() return } const user = signedInUser(req) if (!user) { res.writeHead(401).end() return } if (!mayUseNexafon(user)) { res.writeHead(403).end() return } const token = createUserToken({ userId: user.id, name: user.name, role: user.role, email: user.email, // Nexafon links a first sign-in to the member with this email only when it is verified: never send true for an // address your app has not confirmed, or whoever sets a member's email on your app acts as that member. emailVerified: user.emailVerified, }) res.writeHead(200, { 'content-type': 'text/plain', 'cache-control': 'no-store' }).end(token)}signedInUser stands for your app’s own session: answer 401 when nobody is signed in. The example has no sign-in,
so on a local run it signs for the demo member named in EXAMPLE_DEMO_USER_EMAIL and answers 401 without one;
replace it with your session. mayUseNexafon answers 403 to signed-in users who must not use Nexafon: sign only for
your staff, never for customers who signed up, since a token can make its user a member of your workspace. The example
treats its demo user as staff.
The example mounts it as middleware of the Vite dev and preview servers in examples/vue/vite.config.ts; in
production it is a route of your own server, behind your own session check.
The full example is examples/vue, tested with Playwright.