import type { FileComponentsResponse, FileMetaResponse, FileNodesResponse, FilePagesResponse, VariablesResponse } from "./figma-api.js"; export type FetchLike = (input: string, init?: { headers?: Record; }) => Promise; export interface FigmaRestClientOptions { /** Personal access token (sent as `X-Figma-Token`). */ token?: string; /** OAuth bearer token (sent as `Authorization: Bearer`). Takes precedence. */ oauthToken?: string; /** Override the API base (tests). Defaults to the public API. */ baseUrl?: string; /** Injectable fetch. Defaults to `globalThis.fetch`. */ fetch?: FetchLike; /** * Attempts per request before a retryable failure is raised. 1 disables * retrying. Defaults to {@link DEFAULT_ATTEMPTS}. */ attempts?: number; /** Injectable delay (tests). Defaults to a real timer. */ sleep?: (ms: number) => Promise; } /** * Four attempts: ~1s + ~2s + ~4s of backoff at worst, which clears the short * per-token window Figma applies to a burst of node reads without turning a * genuinely exhausted quota into a seven-minute job. */ export declare const DEFAULT_ATTEMPTS = 4; export interface RenderedImage { bytes: Uint8Array; /** The signed URL the bytes were downloaded from (trace/debug). */ url: string; } export declare class FigmaRestClient { #private; constructor(opts: FigmaRestClientOptions); /** * `GET /v1/files/:key?depth=1` — the file's own metadata, without dragging * the document down the wire. * * `version` changes on every edit, so a caller holding cached references can * decide in ONE request whether any of them can have moved, rather than * re-reading every node to find out that nothing did. */ getFileMeta(fileKey: string): Promise; /** * `GET /v1/files/:key/nodes?ids=` — structure for the requested nodes. * * `depth` bounds how far the response descends. Omitted, Figma returns the * whole subtree, which for a kit page is megabytes; `depth: 1` is enough when * the caller only wants the node's own fields (its * `componentPropertyDefinitions`, its name), and a deeper bound is how a * page walk trades request size against how much of the tree it can see. */ getFileNodes(fileKey: string, ids: string[], opts?: { depth?: number; }): Promise; /** * `GET /v1/files/:key?depth=1` — the document with its children truncated to * the page level, i.e. every page's `id` and `name` and nothing else. * * Distinct from {@link getFileMeta}, which reads the same response for its * `version`. Enumerating pages any other way costs one full subtree dump per * page; this is one request for the whole file. */ getFilePages(fileKey: string): Promise; /** * `GET /v1/files/:key/components` — what the file publishes. * * Returns `{}` rather than throwing on 403/404, because "this file publishes * nothing" is a normal answer for a community duplicate and the caller's * fallback is a tree walk, not a failure. */ getFileComponents(fileKey: string): Promise; /** * `GET /v1/files/:key/variables/local` — variable collections + modes. * Enterprise-only; returns `{}` (not an error) on 403/404 so the adapter * degrades to structure-only tokens. */ getLocalVariables(fileKey: string): Promise; /** * `GET /v1/images/:key?ids=&format=…` then download the result. `png` honours * `scale`; `svg` is resolution-free so `scale` is omitted (Figma ignores it). */ renderImage(fileKey: string, nodeId: string, opts?: { scale?: number; format?: "png" | "svg"; /** Include only the node's own contents; false also renders overlapping layers. */ contentsOnly?: boolean; /** * SVG only: stamp `data-node-id` onto every exported element. * * This is what turns an export from a picture into a **document you can * address**. Given a node id, a consumer can find that shape in the * markup — hide it, outline it, or drop a code render into the hole it * leaves — none of which a raster can answer, because a raster has no * structure to ask. * * `svg_outline_text` is deliberately left at Figma's default (`true`): * outlined text renders identically everywhere, and a specimen sheet is * mostly labels, so a font substitution on the reader's machine would * make the design half of a comparison wrong in exactly the way it is * supposed to be right. */ includeNodeId?: boolean; }): Promise; /** * `GET /v1/images/:key?ids=a,b,c&format=…` — signed URLs for MANY nodes in * ONE request, keyed by node id. A node the response omits maps to `null`. * * The endpoint has always accepted a comma-separated `ids`, exactly like * `/v1/files/:key/nodes`, but {@link renderImage} asked for a single node and * the import called it per node. Structure was batched; renders were not, so * refreshing a 581-node kit spent ~581 rate-limited requests where ~12 do — * and since the limiter is per token and shared across every repo holding it, * that is what made a full import take several passes instead of one * (wear-m3-catalog, 2026-08-28). * * Callers must group by anything that goes in the query — `format`, `scale`, * `contentsOnly` — since those apply to the whole batch, not per node. */ renderImageUrls(fileKey: string, nodeIds: string[], opts?: { scale?: number; format?: "png" | "svg"; contentsOnly?: boolean; includeNodeId?: boolean; }): Promise>; /** * Download a rendered image from the signed URL {@link renderImageUrls} * returned. Deliberately separate: the URL is served by Figma's CDN rather * than the API, so downloads do NOT spend the per-token rate limit and a * caller may keep draining them after the API itself has started refusing. */ downloadImage(url: string, label?: string): Promise; } //# sourceMappingURL=rest-client.d.ts.map