Files
skills/docs/networking/network/websocket-gateway/src/gateway/presence-webhook.md
2026-05-29 08:20:56 +01:00

2.5 KiB

deliverPresenceWebhook

Purpose

Best-effort, signed delivery of a single presence event to a configured webhook receiver. The gateway calls this function on every presence transition (join / leave / update) when a presenceWebhook is configured on the daemon. Retry, exponential backoff, and circuit-breaking are owned by @suaveplan/webhook-client.deliver, which internally threads @suaveplan/retry — the gateway never has to reinvent that policy.

Features

  • Per-event opt-in filter: config.events constrains which kinds fan out. Default (undefined) fans out every kind.
  • HMAC-SHA-256 signed payloads when config.secret is set, matching the proposal's "signed delivery payload" requirement.
  • Errors are swallowed and routed to an optional onError(err) hook so presence — which is inherently lossy — never crashes the daemon.
  • Deterministic delivery id: presence-<clientId>-<at> makes the receiver's idempotency story easy.

Usage: Basic Example

import { deliverPresenceWebhook } from "@suaveplan/websocket-gateway";

await deliverPresenceWebhook(
    { url: "https://example.com/webhooks/presence", secret: "shared-secret" },
    { kind: "presence:join", clientId: "alice", roomId: "ops", status: "online", at: Date.now() }
);

Usage: Advanced Example

import { deliverPresenceWebhook } from "@suaveplan/websocket-gateway";
import { logger } from "@suaveplan/logger";

await deliverPresenceWebhook(
    {
        url: "https://hooks.example.com/presence",
        secret: process.env.PRESENCE_HMAC,
        events: ["presence:join", "presence:leave"], // skip 'update' chatter
    },
    {
        kind: "presence:update",
        clientId: "alice",
        roomId: undefined,
        status: "away",
        at: Date.now(),
    },
    (err) => logger.warn("presence webhook delivery failed", { err })
);

API Reference

  • deliverPresenceWebhook(config, event, onError?): Promise<void>
  • PresenceWebhookEvent — { kind, clientId, roomId, status, at } value object.

Implementation Notes

The function never throws — webhook-client.deliver already classifies retryable vs terminal status codes and consumes the retry budget internally. Surfacing failures upstream would force the gateway to invent a recovery policy, but presence is best-effort by design (receivers reconcile via the next heartbeat / connection event). Delivery is signed with the same algorithm webhook-client defaults to (sha256); future stronger algorithms (e.g. ed25519) become a config.algorithm switch the moment webhook-client exposes one.