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

signalk-plotterext-bus

v0.5.0

Published

Reference implementation of the Signal K plotter extension message bus: JSON-RPC 2.0 over postMessage with wildcard event subscriptions

Downloads

166

Readme

signalk-plotterext-bus

Reference implementation of the Signal K plotter extension bus — the message protocol between a chartplotter host application (e.g. Freeboard-SK) and extension iframes (panels, widgets, background runtimes) provided by Signal K server plugins via the plotterExtensions resource type.

The documented wire format below is the contract; this package is a convenience. Any conforming implementation interoperates.

Install

npm install signalk-plotterext-bus
  • Extensions import signalk-plotterext-bus/extension.
  • Hosts import signalk-plotterext-bus/host.

Wire Format

Every message is a JSON-RPC 2.0 object inside a routing envelope, sent with postMessage (window-to-iframe or MessageChannel):

{ "bus": "plotterExt/1", "msg": { "jsonrpc": "2.0", "...": "..." } }

The bus field identifies protocol and major version so frames can ignore unrelated postMessage traffic.

Calls

A call is a JSON-RPC request with a fresh per-call correlation id (never correlate by method name — concurrent calls to the same method must not collide):

{ "jsonrpc": "2.0", "id": "ab12-1", "method": "state.get", "params": { "keys": ["path"] } }

Exactly one response per request, result and error mutually exclusive:

{ "jsonrpc": "2.0", "id": "ab12-1", "result": { "values": { "path": "navigation.speedOverGround" } } }
{ "jsonrpc": "2.0", "id": "ab12-1", "error": { "code": -32602, "message": "…", "data": { "reason": "INVALID_PARAMS" } } }

Protocol errors use the JSON-RPC reserved codes (-32601 method not found, -32602 invalid params, -32603 internal). Host API errors use implementation-defined codes (this package defaults to -32000) and put a stable string identifier in error.data.reason. Callers apply timeouts and discard the pending-call entry when one fires.

Events

An event is a JSON-RPC notification (no id); its method is a hierarchical dot-separated event name:

{ "jsonrpc": "2.0", "method": "sk.navigation.speedOverGround", "params": { "path": "navigation.speedOverGround", "value": 3.6 } }

postMessage is point-to-point, so hosts only forward events a context has subscribed to via events.subscribe / events.unsubscribe. Subscription patterns use eventemitter2-style wildcards: * matches exactly one segment, ** matches zero or more segments (map.*, sk.navigation.**).

Connection establishment

  1. The extension sends the notification bus.ready (repeating every ~250 ms until answered, in case the host attaches late).
  2. The host replies with the notification bus.handshake:
{
  "jsonrpc": "2.0",
  "method": "bus.handshake",
  "params": {
    "host": "freeboard-sk",
    "hostVersion": "2.14.0",
    "apiVersion": "1",
    "capabilities": ["widgets", "panels.iframe", "signalk.stream"],
    "context": { "kind": "widget", "id": "gauge", "instanceId": "…", "targetInstance": null }
  }
}

Built-in methods

Implemented by HostConnection automatically:

| Method | Params | Result | | --- | --- | --- | | events.subscribe | { patterns: string[] } | { subscriptionId } | | events.unsubscribe | { subscriptionId } | {} |

Host API methods (state.*, signalk.*, map.*, …) are supplied by the embedding host application; see the plotter extension specification for the vocabulary.

Usage — extension side

import { connectExtension } from 'signalk-plotterext-bus/extension'

const client = await connectExtension()
console.log(client.context)           // { kind: 'widget', id: 'gauge', instanceId: '…' }

// Per-instance configuration
const { path } = await client.state.get(['path'])

// Live Signal K data, relayed by the host
const stop = await client.signalk.subscribe([path], (ev) => {
  render(ev.value)
})

// React to configuration changes made by the config panel
await client.subscribe(['state.changed'], async () => {
  const values = await client.state.get()
  reconfigure(values)
})

Usage — host side

import { HostConnection, windowPort } from 'signalk-plotterext-bus/host'

const conn = new HostConnection({
  port: windowPort(iframe.contentWindow),
  hostInfo: {
    host: 'my-plotter',
    hostVersion: '1.0.0',
    apiVersion: '1',
    capabilities: ['widgets', 'panels.iframe', 'signalk.stream']
  },
  context: { kind: 'widget', id: 'gauge', instanceId, targetInstance: null },
  methods: {
    'state.get': async ({ keys }) => ({ values: await loadState(instanceId, keys) }),
    'state.set': async ({ values }) => { await saveState(instanceId, values) },
    'signalk.subscribe': ({ paths }) => startRelay(conn, paths),
    'signalk.unsubscribe': ({ subscriptionId }) => stopRelay(subscriptionId)
  },
  onSubscriptionsChanged: (patterns) => updateUpstream(patterns)
})

// Later, from the host's data stream:
conn.publish('sk.navigation.speedOverGround', { path, value, timestamp })

Throw RpcError from method handlers to return structured errors:

import { RpcError, RPC_ERRORS } from 'signalk-plotterext-bus/host'
throw new RpcError('unknown path', { code: RPC_ERRORS.INVALID_PARAMS, reason: 'UNKNOWN_PATH' })

Conformance testing

The test suite drives a real HostConnection against a real connectExtension() over a MessageChannel pair with no DOM. A host implementing its own endpoint can reuse the same harness shape to verify conformance.

npm test

License

MIT