MapPackage Realtime Watch

watchMapPackage can follow hosted MapPackage changes over a realtime channel when one is configured by the caller or advertised by the package. The polling watcher remains the fallback path and is still used when no realtime channel is available.

Client Usage

import { watchMapPackage } from "@honua/sdk-js/runtime";

const watcher = watchMapPackage("map_123", {
  client,
  runtime,
  realtime: {
    url: "/api/v1/map-packages/map_123/watch",
    withCredentials: true,
    staleAfterMs: 90_000,
  },
  onEvent(event) {
    if (event.type === "fallback") console.warn(event.reason);
    if (event.type === "reload-required") console.info(event.reason);
  },
});

watcher.dispose();

When realtime is omitted, watchMapPackage looks for an advertised channel on the current or fetched package:

{
  "realtime": {
    "mapPackageWatch": {
      "channel": "honua.map-package.watch.v1",
      "transport": "sse",
      "href": "/api/v1/map-packages/map_123/watch",
      "withCredentials": true,
      "staleAfterMs": 90000,
      "fallback": "polling"
    }
  }
}

The SDK currently ships an SSE adapter and accepts custom transports through realtime.transport. Unsupported advertised transports fall back to polling.

Message Contract

All messages are JSON objects on channel honua.map-package.watch.v1. A server may send the object directly or wrap it as { "event": { ... } }.

Common fields:

interface MapPackageRealtimeMessageBase {
  type: string;
  channel?: "honua.map-package.watch.v1";
  packageId?: string;
  eventId?: string;
  sequence?: number;
  fingerprint?: string;
  updatedAt?: string;
  validator?: { etag?: string; lastModified?: string };
}

Supported message types:

Patch payloads are intentionally distinguishable, but the runtime does not yet apply server patches directly. A patch-only update triggers a refetch through the polling fetch path so existing validation, cache, and diff behavior stays consistent.

Lifecycle And Fallback

watchMapPackage emits typed watch events:

Realtime reconnect defaults to 3 attempts with exponential backoff from 1s to 30s. Configure it with realtime.reconnect, set it to false to skip reconnect and fall back immediately, or use maxAttempts: Infinity to keep retrying.

Duplicate application is avoided with three guards:

dispose() aborts active fetches, aborts the realtime subscription signal, closes the transport handle, clears reconnect/stale/debounce timers, and emits disposed.

Auth

Polling fetches use HonuaClient.pipelineFetch, so they inherit client auth, headers, retries, timeout, and interceptors.

SSE in browsers cannot send arbitrary headers. For the built-in SSE adapter:

When realtime auth fails, servers should send an error message with terminal: true and a stable code; the SDK emits error, then fallback.