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 }