import type { Context } from "@wrnexus/core"; import { exportSubjectContext, importSubjectContext, type SubjectContext } from "@wrnexus/rpc"; import type { PubSub } from "./index.ts"; const PUBSUB_AUDIENCE = "wrnexus-pubsub"; interface SubjectEnvelope { payload: T; identity?: string; } export interface SubjectPubSub { publish(ctx: Context, topic: string, message: T): Promise; subscribe( pattern: string, handler: (message: T, topic: string, subject?: SubjectContext) => void | Promise, ): () => void; } /** * Authenticated pub/sub envelope. The token uses a fixed, purpose-specific * audience; subscribers verify it before exposing the message to a handler. */ export function subjectPubSub(bus: PubSub): SubjectPubSub { return { async publish(ctx, topic, message) { const identity = await exportSubjectContext(ctx, PUBSUB_AUDIENCE); await bus.publish>(topic, { payload: message, ...(identity ? { identity } : {}), }); }, subscribe(pattern, handler) { return bus.subscribe>(pattern, async (envelope, topic) => { if (!envelope || typeof envelope !== "object" || !("payload" in envelope)) return; let subject: SubjectContext | undefined; if (envelope.identity !== undefined) { if (typeof envelope.identity !== "string") return; try { subject = await importSubjectContext(envelope.identity, PUBSUB_AUDIENCE); } catch { return; // Never downgrade a malformed claimed identity to anonymous. } } await handler(envelope.payload as never, topic, subject); }); }, }; }