@muloka/figma-console-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +898 -0
  3. package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts +14 -0
  4. package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts.map +1 -0
  5. package/dist/apps/design-system-dashboard/scoring/accessibility.js +278 -0
  6. package/dist/apps/design-system-dashboard/scoring/accessibility.js.map +1 -0
  7. package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts +29 -0
  8. package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts.map +1 -0
  9. package/dist/apps/design-system-dashboard/scoring/component-metadata.js +358 -0
  10. package/dist/apps/design-system-dashboard/scoring/component-metadata.js.map +1 -0
  11. package/dist/apps/design-system-dashboard/scoring/consistency.d.ts +14 -0
  12. package/dist/apps/design-system-dashboard/scoring/consistency.d.ts.map +1 -0
  13. package/dist/apps/design-system-dashboard/scoring/consistency.js +342 -0
  14. package/dist/apps/design-system-dashboard/scoring/consistency.js.map +1 -0
  15. package/dist/apps/design-system-dashboard/scoring/coverage.d.ts +14 -0
  16. package/dist/apps/design-system-dashboard/scoring/coverage.d.ts.map +1 -0
  17. package/dist/apps/design-system-dashboard/scoring/coverage.js +231 -0
  18. package/dist/apps/design-system-dashboard/scoring/coverage.js.map +1 -0
  19. package/dist/apps/design-system-dashboard/scoring/engine.d.ts +27 -0
  20. package/dist/apps/design-system-dashboard/scoring/engine.d.ts.map +1 -0
  21. package/dist/apps/design-system-dashboard/scoring/engine.js +93 -0
  22. package/dist/apps/design-system-dashboard/scoring/engine.js.map +1 -0
  23. package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts +14 -0
  24. package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts.map +1 -0
  25. package/dist/apps/design-system-dashboard/scoring/naming-semantics.js +309 -0
  26. package/dist/apps/design-system-dashboard/scoring/naming-semantics.js.map +1 -0
  27. package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts +14 -0
  28. package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts.map +1 -0
  29. package/dist/apps/design-system-dashboard/scoring/token-architecture.js +350 -0
  30. package/dist/apps/design-system-dashboard/scoring/token-architecture.js.map +1 -0
  31. package/dist/apps/design-system-dashboard/scoring/types.d.ts +89 -0
  32. package/dist/apps/design-system-dashboard/scoring/types.d.ts.map +1 -0
  33. package/dist/apps/design-system-dashboard/scoring/types.js +41 -0
  34. package/dist/apps/design-system-dashboard/scoring/types.js.map +1 -0
  35. package/dist/apps/design-system-dashboard/server.d.ts +24 -0
  36. package/dist/apps/design-system-dashboard/server.d.ts.map +1 -0
  37. package/dist/apps/design-system-dashboard/server.js +160 -0
  38. package/dist/apps/design-system-dashboard/server.js.map +1 -0
  39. package/dist/apps/token-browser/server.d.ts +26 -0
  40. package/dist/apps/token-browser/server.d.ts.map +1 -0
  41. package/dist/apps/token-browser/server.js +137 -0
  42. package/dist/apps/token-browser/server.js.map +1 -0
  43. package/dist/browser/base.d.ts +58 -0
  44. package/dist/browser/base.d.ts.map +1 -0
  45. package/dist/browser/base.js +6 -0
  46. package/dist/browser/base.js.map +1 -0
  47. package/dist/browser/local.d.ts +87 -0
  48. package/dist/browser/local.d.ts.map +1 -0
  49. package/dist/browser/local.js +318 -0
  50. package/dist/browser/local.js.map +1 -0
  51. package/dist/cloudflare/apps/design-system-dashboard/scoring/accessibility.js +277 -0
  52. package/dist/cloudflare/apps/design-system-dashboard/scoring/component-metadata.js +357 -0
  53. package/dist/cloudflare/apps/design-system-dashboard/scoring/consistency.js +341 -0
  54. package/dist/cloudflare/apps/design-system-dashboard/scoring/coverage.js +230 -0
  55. package/dist/cloudflare/apps/design-system-dashboard/scoring/engine.js +92 -0
  56. package/dist/cloudflare/apps/design-system-dashboard/scoring/naming-semantics.js +308 -0
  57. package/dist/cloudflare/apps/design-system-dashboard/scoring/token-architecture.js +349 -0
  58. package/dist/cloudflare/apps/design-system-dashboard/scoring/types.js +40 -0
  59. package/dist/cloudflare/apps/design-system-dashboard/server.js +159 -0
  60. package/dist/cloudflare/apps/token-browser/server.js +136 -0
  61. package/dist/cloudflare/browser-manager.js +157 -0
  62. package/dist/cloudflare/core/accessibility-tools.js +361 -0
  63. package/dist/cloudflare/core/annotation-tools.js +230 -0
  64. package/dist/cloudflare/core/cloud-websocket-connector.js +419 -0
  65. package/dist/cloudflare/core/cloud-websocket-relay.js +198 -0
  66. package/dist/cloudflare/core/comment-tools.js +292 -0
  67. package/dist/cloudflare/core/config.js +153 -0
  68. package/dist/cloudflare/core/console-monitor.js +427 -0
  69. package/dist/cloudflare/core/deep-component-tools.js +128 -0
  70. package/dist/cloudflare/core/design-code-tools.js +2793 -0
  71. package/dist/cloudflare/core/design-system-manifest.js +265 -0
  72. package/dist/cloudflare/core/design-system-tools.js +882 -0
  73. package/dist/cloudflare/core/diagnose-tool.js +100 -0
  74. package/dist/cloudflare/core/diff/changelog-formatter.js +275 -0
  75. package/dist/cloudflare/core/diff/diff-engine.js +334 -0
  76. package/dist/cloudflare/core/diff/property-compare.js +36 -0
  77. package/dist/cloudflare/core/diff/version-cache.js +74 -0
  78. package/dist/cloudflare/core/enrichment/enrichment-service.js +374 -0
  79. package/dist/cloudflare/core/enrichment/index.js +7 -0
  80. package/dist/cloudflare/core/enrichment/relationship-mapper.js +351 -0
  81. package/dist/cloudflare/core/enrichment/style-resolver.js +346 -0
  82. package/dist/cloudflare/core/figjam-tools.js +547 -0
  83. package/dist/cloudflare/core/figma-api.js +509 -0
  84. package/dist/cloudflare/core/figma-connector.js +7 -0
  85. package/dist/cloudflare/core/figma-reconstruction-spec.js +402 -0
  86. package/dist/cloudflare/core/figma-style-extractor.js +311 -0
  87. package/dist/cloudflare/core/figma-tools.js +3302 -0
  88. package/dist/cloudflare/core/identity.js +96 -0
  89. package/dist/cloudflare/core/library-tools.js +580 -0
  90. package/dist/cloudflare/core/logger.js +53 -0
  91. package/dist/cloudflare/core/port-discovery.js +935 -0
  92. package/dist/cloudflare/core/resolve-package-root.js +11 -0
  93. package/dist/cloudflare/core/slides-tools.js +714 -0
  94. package/dist/cloudflare/core/slot-tools.js +334 -0
  95. package/dist/cloudflare/core/snippet-injector.js +96 -0
  96. package/dist/cloudflare/core/tokens/alias-resolver.js +205 -0
  97. package/dist/cloudflare/core/tokens/config.js +294 -0
  98. package/dist/cloudflare/core/tokens/dialect.js +232 -0
  99. package/dist/cloudflare/core/tokens/figma-converter.js +323 -0
  100. package/dist/cloudflare/core/tokens/formatters/css-vars.js +338 -0
  101. package/dist/cloudflare/core/tokens/formatters/dtcg.js +376 -0
  102. package/dist/cloudflare/core/tokens/formatters/index.js +45 -0
  103. package/dist/cloudflare/core/tokens/formatters/json.js +205 -0
  104. package/dist/cloudflare/core/tokens/formatters/less.js +4 -0
  105. package/dist/cloudflare/core/tokens/formatters/scss.js +258 -0
  106. package/dist/cloudflare/core/tokens/formatters/stubs.js +13 -0
  107. package/dist/cloudflare/core/tokens/formatters/style-dictionary-v3.js +213 -0
  108. package/dist/cloudflare/core/tokens/formatters/tailwind-v3.js +237 -0
  109. package/dist/cloudflare/core/tokens/formatters/tailwind-v4.js +335 -0
  110. package/dist/cloudflare/core/tokens/formatters/tokens-studio.js +256 -0
  111. package/dist/cloudflare/core/tokens/formatters/ts-module.js +198 -0
  112. package/dist/cloudflare/core/tokens/index.js +16 -0
  113. package/dist/cloudflare/core/tokens/parsers/css-vars.js +4 -0
  114. package/dist/cloudflare/core/tokens/parsers/dtcg.js +280 -0
  115. package/dist/cloudflare/core/tokens/parsers/index.js +138 -0
  116. package/dist/cloudflare/core/tokens/parsers/json.js +7 -0
  117. package/dist/cloudflare/core/tokens/parsers/scss.js +4 -0
  118. package/dist/cloudflare/core/tokens/parsers/stubs.js +20 -0
  119. package/dist/cloudflare/core/tokens/parsers/style-dictionary-v3.js +4 -0
  120. package/dist/cloudflare/core/tokens/parsers/tailwind-v3.js +4 -0
  121. package/dist/cloudflare/core/tokens/parsers/tailwind-v4.js +4 -0
  122. package/dist/cloudflare/core/tokens/parsers/tokens-studio.js +4 -0
  123. package/dist/cloudflare/core/tokens/schemas.js +152 -0
  124. package/dist/cloudflare/core/tokens/transforms/color.js +12 -0
  125. package/dist/cloudflare/core/tokens/transforms/index.js +29 -0
  126. package/dist/cloudflare/core/tokens/transforms/size.js +7 -0
  127. package/dist/cloudflare/core/tokens/types.js +18 -0
  128. package/dist/cloudflare/core/tokens-tools.js +1788 -0
  129. package/dist/cloudflare/core/types/design-code.js +4 -0
  130. package/dist/cloudflare/core/types/enriched.js +5 -0
  131. package/dist/cloudflare/core/types/index.js +4 -0
  132. package/dist/cloudflare/core/variable-resolver.js +85 -0
  133. package/dist/cloudflare/core/version-tools.js +1199 -0
  134. package/dist/cloudflare/core/websocket-connector.js +436 -0
  135. package/dist/cloudflare/core/websocket-server.js +956 -0
  136. package/dist/cloudflare/core/write-tools.js +2506 -0
  137. package/dist/cloudflare/index.js +3010 -0
  138. package/dist/core/accessibility-tools.d.ts +21 -0
  139. package/dist/core/accessibility-tools.d.ts.map +1 -0
  140. package/dist/core/accessibility-tools.js +362 -0
  141. package/dist/core/accessibility-tools.js.map +1 -0
  142. package/dist/core/annotation-tools.d.ts +14 -0
  143. package/dist/core/annotation-tools.d.ts.map +1 -0
  144. package/dist/core/annotation-tools.js +231 -0
  145. package/dist/core/annotation-tools.js.map +1 -0
  146. package/dist/core/comment-tools.d.ts +11 -0
  147. package/dist/core/comment-tools.d.ts.map +1 -0
  148. package/dist/core/comment-tools.js +293 -0
  149. package/dist/core/comment-tools.js.map +1 -0
  150. package/dist/core/config.d.ts +17 -0
  151. package/dist/core/config.d.ts.map +1 -0
  152. package/dist/core/config.js +154 -0
  153. package/dist/core/config.js.map +1 -0
  154. package/dist/core/console-monitor.d.ts +82 -0
  155. package/dist/core/console-monitor.d.ts.map +1 -0
  156. package/dist/core/console-monitor.js +428 -0
  157. package/dist/core/console-monitor.js.map +1 -0
  158. package/dist/core/deep-component-tools.d.ts +14 -0
  159. package/dist/core/deep-component-tools.d.ts.map +1 -0
  160. package/dist/core/deep-component-tools.js +129 -0
  161. package/dist/core/deep-component-tools.js.map +1 -0
  162. package/dist/core/design-code-tools.d.ts +116 -0
  163. package/dist/core/design-code-tools.d.ts.map +1 -0
  164. package/dist/core/design-code-tools.js +2794 -0
  165. package/dist/core/design-code-tools.js.map +1 -0
  166. package/dist/core/design-system-manifest.d.ts +273 -0
  167. package/dist/core/design-system-manifest.d.ts.map +1 -0
  168. package/dist/core/design-system-manifest.js +266 -0
  169. package/dist/core/design-system-manifest.js.map +1 -0
  170. package/dist/core/design-system-tools.d.ts +67 -0
  171. package/dist/core/design-system-tools.d.ts.map +1 -0
  172. package/dist/core/design-system-tools.js +883 -0
  173. package/dist/core/design-system-tools.js.map +1 -0
  174. package/dist/core/diagnose-tool.d.ts +41 -0
  175. package/dist/core/diagnose-tool.d.ts.map +1 -0
  176. package/dist/core/diagnose-tool.js +101 -0
  177. package/dist/core/diagnose-tool.js.map +1 -0
  178. package/dist/core/diff/changelog-formatter.d.ts +35 -0
  179. package/dist/core/diff/changelog-formatter.d.ts.map +1 -0
  180. package/dist/core/diff/changelog-formatter.js +276 -0
  181. package/dist/core/diff/changelog-formatter.js.map +1 -0
  182. package/dist/core/diff/diff-engine.d.ts +127 -0
  183. package/dist/core/diff/diff-engine.d.ts.map +1 -0
  184. package/dist/core/diff/diff-engine.js +335 -0
  185. package/dist/core/diff/diff-engine.js.map +1 -0
  186. package/dist/core/diff/property-compare.d.ts +19 -0
  187. package/dist/core/diff/property-compare.d.ts.map +1 -0
  188. package/dist/core/diff/property-compare.js +37 -0
  189. package/dist/core/diff/property-compare.js.map +1 -0
  190. package/dist/core/diff/version-cache.d.ts +40 -0
  191. package/dist/core/diff/version-cache.d.ts.map +1 -0
  192. package/dist/core/diff/version-cache.js +75 -0
  193. package/dist/core/diff/version-cache.js.map +1 -0
  194. package/dist/core/enrichment/enrichment-service.d.ts +52 -0
  195. package/dist/core/enrichment/enrichment-service.d.ts.map +1 -0
  196. package/dist/core/enrichment/enrichment-service.js +375 -0
  197. package/dist/core/enrichment/enrichment-service.js.map +1 -0
  198. package/dist/core/enrichment/index.d.ts +8 -0
  199. package/dist/core/enrichment/index.d.ts.map +1 -0
  200. package/dist/core/enrichment/index.js +8 -0
  201. package/dist/core/enrichment/index.js.map +1 -0
  202. package/dist/core/enrichment/relationship-mapper.d.ts +106 -0
  203. package/dist/core/enrichment/relationship-mapper.d.ts.map +1 -0
  204. package/dist/core/enrichment/relationship-mapper.js +352 -0
  205. package/dist/core/enrichment/relationship-mapper.js.map +1 -0
  206. package/dist/core/enrichment/style-resolver.d.ts +85 -0
  207. package/dist/core/enrichment/style-resolver.d.ts.map +1 -0
  208. package/dist/core/enrichment/style-resolver.js +347 -0
  209. package/dist/core/enrichment/style-resolver.js.map +1 -0
  210. package/dist/core/figjam-tools.d.ts +8 -0
  211. package/dist/core/figjam-tools.d.ts.map +1 -0
  212. package/dist/core/figjam-tools.js +548 -0
  213. package/dist/core/figjam-tools.js.map +1 -0
  214. package/dist/core/figma-api.d.ts +254 -0
  215. package/dist/core/figma-api.d.ts.map +1 -0
  216. package/dist/core/figma-api.js +510 -0
  217. package/dist/core/figma-api.js.map +1 -0
  218. package/dist/core/figma-connector.d.ts +214 -0
  219. package/dist/core/figma-connector.d.ts.map +1 -0
  220. package/dist/core/figma-connector.js +8 -0
  221. package/dist/core/figma-connector.js.map +1 -0
  222. package/dist/core/figma-desktop-connector.d.ts +312 -0
  223. package/dist/core/figma-desktop-connector.d.ts.map +1 -0
  224. package/dist/core/figma-desktop-connector.js +1298 -0
  225. package/dist/core/figma-desktop-connector.js.map +1 -0
  226. package/dist/core/figma-reconstruction-spec.d.ts +166 -0
  227. package/dist/core/figma-reconstruction-spec.d.ts.map +1 -0
  228. package/dist/core/figma-reconstruction-spec.js +403 -0
  229. package/dist/core/figma-reconstruction-spec.js.map +1 -0
  230. package/dist/core/figma-style-extractor.d.ts +76 -0
  231. package/dist/core/figma-style-extractor.d.ts.map +1 -0
  232. package/dist/core/figma-style-extractor.js +312 -0
  233. package/dist/core/figma-style-extractor.js.map +1 -0
  234. package/dist/core/figma-tools.d.ts +22 -0
  235. package/dist/core/figma-tools.d.ts.map +1 -0
  236. package/dist/core/figma-tools.js +3303 -0
  237. package/dist/core/figma-tools.js.map +1 -0
  238. package/dist/core/identity.d.ts +41 -0
  239. package/dist/core/identity.d.ts.map +1 -0
  240. package/dist/core/identity.js +97 -0
  241. package/dist/core/identity.js.map +1 -0
  242. package/dist/core/library-tools.d.ts +17 -0
  243. package/dist/core/library-tools.d.ts.map +1 -0
  244. package/dist/core/library-tools.js +581 -0
  245. package/dist/core/library-tools.js.map +1 -0
  246. package/dist/core/logger.d.ts +22 -0
  247. package/dist/core/logger.d.ts.map +1 -0
  248. package/dist/core/logger.js +54 -0
  249. package/dist/core/logger.js.map +1 -0
  250. package/dist/core/port-discovery.d.ts +211 -0
  251. package/dist/core/port-discovery.d.ts.map +1 -0
  252. package/dist/core/port-discovery.js +936 -0
  253. package/dist/core/port-discovery.js.map +1 -0
  254. package/dist/core/resolve-package-root.d.ts +2 -0
  255. package/dist/core/resolve-package-root.d.ts.map +1 -0
  256. package/dist/core/resolve-package-root.js +12 -0
  257. package/dist/core/resolve-package-root.js.map +1 -0
  258. package/dist/core/slides-tools.d.ts +8 -0
  259. package/dist/core/slides-tools.d.ts.map +1 -0
  260. package/dist/core/slides-tools.js +715 -0
  261. package/dist/core/slides-tools.js.map +1 -0
  262. package/dist/core/slot-tools.d.ts +7 -0
  263. package/dist/core/slot-tools.d.ts.map +1 -0
  264. package/dist/core/slot-tools.js +335 -0
  265. package/dist/core/slot-tools.js.map +1 -0
  266. package/dist/core/snippet-injector.d.ts +24 -0
  267. package/dist/core/snippet-injector.d.ts.map +1 -0
  268. package/dist/core/snippet-injector.js +97 -0
  269. package/dist/core/snippet-injector.js.map +1 -0
  270. package/dist/core/tokens/alias-resolver.d.ts +97 -0
  271. package/dist/core/tokens/alias-resolver.d.ts.map +1 -0
  272. package/dist/core/tokens/alias-resolver.js +206 -0
  273. package/dist/core/tokens/alias-resolver.js.map +1 -0
  274. package/dist/core/tokens/config.d.ts +380 -0
  275. package/dist/core/tokens/config.d.ts.map +1 -0
  276. package/dist/core/tokens/config.js +295 -0
  277. package/dist/core/tokens/config.js.map +1 -0
  278. package/dist/core/tokens/dialect.d.ts +107 -0
  279. package/dist/core/tokens/dialect.d.ts.map +1 -0
  280. package/dist/core/tokens/dialect.js +233 -0
  281. package/dist/core/tokens/dialect.js.map +1 -0
  282. package/dist/core/tokens/figma-converter.d.ts +102 -0
  283. package/dist/core/tokens/figma-converter.d.ts.map +1 -0
  284. package/dist/core/tokens/figma-converter.js +324 -0
  285. package/dist/core/tokens/figma-converter.js.map +1 -0
  286. package/dist/core/tokens/formatters/css-vars.d.ts +24 -0
  287. package/dist/core/tokens/formatters/css-vars.d.ts.map +1 -0
  288. package/dist/core/tokens/formatters/css-vars.js +339 -0
  289. package/dist/core/tokens/formatters/css-vars.js.map +1 -0
  290. package/dist/core/tokens/formatters/dtcg.d.ts +28 -0
  291. package/dist/core/tokens/formatters/dtcg.d.ts.map +1 -0
  292. package/dist/core/tokens/formatters/dtcg.js +377 -0
  293. package/dist/core/tokens/formatters/dtcg.js.map +1 -0
  294. package/dist/core/tokens/formatters/index.d.ts +30 -0
  295. package/dist/core/tokens/formatters/index.d.ts.map +1 -0
  296. package/dist/core/tokens/formatters/index.js +46 -0
  297. package/dist/core/tokens/formatters/index.js.map +1 -0
  298. package/dist/core/tokens/formatters/json.d.ts +37 -0
  299. package/dist/core/tokens/formatters/json.d.ts.map +1 -0
  300. package/dist/core/tokens/formatters/json.js +206 -0
  301. package/dist/core/tokens/formatters/json.js.map +1 -0
  302. package/dist/core/tokens/formatters/less.d.ts +4 -0
  303. package/dist/core/tokens/formatters/less.d.ts.map +1 -0
  304. package/dist/core/tokens/formatters/less.js +5 -0
  305. package/dist/core/tokens/formatters/less.js.map +1 -0
  306. package/dist/core/tokens/formatters/scss.d.ts +26 -0
  307. package/dist/core/tokens/formatters/scss.d.ts.map +1 -0
  308. package/dist/core/tokens/formatters/scss.js +259 -0
  309. package/dist/core/tokens/formatters/scss.js.map +1 -0
  310. package/dist/core/tokens/formatters/stubs.d.ts +9 -0
  311. package/dist/core/tokens/formatters/stubs.d.ts.map +1 -0
  312. package/dist/core/tokens/formatters/stubs.js +14 -0
  313. package/dist/core/tokens/formatters/stubs.js.map +1 -0
  314. package/dist/core/tokens/formatters/style-dictionary-v3.d.ts +45 -0
  315. package/dist/core/tokens/formatters/style-dictionary-v3.d.ts.map +1 -0
  316. package/dist/core/tokens/formatters/style-dictionary-v3.js +214 -0
  317. package/dist/core/tokens/formatters/style-dictionary-v3.js.map +1 -0
  318. package/dist/core/tokens/formatters/tailwind-v3.d.ts +37 -0
  319. package/dist/core/tokens/formatters/tailwind-v3.d.ts.map +1 -0
  320. package/dist/core/tokens/formatters/tailwind-v3.js +238 -0
  321. package/dist/core/tokens/formatters/tailwind-v3.js.map +1 -0
  322. package/dist/core/tokens/formatters/tailwind-v4.d.ts +41 -0
  323. package/dist/core/tokens/formatters/tailwind-v4.d.ts.map +1 -0
  324. package/dist/core/tokens/formatters/tailwind-v4.js +336 -0
  325. package/dist/core/tokens/formatters/tailwind-v4.js.map +1 -0
  326. package/dist/core/tokens/formatters/tokens-studio.d.ts +44 -0
  327. package/dist/core/tokens/formatters/tokens-studio.d.ts.map +1 -0
  328. package/dist/core/tokens/formatters/tokens-studio.js +257 -0
  329. package/dist/core/tokens/formatters/tokens-studio.js.map +1 -0
  330. package/dist/core/tokens/formatters/ts-module.d.ts +35 -0
  331. package/dist/core/tokens/formatters/ts-module.d.ts.map +1 -0
  332. package/dist/core/tokens/formatters/ts-module.js +199 -0
  333. package/dist/core/tokens/formatters/ts-module.js.map +1 -0
  334. package/dist/core/tokens/index.d.ts +18 -0
  335. package/dist/core/tokens/index.d.ts.map +1 -0
  336. package/dist/core/tokens/index.js +17 -0
  337. package/dist/core/tokens/index.js.map +1 -0
  338. package/dist/core/tokens/parsers/css-vars.d.ts +3 -0
  339. package/dist/core/tokens/parsers/css-vars.d.ts.map +1 -0
  340. package/dist/core/tokens/parsers/css-vars.js +5 -0
  341. package/dist/core/tokens/parsers/css-vars.js.map +1 -0
  342. package/dist/core/tokens/parsers/dtcg.d.ts +21 -0
  343. package/dist/core/tokens/parsers/dtcg.d.ts.map +1 -0
  344. package/dist/core/tokens/parsers/dtcg.js +281 -0
  345. package/dist/core/tokens/parsers/dtcg.js.map +1 -0
  346. package/dist/core/tokens/parsers/index.d.ts +37 -0
  347. package/dist/core/tokens/parsers/index.d.ts.map +1 -0
  348. package/dist/core/tokens/parsers/index.js +139 -0
  349. package/dist/core/tokens/parsers/index.js.map +1 -0
  350. package/dist/core/tokens/parsers/json.d.ts +4 -0
  351. package/dist/core/tokens/parsers/json.d.ts.map +1 -0
  352. package/dist/core/tokens/parsers/json.js +8 -0
  353. package/dist/core/tokens/parsers/json.js.map +1 -0
  354. package/dist/core/tokens/parsers/scss.d.ts +3 -0
  355. package/dist/core/tokens/parsers/scss.d.ts.map +1 -0
  356. package/dist/core/tokens/parsers/scss.js +5 -0
  357. package/dist/core/tokens/parsers/scss.js.map +1 -0
  358. package/dist/core/tokens/parsers/stubs.d.ts +15 -0
  359. package/dist/core/tokens/parsers/stubs.d.ts.map +1 -0
  360. package/dist/core/tokens/parsers/stubs.js +21 -0
  361. package/dist/core/tokens/parsers/stubs.js.map +1 -0
  362. package/dist/core/tokens/parsers/style-dictionary-v3.d.ts +3 -0
  363. package/dist/core/tokens/parsers/style-dictionary-v3.d.ts.map +1 -0
  364. package/dist/core/tokens/parsers/style-dictionary-v3.js +5 -0
  365. package/dist/core/tokens/parsers/style-dictionary-v3.js.map +1 -0
  366. package/dist/core/tokens/parsers/tailwind-v3.d.ts +3 -0
  367. package/dist/core/tokens/parsers/tailwind-v3.d.ts.map +1 -0
  368. package/dist/core/tokens/parsers/tailwind-v3.js +5 -0
  369. package/dist/core/tokens/parsers/tailwind-v3.js.map +1 -0
  370. package/dist/core/tokens/parsers/tailwind-v4.d.ts +3 -0
  371. package/dist/core/tokens/parsers/tailwind-v4.d.ts.map +1 -0
  372. package/dist/core/tokens/parsers/tailwind-v4.js +5 -0
  373. package/dist/core/tokens/parsers/tailwind-v4.js.map +1 -0
  374. package/dist/core/tokens/parsers/tokens-studio.d.ts +3 -0
  375. package/dist/core/tokens/parsers/tokens-studio.d.ts.map +1 -0
  376. package/dist/core/tokens/parsers/tokens-studio.js +5 -0
  377. package/dist/core/tokens/parsers/tokens-studio.js.map +1 -0
  378. package/dist/core/tokens/schemas.d.ts +155 -0
  379. package/dist/core/tokens/schemas.d.ts.map +1 -0
  380. package/dist/core/tokens/schemas.js +153 -0
  381. package/dist/core/tokens/schemas.js.map +1 -0
  382. package/dist/core/tokens/transforms/color.d.ts +9 -0
  383. package/dist/core/tokens/transforms/color.d.ts.map +1 -0
  384. package/dist/core/tokens/transforms/color.js +13 -0
  385. package/dist/core/tokens/transforms/color.js.map +1 -0
  386. package/dist/core/tokens/transforms/index.d.ts +36 -0
  387. package/dist/core/tokens/transforms/index.d.ts.map +1 -0
  388. package/dist/core/tokens/transforms/index.js +30 -0
  389. package/dist/core/tokens/transforms/index.js.map +1 -0
  390. package/dist/core/tokens/transforms/size.d.ts +7 -0
  391. package/dist/core/tokens/transforms/size.d.ts.map +1 -0
  392. package/dist/core/tokens/transforms/size.js +8 -0
  393. package/dist/core/tokens/transforms/size.js.map +1 -0
  394. package/dist/core/tokens/types.d.ts +284 -0
  395. package/dist/core/tokens/types.d.ts.map +1 -0
  396. package/dist/core/tokens/types.js +19 -0
  397. package/dist/core/tokens/types.js.map +1 -0
  398. package/dist/core/tokens-tools.d.ts +285 -0
  399. package/dist/core/tokens-tools.d.ts.map +1 -0
  400. package/dist/core/tokens-tools.js +1789 -0
  401. package/dist/core/tokens-tools.js.map +1 -0
  402. package/dist/core/types/design-code.d.ts +271 -0
  403. package/dist/core/types/design-code.d.ts.map +1 -0
  404. package/dist/core/types/design-code.js +5 -0
  405. package/dist/core/types/design-code.js.map +1 -0
  406. package/dist/core/types/enriched.d.ts +213 -0
  407. package/dist/core/types/enriched.d.ts.map +1 -0
  408. package/dist/core/types/enriched.js +6 -0
  409. package/dist/core/types/enriched.js.map +1 -0
  410. package/dist/core/types/index.d.ts +104 -0
  411. package/dist/core/types/index.d.ts.map +1 -0
  412. package/dist/core/types/index.js +5 -0
  413. package/dist/core/types/index.js.map +1 -0
  414. package/dist/core/variable-resolver.d.ts +45 -0
  415. package/dist/core/variable-resolver.d.ts.map +1 -0
  416. package/dist/core/variable-resolver.js +86 -0
  417. package/dist/core/variable-resolver.js.map +1 -0
  418. package/dist/core/version-tools.d.ts +59 -0
  419. package/dist/core/version-tools.d.ts.map +1 -0
  420. package/dist/core/version-tools.js +1200 -0
  421. package/dist/core/version-tools.js.map +1 -0
  422. package/dist/core/websocket-connector.d.ts +247 -0
  423. package/dist/core/websocket-connector.d.ts.map +1 -0
  424. package/dist/core/websocket-connector.js +437 -0
  425. package/dist/core/websocket-connector.js.map +1 -0
  426. package/dist/core/websocket-server.d.ts +290 -0
  427. package/dist/core/websocket-server.d.ts.map +1 -0
  428. package/dist/core/websocket-server.js +957 -0
  429. package/dist/core/websocket-server.js.map +1 -0
  430. package/dist/core/write-tools.d.ts +7 -0
  431. package/dist/core/write-tools.d.ts.map +1 -0
  432. package/dist/core/write-tools.js +2507 -0
  433. package/dist/core/write-tools.js.map +1 -0
  434. package/dist/local.d.ts +105 -0
  435. package/dist/local.d.ts.map +1 -0
  436. package/dist/local.js +3314 -0
  437. package/dist/local.js.map +1 -0
  438. package/figma-desktop-bridge/README.md +365 -0
  439. package/figma-desktop-bridge/code.js +7359 -0
  440. package/figma-desktop-bridge/icon.png +0 -0
  441. package/figma-desktop-bridge/manifest.json +67 -0
  442. package/figma-desktop-bridge/ui.html +2783 -0
  443. package/package.json +103 -0
@@ -0,0 +1,509 @@
1
+ /**
2
+ * Figma REST API Client
3
+ * Handles HTTP calls to Figma's REST API for file data, variables, components, and styles
4
+ */
5
+ import { createChildLogger } from './logger.js';
6
+ const logger = createChildLogger({ component: 'figma-api' });
7
+ const FIGMA_API_BASE = 'https://api.figma.com/v1';
8
+ /**
9
+ * Extract file key from Figma URL
10
+ * Branch-aware: for branch URLs (/design/KEY/branch/BRANCHKEY/Name) returns the
11
+ * BRANCH key — the branch is its own file in the REST API, and returning the
12
+ * main key would silently target the wrong file (comments/diffs/file-data).
13
+ * @example https://www.figma.com/design/abc123/My-File -> abc123
14
+ * @example https://www.figma.com/design/abc123/branch/xyz789/My-File -> xyz789
15
+ */
16
+ export function extractFileKey(url) {
17
+ try {
18
+ const urlObj = new URL(url);
19
+ // Branch URLs: /design/FILE_KEY/branch/BRANCH_KEY — the branch key is the
20
+ // effective file key for all REST API calls.
21
+ const branchMatch = urlObj.pathname.match(/\/(design|file|board|slides)\/[a-zA-Z0-9]+\/branch\/([a-zA-Z0-9]+)/);
22
+ if (branchMatch) {
23
+ return branchMatch[2];
24
+ }
25
+ // Match patterns like /design/FILE_KEY, /file/FILE_KEY, /board/FILE_KEY (FigJam), /slides/FILE_KEY
26
+ const match = urlObj.pathname.match(/\/(design|file|board|slides)\/([a-zA-Z0-9]+)/);
27
+ return match ? match[2] : null;
28
+ }
29
+ catch (error) {
30
+ logger.error({ error, url }, 'Failed to extract file key from URL');
31
+ return null;
32
+ }
33
+ }
34
+ /**
35
+ * Normalize a node ID to Figma's canonical colon form.
36
+ * URLs use dashes ("695-313") but the REST API keys response maps by colon
37
+ * form ("695:313") — indexing a response with a dashed ID silently returns
38
+ * undefined, which reads as "node may not exist".
39
+ */
40
+ export function normalizeNodeId(nodeId) {
41
+ return nodeId.replace(/-/g, ':');
42
+ }
43
+ /**
44
+ * Extract comprehensive URL info including branch and node IDs
45
+ * Supports both URL formats:
46
+ * - Path-based: /design/{fileKey}/branch/{branchKey}/{fileName}
47
+ * - Query-based: /design/{fileKey}/{fileName}?branch-id={branchId}
48
+ *
49
+ * @example https://www.figma.com/design/abc123/branch/xyz789/My-File?node-id=1-2
50
+ * -> { fileKey: 'abc123', branchId: 'xyz789', nodeId: '1:2' }
51
+ * @example https://www.figma.com/design/abc123/My-File?branch-id=xyz789&node-id=1-2
52
+ * -> { fileKey: 'abc123', branchId: 'xyz789', nodeId: '1:2' }
53
+ */
54
+ export function extractFigmaUrlInfo(url) {
55
+ try {
56
+ const urlObj = new URL(url);
57
+ // First try: Path-based branch format /design/{fileKey}/branch/{branchKey}/{fileName}
58
+ const branchPathMatch = urlObj.pathname.match(/\/(design|file|board|slides)\/([a-zA-Z0-9]+)\/branch\/([a-zA-Z0-9]+)/);
59
+ if (branchPathMatch) {
60
+ const fileKey = branchPathMatch[2];
61
+ const branchId = branchPathMatch[3];
62
+ const nodeIdParam = urlObj.searchParams.get('node-id');
63
+ const nodeId = nodeIdParam ? nodeIdParam.replace(/-/g, ':') : undefined;
64
+ return { fileKey, branchId, nodeId };
65
+ }
66
+ // Second try: Standard format /design/{fileKey}/{fileName} with optional ?branch-id=
67
+ const standardMatch = urlObj.pathname.match(/\/(design|file|board|slides)\/([a-zA-Z0-9]+)/);
68
+ if (!standardMatch)
69
+ return null;
70
+ const fileKey = standardMatch[2];
71
+ const branchId = urlObj.searchParams.get('branch-id') || undefined;
72
+ const nodeIdParam = urlObj.searchParams.get('node-id');
73
+ // Convert node-id from URL format (1-2) to Figma format (1:2)
74
+ const nodeId = nodeIdParam ? nodeIdParam.replace(/-/g, ':') : undefined;
75
+ return { fileKey, branchId, nodeId };
76
+ }
77
+ catch (error) {
78
+ logger.error({ error, url }, 'Failed to extract Figma URL info');
79
+ return null;
80
+ }
81
+ }
82
+ /**
83
+ * Wrap a promise with a timeout
84
+ * @param promise The promise to wrap
85
+ * @param ms Timeout in milliseconds
86
+ * @param label Label for error message
87
+ * @returns Promise that rejects if timeout exceeded
88
+ */
89
+ export function withTimeout(promise, ms, label) {
90
+ const timeoutPromise = new Promise((_, reject) => {
91
+ const timeoutId = setTimeout(() => {
92
+ reject(new Error(`${label} timed out after ${ms}ms`));
93
+ }, ms);
94
+ // Ensure timeout is cleared if promise resolves/rejects first.
95
+ // The .catch() prevents an unhandled rejection when the original
96
+ // promise rejects — .finally() returns a new promise that inherits
97
+ // the rejection, and without .catch() it becomes unhandled.
98
+ promise.finally(() => clearTimeout(timeoutId)).catch(() => { });
99
+ });
100
+ return Promise.race([promise, timeoutPromise]);
101
+ }
102
+ /**
103
+ * Figma API Client
104
+ * Makes authenticated requests to Figma REST API
105
+ */
106
+ export class FigmaAPI {
107
+ constructor(config) {
108
+ this.accessToken = config.accessToken;
109
+ }
110
+ /**
111
+ * Make authenticated request to Figma API
112
+ */
113
+ async request(endpoint, options = {}) {
114
+ const url = `${FIGMA_API_BASE}${endpoint}`;
115
+ // Detect token type and use appropriate authentication header
116
+ // OAuth tokens start with 'figu_' and require Authorization: Bearer header
117
+ // Personal Access Tokens use X-Figma-Token header
118
+ const isOAuthToken = this.accessToken.startsWith('figu_');
119
+ logger.debug({ url, authMethod: isOAuthToken ? 'Bearer' : 'X-Figma-Token' }, 'Making Figma API request');
120
+ const headers = {
121
+ 'Content-Type': 'application/json',
122
+ ...(options.headers || {}),
123
+ };
124
+ // Add authentication header based on token type
125
+ if (isOAuthToken) {
126
+ headers['Authorization'] = `Bearer ${this.accessToken}`;
127
+ }
128
+ else {
129
+ headers['X-Figma-Token'] = this.accessToken;
130
+ }
131
+ // Up to 3 total attempts on 429 (rate limit), honoring Retry-After when
132
+ // present (seconds), else exponential backoff (1s, 2s). Delays here run
133
+ // inside the request promise — callers wrapping with withTimeout() still
134
+ // get their race-based rejection if the overall wait exceeds their budget.
135
+ const MAX_ATTEMPTS = 3;
136
+ let response;
137
+ for (let attempt = 1;; attempt++) {
138
+ response = await fetch(url, {
139
+ ...options,
140
+ headers,
141
+ });
142
+ if (response.status !== 429 || attempt >= MAX_ATTEMPTS) {
143
+ break;
144
+ }
145
+ const retryAfterHeader = response.headers.get('retry-after');
146
+ const retryAfterSeconds = retryAfterHeader ? Number(retryAfterHeader) : NaN;
147
+ // Cap Retry-After waits at 30s so a pathological header can't hang callers.
148
+ const delayMs = Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0
149
+ ? Math.min(retryAfterSeconds, 30) * 1000
150
+ : attempt * 1000; // 1s after attempt 1, 2s after attempt 2
151
+ logger.warn({ url, attempt, delayMs, retryAfterHeader }, 'Figma API rate limited (429), retrying');
152
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
153
+ }
154
+ if (!response.ok) {
155
+ const errorText = await response.text();
156
+ logger.error({ status: response.status, statusText: response.statusText, body: errorText }, 'Figma API request failed');
157
+ // The `Figma API error (<status>):` prefix is LOAD-BEARING — downstream
158
+ // tool handlers branch on errorMessage.includes("403") etc. Keep it
159
+ // verbatim at the start of the message; only APPEND guidance after it.
160
+ let message = `Figma API error (${response.status}): ${errorText}`;
161
+ // Token-auth failures (expired/invalid token) get actionable guidance.
162
+ // Plan-gate 403s (e.g. Variables API on non-Enterprise) do NOT match the
163
+ // token pattern and must not be flagged as auth errors.
164
+ const isAuthError = (response.status === 401 || response.status === 403) &&
165
+ /invalid token|token expired|unauthorized/i.test(errorText);
166
+ if (isAuthError) {
167
+ message +=
168
+ ' — Your Figma access token is expired or invalid. Generate a new personal access token at figma.com → Settings → Security → Personal access tokens, then update FIGMA_ACCESS_TOKEN in your MCP config. If Figma Desktop is open with the Desktop Bridge plugin running, most tools work without any REST token.';
169
+ }
170
+ else if (response.status === 429) {
171
+ message += ' Rate limited by Figma — wait a moment and retry.';
172
+ }
173
+ const err = new Error(message);
174
+ err.status = response.status;
175
+ if (isAuthError) {
176
+ err.isAuthError = true;
177
+ }
178
+ throw err;
179
+ }
180
+ const data = await response.json();
181
+ return data;
182
+ }
183
+ /**
184
+ * GET /v1/files/:file_key
185
+ * Get full file data including document tree, components, and styles
186
+ */
187
+ async getFile(fileKey, options) {
188
+ let endpoint = `/files/${fileKey}`;
189
+ const params = new URLSearchParams();
190
+ if (options?.version)
191
+ params.append('version', options.version);
192
+ if (options?.ids)
193
+ params.append('ids', options.ids.join(','));
194
+ if (options?.depth !== undefined)
195
+ params.append('depth', options.depth.toString());
196
+ if (options?.geometry)
197
+ params.append('geometry', options.geometry);
198
+ if (options?.plugin_data)
199
+ params.append('plugin_data', options.plugin_data);
200
+ if (options?.branch_data)
201
+ params.append('branch_data', 'true');
202
+ if (params.toString()) {
203
+ endpoint += `?${params.toString()}`;
204
+ }
205
+ return this.request(endpoint);
206
+ }
207
+ /**
208
+ * GET /v1/files/:file_key/variables/local
209
+ * Get local variables (design tokens) from a file
210
+ */
211
+ async getLocalVariables(fileKey) {
212
+ const response = await this.request(`/files/${fileKey}/variables/local`);
213
+ // Figma API returns {status, error, meta: {variableCollections, variables}}
214
+ // Extract meta to match expected format
215
+ return response.meta || response;
216
+ }
217
+ /**
218
+ * GET /v1/files/:file_key/variables/published
219
+ * Get published variables from a file
220
+ */
221
+ async getPublishedVariables(fileKey) {
222
+ const response = await this.request(`/files/${fileKey}/variables/published`);
223
+ // Figma API returns {status, error, meta: {variableCollections, variables}}
224
+ // Extract meta to match expected format
225
+ return response.meta || response;
226
+ }
227
+ /**
228
+ * GET /v1/files/:file_key/nodes
229
+ * Get specific nodes by ID
230
+ *
231
+ * Node IDs are normalized to Figma's colon form ("695-313" -> "695:313")
232
+ * before the request, and the response map is aliased back under any
233
+ * dashed IDs the caller passed — Figma keys the response by colon-format
234
+ * IDs, so without the alias a dashed lookup silently returns undefined.
235
+ */
236
+ async getNodes(fileKey, nodeIds, options) {
237
+ let endpoint = `/files/${fileKey}/nodes`;
238
+ const normalizedIds = nodeIds.map((id) => normalizeNodeId(id));
239
+ const params = new URLSearchParams();
240
+ params.append('ids', normalizedIds.join(','));
241
+ if (options?.version)
242
+ params.append('version', options.version);
243
+ if (options?.depth !== undefined)
244
+ params.append('depth', options.depth.toString());
245
+ if (options?.geometry)
246
+ params.append('geometry', options.geometry);
247
+ if (options?.plugin_data)
248
+ params.append('plugin_data', options.plugin_data);
249
+ endpoint += `?${params.toString()}`;
250
+ const response = await this.request(endpoint);
251
+ // Defensive aliasing: let callers index response.nodes by the ID form
252
+ // they originally passed (dashed), not just Figma's colon form.
253
+ if (response?.nodes) {
254
+ for (let i = 0; i < nodeIds.length; i++) {
255
+ const original = nodeIds[i];
256
+ const normalized = normalizedIds[i];
257
+ if (original !== normalized && response.nodes[normalized] !== undefined && response.nodes[original] === undefined) {
258
+ response.nodes[original] = response.nodes[normalized];
259
+ }
260
+ }
261
+ }
262
+ return response;
263
+ }
264
+ /**
265
+ * GET /v1/files/:file_key/styles
266
+ * Get styles from a file
267
+ */
268
+ async getStyles(fileKey) {
269
+ return this.request(`/files/${fileKey}/styles`);
270
+ }
271
+ /**
272
+ * GET /v1/files/:file_key/components
273
+ * Get components from a file
274
+ */
275
+ async getComponents(fileKey) {
276
+ return this.request(`/files/${fileKey}/components`);
277
+ }
278
+ /**
279
+ * GET /v1/files/:file_key/component_sets
280
+ * Get component sets (variants) from a file
281
+ */
282
+ async getComponentSets(fileKey) {
283
+ return this.request(`/files/${fileKey}/component_sets`);
284
+ }
285
+ /**
286
+ * GET /v1/components/:key
287
+ * Get metadata for a single published component by its key.
288
+ * Returns { status, error, meta: PublishedComponent } where meta includes
289
+ * file_key, node_id, name, description, containing_frame, user, etc.
290
+ * Use this to resolve a componentKey (from search results) to its source file.
291
+ */
292
+ async getComponentByKey(key) {
293
+ return this.request(`/components/${key}`);
294
+ }
295
+ /**
296
+ * GET /v1/component_sets/:key
297
+ * Get metadata for a single published component set (variant container) by its key.
298
+ * Returns { status, error, meta: PublishedComponentSet } with the same fields
299
+ * as getComponentByKey. The node_id points to the parent COMPONENT_SET node.
300
+ */
301
+ async getComponentSetByKey(key) {
302
+ return this.request(`/component_sets/${key}`);
303
+ }
304
+ /**
305
+ * GET /v1/images/:file_key
306
+ * Renders images for specified nodes
307
+ * @param fileKey - The file key
308
+ * @param nodeIds - Node IDs to render (single string or array)
309
+ * @param options - Rendering options
310
+ * @returns Map of node IDs to image URLs (URLs expire after 30 days)
311
+ */
312
+ async getImages(fileKey, nodeIds, options) {
313
+ const params = new URLSearchParams();
314
+ // Handle single or multiple node IDs. Normalize to Figma's colon form
315
+ // ("695-313" -> "695:313") — the response map is keyed by colon IDs, so
316
+ // a dashed request ID would otherwise never match its own result.
317
+ const originalIds = Array.isArray(nodeIds) ? nodeIds : [nodeIds];
318
+ const normalizedIds = originalIds.map((id) => normalizeNodeId(id));
319
+ const ids = normalizedIds.join(',');
320
+ params.append('ids', ids);
321
+ // Add optional parameters
322
+ if (options?.scale !== undefined)
323
+ params.append('scale', options.scale.toString());
324
+ if (options?.format)
325
+ params.append('format', options.format);
326
+ if (options?.svg_outline_text !== undefined)
327
+ params.append('svg_outline_text', options.svg_outline_text.toString());
328
+ if (options?.svg_include_id !== undefined)
329
+ params.append('svg_include_id', options.svg_include_id.toString());
330
+ if (options?.svg_include_node_id !== undefined)
331
+ params.append('svg_include_node_id', options.svg_include_node_id.toString());
332
+ if (options?.svg_simplify_stroke !== undefined)
333
+ params.append('svg_simplify_stroke', options.svg_simplify_stroke.toString());
334
+ if (options?.contents_only !== undefined)
335
+ params.append('contents_only', options.contents_only.toString());
336
+ const endpoint = `/images/${fileKey}?${params.toString()}`;
337
+ logger.info({ fileKey, ids, options }, 'Rendering images');
338
+ const response = await this.request(endpoint);
339
+ // Defensive aliasing: callers may index the images map by the dashed
340
+ // ID they passed. Figma keys it by colon-format ID — alias both forms.
341
+ if (response?.images) {
342
+ for (let i = 0; i < originalIds.length; i++) {
343
+ const original = originalIds[i];
344
+ const normalized = normalizedIds[i];
345
+ if (original !== normalized && response.images[normalized] !== undefined && response.images[original] === undefined) {
346
+ response.images[original] = response.images[normalized];
347
+ }
348
+ }
349
+ }
350
+ return response;
351
+ }
352
+ /**
353
+ * GET /v1/files/:file_key/comments
354
+ * Get comments on a file
355
+ */
356
+ async getComments(fileKey, options) {
357
+ const params = new URLSearchParams();
358
+ if (options?.as_md)
359
+ params.set('as_md', 'true');
360
+ const query = params.toString() ? `?${params.toString()}` : '';
361
+ return this.request(`/files/${fileKey}/comments${query}`);
362
+ }
363
+ /**
364
+ * POST /v1/files/:file_key/comments
365
+ * Post a comment on a file
366
+ */
367
+ async postComment(fileKey, message, clientMeta, commentId) {
368
+ return this.request(`/files/${fileKey}/comments`, {
369
+ method: 'POST',
370
+ body: JSON.stringify({
371
+ message,
372
+ ...(clientMeta && { client_meta: clientMeta }),
373
+ ...(commentId && { comment_id: commentId }),
374
+ }),
375
+ });
376
+ }
377
+ /**
378
+ * DELETE /v1/files/:file_key/comments/:comment_id
379
+ * Delete a comment on a file
380
+ */
381
+ async deleteComment(fileKey, commentId) {
382
+ return this.request(`/files/${fileKey}/comments/${commentId}`, {
383
+ method: 'DELETE',
384
+ });
385
+ }
386
+ /**
387
+ * GET /v1/files/:file_key/versions
388
+ * List a file's version history. Cursor-style pagination via before/after
389
+ * (cursors are version IDs). Response includes pagination.prev_page and
390
+ * pagination.next_page as full URLs — Figma recommends following those
391
+ * directly rather than reconstructing cursors. Requires the
392
+ * `file_versions:read` OAuth scope (or PAT "Versions" Read permission).
393
+ */
394
+ async getFileVersions(fileKey, options) {
395
+ const params = new URLSearchParams();
396
+ if (options?.page_size !== undefined)
397
+ params.set('page_size', String(options.page_size));
398
+ if (options?.before)
399
+ params.set('before', options.before);
400
+ if (options?.after)
401
+ params.set('after', options.after);
402
+ const query = params.toString() ? `?${params.toString()}` : '';
403
+ return this.request(`/files/${fileKey}/versions${query}`);
404
+ }
405
+ /**
406
+ * Helper: Get all design tokens (variables) with formatted output
407
+ * Both local and published can fail gracefully (e.g., 403 without Enterprise plan)
408
+ */
409
+ async getAllVariables(fileKey) {
410
+ // Wrap both in catch handlers to prevent unhandled promise rejections
411
+ // which can crash the server when REST API returns 403
412
+ const [localResult, publishedResult] = await Promise.all([
413
+ this.getLocalVariables(fileKey).catch((err) => {
414
+ const errorMsg = err instanceof Error ? err.message : String(err);
415
+ logger.warn({ fileKey, error: errorMsg }, 'getLocalVariables failed; returning empty fallback');
416
+ return { error: errorMsg, variables: {}, variableCollections: {} };
417
+ }),
418
+ this.getPublishedVariables(fileKey).catch((err) => {
419
+ const errorMsg = err instanceof Error ? err.message : String(err);
420
+ logger.warn({ fileKey, error: errorMsg }, 'getPublishedVariables failed; returning empty fallback');
421
+ return { error: errorMsg, variables: {} };
422
+ }),
423
+ ]);
424
+ // Fallback shape must match the success path (already-unwrapped meta):
425
+ // { variables, variableCollections } — NOT { meta: {...} } — so consumers
426
+ // like formatVariables() see a consistent shape either way.
427
+ return {
428
+ local: 'error' in localResult ? { variables: {}, variableCollections: {} } : localResult,
429
+ published: 'error' in publishedResult ? { variables: {} } : publishedResult,
430
+ ...(('error' in localResult) && { localError: localResult.error }),
431
+ ...(('error' in publishedResult) && { publishedError: publishedResult.error }),
432
+ };
433
+ }
434
+ /**
435
+ * Helper: Get component metadata with properties
436
+ * Normalizes dashed node IDs ("695-313") to colon form ("695:313") so the
437
+ * response-map lookup matches Figma's colon-keyed response.
438
+ */
439
+ async getComponentData(fileKey, nodeId, depth = 4) {
440
+ const normalizedId = normalizeNodeId(nodeId);
441
+ const response = await this.getNodes(fileKey, [normalizedId], { depth });
442
+ return response.nodes?.[normalizedId] ?? response.nodes?.[nodeId];
443
+ }
444
+ /**
445
+ * Helper: Search for components by name
446
+ */
447
+ async searchComponents(fileKey, searchTerm) {
448
+ const { meta } = await this.getComponents(fileKey);
449
+ const components = meta?.components || [];
450
+ return components.filter((comp) => comp.name?.toLowerCase().includes(searchTerm.toLowerCase()));
451
+ }
452
+ }
453
+ /**
454
+ * Helper function to format variables for display
455
+ */
456
+ export function formatVariables(variablesData) {
457
+ const collections = Object.entries(variablesData.variableCollections || {}).map(([id, collection]) => ({
458
+ id,
459
+ name: collection.name,
460
+ key: collection.key,
461
+ modes: collection.modes,
462
+ variableIds: collection.variableIds,
463
+ }));
464
+ const variables = Object.entries(variablesData.variables || {}).map(([id, variable]) => ({
465
+ id,
466
+ name: variable.name,
467
+ key: variable.key,
468
+ resolvedType: variable.resolvedType,
469
+ valuesByMode: variable.valuesByMode,
470
+ variableCollectionId: variable.variableCollectionId,
471
+ scopes: variable.scopes,
472
+ description: variable.description,
473
+ }));
474
+ const variablesByType = variables.reduce((acc, v) => {
475
+ acc[v.resolvedType] = (acc[v.resolvedType] || 0) + 1;
476
+ return acc;
477
+ }, {});
478
+ return {
479
+ collections,
480
+ variables,
481
+ summary: {
482
+ totalCollections: collections.length,
483
+ totalVariables: variables.length,
484
+ variablesByType,
485
+ },
486
+ };
487
+ }
488
+ /**
489
+ * Helper function to format component data for display
490
+ */
491
+ export function formatComponentData(componentNode) {
492
+ return {
493
+ id: componentNode.id,
494
+ name: componentNode.name,
495
+ type: componentNode.type,
496
+ description: componentNode.description,
497
+ descriptionMarkdown: componentNode.descriptionMarkdown,
498
+ properties: componentNode.componentPropertyDefinitions,
499
+ children: componentNode.children?.map((child) => ({
500
+ id: child.id,
501
+ name: child.name,
502
+ type: child.type,
503
+ })),
504
+ bounds: componentNode.absoluteBoundingBox,
505
+ fills: componentNode.fills,
506
+ strokes: componentNode.strokes,
507
+ effects: componentNode.effects,
508
+ };
509
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Figma Connector Interface
3
+ *
4
+ * Transport abstraction for the WebSocket Desktop Bridge plugin.
5
+ * Allows getDesktopConnector() to return the active WebSocket transport.
6
+ */
7
+ export {};