import WebSocket from 'ws'; import type { Delta } from '@signalk/server-api'; /** * Subset of the Signal K app surface this forwarder needs. We pin to the * minimum so the unit tests can pass a stub without dragging in the full * server-api types. */ export interface DeltaForwarderApp { handleMessage(id: string, msg: Partial): void; debug?(msg: string): void; } export interface DeltaForwarderOptions { /** * Plugin id used when calling `app.handleMessage`. Signal K stamps * the republished delta's `$source` from this; passing the same id * the plugin registers with keeps all forwarded data attributed to * one provider in the SK admin UI. */ pluginId: string; /** ws:// URL of mayara-server's `/signalk/v1/stream` endpoint. */ url: string; /** * Subscriptions sent to mayara on connect. Defaults to * `[{ path: 'notifications.*', policy: 'instant' }]`. Pass a wider set to * also relay radar state, e.g. add `{ path: 'radars.*', policy: 'instant' }`. */ subscriptions?: Array<{ path: string; policy: string; }>; /** * Path prefixes whose value entries are republished upstream. A delta value * survives if its `path` starts with any prefix. Defaults to * `['notifications.']`. Add `'radars.'` to bridge radar control/target state * onto the host Signal K server's own `/signalk/v1/stream`. */ pathPrefixes?: string[]; /** Optional logger; defaults to a no-op. */ debug?: (msg: string) => void; reconnectInterval?: number; /** * Constructor override used by tests; in production this is just the * `ws` package's `WebSocket` class. Typed minimally to avoid pulling * the full ws.d.ts surface into the public API. */ webSocketFactory?: (url: string) => WebSocketLike; } /** * Bridges deltas from mayara-server's Signal K v1 stream into the host * Signal K server via `app.handleMessage`, so mayara's data appears on the * host's own `/signalk/v1/stream`. Which paths are relayed is configurable * (`pathPrefixes` / `subscriptions`); by default only `notifications.*`. * * Two use cases: * - `notifications.*` (default): guard-zone alarms etc., so they reach the SK * admin notifications panel, the chart plotter, and other SK consumers. * - `radars.*` (opt-in): radar control/target state modelled as * `radars.{id}.controls.*` — mayara publishes these on its own stream; * relaying them surfaces live radar state on the host stream, the control * half of the Radar API's `streamUrl` (the PUT half is registerPutHandler). * * On connect we send the configured subscriptions so mayara filters * appropriately. Each incoming delta is forwarded as-is — mayara has already * shaped it to the SK spec — and the SK server stamps `$source` from * `pluginId` and `context` = self on republish. */ export declare class DeltaForwarder { private readonly pluginId; private readonly url; private readonly subscriptions; private readonly pathPrefixes; private readonly debug; private readonly reconnectMs; private readonly webSocketFactory; private ws; private reconnectTimer; private closed; private connected; private readonly app; constructor(app: DeltaForwarderApp, options: DeltaForwarderOptions); start(): void; private connect; /** * Parse one inbound text frame and forward every subscribed-path * value entry to the host SK server. Non-text frames, non-JSON * payloads, deltas with nothing at a subscribed path, and the upstream * "hello" handshake are all silently dropped. * * Exposed `protected` so the tests can inject frames without going * through the real WebSocket. */ protected handleMessage(data: WebSocket.RawData): void; /** * Returns a copy of `parsed` containing only the value entries whose `path` * matches one of the configured prefixes. Returns null if `parsed` isn't a * Signal K delta, has no `updates`, or carries no matching paths. */ private extractDelta; private scheduleReconnect; isConnected(): boolean; stop(): void; } /** * Minimum WebSocket surface this module touches. Lets tests inject a * stub without importing the full `ws` type tree. */ export interface WebSocketLike { on(event: 'open', listener: () => void): void; on(event: 'message', listener: (data: WebSocket.RawData) => void): void; on(event: 'error', listener: (err: Error) => void): void; on(event: 'close', listener: (code: number) => void): void; send(data: string): void; close(): void; } //# sourceMappingURL=delta-forwarder.d.ts.map