/** * Outpost on-box realtime publisher — mission-control US-009. * * The box already holds a Cognito session (seeded from the caller's refresh * token in user-data, kept fresh by the box's auth timers — see provision.ts). * This module turns that session into a `PublishPort` for the session-heartbeat * emitter using the EXACT on-box credential pattern the rest of the realtime * fabric uses (docs/realtime-fabric.md): * * 1. POST {HQAPI}/v1/realtime/credentials with the box's Cognito JWT. * The Lambda resolves the caller's `personUid` from the verified JWT * (never request input) and vends short-lived STS creds whose session * policy scopes `iot:Connect/Publish/...` to `hq/{personUid}/*` only. * 2. SigV4-sign an IoT Data-plane publish with those creds to * `hq/{personUid}/sessions`. * * No new auth surface, no embedded long-lived key, no per-device cert — the * per-identity STS session policy is the isolation boundary (US-010). * * The HTTP fetch + IoT client are injected so this is unit-testable without a * live endpoint; `defaultRealtimeCredentialsFetcher` and the IoT publish are * the production wiring. */ import { IoTDataPlaneClient } from "@aws-sdk/client-iot-data-plane"; import type { PublishPort } from "./session-heartbeat.js"; import { sessionsTopicForPerson } from "./session-heartbeat.js"; /** Shape returned by `POST /v1/realtime/credentials` (mirrors the handler). */ export interface RealtimeCredentialsResponse { credentials: { accessKeyId: string; secretAccessKey: string; sessionToken: string; expiration: string; }; iotEndpoint: string; region: string; /** The caller's own topic — `hq/{personUid}/...`. */ topic: string; expiresAt: string; } /** Fetches scoped realtime credentials for the box. Injected for tests. */ export type RealtimeCredentialsFetcher = () => Promise; /** Ceiling on a single credentials request. */ export declare const DEFAULT_CREDENTIALS_TIMEOUT_MS = 10000; /** * Build the production credentials fetcher. Reads the box's current Cognito * id/access token via the injected `getJwt` and POSTs it to the * realtime-credentials endpoint. */ export declare function defaultRealtimeCredentialsFetcher(opts: { apiBaseUrl: string; getJwt: () => Promise; fetchImpl?: typeof fetch; /** Bound the request. Defaults to {@link DEFAULT_CREDENTIALS_TIMEOUT_MS}. */ timeoutMs?: number; }): RealtimeCredentialsFetcher; /** * Create a `PublishPort` that vends scoped creds (refreshing before expiry) and * publishes the compact payload to the box's own sessions topic over MQTT/IoT. * * @param fetchCredentials vends per-identity-scoped STS creds + IoT endpoint * @param makeClient builds an IoT client from creds (injected for tests) * @param now clock injection */ export declare function createIotPublishPort(opts: { fetchCredentials: RealtimeCredentialsFetcher; makeClient?: (args: { endpoint: string; region: string; credentials: RealtimeCredentialsResponse["credentials"]; }) => IoTDataPlaneClient; now?: () => Date; }): PublishPort; /** Re-export for the runner so it imports one module. */ export { sessionsTopicForPerson }; //# sourceMappingURL=session-heartbeat-publisher.d.ts.map