katie-publisher-sdk-js
v0.2.0
Published
JavaScript SDK for publishing messages to Katie channels
Downloads
132
Maintainers
Readme
katie-publisher-sdk-js
JavaScript SDK for publishing voice messages to Katie channels. Text messages are sent to the Katie API, converted to speech, and delivered to subscribed devices in real-time.
Installation
npm install katie-publisher-sdk-jsRequires Node.js >= 18 (uses native fetch).
Quick Start
import { MessagingClient } from 'katie-publisher-sdk-js';
const client = new MessagingClient({
baseUrl: 'https://katiespeaker.com',
channelApiKey: 'your-channel-api-key',
});
// Publish a message (converted to speech and sent to subscribers)
await client.publish('Hello, World!');
// Broadcast to ALL subscribers (bypasses filters)
await client.broadcast('Emergency announcement');SDK Reference
new MessagingClient({ baseUrl, channelApiKey, timeout? })
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| baseUrl | string | Yes | — | Base URL of the Katie API (e.g., "https://katiespeaker.com") |
| channelApiKey | string | Yes | — | API key for your channel |
| timeout | number | No | 10000 | Request timeout in milliseconds |
client.publish(message, options?)
Send a message to the channel. Subscribers can filter messages based on the meta object.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| message | string | Yes | — | Message content (used for display) |
| options.ttlSeconds | number | No | undefined | Time-to-live in seconds; message expires if not processed in time |
| options.meta | object | No | undefined | Metadata object; subscribers can filter based on these values |
| options.messageTts | string | No | undefined | TTS-optimized text used for speech synthesis instead of message |
Returns: Promise<{ messageId: string, channel: string }> with messageId (unique identifier) and channel (channel ID).
Throws: MessagingPublishError on failure.
client.broadcast(message, options?)
Broadcast a message to all subscribers, bypassing their filter settings. Automatically sets meta.broadcast = true (merged with any meta you provide).
Parameters, return value, and exceptions are the same as publish().
client.getSubscriberFilters()
Fetch aggregated subscription filters for this channel. Returns the union of filter rules across all subscribers without exposing individual subscriber details. The result is cached internally for use by shouldPublish().
Returns: Promise<object> with:
| Field | Type | Description |
|-------|------|-------------|
| channelId | number | Numeric channel ID |
| channelName | string | Channel name |
| subscriberCount | number | Total number of subscriptions |
| hasUnfilteredSubscribers | boolean | true if any subscription has no filter (always receives) |
| filters | Array<{field, op, value}> | Deduplicated filter rules across all subscribers |
Throws: MessagingPublishError on failure.
client.refreshFilters()
Re-fetch subscriber filters from the API and update the internal cache. Equivalent to getSubscriberFilters().
client.shouldPublish(meta?)
Check locally whether any subscriber would receive a message with the given meta payload. Uses the cached result from getSubscriberFilters() (auto-fetches on first call).
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| meta | object | No | undefined | The metadata you intend to publish with |
Returns: Promise<boolean> — true if at least one subscriber would receive the message, false otherwise.
Note: This is a conservative (optimistic) check. It may return true when the server would reject (because per-subscriber filter grouping is not exposed), but it will never return false when a subscriber would have received. This means you won't accidentally skip messages that should be delivered.
Throws: MessagingPublishError if the initial filter fetch fails.
MessagingPublishError
Thrown when a publish or broadcast request fails.
| Attribute | Type | Description |
|-----------|------|-------------|
| statusCode | number or null | HTTP status code (if available) |
| response | object or null | Parsed error response body (if available) |
Usage Examples
Basic publish
await client.publish('The weekly report is ready.');Publish with metadata (subscriber filtering)
await client.publish('AAPL is up 3% today', {
meta: { symbol: 'AAPL', category: 'stocks' },
});Subscribers who filter on symbol=AAPL will receive this message; others won't.
Broadcast (critical announcements)
await client.broadcast('Emergency: Building evacuation required');All subscribers receive the message regardless of their filter settings.
TTS-optimized text
When the display text differs from how it should be spoken:
await client.publish('AAPL: $150.25 (+2.5%)', {
messageTts: 'Apple stock is at 150 dollars and 25 cents, up 2.5 percent',
});TTL (message expiry)
await client.publish('The time is 3:30 PM', {
ttlSeconds: 60,
});The message expires after 60 seconds if not processed.
Smart publishing (skip when no subscribers match)
// Fetch filters once at startup
await client.getSubscriberFilters();
// Before each publish, check locally if anyone would receive it
const meta = { symbol: 'AAPL', category: 'stocks' };
if (await client.shouldPublish(meta)) {
await client.publish('AAPL is up 3%', { meta });
} else {
console.log('No matching subscribers, skipping');
}Inspect subscriber filters
const info = await client.getSubscriberFilters();
console.log(`Subscribers: ${info.subscriberCount}`);
console.log(`Unfiltered: ${info.hasUnfilteredSubscribers}`);
for (const f of info.filters) {
console.log(` ${f.field} ${f.op} ${f.value}`);
}Periodic filter refresh (long-running publishers)
await client.getSubscriberFilters(); // initial fetch
setInterval(() => client.refreshFilters(), 5 * 60 * 1000); // every 5 min
async function tick() {
const meta = getCurrentMeta();
if (await client.shouldPublish(meta)) {
await client.publish(buildMessage(), { meta });
}
}Error handling
import { MessagingClient, MessagingPublishError } from 'katie-publisher-sdk-js';
const client = new MessagingClient({
baseUrl: 'https://katiespeaker.com',
channelApiKey: 'your-channel-api-key',
});
try {
await client.publish('Hello!');
} catch (e) {
if (e instanceof MessagingPublishError) {
console.error(`Publish failed: ${e.message}`);
if (e.statusCode) {
console.error(`HTTP status: ${e.statusCode}`);
}
if (e.response) {
console.error(`Error detail: ${JSON.stringify(e.response)}`);
}
}
}CommonJS usage
const { MessagingClient } = require('katie-publisher-sdk-js');API Endpoints
The SDK wraps the following endpoints. Authentication is sent via the
Authorization: Bearer <channel_apikey> header on every request.
POST /v1/messaging/publish
Publish a message for TTS conversion and delivery.
Request headers:
Authorization: Bearer your-channel-api-key
Content-Type: application/jsonRequest body:
{
"message": "Your message here",
"message_tts": "TTS-optimized text",
"ttl_seconds": 60,
"meta": {
"key": "value",
"broadcast": true
}
}Only message is required. All other fields are optional.
Response body:
{
"message_id": "unique-message-id",
"channel": "channel-id"
}GET /v1/messaging/subscriber-filters
Fetch aggregated subscription filters for the channel.
Request headers:
Authorization: Bearer your-channel-api-keyResponse body:
{
"channel_id": 42,
"channel_name": "Stock Alerts",
"subscriber_count": 5,
"has_unfiltered_subscribers": false,
"filters": [
{"field": "symbol", "op": "==", "value": "AAPL"},
{"field": "delivery_hour", "op": ">=", "value": 9}
]
}