import type { AgentEvent, Message, MessageV2 } from "@skaile/workspaces/types"; export type { Message }; /** * Metadata associated with a subscriber for recipients filtering. * * @docLink packages/session/api-reference#interfaces */ export type SubscriberInfo = { userId?: string; roles?: string[]; }; /** * Persistent message storage — append-only log with seq-based pagination. * * Generic over `TMessage` so platforms with typed `MessageMeta` extensions * can use a typed `MessageV2` consistently across their * `append`/`getMessages` surface. Defaults to the concrete {@link Message} * shape (`MessageV2<{}>` plus v1 back-compat fields). * * Each session has exactly one store. Implementations range from JSONL files * (forge apps) to Prisma-backed PostgreSQL (platform) and in-memory arrays * (tests). The store is never queried for transient messages — those are * forwarded and broadcast but never appended. * * @example * ```ts * const store: MessageStore = new PrismaMessageStore(prisma) * await store.append(message) * const history = await store.getMessages(sessionId, { limit: 50 }) * ``` * * @docLink packages/session/api-reference#interfaces */ export interface MessageStore = Message> { /** Persist a message to the session's append-only log. */ append(message: TMessage): Promise; /** * Retrieve messages for a session, ordered by seq ascending. * * @param sessionId - The session to query. * @param opts - Optional pagination parameters. * @param opts.before - Return messages with seq < before (for backward pagination). * @param opts.limit - Maximum number of messages to return. */ getMessages(sessionId: string, opts?: { before?: number; limit?: number; }): Promise; /** * Return the highest seq number for a session, or 0 if no messages exist. * * Used by `SessionDispatcher.init()` to restore the monotonic counter * after a reconnect without re-reading the full message history. * * @param sessionId - The session to query. */ getLatestSeq(sessionId: string): Promise; /** * Retrieve messages for restore: returns the last snapshot (if any) plus * all messages after it. Falls back to getMessages() if no snapshot exists. */ getMessagesFromSnapshot?(sessionId: string): Promise; } /** * Pushes real-time events to connected frontend subscribers. * * One subscriber ID per active WebSocket or SSE connection. Implementations * include `EventEmitterSubscriberTransport` (platform, backed by Node.js * EventEmitter + tRPC SSE iterator) and in-process callbacks (forge/tests). * * @example * ```ts * const transport: SubscriberTransport = new EventEmitterSubscriberTransport() * transport.send('conn-abc', event) // push to one subscriber * transport.remove('conn-abc') // clean up on disconnect * ``` * * @docLink packages/session/api-reference#interfaces */ export interface SubscriberTransport { /** * Send an event to a specific subscriber. * * **Visibility-filtering contract (since @skaile/workspaces/types 3.2):** * implementations handling sessions where `UserMessageEvent` carries * `visibilityMode !== "Public"` MUST gate delivery on the subscriber's * identity (`SubscriberInfo.userId` and/or `roles`) against the * event's `privateRecipientIds`. A naive forwarder that delivers * every event to every subscriber will broadcast Private messages to * non-recipients. The reference platform implementation gates this * in its tRPC SSE iterator before yielding each event upstream. * Non-platform consumers (e.g. forge apps) that don't run multi-user * sessions can ignore this clause — they will only ever see * `visibilityMode: "Public"` (or undefined) on the wire. * * @param subscriberId - Opaque identifier assigned at subscribe time. * @param event - The agent event to deliver. */ send(subscriberId: string, event: AgentEvent): void; /** * Remove a subscriber and release any associated resources. * * Safe to call multiple times for the same ID. * * @param subscriberId - The subscriber to remove. */ remove(subscriberId: string): void; } //# sourceMappingURL=types.d.ts.map