/** * Types for the deployment-scoped (external) artifact plane. * * Mirrors TORUK Core's wire contract, verified against * TORUK-CORE/packages/server/src/deployments/runtime/artifacts/ * external-artifact.mapper.ts. * * Core is the source of truth for every artifact fact — nothing here is ever * synthesized locally, and there is no placeholder shape for "an artifact we * expect to exist". An artifact the SDK has not fetched is simply not loaded. * * The plane distinction matters and is not cosmetic. Core has a second, * INTERNAL artifact API at `/api/v1/artifacts` that is owner-scoped, requires a * JWT and an organization permission, and returns tenant internals (`ownerId`, * `organizationId`, a permissions block). The SDK never calls it, and the types * below deliberately have no field that would come from it. */ import type { TorukPagination } from '../sessions/sessions.types'; /** * Artifact kind as Core reports it — its `ArtifactType` enum. * * Widened to `string` so a type Core adds later still parses rather than * failing, the same way `TorukSessionStatus` is widened. */ export type TorukArtifactType = 'markdown' | 'code' | 'html' | 'interactive' | 'svg' | 'mermaid' | 'chart' | 'table' | 'pdf' | 'docx' | 'xlsx' | 'pptx' | 'image' | 'python_code' | 'python_result' | string; /** * One artifact generated in the calling visitor's conversation. * * Note what is absent: no `ownerId`, no `organizationId`, no `deploymentId`, * no permissions block, and no `downloadUrl`. Core's external mapper publishes * none of them, and the SDK composes the download path itself from the * deployment and session it already holds. */ export type TorukArtifact = { id: string; type: TorukArtifactType; title: string | null; /** * Inline payload for text-based types (markdown, code, mermaid, an HTML * preview). `null` for binary types, whose bytes come from `download()`. */ content: string | null; mimeType: string | null; version: number; /** Whether bytes can be fetched for this artifact. Core reports true for all of them. */ downloadable: boolean; /** The conversation key it was generated in. */ sessionId: string | null; /** The assistant turn it belongs to — how the widget attaches it to a message. */ messageId: string | null; /** ISO-8601 timestamps as serialized by Core. */ createdAt: string; updatedAt: string; }; export type TorukArtifactList = { items: TorukArtifact[]; pagination: TorukPagination; }; /** * Options every artifact method accepts. * * `sessionId` is required on all of them, and that is the security model rather * than an ergonomic choice: an external artifact is owned by nobody, so the * conversation the caller already owns is the only thing that can vouch for * them. Core's routes are nested under the session for the same reason, and * there is deliberately no way to address an artifact by id alone. */ export type ArtifactRequestOptions = { /** * Overrides the client-level `deploymentId`. One of the two must be set or * the SDK throws a configuration error before any request is made. */ deploymentId?: string; signal?: AbortSignal; headers?: Record; }; export type ListArtifactsInput = ArtifactRequestOptions & { /** The session UUID, as returned by `sessions.create()` / `sessions.list()`. */ sessionId: string; /** 1-based. Core defaults to 1. */ page?: number; /** Core defaults to 20, max 100. */ limit?: number; /** Narrow to one artifact kind. Omit for all of them. */ type?: TorukArtifactType; }; export type GetArtifactInput = ArtifactRequestOptions & { sessionId: string; artifactId: string; }; export type DownloadArtifactInput = ArtifactRequestOptions & { sessionId: string; artifactId: string; }; /** * A downloaded artifact's bytes, plus the filename Core derived from its title. * * A `Blob` rather than a URL: the bytes come back over the same authenticated * transport as everything else, and handing out an object URL would invite the * caller to treat it as a durable link when it is not. */ export type TorukArtifactDownload = { blob: Blob; fileName: string; mimeType: string; };