@payloadcms/figma 0.0.1-alpha.1 → 0.0.1-alpha.10

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 (308) hide show
  1. package/dist/api/control-plane.d.ts.map +1 -1
  2. package/dist/api/control-plane.js +2 -7
  3. package/dist/api/control-plane.js.map +1 -1
  4. package/dist/api/figma-api.js +3 -3
  5. package/dist/api/figma-api.js.map +1 -1
  6. package/dist/auth/jwt-validator.js.map +1 -1
  7. package/dist/auth/oauth-flow.d.ts.map +1 -1
  8. package/dist/auth/oauth-flow.js +3 -6
  9. package/dist/auth/oauth-flow.js.map +1 -1
  10. package/dist/auth/project-token.d.ts.map +1 -1
  11. package/dist/auth/project-token.js +1 -4
  12. package/dist/auth/project-token.js.map +1 -1
  13. package/dist/auth/refresh.d.ts.map +1 -1
  14. package/dist/auth/refresh.js +19 -28
  15. package/dist/auth/refresh.js.map +1 -1
  16. package/dist/auth/types.d.ts +1 -1
  17. package/dist/auth/types.d.ts.map +1 -1
  18. package/dist/auth/types.js.map +1 -1
  19. package/dist/cli.js +1 -3
  20. package/dist/cli.js.map +1 -1
  21. package/dist/commands/deploy.d.ts.map +1 -1
  22. package/dist/commands/deploy.js +17 -10
  23. package/dist/commands/deploy.js.map +1 -1
  24. package/dist/commands/init.d.ts +4 -0
  25. package/dist/commands/init.d.ts.map +1 -1
  26. package/dist/commands/init.js +21 -85
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/list-tokens.d.ts +1 -1
  29. package/dist/commands/list-tokens.d.ts.map +1 -1
  30. package/dist/commands/list-tokens.js +6 -5
  31. package/dist/commands/list-tokens.js.map +1 -1
  32. package/dist/commands/login.d.ts +2 -11
  33. package/dist/commands/login.d.ts.map +1 -1
  34. package/dist/commands/login.js +4 -7
  35. package/dist/commands/login.js.map +1 -1
  36. package/dist/commands/logout.d.ts +1 -1
  37. package/dist/commands/logout.js +1 -1
  38. package/dist/commands/logout.js.map +1 -1
  39. package/dist/exports/client.d.ts +3 -0
  40. package/dist/exports/client.d.ts.map +1 -0
  41. package/dist/exports/client.js +4 -0
  42. package/dist/exports/client.js.map +1 -0
  43. package/dist/oauth/components/LoginButton/index.d.ts +9 -0
  44. package/dist/oauth/components/LoginButton/index.d.ts.map +1 -0
  45. package/dist/oauth/components/LoginButton/index.js +52 -0
  46. package/dist/oauth/components/LoginButton/index.js.map +1 -0
  47. package/dist/oauth/components/LoginButton/index.scss +10 -0
  48. package/dist/oauth/components/LogoutButton/index.d.ts +7 -0
  49. package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -0
  50. package/dist/oauth/components/LogoutButton/index.js +67 -0
  51. package/dist/oauth/components/LogoutButton/index.js.map +1 -0
  52. package/dist/oauth/components/LogoutButton/index.scss +10 -0
  53. package/dist/oauth/defaults.d.ts +10 -0
  54. package/dist/oauth/defaults.d.ts.map +1 -0
  55. package/dist/oauth/defaults.js +91 -0
  56. package/dist/oauth/defaults.js.map +1 -0
  57. package/dist/oauth/endpoints/getLoginEndpoint.d.ts +13 -0
  58. package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -0
  59. package/dist/oauth/endpoints/getLoginEndpoint.js +237 -0
  60. package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -0
  61. package/dist/oauth/endpoints/getLogoutEndpoint.d.ts +12 -0
  62. package/dist/oauth/endpoints/getLogoutEndpoint.d.ts.map +1 -0
  63. package/dist/oauth/endpoints/getLogoutEndpoint.js +99 -0
  64. package/dist/oauth/endpoints/getLogoutEndpoint.js.map +1 -0
  65. package/dist/oauth/endpoints/getMetaEndpoint.d.ts +13 -0
  66. package/dist/oauth/endpoints/getMetaEndpoint.d.ts.map +1 -0
  67. package/dist/oauth/endpoints/getMetaEndpoint.js +25 -0
  68. package/dist/oauth/endpoints/getMetaEndpoint.js.map +1 -0
  69. package/dist/oauth/endpoints/getRedirectToLoginEndpoint.d.ts +13 -0
  70. package/dist/oauth/endpoints/getRedirectToLoginEndpoint.d.ts.map +1 -0
  71. package/dist/oauth/endpoints/getRedirectToLoginEndpoint.js +21 -0
  72. package/dist/oauth/endpoints/getRedirectToLoginEndpoint.js.map +1 -0
  73. package/dist/oauth/exports/client.d.ts +3 -0
  74. package/dist/oauth/exports/client.d.ts.map +1 -0
  75. package/dist/oauth/exports/client.js +4 -0
  76. package/dist/oauth/exports/client.js.map +1 -0
  77. package/dist/oauth/hooks/afterLogout.d.ts +8 -0
  78. package/dist/oauth/hooks/afterLogout.d.ts.map +1 -0
  79. package/dist/oauth/hooks/afterLogout.js +27 -0
  80. package/dist/oauth/hooks/afterLogout.js.map +1 -0
  81. package/dist/oauth/hooks/me.d.ts +5 -0
  82. package/dist/oauth/hooks/me.d.ts.map +1 -0
  83. package/dist/oauth/hooks/me.js +55 -0
  84. package/dist/oauth/hooks/me.js.map +1 -0
  85. package/dist/oauth/hooks/refresh.d.ts +8 -0
  86. package/dist/oauth/hooks/refresh.d.ts.map +1 -0
  87. package/dist/oauth/hooks/refresh.js +91 -0
  88. package/dist/oauth/hooks/refresh.js.map +1 -0
  89. package/dist/oauth/index.d.ts +4 -0
  90. package/dist/oauth/index.d.ts.map +1 -0
  91. package/dist/oauth/index.js +222 -0
  92. package/dist/oauth/index.js.map +1 -0
  93. package/dist/oauth/strategy/index.d.ts +54 -0
  94. package/dist/oauth/strategy/index.d.ts.map +1 -0
  95. package/dist/oauth/strategy/index.js +280 -0
  96. package/dist/oauth/strategy/index.js.map +1 -0
  97. package/dist/oauth/types.d.ts +192 -0
  98. package/dist/oauth/types.d.ts.map +1 -0
  99. package/dist/oauth/types.js +3 -0
  100. package/dist/oauth/types.js.map +1 -0
  101. package/dist/oauth/utilities/clearCookie.d.ts +9 -0
  102. package/dist/oauth/utilities/clearCookie.d.ts.map +1 -0
  103. package/dist/oauth/utilities/clearCookie.js +21 -0
  104. package/dist/oauth/utilities/clearCookie.js.map +1 -0
  105. package/dist/oauth/utilities/createCookieOptions.d.ts +10 -0
  106. package/dist/oauth/utilities/createCookieOptions.d.ts.map +1 -0
  107. package/dist/oauth/utilities/createCookieOptions.js +42 -0
  108. package/dist/oauth/utilities/createCookieOptions.js.map +1 -0
  109. package/dist/oauth/utilities/createDebugLogger.d.ts +4 -0
  110. package/dist/oauth/utilities/createDebugLogger.d.ts.map +1 -0
  111. package/dist/oauth/utilities/createDebugLogger.js +16 -0
  112. package/dist/oauth/utilities/createDebugLogger.js.map +1 -0
  113. package/dist/oauth/utilities/extractOrigin.d.ts +2 -0
  114. package/dist/oauth/utilities/extractOrigin.d.ts.map +1 -0
  115. package/dist/oauth/utilities/extractOrigin.js +12 -0
  116. package/dist/oauth/utilities/extractOrigin.js.map +1 -0
  117. package/dist/oauth/utilities/getAdminCollectionSlug.d.ts +3 -0
  118. package/dist/oauth/utilities/getAdminCollectionSlug.d.ts.map +1 -0
  119. package/dist/oauth/utilities/getAdminCollectionSlug.js +18 -0
  120. package/dist/oauth/utilities/getAdminCollectionSlug.js.map +1 -0
  121. package/dist/oauth/utilities/getAdminPath.d.ts +8 -0
  122. package/dist/oauth/utilities/getAdminPath.d.ts.map +1 -0
  123. package/dist/oauth/utilities/getAdminPath.js +9 -0
  124. package/dist/oauth/utilities/getAdminPath.js.map +1 -0
  125. package/dist/oauth/utilities/getAuthorizeURL.d.ts +17 -0
  126. package/dist/oauth/utilities/getAuthorizeURL.d.ts.map +1 -0
  127. package/dist/oauth/utilities/getAuthorizeURL.js +45 -0
  128. package/dist/oauth/utilities/getAuthorizeURL.js.map +1 -0
  129. package/dist/oauth/utilities/getCookieExpiration.d.ts +4 -0
  130. package/dist/oauth/utilities/getCookieExpiration.d.ts.map +1 -0
  131. package/dist/oauth/utilities/getCookieExpiration.js +11 -0
  132. package/dist/oauth/utilities/getCookieExpiration.js.map +1 -0
  133. package/dist/oauth/utilities/getSecondsFromTokenExp.d.ts +2 -0
  134. package/dist/oauth/utilities/getSecondsFromTokenExp.d.ts.map +1 -0
  135. package/dist/oauth/utilities/getSecondsFromTokenExp.js +7 -0
  136. package/dist/oauth/utilities/getSecondsFromTokenExp.js.map +1 -0
  137. package/dist/oauth/utilities/getTokenExp.d.ts +6 -0
  138. package/dist/oauth/utilities/getTokenExp.d.ts.map +1 -0
  139. package/dist/oauth/utilities/getTokenExp.js +20 -0
  140. package/dist/oauth/utilities/getTokenExp.js.map +1 -0
  141. package/dist/oauth/utilities/getUsernameField.d.ts +9 -0
  142. package/dist/oauth/utilities/getUsernameField.d.ts.map +1 -0
  143. package/dist/oauth/utilities/getUsernameField.js +20 -0
  144. package/dist/oauth/utilities/getUsernameField.js.map +1 -0
  145. package/dist/oauth/utilities/hasUserTokenPropsChanged.d.ts +8 -0
  146. package/dist/oauth/utilities/hasUserTokenPropsChanged.d.ts.map +1 -0
  147. package/dist/oauth/utilities/hasUserTokenPropsChanged.js +25 -0
  148. package/dist/oauth/utilities/hasUserTokenPropsChanged.js.map +1 -0
  149. package/dist/oauth/utilities/mergeHeaders.d.ts +2 -0
  150. package/dist/oauth/utilities/mergeHeaders.d.ts.map +1 -0
  151. package/dist/oauth/utilities/mergeHeaders.js +37 -0
  152. package/dist/oauth/utilities/mergeHeaders.js.map +1 -0
  153. package/dist/oauth/utilities/refreshTokens.d.ts +16 -0
  154. package/dist/oauth/utilities/refreshTokens.d.ts.map +1 -0
  155. package/dist/oauth/utilities/refreshTokens.js +67 -0
  156. package/dist/oauth/utilities/refreshTokens.js.map +1 -0
  157. package/dist/plugin/build-config.d.ts +7 -1
  158. package/dist/plugin/build-config.d.ts.map +1 -1
  159. package/dist/plugin/build-config.js +29 -2
  160. package/dist/plugin/build-config.js.map +1 -1
  161. package/dist/types/config.d.ts +0 -11
  162. package/dist/types/config.d.ts.map +1 -1
  163. package/dist/types/config.js +1 -1
  164. package/dist/types/config.js.map +1 -1
  165. package/dist/utils/config.d.ts +0 -22
  166. package/dist/utils/config.d.ts.map +1 -1
  167. package/dist/utils/config.js +0 -46
  168. package/dist/utils/config.js.map +1 -1
  169. package/dist/utils/messages.js +11 -11
  170. package/dist/utils/messages.js.map +1 -1
  171. package/dist/utils/payload-config-ast.d.ts +17 -1
  172. package/dist/utils/payload-config-ast.d.ts.map +1 -1
  173. package/dist/utils/payload-config-ast.js +166 -14
  174. package/dist/utils/payload-config-ast.js.map +1 -1
  175. package/dist/utils/payload-config-modifier.d.ts +2 -1
  176. package/dist/utils/payload-config-modifier.d.ts.map +1 -1
  177. package/dist/utils/payload-config-modifier.js +50 -79
  178. package/dist/utils/payload-config-modifier.js.map +1 -1
  179. package/dist/utils/payload-package-check.d.ts.map +1 -1
  180. package/dist/utils/payload-package-check.js +14 -33
  181. package/dist/utils/payload-package-check.js.map +1 -1
  182. package/dist/utils/project.d.ts +1 -1
  183. package/dist/utils/project.d.ts.map +1 -1
  184. package/dist/utils/project.js +3 -5
  185. package/dist/utils/project.js.map +1 -1
  186. package/dist/utils/s3-upload.d.ts.map +1 -1
  187. package/dist/utils/s3-upload.js +3 -8
  188. package/dist/utils/s3-upload.js.map +1 -1
  189. package/dist/utils/token-display.d.ts.map +1 -1
  190. package/dist/utils/token-display.js +3 -2
  191. package/dist/utils/token-display.js.map +1 -1
  192. package/package.json +9 -3
  193. package/dist/api/control-plane.spec.d.ts +0 -2
  194. package/dist/api/control-plane.spec.d.ts.map +0 -1
  195. package/dist/api/control-plane.spec.js +0 -296
  196. package/dist/api/control-plane.spec.js.map +0 -1
  197. package/dist/api/figma-api.spec.d.ts +0 -14
  198. package/dist/api/figma-api.spec.d.ts.map +0 -1
  199. package/dist/api/figma-api.spec.js +0 -201
  200. package/dist/api/figma-api.spec.js.map +0 -1
  201. package/dist/auth/__tests__/fixtures.d.ts +0 -26
  202. package/dist/auth/__tests__/fixtures.d.ts.map +0 -1
  203. package/dist/auth/__tests__/fixtures.js +0 -67
  204. package/dist/auth/__tests__/fixtures.js.map +0 -1
  205. package/dist/auth/__tests__/mocks.d.ts +0 -33
  206. package/dist/auth/__tests__/mocks.d.ts.map +0 -1
  207. package/dist/auth/__tests__/mocks.js +0 -63
  208. package/dist/auth/__tests__/mocks.js.map +0 -1
  209. package/dist/auth/callback-server.spec.d.ts +0 -2
  210. package/dist/auth/callback-server.spec.d.ts.map +0 -1
  211. package/dist/auth/callback-server.spec.js +0 -85
  212. package/dist/auth/callback-server.spec.js.map +0 -1
  213. package/dist/auth/crypto-utils.spec.d.ts +0 -2
  214. package/dist/auth/crypto-utils.spec.d.ts.map +0 -1
  215. package/dist/auth/crypto-utils.spec.js +0 -36
  216. package/dist/auth/crypto-utils.spec.js.map +0 -1
  217. package/dist/auth/jwt-validator.spec.d.ts +0 -10
  218. package/dist/auth/jwt-validator.spec.d.ts.map +0 -1
  219. package/dist/auth/jwt-validator.spec.js +0 -236
  220. package/dist/auth/jwt-validator.spec.js.map +0 -1
  221. package/dist/auth/oauth-flow.spec.d.ts +0 -2
  222. package/dist/auth/oauth-flow.spec.d.ts.map +0 -1
  223. package/dist/auth/oauth-flow.spec.js +0 -134
  224. package/dist/auth/oauth-flow.spec.js.map +0 -1
  225. package/dist/auth/pkce.spec.d.ts +0 -2
  226. package/dist/auth/pkce.spec.d.ts.map +0 -1
  227. package/dist/auth/pkce.spec.js +0 -32
  228. package/dist/auth/pkce.spec.js.map +0 -1
  229. package/dist/auth/project-token.spec.d.ts +0 -2
  230. package/dist/auth/project-token.spec.d.ts.map +0 -1
  231. package/dist/auth/project-token.spec.js +0 -332
  232. package/dist/auth/project-token.spec.js.map +0 -1
  233. package/dist/auth/refresh.spec.d.ts +0 -2
  234. package/dist/auth/refresh.spec.d.ts.map +0 -1
  235. package/dist/auth/refresh.spec.js +0 -105
  236. package/dist/auth/refresh.spec.js.map +0 -1
  237. package/dist/auth/token-store.spec.d.ts +0 -2
  238. package/dist/auth/token-store.spec.d.ts.map +0 -1
  239. package/dist/auth/token-store.spec.js +0 -276
  240. package/dist/auth/token-store.spec.js.map +0 -1
  241. package/dist/commands/__tests__/test-utils.d.ts +0 -28
  242. package/dist/commands/__tests__/test-utils.d.ts.map +0 -1
  243. package/dist/commands/__tests__/test-utils.js +0 -34
  244. package/dist/commands/__tests__/test-utils.js.map +0 -1
  245. package/dist/commands/deploy.spec.d.ts +0 -2
  246. package/dist/commands/deploy.spec.d.ts.map +0 -1
  247. package/dist/commands/deploy.spec.js +0 -18
  248. package/dist/commands/deploy.spec.js.map +0 -1
  249. package/dist/commands/init.spec.d.ts +0 -2
  250. package/dist/commands/init.spec.d.ts.map +0 -1
  251. package/dist/commands/init.spec.js +0 -283
  252. package/dist/commands/init.spec.js.map +0 -1
  253. package/dist/plugin/build-config.spec.d.ts +0 -2
  254. package/dist/plugin/build-config.spec.d.ts.map +0 -1
  255. package/dist/plugin/build-config.spec.js +0 -72
  256. package/dist/plugin/build-config.spec.js.map +0 -1
  257. package/dist/utils/asset-collection.spec.d.ts +0 -2
  258. package/dist/utils/asset-collection.spec.d.ts.map +0 -1
  259. package/dist/utils/asset-collection.spec.js +0 -155
  260. package/dist/utils/asset-collection.spec.js.map +0 -1
  261. package/dist/utils/build-detection.spec.d.ts +0 -2
  262. package/dist/utils/build-detection.spec.d.ts.map +0 -1
  263. package/dist/utils/build-detection.spec.js +0 -110
  264. package/dist/utils/build-detection.spec.js.map +0 -1
  265. package/dist/utils/config.spec.d.ts +0 -2
  266. package/dist/utils/config.spec.d.ts.map +0 -1
  267. package/dist/utils/config.spec.js +0 -167
  268. package/dist/utils/config.spec.js.map +0 -1
  269. package/dist/utils/download-template.spec.d.ts +0 -2
  270. package/dist/utils/download-template.spec.d.ts.map +0 -1
  271. package/dist/utils/download-template.spec.js +0 -76
  272. package/dist/utils/download-template.spec.js.map +0 -1
  273. package/dist/utils/env-management.spec.d.ts +0 -2
  274. package/dist/utils/env-management.spec.d.ts.map +0 -1
  275. package/dist/utils/env-management.spec.js +0 -123
  276. package/dist/utils/env-management.spec.js.map +0 -1
  277. package/dist/utils/git.spec.d.ts +0 -2
  278. package/dist/utils/git.spec.d.ts.map +0 -1
  279. package/dist/utils/git.spec.js +0 -99
  280. package/dist/utils/git.spec.js.map +0 -1
  281. package/dist/utils/lambda-config.spec.d.ts +0 -2
  282. package/dist/utils/lambda-config.spec.d.ts.map +0 -1
  283. package/dist/utils/lambda-config.spec.js +0 -141
  284. package/dist/utils/lambda-config.spec.js.map +0 -1
  285. package/dist/utils/payload-config-ast.spec.d.ts +0 -2
  286. package/dist/utils/payload-config-ast.spec.d.ts.map +0 -1
  287. package/dist/utils/payload-config-ast.spec.js +0 -303
  288. package/dist/utils/payload-config-ast.spec.js.map +0 -1
  289. package/dist/utils/payload-config-modifier.int.spec.d.ts +0 -2
  290. package/dist/utils/payload-config-modifier.int.spec.d.ts.map +0 -1
  291. package/dist/utils/payload-config-modifier.int.spec.js +0 -116
  292. package/dist/utils/payload-config-modifier.int.spec.js.map +0 -1
  293. package/dist/utils/payload-config-modifier.spec.d.ts +0 -2
  294. package/dist/utils/payload-config-modifier.spec.d.ts.map +0 -1
  295. package/dist/utils/payload-config-modifier.spec.js +0 -162
  296. package/dist/utils/payload-config-modifier.spec.js.map +0 -1
  297. package/dist/utils/payload-package-check.spec.d.ts +0 -2
  298. package/dist/utils/payload-package-check.spec.d.ts.map +0 -1
  299. package/dist/utils/payload-package-check.spec.js +0 -148
  300. package/dist/utils/payload-package-check.spec.js.map +0 -1
  301. package/dist/utils/project.spec.d.ts +0 -2
  302. package/dist/utils/project.spec.d.ts.map +0 -1
  303. package/dist/utils/project.spec.js +0 -222
  304. package/dist/utils/project.spec.js.map +0 -1
  305. package/dist/utils/s3-upload.spec.d.ts +0 -2
  306. package/dist/utils/s3-upload.spec.d.ts.map +0 -1
  307. package/dist/utils/s3-upload.spec.js +0 -140
  308. package/dist/utils/s3-upload.spec.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"control-plane.d.ts","sourceRoot":"","sources":["../../src/api/control-plane.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAqBhD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,UAAU,CAAC,EAAE,MAAM;IACnB,KAAK,CAAC,EAAE,KAAK;gBAFpB,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAA;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAA;IACrB,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE;QACJ,eAAe,EAAE,MAAM,CAAA;QACvB,aAAa,EAAE,MAAM,CAAA;QACrB,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACjD,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAA;IACpB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE;QACJ,aAAa,EAAE,MAAM,CAAA;QACrB,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyCxE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAuCjB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgC7F;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CA4DnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CA0CpC"}
1
+ {"version":3,"file":"control-plane.d.ts","sourceRoot":"","sources":["../../src/api/control-plane.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAoBhD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,UAAU,CAAC,EAAE,MAAM;IACnB,KAAK,CAAC,EAAE,KAAK;gBAFpB,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAA;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAA;IACrB,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE;QACJ,eAAe,EAAE,MAAM,CAAA;QACvB,aAAa,EAAE,MAAM,CAAA;QACrB,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACjD,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAA;IACpB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE;QACJ,aAAa,EAAE,MAAM,CAAA;QACrB,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyCxE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAuCjB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgC7F;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CA0DnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CAwCpC"}
@@ -3,7 +3,6 @@
3
3
  *
4
4
  * TODO: Replace with real API calls when Control Plane is available
5
5
  */ import { getEnvironment } from '../constants.js';
6
- import { isDebug } from '../utils/is-debug.js';
7
6
  import * as log from '../utils/log.js';
8
7
  /**
9
8
  * Control Plane API base URLs
@@ -156,9 +155,7 @@ import * as log from '../utils/log.js';
156
155
  const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
157
156
  if (shouldMock) {
158
157
  // MOCK IMPLEMENTATION: Generate mock deployment and signed URLs
159
- if (isDebug()) {
160
- log.debug('Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
161
- }
158
+ log.debug('Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
162
159
  const deploymentId = `deploy_${Math.random().toString(36).substring(2, 11)}`;
163
160
  const mockBucket = 'figma-cms-deployments-mock';
164
161
  const mockRegion = 'us-west-2';
@@ -212,9 +209,7 @@ import * as log from '../utils/log.js';
212
209
  const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
213
210
  if (shouldMock) {
214
211
  // MOCK IMPLEMENTATION: Return mock deployment status
215
- if (isDebug()) {
216
- log.debug('Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
217
- }
212
+ log.debug('Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
218
213
  return {
219
214
  deploymentId: options.deploymentId,
220
215
  message: 'Deployment initiated successfully'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/api/control-plane.ts"],"sourcesContent":["/**\n * Control Plane API Client\n *\n * TODO: Replace with real API calls when Control Plane is available\n */\n\nimport type { Tenant } from '../types/config.js'\n\nimport { getEnvironment } from '../constants.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\n\n/**\n * Control Plane API base URLs\n */\nconst CONTROL_PLANE_API_URLS = {\n production: 'https://api.figma.com',\n staging: 'https://api.staging.figma.com',\n}\n\n/**\n * Get the Control Plane API base URL based on environment\n */\nfunction getControlPlaneBaseUrl(): string {\n return process.env.FIGMA_API_BASE_URL || CONTROL_PLANE_API_URLS[getEnvironment()]\n}\n\n/**\n * Error thrown when Control Plane API calls fail\n */\nexport class ControlPlaneError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'ControlPlaneError'\n }\n}\n\n/**\n * Options for creating a new tenant\n */\nexport interface CreateTenantOptions {\n /** Name for the new CMS instance */\n name: string\n /** Optional parent ID */\n parentId?: string\n /** Optional parent type */\n parentType?: 'org' | 'team' | 'workspace'\n}\n\n/**\n * Options for creating a new deployment\n */\nexport interface CreateDeploymentOptions {\n /** List of static asset paths that need upload URLs */\n staticAssets: string[]\n}\n\n/**\n * Response from creating a new deployment\n */\nexport interface CreateDeploymentResponse {\n /** Upload URL for the Lambda function code zip */\n codeUploadUrl: string\n /** Unique deployment ID */\n deploymentId: string\n /** Map of static asset paths to their signed S3 upload URLs */\n staticAssetUploadUrls: Record<string, string>\n}\n\nexport interface CreateDeploymentApiResponse {\n error: boolean\n meta: {\n code_upload_url: string\n deployment_id: string\n static_asset_upload_urls: Record<string, string>\n }\n status: number\n}\n\n/**\n * Options for performing a deployment\n */\nexport interface PerformDeploymentOptions {\n /** Deployment ID from createDeployment */\n deploymentId: string\n}\n\n/**\n * Response from performing a deployment\n */\nexport interface PerformDeploymentResponse {\n /** Deployment ID that was deployed */\n deploymentId: string\n /** Status message */\n message: string\n}\n\nexport interface PerformDeploymentApiResponse {\n error: boolean\n meta: {\n deployment_id: string\n message: string\n status: string\n }\n status: number\n}\n\n/**\n * List all tenant instances for the authenticated user\n * Maps to: GET /v1/tenant\n *\n * @param accessToken - OAuth access token\n * @returns Array of tenant instances\n */\nexport async function listTenants(accessToken: string): Promise<Tenant[]> {\n // Check if control plane API should be mocked\n // Default to true until real API is available\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return sample tenants for testing\n log.debug('Using mock Control Plane API for listTenants (FIGMA_MOCK_CONTROL_PLANE != \"false\")')\n return [\n {\n id: 'tenant_abc123',\n createdAt: '2025-01-15T10:00:00Z',\n domain: 'my-blog.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n },\n {\n id: 'tenant_def456',\n createdAt: '2025-01-10T14:30:00Z',\n domain: 'my-store.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n },\n ]\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to list tenants: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Create a new tenant instance\n * Maps to: POST /v1/tenant\n *\n * @param accessToken - OAuth access token\n * @param options - Tenant creation options\n * @returns Newly created tenant\n */\nexport async function createTenant(\n accessToken: string,\n options: CreateTenantOptions,\n): Promise<Tenant> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate mock tenant for testing\n log.debug('Using mock Control Plane API for createTenant (FIGMA_MOCK_CONTROL_PLANE != \"false\")')\n const tenantId = `tenant_${Math.random().toString(36).substring(2, 11)}`\n const slug = options.name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const domain = `${slug}.figmacms.com`\n\n return {\n id: tenantId,\n createdAt: new Date().toISOString(),\n domain,\n parentId: options.parentId || 'team_456',\n parentType: options.parentType || 'team',\n status: 'provisioning',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant`, {\n body: JSON.stringify({ name: options.name }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to create tenant: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Get details for a specific tenant\n * Maps to: GET /v1/tenant/{tenant_id}\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @returns Tenant details\n */\nexport async function getTenantDetails(accessToken: string, tenantId: string): Promise<Tenant> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock tenant details for testing\n log.debug(\n 'Using mock Control Plane API for getTenantDetails (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n return {\n id: tenantId,\n createdAt: '2025-01-15T10:00:00Z',\n domain: 'example.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to get tenant details: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Create a new deployment and get signed upload URLs\n * Maps to: POST /v1/tenant/{tenant_id}/deploy/create\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @param options - Deployment creation options\n * @returns Deployment ID and upload URLs\n */\nexport async function createDeployment(\n accessToken: string,\n tenantId: string,\n options: CreateDeploymentOptions,\n): Promise<CreateDeploymentResponse> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate mock deployment and signed URLs\n if (isDebug()) {\n log.debug(\n 'Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n }\n\n const deploymentId = `deploy_${Math.random().toString(36).substring(2, 11)}`\n const mockBucket = 'figma-cms-deployments-mock'\n const mockRegion = 'us-west-2'\n const mockBaseUrl = `https://${mockBucket}.s3.${mockRegion}.amazonaws.com`\n\n // Generate mock signed URLs for static assets\n const staticAssetUploadUrls: Record<string, string> = {}\n for (const assetPath of options.staticAssets) {\n const encodedPath = encodeURIComponent(assetPath)\n staticAssetUploadUrls[assetPath] =\n `${mockBaseUrl}/${tenantId}/${deploymentId}/static/${encodedPath}?X-Amz-Signature=mock`\n }\n\n // Generate mock signed URL for code zip\n const codeUploadUrl = `${mockBaseUrl}/${tenantId}/${deploymentId}/lambda.zip?X-Amz-Signature=mock`\n\n return {\n codeUploadUrl,\n deploymentId,\n staticAssetUploadUrls,\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/create`, {\n body: JSON.stringify({ static_assets: options.staticAssets }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to create deployment: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as CreateDeploymentApiResponse\n\n // Map API response format to our interface\n return {\n codeUploadUrl: data.meta.code_upload_url,\n deploymentId: data.meta.deployment_id,\n staticAssetUploadUrls: data.meta.static_asset_upload_urls,\n }\n}\n\n/**\n * Perform deployment for a created deployment ID\n * Maps to: POST /v1/tenant/{tenant_id}/deploy/perform\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @param options - Deployment perform options\n * @returns Deployment status and message\n */\nexport async function performDeployment(\n accessToken: string,\n tenantId: string,\n options: PerformDeploymentOptions,\n): Promise<PerformDeploymentResponse> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock deployment status\n if (isDebug()) {\n log.debug(\n 'Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n }\n\n return {\n deploymentId: options.deploymentId,\n message: 'Deployment initiated successfully',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/perform`, {\n body: JSON.stringify({ deployment_id: options.deploymentId }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to perform deployment: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as PerformDeploymentApiResponse\n\n // Map API response to our interface\n return {\n deploymentId: data.meta.deployment_id,\n message: data.meta.message || 'Deployment initiated',\n }\n}\n"],"names":["getEnvironment","isDebug","log","CONTROL_PLANE_API_URLS","production","staging","getControlPlaneBaseUrl","process","env","FIGMA_API_BASE_URL","ControlPlaneError","Error","message","statusCode","cause","name","listTenants","accessToken","shouldMock","FIGMA_MOCK_CONTROL_PLANE","debug","id","createdAt","domain","parentId","parentType","status","response","fetch","headers","Authorization","ok","statusText","json","createTenant","options","tenantId","Math","random","toString","substring","slug","toLowerCase","replace","Date","toISOString","body","JSON","stringify","method","getTenantDetails","createDeployment","deploymentId","mockBucket","mockRegion","mockBaseUrl","staticAssetUploadUrls","assetPath","staticAssets","encodedPath","encodeURIComponent","codeUploadUrl","static_assets","data","meta","code_upload_url","deployment_id","static_asset_upload_urls","performDeployment"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/api/control-plane.ts"],"sourcesContent":["/**\n * Control Plane API Client\n *\n * TODO: Replace with real API calls when Control Plane is available\n */\n\nimport type { Tenant } from '../types/config.js'\n\nimport { getEnvironment } from '../constants.js'\nimport * as log from '../utils/log.js'\n\n/**\n * Control Plane API base URLs\n */\nconst CONTROL_PLANE_API_URLS = {\n production: 'https://api.figma.com',\n staging: 'https://api.staging.figma.com',\n}\n\n/**\n * Get the Control Plane API base URL based on environment\n */\nfunction getControlPlaneBaseUrl(): string {\n return process.env.FIGMA_API_BASE_URL || CONTROL_PLANE_API_URLS[getEnvironment()]\n}\n\n/**\n * Error thrown when Control Plane API calls fail\n */\nexport class ControlPlaneError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'ControlPlaneError'\n }\n}\n\n/**\n * Options for creating a new tenant\n */\nexport interface CreateTenantOptions {\n /** Name for the new CMS instance */\n name: string\n /** Optional parent ID */\n parentId?: string\n /** Optional parent type */\n parentType?: 'org' | 'team' | 'workspace'\n}\n\n/**\n * Options for creating a new deployment\n */\nexport interface CreateDeploymentOptions {\n /** List of static asset paths that need upload URLs */\n staticAssets: string[]\n}\n\n/**\n * Response from creating a new deployment\n */\nexport interface CreateDeploymentResponse {\n /** Upload URL for the Lambda function code zip */\n codeUploadUrl: string\n /** Unique deployment ID */\n deploymentId: string\n /** Map of static asset paths to their signed S3 upload URLs */\n staticAssetUploadUrls: Record<string, string>\n}\n\nexport interface CreateDeploymentApiResponse {\n error: boolean\n meta: {\n code_upload_url: string\n deployment_id: string\n static_asset_upload_urls: Record<string, string>\n }\n status: number\n}\n\n/**\n * Options for performing a deployment\n */\nexport interface PerformDeploymentOptions {\n /** Deployment ID from createDeployment */\n deploymentId: string\n}\n\n/**\n * Response from performing a deployment\n */\nexport interface PerformDeploymentResponse {\n /** Deployment ID that was deployed */\n deploymentId: string\n /** Status message */\n message: string\n}\n\nexport interface PerformDeploymentApiResponse {\n error: boolean\n meta: {\n deployment_id: string\n message: string\n status: string\n }\n status: number\n}\n\n/**\n * List all tenant instances for the authenticated user\n * Maps to: GET /v1/tenant\n *\n * @param accessToken - OAuth access token\n * @returns Array of tenant instances\n */\nexport async function listTenants(accessToken: string): Promise<Tenant[]> {\n // Check if control plane API should be mocked\n // Default to true until real API is available\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return sample tenants for testing\n log.debug('Using mock Control Plane API for listTenants (FIGMA_MOCK_CONTROL_PLANE != \"false\")')\n return [\n {\n id: 'tenant_abc123',\n createdAt: '2025-01-15T10:00:00Z',\n domain: 'my-blog.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n },\n {\n id: 'tenant_def456',\n createdAt: '2025-01-10T14:30:00Z',\n domain: 'my-store.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n },\n ]\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to list tenants: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Create a new tenant instance\n * Maps to: POST /v1/tenant\n *\n * @param accessToken - OAuth access token\n * @param options - Tenant creation options\n * @returns Newly created tenant\n */\nexport async function createTenant(\n accessToken: string,\n options: CreateTenantOptions,\n): Promise<Tenant> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate mock tenant for testing\n log.debug('Using mock Control Plane API for createTenant (FIGMA_MOCK_CONTROL_PLANE != \"false\")')\n const tenantId = `tenant_${Math.random().toString(36).substring(2, 11)}`\n const slug = options.name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const domain = `${slug}.figmacms.com`\n\n return {\n id: tenantId,\n createdAt: new Date().toISOString(),\n domain,\n parentId: options.parentId || 'team_456',\n parentType: options.parentType || 'team',\n status: 'provisioning',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant`, {\n body: JSON.stringify({ name: options.name }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to create tenant: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Get details for a specific tenant\n * Maps to: GET /v1/tenant/{tenant_id}\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @returns Tenant details\n */\nexport async function getTenantDetails(accessToken: string, tenantId: string): Promise<Tenant> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock tenant details for testing\n log.debug(\n 'Using mock Control Plane API for getTenantDetails (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n return {\n id: tenantId,\n createdAt: '2025-01-15T10:00:00Z',\n domain: 'example.figmacms.com',\n parentId: 'team_456',\n parentType: 'team',\n status: 'active',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to get tenant details: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json()\n}\n\n/**\n * Create a new deployment and get signed upload URLs\n * Maps to: POST /v1/tenant/{tenant_id}/deploy/create\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @param options - Deployment creation options\n * @returns Deployment ID and upload URLs\n */\nexport async function createDeployment(\n accessToken: string,\n tenantId: string,\n options: CreateDeploymentOptions,\n): Promise<CreateDeploymentResponse> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate mock deployment and signed URLs\n log.debug(\n 'Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n\n const deploymentId = `deploy_${Math.random().toString(36).substring(2, 11)}`\n const mockBucket = 'figma-cms-deployments-mock'\n const mockRegion = 'us-west-2'\n const mockBaseUrl = `https://${mockBucket}.s3.${mockRegion}.amazonaws.com`\n\n // Generate mock signed URLs for static assets\n const staticAssetUploadUrls: Record<string, string> = {}\n for (const assetPath of options.staticAssets) {\n const encodedPath = encodeURIComponent(assetPath)\n staticAssetUploadUrls[assetPath] =\n `${mockBaseUrl}/${tenantId}/${deploymentId}/static/${encodedPath}?X-Amz-Signature=mock`\n }\n\n // Generate mock signed URL for code zip\n const codeUploadUrl = `${mockBaseUrl}/${tenantId}/${deploymentId}/lambda.zip?X-Amz-Signature=mock`\n\n return {\n codeUploadUrl,\n deploymentId,\n staticAssetUploadUrls,\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/create`, {\n body: JSON.stringify({ static_assets: options.staticAssets }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to create deployment: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as CreateDeploymentApiResponse\n\n // Map API response format to our interface\n return {\n codeUploadUrl: data.meta.code_upload_url,\n deploymentId: data.meta.deployment_id,\n staticAssetUploadUrls: data.meta.static_asset_upload_urls,\n }\n}\n\n/**\n * Perform deployment for a created deployment ID\n * Maps to: POST /v1/tenant/{tenant_id}/deploy/perform\n *\n * @param accessToken - OAuth access token\n * @param tenantId - Tenant ID\n * @param options - Deployment perform options\n * @returns Deployment status and message\n */\nexport async function performDeployment(\n accessToken: string,\n tenantId: string,\n options: PerformDeploymentOptions,\n): Promise<PerformDeploymentResponse> {\n // Check if control plane API should be mocked\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock deployment status\n log.debug(\n 'Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE != \"false\")',\n )\n\n return {\n deploymentId: options.deploymentId,\n message: 'Deployment initiated successfully',\n }\n }\n\n // REAL API IMPLEMENTATION\n const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/perform`, {\n body: JSON.stringify({ deployment_id: options.deploymentId }),\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new ControlPlaneError(\n `Failed to perform deployment: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as PerformDeploymentApiResponse\n\n // Map API response to our interface\n return {\n deploymentId: data.meta.deployment_id,\n message: data.meta.message || 'Deployment initiated',\n }\n}\n"],"names":["getEnvironment","log","CONTROL_PLANE_API_URLS","production","staging","getControlPlaneBaseUrl","process","env","FIGMA_API_BASE_URL","ControlPlaneError","Error","message","statusCode","cause","name","listTenants","accessToken","shouldMock","FIGMA_MOCK_CONTROL_PLANE","debug","id","createdAt","domain","parentId","parentType","status","response","fetch","headers","Authorization","ok","statusText","json","createTenant","options","tenantId","Math","random","toString","substring","slug","toLowerCase","replace","Date","toISOString","body","JSON","stringify","method","getTenantDetails","createDeployment","deploymentId","mockBucket","mockRegion","mockBaseUrl","staticAssetUploadUrls","assetPath","staticAssets","encodedPath","encodeURIComponent","codeUploadUrl","static_assets","data","meta","code_upload_url","deployment_id","static_asset_upload_urls","performDeployment"],"mappings":"AAAA;;;;CAIC,GAID,SAASA,cAAc,QAAQ,kBAAiB;AAChD,YAAYC,SAAS,kBAAiB;AAEtC;;CAEC,GACD,MAAMC,yBAAyB;IAC7BC,YAAY;IACZC,SAAS;AACX;AAEA;;CAEC,GACD,SAASC;IACP,OAAOC,QAAQC,GAAG,CAACC,kBAAkB,IAAIN,sBAAsB,CAACF,iBAAiB;AACnF;AAEA;;CAEC,GACD,OAAO,MAAMS,0BAA0BC;;;IACrC,YACEC,OAAe,EACf,AAAOC,UAAmB,EAC1B,AAAOC,KAAa,CACpB;QACA,KAAK,CAACF,eAHCC,aAAAA,iBACAC,QAAAA;QAGP,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAwEA;;;;;;CAMC,GACD,OAAO,eAAeC,YAAYC,WAAmB;IACnD,8CAA8C;IAC9C,8CAA8C;IAC9C,MAAMC,aAAaX,QAAQC,GAAG,CAACW,wBAAwB,KAAK;IAE5D,IAAID,YAAY;QACd,yDAAyD;QACzDhB,IAAIkB,KAAK,CAAC;QACV,OAAO;YACL;gBACEC,IAAI;gBACJC,WAAW;gBACXC,QAAQ;gBACRC,UAAU;gBACVC,YAAY;gBACZC,QAAQ;YACV;YACA;gBACEL,IAAI;gBACJC,WAAW;gBACXC,QAAQ;gBACRC,UAAU;gBACVC,YAAY;gBACZC,QAAQ;YACV;SACD;IACH;IAEA,0BAA0B;IAC1B,MAAMC,WAAW,MAAMC,MAAM,GAAGtB,yBAAyB,UAAU,CAAC,EAAE;QACpEuB,SAAS;YAAEC,eAAe,CAAC,OAAO,EAAEb,aAAa;QAAC;IACpD;IAEA,IAAI,CAACU,SAASI,EAAE,EAAE;QAChB,MAAM,IAAIrB,kBACR,CAAC,wBAAwB,EAAEiB,SAASD,MAAM,CAAC,CAAC,EAAEC,SAASK,UAAU,EAAE,EACnEL,SAASD,MAAM;IAEnB;IAEA,OAAOC,SAASM,IAAI;AACtB;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeC,aACpBjB,WAAmB,EACnBkB,OAA4B;IAE5B,8CAA8C;IAC9C,MAAMjB,aAAaX,QAAQC,GAAG,CAACW,wBAAwB,KAAK;IAE5D,IAAID,YAAY;QACd,wDAAwD;QACxDhB,IAAIkB,KAAK,CAAC;QACV,MAAMgB,WAAW,CAAC,OAAO,EAAEC,KAAKC,MAAM,GAAGC,QAAQ,CAAC,IAAIC,SAAS,CAAC,GAAG,KAAK;QACxE,MAAMC,OAAON,QAAQpB,IAAI,CAAC2B,WAAW,GAAGC,OAAO,CAAC,eAAe;QAC/D,MAAMpB,SAAS,GAAGkB,KAAK,aAAa,CAAC;QAErC,OAAO;YACLpB,IAAIe;YACJd,WAAW,IAAIsB,OAAOC,WAAW;YACjCtB;YACAC,UAAUW,QAAQX,QAAQ,IAAI;YAC9BC,YAAYU,QAAQV,UAAU,IAAI;YAClCC,QAAQ;QACV;IACF;IAEA,0BAA0B;IAC1B,MAAMC,WAAW,MAAMC,MAAM,GAAGtB,yBAAyB,UAAU,CAAC,EAAE;QACpEwC,MAAMC,KAAKC,SAAS,CAAC;YAAEjC,MAAMoB,QAAQpB,IAAI;QAAC;QAC1Cc,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEb,aAAa;YACtC,gBAAgB;QAClB;QACAgC,QAAQ;IACV;IAEA,IAAI,CAACtB,SAASI,EAAE,EAAE;QAChB,MAAM,IAAIrB,kBACR,CAAC,yBAAyB,EAAEiB,SAASD,MAAM,CAAC,CAAC,EAAEC,SAASK,UAAU,EAAE,EACpEL,SAASD,MAAM;IAEnB;IAEA,OAAOC,SAASM,IAAI;AACtB;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeiB,iBAAiBjC,WAAmB,EAAEmB,QAAgB;IAC1E,8CAA8C;IAC9C,MAAMlB,aAAaX,QAAQC,GAAG,CAACW,wBAAwB,KAAK;IAE5D,IAAID,YAAY;QACd,8DAA8D;QAC9DhB,IAAIkB,KAAK,CACP;QAEF,OAAO;YACLC,IAAIe;YACJd,WAAW;YACXC,QAAQ;YACRC,UAAU;YACVC,YAAY;YACZC,QAAQ;QACV;IACF;IAEA,0BAA0B;IAC1B,MAAMC,WAAW,MAAMC,MAAM,GAAGtB,yBAAyB,WAAW,EAAE8B,UAAU,EAAE;QAChFP,SAAS;YAAEC,eAAe,CAAC,OAAO,EAAEb,aAAa;QAAC;IACpD;IAEA,IAAI,CAACU,SAASI,EAAE,EAAE;QAChB,MAAM,IAAIrB,kBACR,CAAC,8BAA8B,EAAEiB,SAASD,MAAM,CAAC,CAAC,EAAEC,SAASK,UAAU,EAAE,EACzEL,SAASD,MAAM;IAEnB;IAEA,OAAOC,SAASM,IAAI;AACtB;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAekB,iBACpBlC,WAAmB,EACnBmB,QAAgB,EAChBD,OAAgC;IAEhC,8CAA8C;IAC9C,MAAMjB,aAAaX,QAAQC,GAAG,CAACW,wBAAwB,KAAK;IAE5D,IAAID,YAAY;QACd,gEAAgE;QAChEhB,IAAIkB,KAAK,CACP;QAGF,MAAMgC,eAAe,CAAC,OAAO,EAAEf,KAAKC,MAAM,GAAGC,QAAQ,CAAC,IAAIC,SAAS,CAAC,GAAG,KAAK;QAC5E,MAAMa,aAAa;QACnB,MAAMC,aAAa;QACnB,MAAMC,cAAc,CAAC,QAAQ,EAAEF,WAAW,IAAI,EAAEC,WAAW,cAAc,CAAC;QAE1E,8CAA8C;QAC9C,MAAME,wBAAgD,CAAC;QACvD,KAAK,MAAMC,aAAatB,QAAQuB,YAAY,CAAE;YAC5C,MAAMC,cAAcC,mBAAmBH;YACvCD,qBAAqB,CAACC,UAAU,GAC9B,GAAGF,YAAY,CAAC,EAAEnB,SAAS,CAAC,EAAEgB,aAAa,QAAQ,EAAEO,YAAY,qBAAqB,CAAC;QAC3F;QAEA,wCAAwC;QACxC,MAAME,gBAAgB,GAAGN,YAAY,CAAC,EAAEnB,SAAS,CAAC,EAAEgB,aAAa,gCAAgC,CAAC;QAElG,OAAO;YACLS;YACAT;YACAI;QACF;IACF;IAEA,0BAA0B;IAC1B,MAAM7B,WAAW,MAAMC,MAAM,GAAGtB,yBAAyB,WAAW,EAAE8B,SAAS,cAAc,CAAC,EAAE;QAC9FU,MAAMC,KAAKC,SAAS,CAAC;YAAEc,eAAe3B,QAAQuB,YAAY;QAAC;QAC3D7B,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEb,aAAa;YACtC,gBAAgB;QAClB;QACAgC,QAAQ;IACV;IAEA,IAAI,CAACtB,SAASI,EAAE,EAAE;QAChB,MAAM,IAAIrB,kBACR,CAAC,6BAA6B,EAAEiB,SAASD,MAAM,CAAC,CAAC,EAAEC,SAASK,UAAU,EAAE,EACxEL,SAASD,MAAM;IAEnB;IAEA,MAAMqC,OAAQ,MAAMpC,SAASM,IAAI;IAEjC,2CAA2C;IAC3C,OAAO;QACL4B,eAAeE,KAAKC,IAAI,CAACC,eAAe;QACxCb,cAAcW,KAAKC,IAAI,CAACE,aAAa;QACrCV,uBAAuBO,KAAKC,IAAI,CAACG,wBAAwB;IAC3D;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeC,kBACpBnD,WAAmB,EACnBmB,QAAgB,EAChBD,OAAiC;IAEjC,8CAA8C;IAC9C,MAAMjB,aAAaX,QAAQC,GAAG,CAACW,wBAAwB,KAAK;IAE5D,IAAID,YAAY;QACd,qDAAqD;QACrDhB,IAAIkB,KAAK,CACP;QAGF,OAAO;YACLgC,cAAcjB,QAAQiB,YAAY;YAClCxC,SAAS;QACX;IACF;IAEA,0BAA0B;IAC1B,MAAMe,WAAW,MAAMC,MAAM,GAAGtB,yBAAyB,WAAW,EAAE8B,SAAS,eAAe,CAAC,EAAE;QAC/FU,MAAMC,KAAKC,SAAS,CAAC;YAAEkB,eAAe/B,QAAQiB,YAAY;QAAC;QAC3DvB,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEb,aAAa;YACtC,gBAAgB;QAClB;QACAgC,QAAQ;IACV;IAEA,IAAI,CAACtB,SAASI,EAAE,EAAE;QAChB,MAAM,IAAIrB,kBACR,CAAC,8BAA8B,EAAEiB,SAASD,MAAM,CAAC,CAAC,EAAEC,SAASK,UAAU,EAAE,EACzEL,SAASD,MAAM;IAEnB;IAEA,MAAMqC,OAAQ,MAAMpC,SAASM,IAAI;IAEjC,oCAAoC;IACpC,OAAO;QACLmB,cAAcW,KAAKC,IAAI,CAACE,aAAa;QACrCtD,SAASmD,KAAKC,IAAI,CAACpD,OAAO,IAAI;IAChC;AACF"}
@@ -42,12 +42,12 @@
42
42
  * @throws {FigmaApiError} If the API call fails
43
43
  */ export async function getProjectToken(accessToken, tenantId) {
44
44
  // Check if project token API should be mocked
45
- // Default to true until real API is available
46
- const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false';
45
+ // Default to false (use real API)
46
+ const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN === 'true';
47
47
  try {
48
48
  if (shouldMock) {
49
49
  // MOCK IMPLEMENTATION: Generate a mock JWT token for testing
50
- log.debug('Using mock project token API for getProjectToken (FIGMA_MOCK_PROJECT_TOKEN != "false")');
50
+ log.debug('Using mock project token API for getProjectToken (FIGMA_MOCK_PROJECT_TOKEN = "true")');
51
51
  const mockToken = createMockJWT(tenantId, 25) // 25 minutes expiry
52
52
  ;
53
53
  // Mock response data
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/api/figma-api.ts"],"sourcesContent":["/**\n * Figma API Client\n *\n * Client for Figma REST API (Pixie) endpoints\n * Handles project token generation and other CMS-related API calls\n */\n\nimport type { ProjectToken, ProjectTokenResponse } from '../auth/types.js'\n\nimport * as log from '../utils/log.js'\n\n/**\n * Error thrown when Figma API calls fail\n */\nexport class FigmaApiError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'FigmaApiError'\n }\n}\n\n/**\n * Base URLs for Figma API\n */\nconst API_BASE_URLS = {\n prod: 'https://api.figma.com',\n staging: 'https://api.staging.figma.com',\n}\n\n/**\n * Get the Figma API base URL based on environment\n * TODO: Use this once real API endpoints are available\n */\nfunction _getApiBaseUrl(): string {\n // For now, default to staging to match OAuth config\n return process.env.FIGMA_API_BASE_URL || API_BASE_URLS.staging\n}\n\n/**\n * Get a project token (JWT) for a specific tenant/CMS\n *\n * This token is used by local Payload instances to authenticate\n * requests to the Content API. The token contains the CMS ID and\n * user identifying information in its claims.\n *\n * Endpoint: GET https://api.figma.com/v1/cms/:id/token/\n *\n * @param accessToken - OAuth access token for authentication\n * @param tenantId - The tenant/CMS ID\n * @returns ProjectToken with JWT and expiry information\n * @throws {FigmaApiError} If the API call fails\n */\nexport async function getProjectToken(\n accessToken: string,\n tenantId: string,\n): Promise<ProjectToken> {\n // Check if project token API should be mocked\n // Default to true until real API is available\n const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false'\n\n try {\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate a mock JWT token for testing\n log.debug(\n 'Using mock project token API for getProjectToken (FIGMA_MOCK_PROJECT_TOKEN != \"false\")',\n )\n const mockToken = createMockJWT(tenantId, 25) // 25 minutes expiry\n\n // Mock response data\n const data: ProjectTokenResponse = {\n meta: {\n token: mockToken,\n },\n }\n\n if (!data.meta?.token) {\n throw new FigmaApiError('Invalid response: missing token in meta')\n }\n\n // Parse the JWT to extract expiry (it's in the payload)\n const expiresAt = parseJwtExpiry(data.meta.token)\n\n return {\n expiresAt,\n tenantId,\n token: data.meta.token,\n }\n }\n\n // REAL API IMPLEMENTATION\n const baseUrl = _getApiBaseUrl()\n const url = `${baseUrl}/v1/cms/${tenantId}/token/`\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n // Handle error responses\n let errorMessage = `Failed to get project token: ${response.status} ${response.statusText}`\n\n try {\n const errorBody = await response.json()\n if (errorBody.error || errorBody.message) {\n errorMessage = errorBody.error || errorBody.message\n }\n } catch {\n // Ignore JSON parse errors for error body\n }\n\n throw new FigmaApiError(errorMessage, response.status)\n }\n\n const data: ProjectTokenResponse = await response.json()\n\n if (!data.meta?.token) {\n throw new FigmaApiError('Invalid response: missing token in meta')\n }\n\n // Parse the JWT to extract expiry (it's in the payload)\n const expiresAt = parseJwtExpiry(data.meta.token)\n\n return {\n expiresAt,\n tenantId,\n token: data.meta.token,\n }\n } catch (error) {\n if (error instanceof FigmaApiError) {\n throw error\n }\n\n // Handle network errors and other unexpected errors\n throw new FigmaApiError(\n `Failed to get project token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n undefined,\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Create a mock JWT token for testing\n * TODO: Remove this when real API is available\n */\nfunction createMockJWT(tenantId: string, expiresInMinutes: number): string {\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n }\n\n const now = Math.floor(Date.now() / 1000) // Current time in seconds\n const exp = now + expiresInMinutes * 60 // Expiry in seconds\n\n const payload = {\n aud: tenantId, // Audience claim contains the CMS ID\n email: 'developer@example.com',\n exp,\n iat: now,\n sub: 'user123',\n }\n\n // Base64url encode\n const encodeBase64Url = (obj: object): string => {\n return Buffer.from(JSON.stringify(obj))\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n }\n\n const headerEncoded = encodeBase64Url(header)\n const payloadEncoded = encodeBase64Url(payload)\n const signature = 'mock_signature_' + Math.random().toString(36).substring(2, 15)\n\n return `${headerEncoded}.${payloadEncoded}.${signature}`\n}\n\n/**\n * Parse JWT expiry from token\n * JWTs contain an 'exp' claim in the payload (second part)\n *\n * @param token - JWT token string\n * @returns Unix timestamp in milliseconds when token expires\n * @throws {FigmaApiError} If JWT cannot be parsed\n */\nfunction parseJwtExpiry(token: string): number {\n try {\n // JWT format: header.payload.signature\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format')\n }\n\n // Decode the payload (second part)\n const payload = parts[1]\n // Use atob for base64url decoding (handle padding and URL-safe characters)\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/')\n const paddedBase64 = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=')\n\n const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8')) as {\n exp?: number\n }\n\n if (!decodedPayload.exp || typeof decodedPayload.exp !== 'number') {\n throw new Error('JWT payload missing exp claim')\n }\n\n // JWT exp claim is in seconds, convert to milliseconds\n return decodedPayload.exp * 1000\n } catch (error) {\n throw new FigmaApiError(\n `Failed to parse JWT expiry: ${error instanceof Error ? error.message : 'Unknown error'}`,\n undefined,\n error instanceof Error ? error : undefined,\n )\n }\n}\n"],"names":["log","FigmaApiError","Error","message","statusCode","cause","name","API_BASE_URLS","prod","staging","_getApiBaseUrl","process","env","FIGMA_API_BASE_URL","getProjectToken","accessToken","tenantId","shouldMock","FIGMA_MOCK_PROJECT_TOKEN","debug","mockToken","createMockJWT","data","meta","token","expiresAt","parseJwtExpiry","baseUrl","url","response","fetch","headers","Authorization","method","ok","errorMessage","status","statusText","errorBody","json","error","undefined","expiresInMinutes","header","alg","typ","now","Math","floor","Date","exp","payload","aud","email","iat","sub","encodeBase64Url","obj","Buffer","from","JSON","stringify","toString","replace","headerEncoded","payloadEncoded","signature","random","substring","parts","split","length","base64","paddedBase64","padEnd","decodedPayload","parse"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/api/figma-api.ts"],"sourcesContent":["/**\n * Figma API Client\n *\n * Client for Figma REST API (Pixie) endpoints\n * Handles project token generation and other CMS-related API calls\n */\n\nimport type { ProjectToken, ProjectTokenResponse } from '../auth/types.js'\n\nimport * as log from '../utils/log.js'\n\n/**\n * Error thrown when Figma API calls fail\n */\nexport class FigmaApiError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'FigmaApiError'\n }\n}\n\n/**\n * Base URLs for Figma API\n */\nconst API_BASE_URLS = {\n prod: 'https://api.figma.com',\n staging: 'https://api.staging.figma.com',\n}\n\n/**\n * Get the Figma API base URL based on environment\n * TODO: Use this once real API endpoints are available\n */\nfunction _getApiBaseUrl(): string {\n // For now, default to staging to match OAuth config\n return process.env.FIGMA_API_BASE_URL || API_BASE_URLS.staging\n}\n\n/**\n * Get a project token (JWT) for a specific tenant/CMS\n *\n * This token is used by local Payload instances to authenticate\n * requests to the Content API. The token contains the CMS ID and\n * user identifying information in its claims.\n *\n * Endpoint: GET https://api.figma.com/v1/cms/:id/token/\n *\n * @param accessToken - OAuth access token for authentication\n * @param tenantId - The tenant/CMS ID\n * @returns ProjectToken with JWT and expiry information\n * @throws {FigmaApiError} If the API call fails\n */\nexport async function getProjectToken(\n accessToken: string,\n tenantId: string,\n): Promise<ProjectToken> {\n // Check if project token API should be mocked\n // Default to false (use real API)\n const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN === 'true'\n\n try {\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Generate a mock JWT token for testing\n log.debug(\n 'Using mock project token API for getProjectToken (FIGMA_MOCK_PROJECT_TOKEN = \"true\")',\n )\n const mockToken = createMockJWT(tenantId, 25) // 25 minutes expiry\n\n // Mock response data\n const data: ProjectTokenResponse = {\n meta: {\n token: mockToken,\n },\n }\n\n if (!data.meta?.token) {\n throw new FigmaApiError('Invalid response: missing token in meta')\n }\n\n // Parse the JWT to extract expiry (it's in the payload)\n const expiresAt = parseJwtExpiry(data.meta.token)\n\n return {\n expiresAt,\n tenantId,\n token: data.meta.token,\n }\n }\n\n // REAL API IMPLEMENTATION\n const baseUrl = _getApiBaseUrl()\n const url = `${baseUrl}/v1/cms/${tenantId}/token/`\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n // Handle error responses\n let errorMessage = `Failed to get project token: ${response.status} ${response.statusText}`\n\n try {\n const errorBody = await response.json()\n if (errorBody.error || errorBody.message) {\n errorMessage = errorBody.error || errorBody.message\n }\n } catch {\n // Ignore JSON parse errors for error body\n }\n\n throw new FigmaApiError(errorMessage, response.status)\n }\n\n const data: ProjectTokenResponse = await response.json()\n\n if (!data.meta?.token) {\n throw new FigmaApiError('Invalid response: missing token in meta')\n }\n\n // Parse the JWT to extract expiry (it's in the payload)\n const expiresAt = parseJwtExpiry(data.meta.token)\n\n return {\n expiresAt,\n tenantId,\n token: data.meta.token,\n }\n } catch (error) {\n if (error instanceof FigmaApiError) {\n throw error\n }\n\n // Handle network errors and other unexpected errors\n throw new FigmaApiError(\n `Failed to get project token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n undefined,\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Create a mock JWT token for testing\n * TODO: Remove this when real API is available\n */\nfunction createMockJWT(tenantId: string, expiresInMinutes: number): string {\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n }\n\n const now = Math.floor(Date.now() / 1000) // Current time in seconds\n const exp = now + expiresInMinutes * 60 // Expiry in seconds\n\n const payload = {\n aud: tenantId, // Audience claim contains the CMS ID\n email: 'developer@example.com',\n exp,\n iat: now,\n sub: 'user123',\n }\n\n // Base64url encode\n const encodeBase64Url = (obj: object): string => {\n return Buffer.from(JSON.stringify(obj))\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n }\n\n const headerEncoded = encodeBase64Url(header)\n const payloadEncoded = encodeBase64Url(payload)\n const signature = 'mock_signature_' + Math.random().toString(36).substring(2, 15)\n\n return `${headerEncoded}.${payloadEncoded}.${signature}`\n}\n\n/**\n * Parse JWT expiry from token\n * JWTs contain an 'exp' claim in the payload (second part)\n *\n * @param token - JWT token string\n * @returns Unix timestamp in milliseconds when token expires\n * @throws {FigmaApiError} If JWT cannot be parsed\n */\nfunction parseJwtExpiry(token: string): number {\n try {\n // JWT format: header.payload.signature\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format')\n }\n\n // Decode the payload (second part)\n const payload = parts[1]\n // Use atob for base64url decoding (handle padding and URL-safe characters)\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/')\n const paddedBase64 = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=')\n\n const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8')) as {\n exp?: number\n }\n\n if (!decodedPayload.exp || typeof decodedPayload.exp !== 'number') {\n throw new Error('JWT payload missing exp claim')\n }\n\n // JWT exp claim is in seconds, convert to milliseconds\n return decodedPayload.exp * 1000\n } catch (error) {\n throw new FigmaApiError(\n `Failed to parse JWT expiry: ${error instanceof Error ? error.message : 'Unknown error'}`,\n undefined,\n error instanceof Error ? error : undefined,\n )\n }\n}\n"],"names":["log","FigmaApiError","Error","message","statusCode","cause","name","API_BASE_URLS","prod","staging","_getApiBaseUrl","process","env","FIGMA_API_BASE_URL","getProjectToken","accessToken","tenantId","shouldMock","FIGMA_MOCK_PROJECT_TOKEN","debug","mockToken","createMockJWT","data","meta","token","expiresAt","parseJwtExpiry","baseUrl","url","response","fetch","headers","Authorization","method","ok","errorMessage","status","statusText","errorBody","json","error","undefined","expiresInMinutes","header","alg","typ","now","Math","floor","Date","exp","payload","aud","email","iat","sub","encodeBase64Url","obj","Buffer","from","JSON","stringify","toString","replace","headerEncoded","payloadEncoded","signature","random","substring","parts","split","length","base64","paddedBase64","padEnd","decodedPayload","parse"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/jwt-validator.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose'\nimport {\n JWKSMultipleMatchingKeys,\n JWKSNoMatchingKey,\n JWSInvalid,\n JWSSignatureVerificationFailed,\n JWTExpired,\n} from 'jose/errors'\n\nimport type { JWTPayload } from './types.js'\n\nimport { getJWKSUri } from '../constants.js'\n\n/**\n * JWT validation error with specific error codes\n */\nexport class JWTValidationError extends Error {\n constructor(\n message: string,\n public code: 'EXPIRED' | 'JWKS_FETCH_FAILED' | 'MISSING_KID' | 'SIGNATURE_INVALID',\n public cause?: Error,\n ) {\n super(message)\n this.name = 'JWTValidationError'\n }\n}\n\n/**\n * JWKS resolvers cached per environment\n * Uses jose's createRemoteJWKSet which handles:\n * - Automatic JWKS fetching from URI\n * - Built-in caching with configurable max age\n * - Automatic key rotation handling\n * - Cooldown protection between refetches\n */\nconst jwksResolvers = new Map<string, ReturnType<typeof createRemoteJWKSet>>()\n\n/**\n * Get or create a JWKS resolver for a given environment\n *\n * The resolver is cached in module scope and reused across validations.\n * Jose handles all the complexity of fetching, caching, and rotating keys.\n *\n * @param environment - Figma environment ('production' or 'staging')\n * @returns JWKS resolver function\n */\nfunction getJWKSResolver(environment: 'production' | 'staging') {\n const jwksUri = getJWKSUri(environment)\n\n if (!jwksResolvers.has(jwksUri)) {\n jwksResolvers.set(\n jwksUri,\n createRemoteJWKSet(new URL(jwksUri), {\n cacheMaxAge: 24 * 60 * 60 * 1000, // 24 hours\n cooldownDuration: 30000, // 30 seconds between refetches\n }),\n )\n }\n\n return jwksResolvers.get(jwksUri)!\n}\n\n/**\n * Validate a project token JWT\n *\n * This function:\n * 1. Gets the JWKS resolver for the environment (cached)\n * 2. Uses jose's jwtVerify to validate signature and claims in one call\n * 3. Maps jose errors to our custom error types\n *\n * Jose automatically:\n * - Fetches JWKS from the URI (with caching)\n * - Matches the key by kid from the JWT header\n * - Verifies the signature using the correct algorithm\n * - Validates standard claims (exp, iat, nbf)\n * - Handles clock skew tolerance\n *\n * @param token - JWT token string\n * @param environment - Figma environment ('production' or 'staging')\n * @returns Promise resolving to validated JWT payload\n * @throws {JWTValidationError} If validation fails\n */\nexport async function validateProjectToken(\n token: string,\n environment: 'production' | 'staging',\n): Promise<JWTPayload> {\n try {\n const JWKS = getJWKSResolver(environment)\n\n const { payload } = await jwtVerify(token, JWKS, {\n clockTolerance: 300, // 5 minutes clock skew tolerance\n // Optional additional validation (uncomment if Figma provides these):\n // issuer: 'https://api.figma.com',\n // audience: 'payloadcms-figma',\n })\n\n return payload as JWTPayload\n } catch (error: unknown) {\n // Map jose errors to our custom error types using instanceof checks\n // This is more reliable than checking error.code strings\n\n // Token expired\n if (error instanceof JWTExpired) {\n throw new JWTValidationError('Project token has expired', 'EXPIRED', error)\n }\n\n // Key not found in JWKS (possible key rotation or invalid kid)\n if (error instanceof JWKSNoMatchingKey) {\n throw new JWTValidationError(\n 'Key not found in JWKS - this may indicate key rotation or an invalid token',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Multiple matching keys (JWKS configuration issue)\n if (error instanceof JWKSMultipleMatchingKeys) {\n throw new JWTValidationError(\n 'Multiple matching keys found in JWKS',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Invalid signature or other verification failure\n if (error instanceof JWSSignatureVerificationFailed) {\n throw new JWTValidationError(\n 'JWT signature verification failed - token may be tampered with',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Missing or invalid kid/alg in JWT header\n if (error instanceof JWSInvalid) {\n throw new JWTValidationError(\n 'Invalid JWT structure - missing required header fields (kid or alg)',\n 'MISSING_KID',\n error,\n )\n }\n\n // Network or fetch errors (not jose errors, generic Error instances)\n if (error instanceof Error) {\n const message = error.message\n if (\n message.includes('fetch') ||\n message.includes('network') ||\n message.includes('ENOTFOUND') ||\n message.includes('ECONNREFUSED')\n ) {\n throw new JWTValidationError(`Failed to fetch JWKS: ${message}`, 'JWKS_FETCH_FAILED', error)\n }\n }\n\n // Generic error fallback\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new JWTValidationError(\n `JWT validation failed: ${message}`,\n 'SIGNATURE_INVALID',\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Clear JWKS cache (useful for testing or forcing refresh)\n *\n * This clears the cached JWKS resolvers, forcing fresh fetches\n * on the next validation. Useful for:\n * - Testing with different JWKS\n * - Forcing key rotation updates\n * - Clearing state between test runs\n */\nexport function clearJWKSCache(): void {\n jwksResolvers.clear()\n}\n"],"names":["createRemoteJWKSet","jwtVerify","JWKSMultipleMatchingKeys","JWKSNoMatchingKey","JWSInvalid","JWSSignatureVerificationFailed","JWTExpired","getJWKSUri","JWTValidationError","Error","message","code","cause","name","jwksResolvers","Map","getJWKSResolver","environment","jwksUri","has","set","URL","cacheMaxAge","cooldownDuration","get","validateProjectToken","token","JWKS","payload","clockTolerance","error","includes","undefined","clearJWKSCache","clear"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,SAAS,QAAQ,OAAM;AACpD,SACEC,wBAAwB,EACxBC,iBAAiB,EACjBC,UAAU,EACVC,8BAA8B,EAC9BC,UAAU,QACL,cAAa;AAIpB,SAASC,UAAU,QAAQ,kBAAiB;AAE5C;;CAEC,GACD,OAAO,MAAMC,2BAA2BC;;;IACtC,YACEC,OAAe,EACf,AAAOC,IAA2E,EAClF,AAAOC,KAAa,CACpB;QACA,KAAK,CAACF,eAHCC,OAAAA,WACAC,QAAAA;QAGP,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA;;;;;;;CAOC,GACD,MAAMC,gBAAgB,IAAIC;AAE1B;;;;;;;;CAQC,GACD,SAASC,gBAAgBC,WAAqC;IAC5D,MAAMC,UAAUX,WAAWU;IAE3B,IAAI,CAACH,cAAcK,GAAG,CAACD,UAAU;QAC/BJ,cAAcM,GAAG,CACfF,SACAlB,mBAAmB,IAAIqB,IAAIH,UAAU;YACnCI,aAAa,KAAK,KAAK,KAAK;YAC5BC,kBAAkB;QACpB;IAEJ;IAEA,OAAOT,cAAcU,GAAG,CAACN;AAC3B;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,eAAeO,qBACpBC,KAAa,EACbT,WAAqC;IAErC,IAAI;QACF,MAAMU,OAAOX,gBAAgBC;QAE7B,MAAM,EAAEW,OAAO,EAAE,GAAG,MAAM3B,UAAUyB,OAAOC,MAAM;YAC/CE,gBAAgB;QAIlB;QAEA,OAAOD;IACT,EAAE,OAAOE,OAAgB;QACvB,oEAAoE;QACpE,yDAAyD;QAEzD,gBAAgB;QAChB,IAAIA,iBAAiBxB,YAAY;YAC/B,MAAM,IAAIE,mBAAmB,6BAA6B,WAAWsB;QACvE;QAEA,+DAA+D;QAC/D,IAAIA,iBAAiB3B,mBAAmB;YACtC,MAAM,IAAIK,mBACR,8EACA,qBACAsB;QAEJ;QAEA,oDAAoD;QACpD,IAAIA,iBAAiB5B,0BAA0B;YAC7C,MAAM,IAAIM,mBACR,wCACA,qBACAsB;QAEJ;QAEA,kDAAkD;QAClD,IAAIA,iBAAiBzB,gCAAgC;YACnD,MAAM,IAAIG,mBACR,kEACA,qBACAsB;QAEJ;QAEA,2CAA2C;QAC3C,IAAIA,iBAAiB1B,YAAY;YAC/B,MAAM,IAAII,mBACR,uEACA,eACAsB;QAEJ;QAEA,qEAAqE;QACrE,IAAIA,iBAAiBrB,OAAO;YAC1B,MAAMC,UAAUoB,MAAMpB,OAAO;YAC7B,IACEA,QAAQqB,QAAQ,CAAC,YACjBrB,QAAQqB,QAAQ,CAAC,cACjBrB,QAAQqB,QAAQ,CAAC,gBACjBrB,QAAQqB,QAAQ,CAAC,iBACjB;gBACA,MAAM,IAAIvB,mBAAmB,CAAC,sBAAsB,EAAEE,SAAS,EAAE,qBAAqBoB;YACxF;QACF;QAEA,yBAAyB;QACzB,MAAMpB,UAAUoB,iBAAiBrB,QAAQqB,MAAMpB,OAAO,GAAG;QACzD,MAAM,IAAIF,mBACR,CAAC,uBAAuB,EAAEE,SAAS,EACnC,qBACAoB,iBAAiBrB,QAAQqB,QAAQE;IAErC;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC;IACdnB,cAAcoB,KAAK;AACrB"}
1
+ {"version":3,"sources":["../../src/auth/jwt-validator.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose'\nimport {\n JWKSMultipleMatchingKeys,\n JWKSNoMatchingKey,\n JWSInvalid,\n JWSSignatureVerificationFailed,\n JWTExpired,\n} from 'jose/errors'\n\nimport type { JWTPayload } from './types.js'\n\nimport { getJWKSUri } from '../constants.js'\n\n/**\n * JWT validation error with specific error codes\n */\nexport class JWTValidationError extends Error {\n constructor(\n message: string,\n public code: 'EXPIRED' | 'JWKS_FETCH_FAILED' | 'MISSING_KID' | 'SIGNATURE_INVALID',\n public cause?: Error,\n ) {\n super(message)\n this.name = 'JWTValidationError'\n }\n}\n\n/**\n * JWKS resolvers cached per environment\n * Uses jose's createRemoteJWKSet which handles:\n * - Automatic JWKS fetching from URI\n * - Built-in caching with configurable max age\n * - Automatic key rotation handling\n * - Cooldown protection between refetches\n */\nconst jwksResolvers = new Map<string, ReturnType<typeof createRemoteJWKSet>>()\n\n/**\n * Get or create a JWKS resolver for a given environment\n *\n * The resolver is cached in module scope and reused across validations.\n * Jose handles all the complexity of fetching, caching, and rotating keys.\n *\n * @param environment - Figma environment ('production' or 'staging')\n * @returns JWKS resolver function\n */\nfunction getJWKSResolver(environment: 'production' | 'staging') {\n const jwksUri = getJWKSUri(environment)\n\n if (!jwksResolvers.has(jwksUri)) {\n jwksResolvers.set(\n jwksUri,\n createRemoteJWKSet(new URL(jwksUri), {\n cacheMaxAge: 24 * 60 * 60 * 1000, // 24 hours\n cooldownDuration: 30000, // 30 seconds between refetches\n }),\n )\n }\n\n return jwksResolvers.get(jwksUri)!\n}\n\n/**\n * Validate a project token JWT\n *\n * This function:\n * 1. Gets the JWKS resolver for the environment (cached)\n * 2. Uses jose's jwtVerify to validate signature and claims in one call\n * 3. Maps jose errors to our custom error types\n *\n * Jose automatically:\n * - Fetches JWKS from the URI (with caching)\n * - Matches the key by kid from the JWT header\n * - Verifies the signature using the correct algorithm\n * - Validates standard claims (exp, iat, nbf)\n * - Handles clock skew tolerance\n *\n * @param token - JWT token string\n * @param environment - Figma environment ('production' or 'staging')\n * @returns Promise resolving to validated JWT payload\n * @throws {JWTValidationError} If validation fails\n */\nexport async function validateProjectToken(\n token: string,\n environment: 'production' | 'staging',\n): Promise<JWTPayload> {\n try {\n const JWKS = getJWKSResolver(environment)\n\n const { payload } = await jwtVerify(token, JWKS, {\n clockTolerance: 300, // 5 minutes clock skew tolerance\n // Optional additional validation (uncomment if Figma provides these):\n // issuer: 'https://api.figma.com',\n // audience: 'payloadcms-figma',\n })\n\n return payload\n } catch (error: unknown) {\n // Map jose errors to our custom error types using instanceof checks\n // This is more reliable than checking error.code strings\n\n // Token expired\n if (error instanceof JWTExpired) {\n throw new JWTValidationError('Project token has expired', 'EXPIRED', error)\n }\n\n // Key not found in JWKS (possible key rotation or invalid kid)\n if (error instanceof JWKSNoMatchingKey) {\n throw new JWTValidationError(\n 'Key not found in JWKS - this may indicate key rotation or an invalid token',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Multiple matching keys (JWKS configuration issue)\n if (error instanceof JWKSMultipleMatchingKeys) {\n throw new JWTValidationError(\n 'Multiple matching keys found in JWKS',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Invalid signature or other verification failure\n if (error instanceof JWSSignatureVerificationFailed) {\n throw new JWTValidationError(\n 'JWT signature verification failed - token may be tampered with',\n 'SIGNATURE_INVALID',\n error,\n )\n }\n\n // Missing or invalid kid/alg in JWT header\n if (error instanceof JWSInvalid) {\n throw new JWTValidationError(\n 'Invalid JWT structure - missing required header fields (kid or alg)',\n 'MISSING_KID',\n error,\n )\n }\n\n // Network or fetch errors (not jose errors, generic Error instances)\n if (error instanceof Error) {\n const message = error.message\n if (\n message.includes('fetch') ||\n message.includes('network') ||\n message.includes('ENOTFOUND') ||\n message.includes('ECONNREFUSED')\n ) {\n throw new JWTValidationError(`Failed to fetch JWKS: ${message}`, 'JWKS_FETCH_FAILED', error)\n }\n }\n\n // Generic error fallback\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new JWTValidationError(\n `JWT validation failed: ${message}`,\n 'SIGNATURE_INVALID',\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Clear JWKS cache (useful for testing or forcing refresh)\n *\n * This clears the cached JWKS resolvers, forcing fresh fetches\n * on the next validation. Useful for:\n * - Testing with different JWKS\n * - Forcing key rotation updates\n * - Clearing state between test runs\n */\nexport function clearJWKSCache(): void {\n jwksResolvers.clear()\n}\n"],"names":["createRemoteJWKSet","jwtVerify","JWKSMultipleMatchingKeys","JWKSNoMatchingKey","JWSInvalid","JWSSignatureVerificationFailed","JWTExpired","getJWKSUri","JWTValidationError","Error","message","code","cause","name","jwksResolvers","Map","getJWKSResolver","environment","jwksUri","has","set","URL","cacheMaxAge","cooldownDuration","get","validateProjectToken","token","JWKS","payload","clockTolerance","error","includes","undefined","clearJWKSCache","clear"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,SAAS,QAAQ,OAAM;AACpD,SACEC,wBAAwB,EACxBC,iBAAiB,EACjBC,UAAU,EACVC,8BAA8B,EAC9BC,UAAU,QACL,cAAa;AAIpB,SAASC,UAAU,QAAQ,kBAAiB;AAE5C;;CAEC,GACD,OAAO,MAAMC,2BAA2BC;;;IACtC,YACEC,OAAe,EACf,AAAOC,IAA2E,EAClF,AAAOC,KAAa,CACpB;QACA,KAAK,CAACF,eAHCC,OAAAA,WACAC,QAAAA;QAGP,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA;;;;;;;CAOC,GACD,MAAMC,gBAAgB,IAAIC;AAE1B;;;;;;;;CAQC,GACD,SAASC,gBAAgBC,WAAqC;IAC5D,MAAMC,UAAUX,WAAWU;IAE3B,IAAI,CAACH,cAAcK,GAAG,CAACD,UAAU;QAC/BJ,cAAcM,GAAG,CACfF,SACAlB,mBAAmB,IAAIqB,IAAIH,UAAU;YACnCI,aAAa,KAAK,KAAK,KAAK;YAC5BC,kBAAkB;QACpB;IAEJ;IAEA,OAAOT,cAAcU,GAAG,CAACN;AAC3B;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,eAAeO,qBACpBC,KAAa,EACbT,WAAqC;IAErC,IAAI;QACF,MAAMU,OAAOX,gBAAgBC;QAE7B,MAAM,EAAEW,OAAO,EAAE,GAAG,MAAM3B,UAAUyB,OAAOC,MAAM;YAC/CE,gBAAgB;QAIlB;QAEA,OAAOD;IACT,EAAE,OAAOE,OAAgB;QACvB,oEAAoE;QACpE,yDAAyD;QAEzD,gBAAgB;QAChB,IAAIA,iBAAiBxB,YAAY;YAC/B,MAAM,IAAIE,mBAAmB,6BAA6B,WAAWsB;QACvE;QAEA,+DAA+D;QAC/D,IAAIA,iBAAiB3B,mBAAmB;YACtC,MAAM,IAAIK,mBACR,8EACA,qBACAsB;QAEJ;QAEA,oDAAoD;QACpD,IAAIA,iBAAiB5B,0BAA0B;YAC7C,MAAM,IAAIM,mBACR,wCACA,qBACAsB;QAEJ;QAEA,kDAAkD;QAClD,IAAIA,iBAAiBzB,gCAAgC;YACnD,MAAM,IAAIG,mBACR,kEACA,qBACAsB;QAEJ;QAEA,2CAA2C;QAC3C,IAAIA,iBAAiB1B,YAAY;YAC/B,MAAM,IAAII,mBACR,uEACA,eACAsB;QAEJ;QAEA,qEAAqE;QACrE,IAAIA,iBAAiBrB,OAAO;YAC1B,MAAMC,UAAUoB,MAAMpB,OAAO;YAC7B,IACEA,QAAQqB,QAAQ,CAAC,YACjBrB,QAAQqB,QAAQ,CAAC,cACjBrB,QAAQqB,QAAQ,CAAC,gBACjBrB,QAAQqB,QAAQ,CAAC,iBACjB;gBACA,MAAM,IAAIvB,mBAAmB,CAAC,sBAAsB,EAAEE,SAAS,EAAE,qBAAqBoB;YACxF;QACF;QAEA,yBAAyB;QACzB,MAAMpB,UAAUoB,iBAAiBrB,QAAQqB,MAAMpB,OAAO,GAAG;QACzD,MAAM,IAAIF,mBACR,CAAC,uBAAuB,EAAEE,SAAS,EACnC,qBACAoB,iBAAiBrB,QAAQqB,QAAQE;IAErC;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC;IACdnB,cAAcoB,KAAK;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-flow.d.ts","sourceRoot":"","sources":["../../src/auth/oauth-flow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAU7C;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAG9B,KAAK,CAAC,EAAE,KAAK;gBADpB,OAAO,EAAE,MAAM,EACR,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oBAAoB;IACpB,MAAM,EAAE,WAAW,CAAA;IACnB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAwI1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAyBxF"}
1
+ {"version":3,"file":"oauth-flow.d.ts","sourceRoot":"","sources":["../../src/auth/oauth-flow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAS7C;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAG9B,KAAK,CAAC,EAAE,KAAK;gBADpB,OAAO,EAAE,MAAM,EACR,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oBAAoB;IACpB,MAAM,EAAE,WAAW,CAAA;IACnB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAsI1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAyBxF"}
@@ -1,7 +1,6 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import crypto from 'crypto';
3
3
  import { OAUTH_CONFIG } from '../config/oauth.js';
4
- import { isDebug } from '../utils/is-debug.js';
5
4
  import * as log from '../utils/log.js';
6
5
  import { buildAuthorizationUrl, openBrowser } from './browser.js';
7
6
  import { CallbackServer } from './callback-server.js';
@@ -33,13 +32,11 @@ import { exchangeCodeForTokens, refreshAccessToken } from './refresh.js';
33
32
  * @throws OAuthFlowError if any step fails
34
33
  */ export async function executeOAuthFlow(tokenStore, options = {}) {
35
34
  // Check if OAuth flow should be mocked
36
- // Default to true for OAuth (allow testing without real authentication by default)
37
- const shouldMock = process.env.FIGMA_MOCK_OAUTH !== 'false';
35
+ // Default to false for OAuth
36
+ const shouldMock = process.env.FIGMA_MOCK_OAUTH === 'true';
38
37
  if (shouldMock) {
39
38
  // MOCK IMPLEMENTATION: Return mock tokens for testing
40
- if (isDebug()) {
41
- log.debug('Using mock OAuth flow (FIGMA_MOCK_OAUTH != "false")');
42
- }
39
+ log.debug('Using mock OAuth flow (FIGMA_MOCK_OAUTH = true)');
43
40
  const mockTokens = {
44
41
  accessToken: 'figt_mock_access_token_' + crypto.randomBytes(16).toString('hex'),
45
42
  expiresAt: Date.now() + 2 * 60 * 60 * 1000,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/oauth-flow.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport crypto from 'crypto'\n\nimport type { TokenStore } from './token-store.js'\nimport type { FigmaTokens } from './types.js'\n\nimport { OAUTH_CONFIG } from '../config/oauth.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\nimport { buildAuthorizationUrl, openBrowser } from './browser.js'\nimport { CallbackServer } from './callback-server.js'\nimport { generatePKCEPair } from './pkce.js'\nimport { exchangeCodeForTokens, refreshAccessToken } from './refresh.js'\n\n/**\n * Error during OAuth flow\n */\nexport class OAuthFlowError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'OAuthFlowError'\n }\n}\n\n/**\n * Options for OAuth flow\n */\nexport interface OAuthFlowOptions {\n /** OAuth2 client ID (defaults to config) */\n clientId?: string\n /** Callback server port (defaults to 3000) */\n port?: number\n /** Redirect URI (defaults to config) */\n redirectUri?: string\n /** OAuth scopes (defaults to config) */\n scopes?: string[]\n /** Callback timeout in milliseconds (defaults to 120000) */\n timeoutMs?: number\n}\n\n/**\n * Result of OAuth flow\n */\nexport interface OAuthFlowResult {\n /** OAuth2 tokens */\n tokens: FigmaTokens\n /** Figma user ID */\n userId?: string\n}\n\n/**\n * Execute complete OAuth2 authorization flow\n *\n * This orchestrates the full OAuth flow:\n * 1. Generate PKCE pair for security\n * 2. Start local callback server\n * 3. Open browser to authorization URL\n * 4. Wait for user to authorize\n * 5. Exchange authorization code for tokens\n * 6. Store tokens securely\n *\n * @param tokenStore - Token store for persisting tokens\n * @param options - Flow configuration options\n * @returns Promise resolving to OAuth flow result\n * @throws OAuthFlowError if any step fails\n */\nexport async function executeOAuthFlow(\n tokenStore: TokenStore,\n options: OAuthFlowOptions = {},\n): Promise<OAuthFlowResult> {\n // Check if OAuth flow should be mocked\n // Default to true for OAuth (allow testing without real authentication by default)\n const shouldMock = process.env.FIGMA_MOCK_OAUTH !== 'false'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock tokens for testing\n if (isDebug()) {\n log.debug('Using mock OAuth flow (FIGMA_MOCK_OAUTH != \"false\")')\n }\n const mockTokens: FigmaTokens = {\n accessToken: 'figt_mock_access_token_' + crypto.randomBytes(16).toString('hex'),\n expiresAt: Date.now() + 2 * 60 * 60 * 1000, // 2 hours\n refreshToken: 'figt_mock_refresh_token_' + crypto.randomBytes(16).toString('hex'),\n scopes: (options.scopes || OAUTH_CONFIG.scopes) as FigmaTokens['scopes'],\n tokenType: 'Bearer',\n }\n\n // Store mock tokens\n tokenStore.setTokens(mockTokens)\n\n return {\n tokens: mockTokens,\n userId: 'mock_user_123',\n }\n }\n\n // REAL OAUTH IMPLEMENTATION\n const {\n clientId = OAUTH_CONFIG.clientId,\n port = 3000,\n redirectUri = OAUTH_CONFIG.redirectUri,\n scopes = OAUTH_CONFIG.scopes,\n timeoutMs = 120000,\n } = options\n\n // Generate PKCE pair for enhanced security\n const { codeChallenge, codeChallengeMethod, codeVerifier } = generatePKCEPair()\n\n // Generate random state for CSRF protection\n const state = crypto.randomBytes(32).toString('base64url')\n\n // Create callback server\n const callbackServer = new CallbackServer({ port, timeoutMs })\n\n try {\n // Start waiting for callback (this starts the server and captures actual port)\n const callbackPromise = callbackServer.waitForCallback(state)\n\n // Wait a bit for server to start and determine actual port\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n // Get the actual port (may differ from preferred if that was in use)\n const actualPort = callbackServer.getActualPort()\n\n // Build redirect URI with actual port\n const actualRedirectUri = redirectUri.replace(/:\\d+/, `:${actualPort}`)\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n authorizationUrl: OAUTH_CONFIG.authorizationUrl,\n clientId,\n codeChallenge,\n codeChallengeMethod,\n redirectUri: actualRedirectUri,\n scopes,\n state,\n })\n\n // Prompt user to open browser\n const shouldOpenBrowser = await p.confirm({\n initialValue: true,\n message: 'Log in or create Figma account in your browser?',\n })\n\n if (p.isCancel(shouldOpenBrowser)) {\n throw new OAuthFlowError('Authentication cancelled by user')\n }\n\n if (shouldOpenBrowser) {\n // Try to open browser, but don't fail if it doesn't work\n try {\n await openBrowser(authUrl)\n } catch (_error) {\n // Browser opening failed, show URL for manual opening\n log.warning('Could not open browser automatically.')\n log.info(`Please open this URL in your browser:`)\n log.info(` ${authUrl}`)\n }\n } else {\n // User declined automatic opening, show URL\n log.info(`Please open this URL manually in your browser:`)\n log.info(` ${authUrl}`)\n }\n\n // Wait for callback\n const { code } = await callbackPromise\n\n // Exchange authorization code for tokens\n let tokens: FigmaTokens\n try {\n tokens = await exchangeCodeForTokens(code, codeVerifier, actualRedirectUri, clientId)\n } catch (error) {\n throw new OAuthFlowError(\n 'Failed to exchange authorization code for tokens',\n error instanceof Error ? error : undefined,\n )\n }\n\n // Store tokens\n try {\n tokenStore.setTokens(tokens)\n } catch (error) {\n throw new OAuthFlowError('Failed to store tokens', error instanceof Error ? error : undefined)\n }\n\n return {\n tokens,\n userId: tokens.userId,\n }\n } catch (error) {\n // Clean up server on error\n callbackServer.stop()\n\n if (error instanceof OAuthFlowError) {\n throw error\n }\n\n throw new OAuthFlowError(\n `OAuth flow failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error instanceof Error ? error : undefined,\n )\n } finally {\n // Ensure server is always stopped\n callbackServer.stop()\n }\n}\n\n/**\n * Get valid access token, refreshing if necessary\n *\n * Checks if stored tokens exist and are valid. If expired, automatically\n * refreshes using the refresh token. If no tokens exist, returns null.\n *\n * @param tokenStore - Token store to use\n * @returns Promise resolving to access token or null if no valid tokens\n * @throws OAuthFlowError if refresh fails\n */\nexport async function getValidAccessToken(tokenStore: TokenStore): Promise<null | string> {\n // Check if we have valid tokens\n if (tokenStore.hasValidTokens()) {\n return tokenStore.getAccessToken()\n }\n\n // Check if we have a refresh token\n const refreshToken = tokenStore.getRefreshToken()\n if (!refreshToken) {\n return null\n }\n\n // Try to refresh\n try {\n const tokens = await refreshAccessToken(refreshToken)\n tokenStore.setTokens(tokens)\n return tokens.accessToken\n } catch (error) {\n // Refresh failed - clear invalid tokens\n tokenStore.clearTokens()\n throw new OAuthFlowError(\n 'Failed to refresh access token',\n error instanceof Error ? error : undefined,\n )\n }\n}\n"],"names":["p","crypto","OAUTH_CONFIG","isDebug","log","buildAuthorizationUrl","openBrowser","CallbackServer","generatePKCEPair","exchangeCodeForTokens","refreshAccessToken","OAuthFlowError","Error","message","cause","name","executeOAuthFlow","tokenStore","options","shouldMock","process","env","FIGMA_MOCK_OAUTH","debug","mockTokens","accessToken","randomBytes","toString","expiresAt","Date","now","refreshToken","scopes","tokenType","setTokens","tokens","userId","clientId","port","redirectUri","timeoutMs","codeChallenge","codeChallengeMethod","codeVerifier","state","callbackServer","callbackPromise","waitForCallback","Promise","resolve","setTimeout","actualPort","getActualPort","actualRedirectUri","replace","authUrl","authorizationUrl","shouldOpenBrowser","confirm","initialValue","isCancel","_error","warning","info","code","error","undefined","stop","getValidAccessToken","hasValidTokens","getAccessToken","getRefreshToken","clearTokens"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/auth/oauth-flow.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport crypto from 'crypto'\n\nimport type { TokenStore } from './token-store.js'\nimport type { FigmaTokens } from './types.js'\n\nimport { OAUTH_CONFIG } from '../config/oauth.js'\nimport * as log from '../utils/log.js'\nimport { buildAuthorizationUrl, openBrowser } from './browser.js'\nimport { CallbackServer } from './callback-server.js'\nimport { generatePKCEPair } from './pkce.js'\nimport { exchangeCodeForTokens, refreshAccessToken } from './refresh.js'\n\n/**\n * Error during OAuth flow\n */\nexport class OAuthFlowError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'OAuthFlowError'\n }\n}\n\n/**\n * Options for OAuth flow\n */\nexport interface OAuthFlowOptions {\n /** OAuth2 client ID (defaults to config) */\n clientId?: string\n /** Callback server port (defaults to 3000) */\n port?: number\n /** Redirect URI (defaults to config) */\n redirectUri?: string\n /** OAuth scopes (defaults to config) */\n scopes?: string[]\n /** Callback timeout in milliseconds (defaults to 120000) */\n timeoutMs?: number\n}\n\n/**\n * Result of OAuth flow\n */\nexport interface OAuthFlowResult {\n /** OAuth2 tokens */\n tokens: FigmaTokens\n /** Figma user ID */\n userId?: string\n}\n\n/**\n * Execute complete OAuth2 authorization flow\n *\n * This orchestrates the full OAuth flow:\n * 1. Generate PKCE pair for security\n * 2. Start local callback server\n * 3. Open browser to authorization URL\n * 4. Wait for user to authorize\n * 5. Exchange authorization code for tokens\n * 6. Store tokens securely\n *\n * @param tokenStore - Token store for persisting tokens\n * @param options - Flow configuration options\n * @returns Promise resolving to OAuth flow result\n * @throws OAuthFlowError if any step fails\n */\nexport async function executeOAuthFlow(\n tokenStore: TokenStore,\n options: OAuthFlowOptions = {},\n): Promise<OAuthFlowResult> {\n // Check if OAuth flow should be mocked\n // Default to false for OAuth\n const shouldMock = process.env.FIGMA_MOCK_OAUTH === 'true'\n\n if (shouldMock) {\n // MOCK IMPLEMENTATION: Return mock tokens for testing\n log.debug('Using mock OAuth flow (FIGMA_MOCK_OAUTH = true)')\n const mockTokens: FigmaTokens = {\n accessToken: 'figt_mock_access_token_' + crypto.randomBytes(16).toString('hex'),\n expiresAt: Date.now() + 2 * 60 * 60 * 1000, // 2 hours\n refreshToken: 'figt_mock_refresh_token_' + crypto.randomBytes(16).toString('hex'),\n scopes: (options.scopes || OAUTH_CONFIG.scopes) as FigmaTokens['scopes'],\n tokenType: 'Bearer',\n }\n\n // Store mock tokens\n tokenStore.setTokens(mockTokens)\n\n return {\n tokens: mockTokens,\n userId: 'mock_user_123',\n }\n }\n\n // REAL OAUTH IMPLEMENTATION\n const {\n clientId = OAUTH_CONFIG.clientId,\n port = 3000,\n redirectUri = OAUTH_CONFIG.redirectUri,\n scopes = OAUTH_CONFIG.scopes,\n timeoutMs = 120000,\n } = options\n\n // Generate PKCE pair for enhanced security\n const { codeChallenge, codeChallengeMethod, codeVerifier } = generatePKCEPair()\n\n // Generate random state for CSRF protection\n const state = crypto.randomBytes(32).toString('base64url')\n\n // Create callback server\n const callbackServer = new CallbackServer({ port, timeoutMs })\n\n try {\n // Start waiting for callback (this starts the server and captures actual port)\n const callbackPromise = callbackServer.waitForCallback(state)\n\n // Wait a bit for server to start and determine actual port\n await new Promise((resolve) => setTimeout(resolve, 100))\n\n // Get the actual port (may differ from preferred if that was in use)\n const actualPort = callbackServer.getActualPort()\n\n // Build redirect URI with actual port\n const actualRedirectUri = redirectUri.replace(/:\\d+/, `:${actualPort}`)\n\n // Build authorization URL\n const authUrl = buildAuthorizationUrl({\n authorizationUrl: OAUTH_CONFIG.authorizationUrl,\n clientId,\n codeChallenge,\n codeChallengeMethod,\n redirectUri: actualRedirectUri,\n scopes,\n state,\n })\n\n // Prompt user to open browser\n const shouldOpenBrowser = await p.confirm({\n initialValue: true,\n message: 'Log in or create Figma account in your browser?',\n })\n\n if (p.isCancel(shouldOpenBrowser)) {\n throw new OAuthFlowError('Authentication cancelled by user')\n }\n\n if (shouldOpenBrowser) {\n // Try to open browser, but don't fail if it doesn't work\n try {\n await openBrowser(authUrl)\n } catch (_error) {\n // Browser opening failed, show URL for manual opening\n log.warning('Could not open browser automatically.')\n log.info(`Please open this URL in your browser:`)\n log.info(` ${authUrl}`)\n }\n } else {\n // User declined automatic opening, show URL\n log.info(`Please open this URL manually in your browser:`)\n log.info(` ${authUrl}`)\n }\n\n // Wait for callback\n const { code } = await callbackPromise\n\n // Exchange authorization code for tokens\n let tokens: FigmaTokens\n try {\n tokens = await exchangeCodeForTokens(code, codeVerifier, actualRedirectUri, clientId)\n } catch (error) {\n throw new OAuthFlowError(\n 'Failed to exchange authorization code for tokens',\n error instanceof Error ? error : undefined,\n )\n }\n\n // Store tokens\n try {\n tokenStore.setTokens(tokens)\n } catch (error) {\n throw new OAuthFlowError('Failed to store tokens', error instanceof Error ? error : undefined)\n }\n\n return {\n tokens,\n userId: tokens.userId,\n }\n } catch (error) {\n // Clean up server on error\n callbackServer.stop()\n\n if (error instanceof OAuthFlowError) {\n throw error\n }\n\n throw new OAuthFlowError(\n `OAuth flow failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error instanceof Error ? error : undefined,\n )\n } finally {\n // Ensure server is always stopped\n callbackServer.stop()\n }\n}\n\n/**\n * Get valid access token, refreshing if necessary\n *\n * Checks if stored tokens exist and are valid. If expired, automatically\n * refreshes using the refresh token. If no tokens exist, returns null.\n *\n * @param tokenStore - Token store to use\n * @returns Promise resolving to access token or null if no valid tokens\n * @throws OAuthFlowError if refresh fails\n */\nexport async function getValidAccessToken(tokenStore: TokenStore): Promise<null | string> {\n // Check if we have valid tokens\n if (tokenStore.hasValidTokens()) {\n return tokenStore.getAccessToken()\n }\n\n // Check if we have a refresh token\n const refreshToken = tokenStore.getRefreshToken()\n if (!refreshToken) {\n return null\n }\n\n // Try to refresh\n try {\n const tokens = await refreshAccessToken(refreshToken)\n tokenStore.setTokens(tokens)\n return tokens.accessToken\n } catch (error) {\n // Refresh failed - clear invalid tokens\n tokenStore.clearTokens()\n throw new OAuthFlowError(\n 'Failed to refresh access token',\n error instanceof Error ? error : undefined,\n )\n }\n}\n"],"names":["p","crypto","OAUTH_CONFIG","log","buildAuthorizationUrl","openBrowser","CallbackServer","generatePKCEPair","exchangeCodeForTokens","refreshAccessToken","OAuthFlowError","Error","message","cause","name","executeOAuthFlow","tokenStore","options","shouldMock","process","env","FIGMA_MOCK_OAUTH","debug","mockTokens","accessToken","randomBytes","toString","expiresAt","Date","now","refreshToken","scopes","tokenType","setTokens","tokens","userId","clientId","port","redirectUri","timeoutMs","codeChallenge","codeChallengeMethod","codeVerifier","state","callbackServer","callbackPromise","waitForCallback","Promise","resolve","setTimeout","actualPort","getActualPort","actualRedirectUri","replace","authUrl","authorizationUrl","shouldOpenBrowser","confirm","initialValue","isCancel","_error","warning","info","code","error","undefined","stop","getValidAccessToken","hasValidTokens","getAccessToken","getRefreshToken","clearTokens"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"project-token.d.ts","sourceRoot":"","sources":["../../src/auth/project-token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAUlD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,KAAK,CAAC,EAAE,KAAK;gBADpB,OAAO,EAAE,MAAM,EACR,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAmExB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAMxB"}
1
+ {"version":3,"file":"project-token.d.ts","sourceRoot":"","sources":["../../src/auth/project-token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AASlD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,KAAK,CAAC,EAAE,KAAK;gBADpB,OAAO,EAAE,MAAM,EACR,KAAK,CAAC,EAAE,KAAK,YAAA;CAKvB;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAiExB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAMxB"}
@@ -6,7 +6,6 @@
6
6
  * and have a shorter lifespan (15-30 minutes) than OAuth tokens.
7
7
  */ import { getProjectToken as fetchProjectToken } from '../api/figma-api.js';
8
8
  import { getEnvironment } from '../constants.js';
9
- import { isDebug } from '../utils/is-debug.js';
10
9
  import * as log from '../utils/log.js';
11
10
  import { JWTValidationError, validateProjectToken } from './jwt-validator.js';
12
11
  import { getValidAccessToken } from './oauth-flow.js';
@@ -85,9 +84,7 @@ import { getValidAccessToken } from './oauth-flow.js';
85
84
  let validatedClaims;
86
85
  if (shouldMock) {
87
86
  // MOCK: Skip JWT validation and parse claims directly
88
- if (isDebug()) {
89
- log.debug('Skipping JWT validation for mock project token');
90
- }
87
+ log.debug('Skipping JWT validation for mock project token');
91
88
  validatedClaims = parseJWTClaims(projectToken.token);
92
89
  } else {
93
90
  // REAL: Validate JWT signature against JWKS
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/project-token.ts"],"sourcesContent":["/**\n * Project Token Management\n *\n * Handles project token (JWT) generation and refresh for authenticating\n * to the Content API. Project tokens are scoped to a specific tenant/CMS\n * and have a shorter lifespan (15-30 minutes) than OAuth tokens.\n */\n\nimport type { TokenStore } from './token-store.js'\nimport type { JWTPayload } from './types.js'\n\nimport { getProjectToken as fetchProjectToken } from '../api/figma-api.js'\nimport { getEnvironment } from '../constants.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\nimport { JWTValidationError, validateProjectToken } from './jwt-validator.js'\nimport { getValidAccessToken } from './oauth-flow.js'\n\n/**\n * Error during project token operations\n */\nexport class ProjectTokenError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'ProjectTokenError'\n }\n}\n\n/**\n * Parse JWT claims from token without validation\n * Used for mock tokens where signature validation is not needed\n *\n * @param token - JWT token string\n * @returns Parsed JWT payload\n * @throws {ProjectTokenError} If JWT cannot be parsed\n */\nfunction parseJWTClaims(token: string): JWTPayload {\n try {\n // JWT format: header.payload.signature\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format')\n }\n\n // Decode the payload (second part)\n const payload = parts[1]\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/')\n const paddedBase64 = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=')\n\n const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8'))\n\n return decodedPayload as JWTPayload\n } catch (error) {\n throw new ProjectTokenError(\n `Failed to parse JWT claims: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Get a valid project token for a tenant, refreshing if necessary\n *\n * This function:\n * 1. Checks if a stored project token exists and is valid (not expired)\n * 2. If expired or missing, gets a valid user access token\n * 3. Calls the Figma API to generate a new project token\n * 4. Stores the new project token in encrypted storage\n * 5. Returns the JWT string\n *\n * The project token is used by local Payload instances to authenticate\n * requests to the Content API without requiring a round-trip to Sinatra.\n *\n * @param tokenStore - Token store for persisting tokens\n * @param tenantId - The tenant/CMS ID to get a token for\n * @returns Promise resolving to JWT token string or null if failed\n * @throws {ProjectTokenError} If token generation fails\n */\nexport async function getValidProjectToken(\n tokenStore: TokenStore,\n tenantId: string,\n): Promise<null | string> {\n // Check if we have a valid project token already\n if (tokenStore.hasValidProjectToken(tenantId)) {\n const projectToken = tokenStore.getProjectToken(tenantId)\n return projectToken?.token || null\n }\n\n // We need to refresh the project token\n // First, get a valid user access token (will auto-refresh if needed)\n let accessToken: null | string\n try {\n accessToken = await getValidAccessToken(tokenStore)\n } catch (error) {\n throw new ProjectTokenError(\n 'Failed to get valid access token for project token refresh',\n error instanceof Error ? error : undefined,\n )\n }\n\n if (!accessToken) {\n // No valid user tokens available - user needs to authenticate\n return null\n }\n\n // Fetch a new project token from the Figma API\n const projectToken = await fetchProjectToken(accessToken, tenantId)\n\n // Validate the JWT signature and claims (skip for mocks)\n const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false'\n let validatedClaims: JWTPayload\n\n if (shouldMock) {\n // MOCK: Skip JWT validation and parse claims directly\n if (isDebug()) {\n log.debug('Skipping JWT validation for mock project token')\n }\n validatedClaims = parseJWTClaims(projectToken.token)\n } else {\n // REAL: Validate JWT signature against JWKS\n try {\n validatedClaims = await validateProjectToken(projectToken.token, getEnvironment())\n } catch (validationError) {\n // Handle validation errors\n if (validationError instanceof JWTValidationError) {\n throw new ProjectTokenError(\n `Project token validation failed: ${validationError.message}`,\n validationError,\n )\n }\n throw validationError\n }\n }\n\n // Ensure exp claim is present\n if (!validatedClaims.exp) {\n throw new ProjectTokenError('Project token missing expiration (exp) claim')\n }\n\n // Store the project token with validated expiration and claims\n tokenStore.setProjectToken(tenantId, {\n claims: validatedClaims,\n expiresAt: validatedClaims.exp * 1000, // Convert from seconds to milliseconds\n tenantId,\n token: projectToken.token,\n })\n\n return projectToken.token\n}\n\n/**\n * Refresh a project token for a tenant\n *\n * Forces a refresh of the project token even if the current one is still valid.\n * Useful for testing or when you want to ensure you have the freshest token.\n *\n * @param tokenStore - Token store for persisting tokens\n * @param tenantId - The tenant/CMS ID to refresh token for\n * @returns Promise resolving to JWT token string or null if failed\n * @throws {ProjectTokenError} If token refresh fails\n */\nexport async function refreshProjectToken(\n tokenStore: TokenStore,\n tenantId: string,\n): Promise<null | string> {\n // Clear the existing project token to force a refresh\n tokenStore.clearProjectToken(tenantId)\n\n // Get a new token (which will fetch from API since we just cleared it)\n return getValidProjectToken(tokenStore, tenantId)\n}\n"],"names":["getProjectToken","fetchProjectToken","getEnvironment","isDebug","log","JWTValidationError","validateProjectToken","getValidAccessToken","ProjectTokenError","Error","message","cause","name","parseJWTClaims","token","parts","split","length","payload","base64","replace","paddedBase64","padEnd","decodedPayload","JSON","parse","Buffer","from","toString","error","undefined","getValidProjectToken","tokenStore","tenantId","hasValidProjectToken","projectToken","accessToken","shouldMock","process","env","FIGMA_MOCK_PROJECT_TOKEN","validatedClaims","debug","validationError","exp","setProjectToken","claims","expiresAt","refreshProjectToken","clearProjectToken"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/auth/project-token.ts"],"sourcesContent":["/**\n * Project Token Management\n *\n * Handles project token (JWT) generation and refresh for authenticating\n * to the Content API. Project tokens are scoped to a specific tenant/CMS\n * and have a shorter lifespan (15-30 minutes) than OAuth tokens.\n */\n\nimport type { TokenStore } from './token-store.js'\nimport type { JWTPayload } from './types.js'\n\nimport { getProjectToken as fetchProjectToken } from '../api/figma-api.js'\nimport { getEnvironment } from '../constants.js'\nimport * as log from '../utils/log.js'\nimport { JWTValidationError, validateProjectToken } from './jwt-validator.js'\nimport { getValidAccessToken } from './oauth-flow.js'\n\n/**\n * Error during project token operations\n */\nexport class ProjectTokenError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message)\n this.name = 'ProjectTokenError'\n }\n}\n\n/**\n * Parse JWT claims from token without validation\n * Used for mock tokens where signature validation is not needed\n *\n * @param token - JWT token string\n * @returns Parsed JWT payload\n * @throws {ProjectTokenError} If JWT cannot be parsed\n */\nfunction parseJWTClaims(token: string): JWTPayload {\n try {\n // JWT format: header.payload.signature\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format')\n }\n\n // Decode the payload (second part)\n const payload = parts[1]\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/')\n const paddedBase64 = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=')\n\n const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8'))\n\n return decodedPayload as JWTPayload\n } catch (error) {\n throw new ProjectTokenError(\n `Failed to parse JWT claims: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error instanceof Error ? error : undefined,\n )\n }\n}\n\n/**\n * Get a valid project token for a tenant, refreshing if necessary\n *\n * This function:\n * 1. Checks if a stored project token exists and is valid (not expired)\n * 2. If expired or missing, gets a valid user access token\n * 3. Calls the Figma API to generate a new project token\n * 4. Stores the new project token in encrypted storage\n * 5. Returns the JWT string\n *\n * The project token is used by local Payload instances to authenticate\n * requests to the Content API without requiring a round-trip to Sinatra.\n *\n * @param tokenStore - Token store for persisting tokens\n * @param tenantId - The tenant/CMS ID to get a token for\n * @returns Promise resolving to JWT token string or null if failed\n * @throws {ProjectTokenError} If token generation fails\n */\nexport async function getValidProjectToken(\n tokenStore: TokenStore,\n tenantId: string,\n): Promise<null | string> {\n // Check if we have a valid project token already\n if (tokenStore.hasValidProjectToken(tenantId)) {\n const projectToken = tokenStore.getProjectToken(tenantId)\n return projectToken?.token || null\n }\n\n // We need to refresh the project token\n // First, get a valid user access token (will auto-refresh if needed)\n let accessToken: null | string\n try {\n accessToken = await getValidAccessToken(tokenStore)\n } catch (error) {\n throw new ProjectTokenError(\n 'Failed to get valid access token for project token refresh',\n error instanceof Error ? error : undefined,\n )\n }\n\n if (!accessToken) {\n // No valid user tokens available - user needs to authenticate\n return null\n }\n\n // Fetch a new project token from the Figma API\n const projectToken = await fetchProjectToken(accessToken, tenantId)\n\n // Validate the JWT signature and claims (skip for mocks)\n const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false'\n let validatedClaims: JWTPayload\n\n if (shouldMock) {\n // MOCK: Skip JWT validation and parse claims directly\n log.debug('Skipping JWT validation for mock project token')\n validatedClaims = parseJWTClaims(projectToken.token)\n } else {\n // REAL: Validate JWT signature against JWKS\n try {\n validatedClaims = await validateProjectToken(projectToken.token, getEnvironment())\n } catch (validationError) {\n // Handle validation errors\n if (validationError instanceof JWTValidationError) {\n throw new ProjectTokenError(\n `Project token validation failed: ${validationError.message}`,\n validationError,\n )\n }\n throw validationError\n }\n }\n\n // Ensure exp claim is present\n if (!validatedClaims.exp) {\n throw new ProjectTokenError('Project token missing expiration (exp) claim')\n }\n\n // Store the project token with validated expiration and claims\n tokenStore.setProjectToken(tenantId, {\n claims: validatedClaims,\n expiresAt: validatedClaims.exp * 1000, // Convert from seconds to milliseconds\n tenantId,\n token: projectToken.token,\n })\n\n return projectToken.token\n}\n\n/**\n * Refresh a project token for a tenant\n *\n * Forces a refresh of the project token even if the current one is still valid.\n * Useful for testing or when you want to ensure you have the freshest token.\n *\n * @param tokenStore - Token store for persisting tokens\n * @param tenantId - The tenant/CMS ID to refresh token for\n * @returns Promise resolving to JWT token string or null if failed\n * @throws {ProjectTokenError} If token refresh fails\n */\nexport async function refreshProjectToken(\n tokenStore: TokenStore,\n tenantId: string,\n): Promise<null | string> {\n // Clear the existing project token to force a refresh\n tokenStore.clearProjectToken(tenantId)\n\n // Get a new token (which will fetch from API since we just cleared it)\n return getValidProjectToken(tokenStore, tenantId)\n}\n"],"names":["getProjectToken","fetchProjectToken","getEnvironment","log","JWTValidationError","validateProjectToken","getValidAccessToken","ProjectTokenError","Error","message","cause","name","parseJWTClaims","token","parts","split","length","payload","base64","replace","paddedBase64","padEnd","decodedPayload","JSON","parse","Buffer","from","toString","error","undefined","getValidProjectToken","tokenStore","tenantId","hasValidProjectToken","projectToken","accessToken","shouldMock","process","env","FIGMA_MOCK_PROJECT_TOKEN","validatedClaims","debug","validationError","exp","setProjectToken","claims","expiresAt","refreshProjectToken","clearProjectToken"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,YAAY,CAAA;AAMjE;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,UAAU,CAAC,EAAE,MAAM;gBAD1B,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,QAAQ,GAAE,MAA8B,GACvC,OAAO,CAAC,WAAW,CAAC,CAmDtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,WAAW,GAAE,MAAiC,EAC9C,QAAQ,GAAE,MAA8B,GACvC,OAAO,CAAC,WAAW,CAAC,CA8FtB"}
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,YAAY,CAAA;AAKjE;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,UAAU,CAAC,EAAE,MAAM;gBAD1B,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,QAAQ,GAAE,MAA8B,GACvC,OAAO,CAAC,WAAW,CAAC,CAmDtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,WAAW,GAAE,MAAiC,EAC9C,QAAQ,GAAE,MAA8B,GACvC,OAAO,CAAC,WAAW,CAAC,CAuFtB"}
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable perfectionist/sort-objects */ import { OAUTH_CONFIG } from '../config/oauth.js';
2
- import { isDebug } from '../utils/is-debug.js';
3
2
  import * as log from '../utils/log.js';
4
3
  /**
5
4
  * Error thrown when token refresh fails
@@ -88,43 +87,35 @@ import * as log from '../utils/log.js';
88
87
  'Content-Type': 'application/x-www-form-urlencoded'
89
88
  };
90
89
  // Debug logging
91
- if (isDebug()) {
92
- log.debug(`Token exchange request: ${JSON.stringify({
93
- url: OAUTH_CONFIG.tokenUrl,
94
- headers,
95
- body: params.toString()
96
- })}`);
97
- }
90
+ log.debug(`Token exchange request: ${JSON.stringify({
91
+ url: OAUTH_CONFIG.tokenUrl,
92
+ headers,
93
+ body: params.toString()
94
+ })}`);
98
95
  const response = await fetch(OAUTH_CONFIG.tokenUrl, {
99
96
  method: 'POST',
100
97
  headers,
101
98
  body: params.toString()
102
99
  });
103
- if (isDebug()) {
104
- log.debug(`Token exchange response: ${JSON.stringify({
105
- status: response.status,
106
- statusText: response.statusText,
107
- headers: Object.fromEntries(response.headers.entries())
108
- })}`);
109
- }
100
+ log.debug(`Token exchange response: ${JSON.stringify({
101
+ status: response.status,
102
+ statusText: response.statusText,
103
+ headers: Object.fromEntries(response.headers.entries())
104
+ })}`);
110
105
  if (!response.ok) {
111
106
  const errorText = await response.text();
112
- if (isDebug()) {
113
- log.debug(`Error response body: ${errorText}`);
114
- }
107
+ log.debug(`Error response body: ${errorText}`);
115
108
  throw new TokenRefreshError(`Token exchange failed: ${response.statusText}. ${errorText}`, response.status);
116
109
  }
117
110
  const data = await response.json();
118
- if (isDebug()) {
119
- log.debug(`Token response: ${JSON.stringify({
120
- access_token: data.access_token,
121
- token_type: data.token_type,
122
- expires_in: data.expires_in,
123
- scope: data.scope,
124
- user_id_string: data.user_id_string,
125
- refresh_token: data.refresh_token?.substring(0, 10) + '...'
126
- })}`);
127
- }
111
+ log.debug(`Token response: ${JSON.stringify({
112
+ access_token: data.access_token,
113
+ token_type: data.token_type,
114
+ expires_in: data.expires_in,
115
+ scope: data.scope,
116
+ user_id_string: data.user_id_string,
117
+ refresh_token: data.refresh_token?.substring(0, 10) + '...'
118
+ })}`);
128
119
  // Validate response contains required fields
129
120
  if (!data.access_token || !data.refresh_token || !data.expires_in) {
130
121
  throw new TokenRefreshError('Invalid token response: missing required fields');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/refresh.ts"],"sourcesContent":["/* eslint-disable perfectionist/sort-objects */\nimport type { FigmaTokenResponse, FigmaTokens } from './types.js'\n\nimport { OAUTH_CONFIG } from '../config/oauth.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\n\n/**\n * Error thrown when token refresh fails\n */\nexport class TokenRefreshError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message)\n this.name = 'TokenRefreshError'\n }\n}\n\n/**\n * Refresh an expired OAuth2 access token using a refresh token\n *\n * Makes a POST request to Figma's token endpoint with the refresh token\n * to obtain a new access token. Uses public client pattern (no client secret).\n *\n * @param refreshToken - The refresh token to use\n * @param clientId - OAuth2 client ID (defaults to config)\n * @returns Promise resolving to new tokens\n * @throws TokenRefreshError if refresh fails\n */\nexport async function refreshAccessToken(\n refreshToken: string,\n clientId: string = OAUTH_CONFIG.clientId,\n): Promise<FigmaTokens> {\n // Prepare form data for token refresh request (public client)\n const params = new URLSearchParams({\n client_id: clientId,\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n })\n\n try {\n const response = await fetch(OAUTH_CONFIG.refreshUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params.toString(),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new TokenRefreshError(\n `Token refresh failed: ${response.statusText}. ${errorText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as FigmaTokenResponse\n\n // Validate response contains required fields\n if (!data.access_token || !data.refresh_token || !data.expires_in) {\n throw new TokenRefreshError('Invalid token response: missing required fields')\n }\n\n // Convert response to our internal token format\n const expiresAt = Date.now() + data.expires_in * 1000\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt,\n userId: data.user_id_string,\n }\n } catch (error) {\n if (error instanceof TokenRefreshError) {\n throw error\n }\n\n // Handle network errors and other exceptions\n throw new TokenRefreshError(\n `Failed to refresh token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n}\n\n/**\n * Exchange an authorization code for OAuth2 tokens\n *\n * This is used during the initial OAuth flow after the user authorizes the app.\n * Uses public client pattern with PKCE (code verifier is required).\n *\n * @param code - Authorization code from OAuth callback\n * @param codeVerifier - PKCE code verifier (required for public clients)\n * @param redirectUri - Redirect URI used in the authorization request\n * @param clientId - OAuth2 client ID (defaults to config)\n * @returns Promise resolving to tokens\n * @throws TokenRefreshError if exchange fails\n */\nexport async function exchangeCodeForTokens(\n code: string,\n codeVerifier: string,\n redirectUri: string = OAUTH_CONFIG.redirectUri,\n clientId: string = OAUTH_CONFIG.clientId,\n): Promise<FigmaTokens> {\n // Prepare form data for token exchange (public client with PKCE)\n const params = new URLSearchParams({\n client_id: clientId,\n code,\n code_verifier: codeVerifier,\n grant_type: 'authorization_code',\n redirect_uri: redirectUri,\n })\n\n try {\n // Public client - no client secret or Basic Auth header needed\n // Security is provided by PKCE (code_verifier in the request body)\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n }\n\n // Debug logging\n if (isDebug()) {\n log.debug(\n `Token exchange request: ${JSON.stringify({\n url: OAUTH_CONFIG.tokenUrl,\n headers,\n body: params.toString(),\n })}`,\n )\n }\n\n const response = await fetch(OAUTH_CONFIG.tokenUrl, {\n method: 'POST',\n headers,\n body: params.toString(),\n })\n\n if (isDebug()) {\n log.debug(\n `Token exchange response: ${JSON.stringify({\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n })}`,\n )\n }\n\n if (!response.ok) {\n const errorText = await response.text()\n if (isDebug()) {\n log.debug(`Error response body: ${errorText}`)\n }\n throw new TokenRefreshError(\n `Token exchange failed: ${response.statusText}. ${errorText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as FigmaTokenResponse\n\n if (isDebug()) {\n log.debug(\n `Token response: ${JSON.stringify({\n access_token: data.access_token,\n token_type: data.token_type,\n expires_in: data.expires_in,\n scope: data.scope,\n user_id_string: data.user_id_string,\n refresh_token: data.refresh_token?.substring(0, 10) + '...',\n })}`,\n )\n }\n\n // Validate response contains required fields\n if (!data.access_token || !data.refresh_token || !data.expires_in) {\n throw new TokenRefreshError('Invalid token response: missing required fields')\n }\n\n // Convert response to our internal token format\n const expiresAt = Date.now() + data.expires_in * 1000\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt,\n userId: data.user_id_string,\n }\n } catch (error) {\n if (error instanceof TokenRefreshError) {\n throw error\n }\n\n // Handle network errors and other exceptions\n throw new TokenRefreshError(\n `Failed to exchange code for tokens: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n}\n"],"names":["OAUTH_CONFIG","isDebug","log","TokenRefreshError","Error","message","statusCode","name","refreshAccessToken","refreshToken","clientId","params","URLSearchParams","client_id","grant_type","refresh_token","response","fetch","refreshUrl","method","headers","body","toString","ok","errorText","text","statusText","status","data","json","access_token","expires_in","expiresAt","Date","now","accessToken","userId","user_id_string","error","exchangeCodeForTokens","code","codeVerifier","redirectUri","code_verifier","redirect_uri","debug","JSON","stringify","url","tokenUrl","Object","fromEntries","entries","token_type","scope","substring"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/auth/refresh.ts"],"sourcesContent":["/* eslint-disable perfectionist/sort-objects */\nimport type { FigmaTokenResponse, FigmaTokens } from './types.js'\n\nimport { OAUTH_CONFIG } from '../config/oauth.js'\nimport * as log from '../utils/log.js'\n\n/**\n * Error thrown when token refresh fails\n */\nexport class TokenRefreshError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message)\n this.name = 'TokenRefreshError'\n }\n}\n\n/**\n * Refresh an expired OAuth2 access token using a refresh token\n *\n * Makes a POST request to Figma's token endpoint with the refresh token\n * to obtain a new access token. Uses public client pattern (no client secret).\n *\n * @param refreshToken - The refresh token to use\n * @param clientId - OAuth2 client ID (defaults to config)\n * @returns Promise resolving to new tokens\n * @throws TokenRefreshError if refresh fails\n */\nexport async function refreshAccessToken(\n refreshToken: string,\n clientId: string = OAUTH_CONFIG.clientId,\n): Promise<FigmaTokens> {\n // Prepare form data for token refresh request (public client)\n const params = new URLSearchParams({\n client_id: clientId,\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n })\n\n try {\n const response = await fetch(OAUTH_CONFIG.refreshUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params.toString(),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new TokenRefreshError(\n `Token refresh failed: ${response.statusText}. ${errorText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as FigmaTokenResponse\n\n // Validate response contains required fields\n if (!data.access_token || !data.refresh_token || !data.expires_in) {\n throw new TokenRefreshError('Invalid token response: missing required fields')\n }\n\n // Convert response to our internal token format\n const expiresAt = Date.now() + data.expires_in * 1000\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt,\n userId: data.user_id_string,\n }\n } catch (error) {\n if (error instanceof TokenRefreshError) {\n throw error\n }\n\n // Handle network errors and other exceptions\n throw new TokenRefreshError(\n `Failed to refresh token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n}\n\n/**\n * Exchange an authorization code for OAuth2 tokens\n *\n * This is used during the initial OAuth flow after the user authorizes the app.\n * Uses public client pattern with PKCE (code verifier is required).\n *\n * @param code - Authorization code from OAuth callback\n * @param codeVerifier - PKCE code verifier (required for public clients)\n * @param redirectUri - Redirect URI used in the authorization request\n * @param clientId - OAuth2 client ID (defaults to config)\n * @returns Promise resolving to tokens\n * @throws TokenRefreshError if exchange fails\n */\nexport async function exchangeCodeForTokens(\n code: string,\n codeVerifier: string,\n redirectUri: string = OAUTH_CONFIG.redirectUri,\n clientId: string = OAUTH_CONFIG.clientId,\n): Promise<FigmaTokens> {\n // Prepare form data for token exchange (public client with PKCE)\n const params = new URLSearchParams({\n client_id: clientId,\n code,\n code_verifier: codeVerifier,\n grant_type: 'authorization_code',\n redirect_uri: redirectUri,\n })\n\n try {\n // Public client - no client secret or Basic Auth header needed\n // Security is provided by PKCE (code_verifier in the request body)\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n }\n\n // Debug logging\n log.debug(\n `Token exchange request: ${JSON.stringify({\n url: OAUTH_CONFIG.tokenUrl,\n headers,\n body: params.toString(),\n })}`,\n )\n\n const response = await fetch(OAUTH_CONFIG.tokenUrl, {\n method: 'POST',\n headers,\n body: params.toString(),\n })\n\n log.debug(\n `Token exchange response: ${JSON.stringify({\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n })}`,\n )\n\n if (!response.ok) {\n const errorText = await response.text()\n log.debug(`Error response body: ${errorText}`)\n\n throw new TokenRefreshError(\n `Token exchange failed: ${response.statusText}. ${errorText}`,\n response.status,\n )\n }\n\n const data = (await response.json()) as FigmaTokenResponse\n\n log.debug(\n `Token response: ${JSON.stringify({\n access_token: data.access_token,\n token_type: data.token_type,\n expires_in: data.expires_in,\n scope: data.scope,\n user_id_string: data.user_id_string,\n refresh_token: data.refresh_token?.substring(0, 10) + '...',\n })}`,\n )\n\n // Validate response contains required fields\n if (!data.access_token || !data.refresh_token || !data.expires_in) {\n throw new TokenRefreshError('Invalid token response: missing required fields')\n }\n\n // Convert response to our internal token format\n const expiresAt = Date.now() + data.expires_in * 1000\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt,\n userId: data.user_id_string,\n }\n } catch (error) {\n if (error instanceof TokenRefreshError) {\n throw error\n }\n\n // Handle network errors and other exceptions\n throw new TokenRefreshError(\n `Failed to exchange code for tokens: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n}\n"],"names":["OAUTH_CONFIG","log","TokenRefreshError","Error","message","statusCode","name","refreshAccessToken","refreshToken","clientId","params","URLSearchParams","client_id","grant_type","refresh_token","response","fetch","refreshUrl","method","headers","body","toString","ok","errorText","text","statusText","status","data","json","access_token","expires_in","expiresAt","Date","now","accessToken","userId","user_id_string","error","exchangeCodeForTokens","code","codeVerifier","redirectUri","code_verifier","redirect_uri","debug","JSON","stringify","url","tokenUrl","Object","fromEntries","entries","token_type","scope","substring"],"mappings":"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"}
@@ -174,7 +174,7 @@ export interface JWTPayload extends JoseJWTPayload {
174
174
  * Used by local Payload instances to make authenticated requests
175
175
  */
176
176
  export interface ProjectToken {
177
- /** Validated JWT claims (populated after validation) */
177
+ /** Validated JWT claims */
178
178
  claims?: JWTPayload;
179
179
  /** Unix timestamp (milliseconds) when the token expires (from validated exp claim) */
180
180
  expiresAt: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}