@bitpeakdev/widget
v0.3.0
Published
Embeddable ticket creation and status tracking widget for Suporta helpdesk tenants.
Keywords
Readme
@bitpeakdev/widget
Embeddable ticket creation and status tracking for apps built on the Suporta helpdesk platform. Built for Sman Cars and Food la Route to let their own end-users submit support tickets and check status, without ever logging into Suporta's own portal.
What this is (and isn't)
- A framework-agnostic core client (
SuportaWidgetClient) — plain TypeScript, no framework dependency, works from Vue, React, or vanilla JS. - Vue 3 components built on top of it (
SuportaTicketForm,SuportaTicketList,SuportaTicketDetail) plus auseSuportaTicketscomposable. - Not currently available for Flutter/Dart apps (a different package ecosystem entirely —
food-la-route-appis out of scope for this npm package). - Not real-time — there's no automatic polling. Both
SuportaTicketListandSuportaTicketDetailfetch once on mount and expose a manual "Refresh" button; call the composable'srefresh()yourself if you want your own refresh trigger (e.g. on window focus). - No file attachments on widget-submitted tickets in this version (an unauthenticated upload endpoint is a real abuse vector — deferred).
Getting a token
There's no self-serve UI yet. An admin on the Suporta side runs, per tenant:
php artisan widget:create-installation {company_id} {default_project_id} "Sman Cars Production" --tenant=acme.suportahub.comThis prints a bearer token once — store it in your app's environment configuration (never hard-code it in source; see below).
Is this token a secret?
No — treat it like a Stripe publishable key or an Intercom/Crisp "app ID", not a secret API key. It ends up embedded in your frontend JavaScript, visible to anyone who opens dev tools. It is intentionally scoped narrowly (it can only create/read tickets for one company, via one designated project) and is rate-limited and revocable. Don't reuse it for anything beyond this widget.
Install
npm install @bitpeakdev/widget vue@^3.4The components' styles are shipped as a separate stylesheet — import it once, anywhere in your app's entry point:
import '@bitpeakdev/widget/style.css';Usage — Vue (e.g. smancars-admin, Vite + TypeScript)
<script setup lang="ts">
import { SuportaTicketForm, SuportaTicketList } from '@bitpeakdev/widget';
const config = {
baseUrl: import.meta.env.VITE_SUPORTA_WIDGET_BASE_URL,
token: import.meta.env.VITE_SUPORTA_WIDGET_TOKEN,
};
// Whatever identifies the current end-user in YOUR app — an email, an
// internal user id, etc. Suporta never verifies this, it's purely a
// scoping key so a user only ever sees their own tickets back.
const requesterRef = currentUser.email;
</script>
<template>
<SuportaTicketForm :config="config" :requester-ref="requesterRef" @created="onTicketCreated" />
<SuportaTicketList :config="config" :requester-ref="requesterRef" />
</template>.env:
VITE_SUPORTA_WIDGET_BASE_URL=https://smancars.suportahub.com
VITE_SUPORTA_WIDGET_TOKEN=<the token from widget:create-installation>Usage — Laravel Mix / plain JS (e.g. food-la-route-admin)
The package ships a CommonJS build too, so a webpack/Mix pipeline can require() it directly, or you can skip the Vue components and drive the framework-agnostic client yourself:
const { SuportaWidgetClient } = require('@bitpeakdev/widget');
const client = new SuportaWidgetClient({
baseUrl: process.env.MIX_SUPORTA_WIDGET_BASE_URL,
token: process.env.MIX_SUPORTA_WIDGET_TOKEN,
});
client.createTicket({ title: 'Payment failed', requesterRef: user.email })
.then((ticket) => console.log('Created', ticket.slug))
.catch((err) => console.error(err.code, err.message));Error handling
Every failure is a SuportaWidgetError with a stable .code you can branch on: NETWORK_ERROR, UNAUTHORIZED, VALIDATION_ERROR, RATE_LIMITED, NOT_FOUND, SERVER_ERROR, UNKNOWN_ERROR. Each has a sensible default .message; override presentation in your own UI as needed.
Logout / clearing data
Call clearCache() (returned by useSuportaTickets) when your own app's user logs out. This app never stores a Suporta session — it only clears the local ticket-list cache for that requester.
