test(figma-api): type-check plugin compatibility subset

This commit is contained in:
Danila Poyarkov 2026-05-17 16:24:47 +03:00
parent 2154bb09a2
commit f9a75b70a3
4 changed files with 28 additions and 0 deletions

View file

@ -60,6 +60,7 @@
"devDependencies": {
"@agentclientprotocol/sdk": "^0.14.1",
"@feature-sliced/steiger-plugin": "^0.5.8",
"@figma/plugin-typings": "^1.126.0",
"@hono/node-server": "^1.19.11",
"@iconify-json/lucide": "^1.2.94",
"@modelcontextprotocol/sdk": "^1.27.1",
@ -532,6 +533,8 @@
"@feature-sliced/steiger-plugin": ["@feature-sliced/steiger-plugin@0.5.8", "", { "dependencies": { "@feature-sliced/filesystem": "^3.1.0", "fastest-levenshtein": "^1.0.16", "lodash-es": "^4.17.21", "pluralize": "^8.0.0", "precinct": "^12.2.0", "tsconfck": "^3.1.6" } }, "sha512-SXn2PQS0yVRzhltSM968hz0hWmNj93l7dNU4Qqry3OgSkvrO4kl1/daWYwRYzmm9sImsAUsTztabwLUbF9U9YA=="],
"@figma/plugin-typings": ["@figma/plugin-typings@1.126.0", "", {}, "sha512-7Y8HPIHWgMUoT1L7InyUe5X6S+gPUSlVLi7TQvwnRev6PjDwwNkM/oSio2t69EvsJ+TRPSJSvO7xph+KHIcWeQ=="],
"@firebase/ai": ["@firebase/ai@2.10.0", "", { "dependencies": { "@firebase/app-check-interop-types": "0.3.3", "@firebase/component": "0.7.2", "@firebase/logger": "0.5.0", "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { "@firebase/app": "0.x", "@firebase/app-types": "0.x" } }, "sha512-1lI6HomyoO/8RSJb6ItyHLpHnB2z27m5F4aX/Vpi1nhwWoxdNjkq+6UQOykHyCE0KairojOE5qQ20i1tnF0nNA=="],
"@firebase/analytics": ["@firebase/analytics@0.10.21", "", { "dependencies": { "@firebase/component": "0.7.2", "@firebase/installations": "0.6.21", "@firebase/logger": "0.5.0", "@firebase/util": "1.15.0", "tslib": "^2.1.0" }, "peerDependencies": { "@firebase/app": "0.x" } }, "sha512-j2y2q65BlgLGB5Pwjhv/Jopw2X/TBTzvAtI5z/DSp56U4wBj7LfhBfzbdCtFPges+Wz0g55GdoawXibOH5jGng=="],

View file

@ -89,6 +89,7 @@
"devDependencies": {
"@agentclientprotocol/sdk": "^0.14.1",
"@feature-sliced/steiger-plugin": "^0.5.8",
"@figma/plugin-typings": "^1.126.0",
"@hono/node-server": "^1.19.11",
"@iconify-json/lucide": "^1.2.94",
"@modelcontextprotocol/sdk": "^1.27.1",

View file

@ -0,0 +1,14 @@
/// <reference types="@figma/plugin-typings" />
import type { FigmaAPI } from './index'
type Expect<T extends true> = T
type IsAssignable<Actual, Expected> = Actual extends Expected ? true : false
export type SupportedPluginAPI = Pick<
PluginAPI,
'base64Decode' | 'base64Encode' | 'loadFontAsync' | 'notify'
>
export type FigmaAPICompatibility = Expect<IsAssignable<FigmaAPI, SupportedPluginAPI>>

View file

@ -60,6 +60,8 @@ export function computeImageHash(data: Uint8Array): string {
return [h1, h2, h3, h4, h5].map((h) => h.toString(16).padStart(8, '0')).join('')
}
// TODO(figma-api): Implement the full official PluginAPI interface once our compatibility
// layer covers all required node-specific return types and unsupported APIs are modeled explicitly.
export class FigmaAPI implements NodeProxyHost {
readonly graph: SceneGraph
private _currentPageId: string
@ -384,6 +386,14 @@ export class FigmaAPI implements NodeProxyHost {
return []
}
base64Encode(data: Uint8Array): string {
return data.toBase64()
}
base64Decode(data: string): Uint8Array {
return Uint8Array.fromBase64(data)
}
notify(message: string): { cancel: () => void } {
if (typeof console !== 'undefined') console.warn(`[figma.notify] ${message}`)
return { cancel: noop }