import type { UiComponent } from '@/dynamic-ui'; import type { TorukArtifact, TorukArtifactDownload } from '@/artifacts/artifacts.types'; /** * What the host grants a block that references a persisted artifact. * * Supplied only when the widget actually has a server session to scope the * request through — which is the whole authorization story on the external * plane, so its absence is not a degraded mode to work around but the honest * statement that there is nothing to fetch against. A renderer treats it the * way it treats a missing `onRespond`: render what it was given, ask for * nothing. * * Deliberately narrow. A block gets "load this id" and "download this id" and * no client handle, so a renderer cannot reach a different session's artifacts * or a different API — the session is bound by the host, not chosen here. */ export type DuiArtifactAccess = { load: (artifactId: string) => Promise<{ ok: true; data: TorukArtifact; } | { ok: false; message: string; }>; /** Fetches the bytes and hands them to the browser as a file save. */ save: (artifactId: string) => Promise<{ ok: true; data: TorukArtifactDownload; } | { ok: false; message: string; }>; bytes?: (artifactId: string) => Promise<{ ok: true; data: TorukArtifactDownload; } | { ok: false; message: string; }>; }; /** * What a Dynamic UI renderer receives. * * `props` is model-authored data that has already been through the contract's normalizer, so a * renderer can trust field *types* — but never that an optional field is present. * * `onRespond` is supplied only for interactive blocks and only while the widget can actually * accept a follow-up turn. A renderer treats its absence as "display only", which is what makes * a replayed history message inert without any extra flag. * * `artifacts` follows the same rule for the one block that references server-held content. */ export type DuiBlockProps = { props: Record; onRespond?: (text: string) => void; artifacts?: DuiArtifactAccess; }; export type DuiRenderer = (props: DuiBlockProps) => unknown; export type { UiComponent };