Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/figma

src/get-images.ts

90 lines · 3.4 KB · TypeScript
import { figmaRequest } from './client.ts'
import { mapImageMap } from './models.ts'
import { normalizeNodeIds, parseFileKey } from './setup.ts'
import type { FigmaAuthInput, FigmaImageMap } from './types.ts'
import {
	compactRecord,
	optionalBoolean,
	optionalNumber,
	optionalString,
	requireRecord,
	requireStringArray,
} from './types.ts'
import { requireAuthMode } from './auth.ts'

export type GetImagesInput = FigmaAuthInput & {
	/** File key, or a figma.com file/design/board URL. */
	fileKey: string
	/** Node ids to render. Hyphenated URL ids (`1-2`) are accepted. */
	ids: Array<string> | string
	format?: 'jpg' | 'png' | 'svg' | 'pdf'
	scale?: number
	svgOutlineText?: boolean
	svgIncludeId?: boolean
	svgSimplifyStroke?: boolean
	useAbsoluteBounds?: boolean
	version?: string
}

/**
 * Render images for nodes in a Figma file. Needs `file_content:read`.
 * @example
 * import getImages from 'kody:@kody/figma/get-images'
 * const { images } = await getImages({ fileKey: 'abc123', ids: ['12:34'], format: 'png' })
 */
export async function getImages(input: GetImagesInput): Promise<FigmaImageMap> {
	const fileKey = parseFileKey(input.fileKey)
	const ids = normalizeNodeIds(requireStringArray(input.ids, 'ids'))
	const format = optionalString(input.format, 'format')
	if (format && format !== 'jpg' && format !== 'png' && format !== 'svg' && format !== 'pdf') {
		throw new Error('format must be jpg, png, svg, or pdf.')
	}
	const scale = optionalNumber(input.scale, 'scale')
	if (scale !== undefined && (scale < 0.01 || scale > 4)) {
		throw new Error('scale must be between 0.01 and 4.')
	}
	const result = await figmaRequest<unknown>({
		...input,
		operation: 'files.read',
		path: `/v1/images/${encodeURIComponent(fileKey)}`,
		query: compactRecord({
			ids: ids.join(','),
			format,
			scale,
			svg_outline_text: optionalBoolean(input.svgOutlineText, 'svgOutlineText'),
			svg_include_id: optionalBoolean(input.svgIncludeId, 'svgIncludeId'),
			svg_simplify_stroke: optionalBoolean(input.svgSimplifyStroke, 'svgSimplifyStroke'),
			use_absolute_bounds: optionalBoolean(input.useAbsoluteBounds, 'useAbsoluteBounds'),
			version: optionalString(input.version, 'version'),
		}),
	})
	return mapImageMap(fileKey, result.body)
}

/**
 * Render images for nodes in a Figma file.
 * @example
 * import getImages from 'kody:@kody/figma/get-images'
 * const result = await getImages({ fileKey: 'abc123', ids: '1-2', format: 'png' })
 */
export default async function getImagesEntrypoint(
	params: Partial<GetImagesInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'get-images')
	return getImages({
		fileKey: String(input.fileKey ?? input.fileUrl ?? ''),
		ids: input.ids as GetImagesInput['ids'],
		format: optionalString(input.format, 'format') as GetImagesInput['format'],
		scale: input.scale as number | undefined,
		svgOutlineText: optionalBoolean(input.svgOutlineText, 'svgOutlineText'),
		svgIncludeId: optionalBoolean(input.svgIncludeId, 'svgIncludeId'),
		svgSimplifyStroke: optionalBoolean(input.svgSimplifyStroke, 'svgSimplifyStroke'),
		useAbsoluteBounds: optionalBoolean(input.useAbsoluteBounds, 'useAbsoluteBounds'),
		version: optionalString(input.version, 'version'),
		integrationName: optionalString(input.integrationName, 'integrationName'),
		integration: optionalString(input.integration, 'integration'),
		account: optionalString(input.account, 'account'),
		secretName: optionalString(input.secretName, 'secretName'),
		auth: requireAuthMode(input.auth),
	})
}