/** * The client: fetch `/content` for first paint, then open the stream and feed * every event into the choreographer. * * The event dispatch below is the ONLY place in the SDK that knows event * names, and every name it knows comes from the generated contract. A server * that starts emitting something newer than this build is not an error — it is * an older client, which the protocol explicitly supports — so unknown events * are ignored rather than warned about. */ import { type StreamTarget } from "./protocol.js"; import { CopyChoreographer, type ChoreographerOptions, type CreativeState } from "./state.js"; /** * The image the server sends in `ContentSnapshot.content.image`. It is an * object, not a URL string: for an `` src read `.url`, and for a video * poster read `.heroFrame?.url`. */ export interface ContentImage { url?: string; alt?: string; heroFrame?: { url?: string; }; /** Opaque; shape owned by the server. */ sequence?: unknown; /** Opaque; shape owned by the server. */ focal?: unknown; } export interface ContentSnapshot { campaignId: string; variantId: string; content: { headline?: string; body?: string; cta?: string | { text?: string; }; /** * An object. Use `image.url` as an `` src, not `image` itself. * `null` when the variant has no image: the edge server sends * `"image": null`, and the app server leaves the key out. */ image?: ContentImage | null; experienceManifest?: unknown; }; theme?: { colors: Record; sources: Record; }; products?: unknown[]; meta?: Record; } export interface StreamOptions extends ChoreographerOptions { target: StreamTarget; signal?: AbortSignal; /** Swap the transport (SSR, tests, a customer's instrumented fetch). */ fetchImpl?: typeof fetch; /** Called on every state change. */ onState?: (state: CreativeState) => void; /** * Drive an existing choreographer instead of creating one. For a renderer * that started holding before the request could open (a stream waiting on * a shared variant): one choreographer, so one hold budget, spans the wait * and the stream. The choreographer options in these options are ignored * when this is set. */ choreographer?: CopyChoreographer; /** * Called when the server cannot speak the version this build requested. The * SDK has already kept its own first paint by the time this fires; the hook * exists so a consumer can log it once, not so it can retry. */ onProtocolUnsupported?: (info: { requested: number; supported: number[]; }) => void; } export interface StreamHandle { /** The live choreographer. Subscribe for updates. */ choreographer: CopyChoreographer; /** Resolves when the stream ends, however it ends. Never rejects. */ finished: Promise; /** Stop early. Idempotent. */ close: () => void; } /** * Fetch the first-paint content. * * Content-first, rewrite-once: this is what the SDK paints BEFORE any stream * exists, so there is never a skeleton on screen. If it fails, the consumer's * `fallback` prop is what stands in — which is why that prop is required * rather than optional. */ export declare function fetchContent(target: StreamTarget, options?: { signal?: AbortSignal; fetchImpl?: typeof fetch; }): Promise; /** * Open an island stream and choreograph it. * * Returns immediately with a handle; `finished` resolves with the terminal * state. It never rejects — a broken stream leaves whatever was painted on * screen and reports `phase: "failed"`, because throwing from inside a * customer's render tree is a worse outcome than a creative that stopped * adapting. */ export declare function openStream(options: StreamOptions): StreamHandle; //# sourceMappingURL=client.d.ts.map