npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

katie-publisher-sdk-js

v0.2.0

Published

JavaScript SDK for publishing messages to Katie channels

Downloads

132

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-js

Requires 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/json

Request 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-key

Response 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}
  ]
}