@influxdata/notification-hub-client
v1.1.0
Published
Subscriber client for the InfluxData Notification Hub.
Keywords
Readme
@influxdata/notification-hub-client
Subscriber client for the InfluxData Notification Hub. Zero runtime dependencies; ships as ESM, CommonJS, and a CDN-friendly UMD bundle.
Full design rationale in docs/client-library.md.
Install
npm install @influxdata/notification-hub-clientReference UX standard
For a complete drawer + banner + blocking-modal UX with persistence, see the Subscriber UX Standard (also embedded in the admin UI under Help → Subscriber integration → Subscriber UX Standard). The data and state-management layer ships in this library — NotificationManager, LocalOnlyStorage, UserBoundStorage. UI rendering lives in your app. A runnable end-to-end example is at examples/standard.html.
Quick start
import { NotificationClient } from '@influxdata/notification-hub-client';
const client = new NotificationClient({
hub: 'https://notifications.influxdata.com',
client: 'my-product',
version: '1.0.0',
topics: [
'https://influxdata.com/topics/product/influxdb-v3',
],
});
client.addEventListener('notification', (e) => render(e.detail.post));
client.addEventListener('update', (e) => replace(e.detail.post));
client.addEventListener('retraction', (e) => remove(e.detail.postId));
await client.start();With the full UX standard:
import {
NotificationClient,
NotificationManager,
LocalOnlyStorage,
} from '@influxdata/notification-hub-client';
const client = new NotificationClient({
hub: 'https://notifications.influxdata.com',
client: 'my-product',
topics: ['https://influxdata.com/topics/product/influxdb-v3'],
autoRecordImpressions: false, // manager records on render, not on receipt
});
let manager;
const storage = new LocalOnlyStorage({
client: 'my-product',
onReconciled: () => manager?.notifyExternalChange(),
});
manager = new NotificationManager({ client, storage });
manager.addEventListener('change', updateUI);
await manager.start();
await client.start();
function updateUI() {
setCounter(manager.getUnreadCount());
setDrawer(manager.getDrawerItems());
setBanners(manager.getBannerQueue(3));
setBlocking(manager.getBlockingQueue()[0] ?? null);
}A runnable minimal integration lives at examples/vanilla.html.
Subscribing to every topic
Most subscribers should pin the specific product topics they represent — that way a new topic added to the hub doesn't surprise the UI. A small number of subscribers (the docs site, internal operator dashboards) genuinely want everything; for them, fetch the canonical product taxonomy at startup:
const taxonomy = await fetch(`${HUB}/api/topics`).then((r) => r.json());
// taxonomy.product is string[] — every product topic URI the hub knows.
const client = new NotificationClient({
hub: HUB,
client: 'docs-site',
version: '1.0.0',
topics: taxonomy.product,
});Do not pass '*' or a URI template as a shortcut. The Mercure SSE side
accepts wildcards, but the catch-up endpoint validates against the closed
topic enumeration and silently drops anything not on it — you'd get live
events but an empty catch-up payload, which is almost never the intent.
Script tag (no bundler)
<script src="https://cdn.jsdelivr.net/npm/@influxdata/notification-hub-client@1/dist/index.min.js"></script>
<script>
const client = new InfluxNotifications.NotificationClient({ /* ...same options... */ });
client.addEventListener('notification', (e) => render(e.detail.post));
client.start();
</script>Events
| Event | e.detail | Fires when |
|---|---|---|
| notification | { post } | A new post arrives (catch-up or live) |
| update | { post } | A published post was edited and pushed |
| retraction | { postId } | A post was unpublished |
| expired | { postId } | Sweep tripped on a rendered post past expiresAt |
| connect | {} | SSE opened |
| disconnect | { reason } | SSE closed (browser auto-reconnects) |
| error | { error, phase } | phase is token / catchup / sse / analytics |
Posts are deduplicated by id across the catch-up + live boundary — host
apps never receive the same notification twice.
Development
cd clients/js
npm install
npm test # vitest + happy-dom
npm run build # tsup → dist/{index.js,index.cjs,index.min.js,index.d.ts}Target bundle size: ≤ 8 KB gzipped for the minified UMD build.
License
MIT
