diff --git a/bun.lock b/bun.lock
index 46f403613..7f5f1413e 100644
--- a/bun.lock
+++ b/bun.lock
@@ -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=="],
diff --git a/package.json b/package.json
index 85af9b74e..34ea62e62 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/packages/core/src/figma-api/compatibility.ts b/packages/core/src/figma-api/compatibility.ts
new file mode 100644
index 000000000..bb88b3b13
--- /dev/null
+++ b/packages/core/src/figma-api/compatibility.ts
@@ -0,0 +1,14 @@
+///
+
+import type { FigmaAPI } from './index'
+
+type Expect = T
+
+type IsAssignable = Actual extends Expected ? true : false
+
+export type SupportedPluginAPI = Pick<
+ PluginAPI,
+ 'base64Decode' | 'base64Encode' | 'loadFontAsync' | 'notify'
+>
+
+export type FigmaAPICompatibility = Expect>
diff --git a/packages/core/src/figma-api/index.ts b/packages/core/src/figma-api/index.ts
index cfb85662b..0875756d2 100644
--- a/packages/core/src/figma-api/index.ts
+++ b/packages/core/src/figma-api/index.ts
@@ -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 }