@payloadcms/figma 0.1.0-alpha.2 → 0.1.0-alpha.4

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 (219) hide show
  1. package/dist/api/check-project-subdomain-availability.d.ts +12 -0
  2. package/dist/api/check-project-subdomain-availability.js +32 -0
  3. package/dist/api/control-plane-error.d.ts +6 -0
  4. package/dist/api/control-plane-error.js +8 -0
  5. package/dist/api/control-plane-fetch.d.ts +7 -0
  6. package/dist/api/control-plane-fetch.js +37 -0
  7. package/dist/api/control-plane.d.ts +1 -9
  8. package/dist/api/control-plane.js +2 -48
  9. package/dist/api/create-project.d.ts +18 -0
  10. package/dist/api/create-project.js +37 -0
  11. package/dist/api/list-project-workspaces.d.ts +8 -0
  12. package/dist/api/list-project-workspaces.js +28 -0
  13. package/dist/api/project-resource-type.d.ts +1 -0
  14. package/dist/api/project-resource-type.js +1 -0
  15. package/dist/auth/headless-oauth-flow.d.ts +23 -0
  16. package/dist/auth/headless-oauth-flow.js +69 -0
  17. package/dist/auth/oauth-flow.d.ts +2 -0
  18. package/dist/auth/oauth-flow.js +13 -8
  19. package/dist/auth/token-store.d.ts +4 -1
  20. package/dist/auth/token-store.js +14 -0
  21. package/dist/auth/types.d.ts +12 -0
  22. package/dist/cli.d.ts +39 -0
  23. package/dist/cli.js +71 -36
  24. package/dist/commands/bootstrap.js +2 -1
  25. package/dist/commands/deploy.d.ts +12 -0
  26. package/dist/commands/deploy.js +61 -23
  27. package/dist/commands/detect-project-resource-type.d.ts +3 -0
  28. package/dist/commands/detect-project-resource-type.js +28 -0
  29. package/dist/commands/init.d.ts +2 -2
  30. package/dist/commands/init.js +163 -78
  31. package/dist/commands/login.d.ts +11 -1
  32. package/dist/commands/login.js +66 -4
  33. package/dist/commands/prompt-to-create-project/format-project-subdomain.d.ts +1 -0
  34. package/dist/commands/prompt-to-create-project/format-project-subdomain.js +3 -0
  35. package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.d.ts +1 -0
  36. package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.js +7 -0
  37. package/dist/commands/prompt-to-create-project/get-default-project-name.d.ts +1 -0
  38. package/dist/commands/prompt-to-create-project/get-default-project-name.js +13 -0
  39. package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.d.ts +7 -0
  40. package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.js +32 -0
  41. package/dist/commands/prompt-to-create-project/resolve-project-region.d.ts +8 -0
  42. package/dist/commands/prompt-to-create-project/resolve-project-region.js +27 -0
  43. package/dist/commands/prompt-to-create-project/resolve-project-subdomain.d.ts +9 -0
  44. package/dist/commands/prompt-to-create-project/resolve-project-subdomain.js +54 -0
  45. package/dist/commands/prompt-to-create-project/resolve-text-input.d.ts +9 -0
  46. package/dist/commands/prompt-to-create-project/resolve-text-input.js +23 -0
  47. package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.d.ts +12 -0
  48. package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.js +36 -0
  49. package/dist/commands/prompt-to-create-project/validate-subdomain.d.ts +1 -0
  50. package/dist/commands/prompt-to-create-project/validate-subdomain.js +9 -0
  51. package/dist/commands/prompt-to-create-project.d.ts +24 -0
  52. package/dist/commands/prompt-to-create-project.js +69 -0
  53. package/dist/commands/setup-agent.d.ts +12 -0
  54. package/dist/commands/setup-agent.js +123 -0
  55. package/dist/commands/write-project-configuration.d.ts +12 -0
  56. package/dist/commands/write-project-configuration.js +16 -0
  57. package/dist/db-content-api/index.d.ts +1 -1
  58. package/dist/db-content-api/index.js +90 -55
  59. package/dist/db-content-api/utilities/data/injectGlobalType.d.ts +6 -0
  60. package/dist/db-content-api/utilities/data/injectGlobalType.js +11 -0
  61. package/dist/db-content-api/utilities/data/stringifyNumericIds.d.ts +1 -0
  62. package/dist/db-content-api/utilities/data/stringifyNumericIds.js +19 -0
  63. package/dist/db-content-api/utilities/isRecord.d.ts +9 -0
  64. package/dist/db-content-api/utilities/isRecord.js +19 -0
  65. package/dist/db-content-api/utilities/schema/getDocumentSchema.d.ts +3 -0
  66. package/dist/db-content-api/utilities/schema/getDocumentSchema.js +24 -0
  67. package/dist/db-content-api/utilities/where.js +6 -4
  68. package/dist/exports/client.d.ts +2 -0
  69. package/dist/exports/client.js +2 -0
  70. package/dist/lib/write-agent-config.d.ts +12 -0
  71. package/dist/lib/write-agent-config.js +52 -0
  72. package/dist/plugin/build-config.js +32 -3
  73. package/dist/plugin/cloud-limits/CloudLimitModal/index.d.ts +9 -0
  74. package/dist/plugin/cloud-limits/CloudLimitModal/index.js +78 -0
  75. package/dist/plugin/cloud-limits/CloudLimitModal/index.scss +51 -0
  76. package/dist/plugin/cloud-limits/CloudLimitProvider/index.d.ts +7 -0
  77. package/dist/plugin/cloud-limits/CloudLimitProvider/index.js +169 -0
  78. package/dist/plugin/cloud-limits/SlugRegistryContext/index.d.ts +2 -0
  79. package/dist/plugin/cloud-limits/SlugRegistryContext/index.js +3 -0
  80. package/dist/plugin/cloud-limits/SlugTracker/index.d.ts +9 -0
  81. package/dist/plugin/cloud-limits/SlugTracker/index.js +23 -0
  82. package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.d.ts +2 -0
  83. package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.js +30 -0
  84. package/dist/plugin/cloud-limits/shared.d.ts +10 -0
  85. package/dist/plugin/cloud-limits/shared.js +27 -0
  86. package/dist/skills/deploy-to-figma/SKILL.md +234 -0
  87. package/dist/skills/deploy-to-figma/references/cli-reference.md +146 -0
  88. package/dist/translations/ar.d.ts +12 -0
  89. package/dist/translations/ar.js +12 -0
  90. package/dist/translations/az.d.ts +12 -0
  91. package/dist/translations/az.js +12 -0
  92. package/dist/translations/bg.d.ts +12 -0
  93. package/dist/translations/bg.js +12 -0
  94. package/dist/translations/bnBd.d.ts +12 -0
  95. package/dist/translations/bnBd.js +12 -0
  96. package/dist/translations/bnIn.d.ts +12 -0
  97. package/dist/translations/bnIn.js +12 -0
  98. package/dist/translations/ca.d.ts +12 -0
  99. package/dist/translations/ca.js +12 -0
  100. package/dist/translations/cs.d.ts +12 -0
  101. package/dist/translations/cs.js +12 -0
  102. package/dist/translations/da.d.ts +12 -0
  103. package/dist/translations/da.js +12 -0
  104. package/dist/translations/de.d.ts +12 -0
  105. package/dist/translations/de.js +12 -0
  106. package/dist/translations/en.d.ts +12 -0
  107. package/dist/translations/en.js +12 -0
  108. package/dist/translations/es.d.ts +12 -0
  109. package/dist/translations/es.js +12 -0
  110. package/dist/translations/et.d.ts +12 -0
  111. package/dist/translations/et.js +12 -0
  112. package/dist/translations/fa.d.ts +12 -0
  113. package/dist/translations/fa.js +12 -0
  114. package/dist/translations/fr.d.ts +12 -0
  115. package/dist/translations/fr.js +12 -0
  116. package/dist/translations/he.d.ts +12 -0
  117. package/dist/translations/he.js +12 -0
  118. package/dist/translations/hr.d.ts +12 -0
  119. package/dist/translations/hr.js +12 -0
  120. package/dist/translations/hu.d.ts +12 -0
  121. package/dist/translations/hu.js +12 -0
  122. package/dist/translations/hy.d.ts +12 -0
  123. package/dist/translations/hy.js +12 -0
  124. package/dist/translations/id.d.ts +12 -0
  125. package/dist/translations/id.js +12 -0
  126. package/dist/translations/index.d.ts +533 -0
  127. package/dist/translations/index.js +90 -0
  128. package/dist/translations/is.d.ts +12 -0
  129. package/dist/translations/is.js +12 -0
  130. package/dist/translations/it.d.ts +12 -0
  131. package/dist/translations/it.js +12 -0
  132. package/dist/translations/ja.d.ts +12 -0
  133. package/dist/translations/ja.js +12 -0
  134. package/dist/translations/ko.d.ts +12 -0
  135. package/dist/translations/ko.js +12 -0
  136. package/dist/translations/lt.d.ts +12 -0
  137. package/dist/translations/lt.js +12 -0
  138. package/dist/translations/lv.d.ts +12 -0
  139. package/dist/translations/lv.js +12 -0
  140. package/dist/translations/my.d.ts +12 -0
  141. package/dist/translations/my.js +12 -0
  142. package/dist/translations/nb.d.ts +12 -0
  143. package/dist/translations/nb.js +12 -0
  144. package/dist/translations/nl.d.ts +12 -0
  145. package/dist/translations/nl.js +12 -0
  146. package/dist/translations/pl.d.ts +12 -0
  147. package/dist/translations/pl.js +12 -0
  148. package/dist/translations/pt.d.ts +12 -0
  149. package/dist/translations/pt.js +12 -0
  150. package/dist/translations/ro.d.ts +12 -0
  151. package/dist/translations/ro.js +12 -0
  152. package/dist/translations/rs.d.ts +12 -0
  153. package/dist/translations/rs.js +12 -0
  154. package/dist/translations/rsLatin.d.ts +12 -0
  155. package/dist/translations/rsLatin.js +12 -0
  156. package/dist/translations/ru.d.ts +12 -0
  157. package/dist/translations/ru.js +12 -0
  158. package/dist/translations/sk.d.ts +12 -0
  159. package/dist/translations/sk.js +12 -0
  160. package/dist/translations/sl.d.ts +12 -0
  161. package/dist/translations/sl.js +12 -0
  162. package/dist/translations/sv.d.ts +12 -0
  163. package/dist/translations/sv.js +12 -0
  164. package/dist/translations/ta.d.ts +12 -0
  165. package/dist/translations/ta.js +12 -0
  166. package/dist/translations/th.d.ts +12 -0
  167. package/dist/translations/th.js +12 -0
  168. package/dist/translations/tr.d.ts +12 -0
  169. package/dist/translations/tr.js +12 -0
  170. package/dist/translations/uk.d.ts +12 -0
  171. package/dist/translations/uk.js +12 -0
  172. package/dist/translations/vi.d.ts +12 -0
  173. package/dist/translations/vi.js +12 -0
  174. package/dist/translations/zh.d.ts +12 -0
  175. package/dist/translations/zh.js +12 -0
  176. package/dist/translations/zhTw.d.ts +12 -0
  177. package/dist/translations/zhTw.js +12 -0
  178. package/dist/types.d.ts +11 -0
  179. package/dist/utils/adapters/nextjs.d.ts +3 -3
  180. package/dist/utils/adapters/nextjs.js +9 -7
  181. package/dist/utils/adapters/nitro.d.ts +3 -3
  182. package/dist/utils/adapters/nitro.js +73 -77
  183. package/dist/utils/adapters/vite.d.ts +1 -1
  184. package/dist/utils/adapters/vite.js +8 -7
  185. package/dist/utils/assert-never.d.ts +1 -0
  186. package/dist/utils/assert-never.js +3 -0
  187. package/dist/utils/asset-collection.d.ts +2 -2
  188. package/dist/utils/asset-collection.js +10 -15
  189. package/dist/utils/build-detection.d.ts +6 -1
  190. package/dist/utils/build-detection.js +68 -89
  191. package/dist/utils/build-lambda-zip.d.ts +5 -6
  192. package/dist/utils/build-lambda-zip.js +31 -48
  193. package/dist/utils/deploy-adapter.d.ts +4 -4
  194. package/dist/utils/deploy-adapter.js +12 -8
  195. package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.d.ts +1 -0
  196. package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.js +15 -0
  197. package/dist/utils/deploy-output/inspectNextjsOutput.d.ts +12 -0
  198. package/dist/utils/deploy-output/inspectNextjsOutput.js +28 -0
  199. package/dist/utils/deploy-output/inspectNitroOutput.d.ts +9 -0
  200. package/dist/utils/deploy-output/inspectNitroOutput.js +13 -0
  201. package/dist/utils/deploy-output/isFile.d.ts +1 -0
  202. package/dist/utils/deploy-output/isFile.js +4 -0
  203. package/dist/utils/deploy-output/readJson.d.ts +1 -0
  204. package/dist/utils/deploy-output/readJson.js +9 -0
  205. package/dist/utils/deploy-output/resolveNitroOutputLayout.d.ts +8 -0
  206. package/dist/utils/deploy-output/resolveNitroOutputLayout.js +16 -0
  207. package/dist/utils/deploy-output/resolveOutputPath.d.ts +2 -0
  208. package/dist/utils/deploy-output/resolveOutputPath.js +9 -0
  209. package/dist/utils/deploy-output/resolveWithin.d.ts +1 -0
  210. package/dist/utils/deploy-output/resolveWithin.js +12 -0
  211. package/dist/utils/lambda-config.js +4 -14
  212. package/dist/utils/messages.js +24 -3
  213. package/dist/utils/payload-generate.d.ts +10 -0
  214. package/dist/utils/payload-generate.js +59 -0
  215. package/dist/utils/pnpm-builds.d.ts +14 -0
  216. package/dist/utils/pnpm-builds.js +125 -0
  217. package/package.json +6 -5
  218. package/dist/lib/download-skill.d.ts +0 -12
  219. package/dist/lib/download-skill.js +0 -77
@@ -0,0 +1,12 @@
1
+ import type { AuthCredential } from '../auth/credentials.js';
2
+ interface CheckProjectSubdomainAvailabilityArgs {
3
+ credential: AuthCredential;
4
+ subdomain: string;
5
+ }
6
+ interface ProjectSubdomainAvailability {
7
+ available: boolean;
8
+ domainName: string;
9
+ reason: string;
10
+ }
11
+ export declare function checkProjectSubdomainAvailability({ credential, subdomain, }: CheckProjectSubdomainAvailabilityArgs): Promise<ProjectSubdomainAvailability>;
12
+ export {};
@@ -0,0 +1,32 @@
1
+ import { getAuthHeaders } from '../auth/credentials.js';
2
+ import { getEnvConfig } from '../constants.js';
3
+ import { controlPlaneFetch } from './control-plane-fetch.js';
4
+ export async function checkProjectSubdomainAvailability({ credential, subdomain }) {
5
+ if (process.env.FIGMA_MOCK_CONTROL_PLANE === 'true') {
6
+ return {
7
+ available: true,
8
+ domainName: `${subdomain}.pung.site`,
9
+ reason: ''
10
+ };
11
+ }
12
+ const response = await controlPlaneFetch({
13
+ context: 'check project subdomain availability',
14
+ options: {
15
+ body: JSON.stringify({
16
+ subdomain
17
+ }),
18
+ headers: {
19
+ ...getAuthHeaders(credential),
20
+ 'Content-Type': 'application/json'
21
+ },
22
+ method: 'POST'
23
+ },
24
+ url: `${getEnvConfig().apiBaseUrl}/v1/cms/check_domain_availability`
25
+ });
26
+ const availabilityResponse = await response.json();
27
+ return {
28
+ available: availabilityResponse.meta.available,
29
+ domainName: availabilityResponse.meta.domain_name,
30
+ reason: availabilityResponse.meta.reason
31
+ };
32
+ }
@@ -0,0 +1,6 @@
1
+ /** Error thrown when Control Plane API calls fail. */
2
+ export declare class ControlPlaneError extends Error {
3
+ statusCode?: number | undefined;
4
+ cause?: Error | undefined;
5
+ constructor(message: string, statusCode?: number | undefined, cause?: Error | undefined);
6
+ }
@@ -0,0 +1,8 @@
1
+ /** Error thrown when Control Plane API calls fail. */ export class ControlPlaneError extends Error {
2
+ statusCode;
3
+ cause;
4
+ constructor(message, statusCode, cause){
5
+ super(message), this.statusCode = statusCode, this.cause = cause;
6
+ this.name = 'ControlPlaneError';
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ interface ControlPlaneFetchArgs {
2
+ context: string;
3
+ options: RequestInit;
4
+ url: string;
5
+ }
6
+ export declare function controlPlaneFetch({ context, options, url }: ControlPlaneFetchArgs): Promise<Response>;
7
+ export {};
@@ -0,0 +1,37 @@
1
+ import { ControlPlaneError } from './control-plane-error.js';
2
+ import { parseControlPlaneApiError } from './error-response.js';
3
+ const MAX_RETRIES = 3;
4
+ const INITIAL_RETRY_DELAY = 1000;
5
+ export async function controlPlaneFetch({ context, options, url }) {
6
+ let lastError;
7
+ for(let attempt = 0; attempt < MAX_RETRIES; attempt++){
8
+ try {
9
+ const response = await fetch(url, options);
10
+ if (response.ok) {
11
+ return response;
12
+ }
13
+ if (response.status < 500) {
14
+ throw new ControlPlaneError(await parseControlPlaneApiError({
15
+ context,
16
+ response
17
+ }), response.status);
18
+ }
19
+ lastError = new ControlPlaneError(await parseControlPlaneApiError({
20
+ context,
21
+ response
22
+ }), response.status);
23
+ } catch (error) {
24
+ if (error instanceof ControlPlaneError) {
25
+ throw error;
26
+ }
27
+ lastError = error instanceof Error ? error : new Error('Unknown error');
28
+ }
29
+ if (attempt < MAX_RETRIES - 1) {
30
+ await sleep(INITIAL_RETRY_DELAY * Math.pow(2, attempt));
31
+ }
32
+ }
33
+ throw new ControlPlaneError(`Network error while ${context}: ${lastError?.message || 'Unknown error'}`, undefined, lastError);
34
+ }
35
+ function sleep(ms) {
36
+ return new Promise((resolve)=>setTimeout(resolve, ms));
37
+ }
@@ -5,14 +5,6 @@
5
5
  */
6
6
  import type { AuthCredential } from '../auth/credentials.js';
7
7
  import type { Tenant } from '../types/config.js';
8
- /**
9
- * Error thrown when Control Plane API calls fail
10
- */
11
- export declare class ControlPlaneError extends Error {
12
- statusCode?: number | undefined;
13
- cause?: Error | undefined;
14
- constructor(message: string, statusCode?: number | undefined, cause?: Error | undefined);
15
- }
16
8
  /**
17
9
  * Options for creating a new tenant
18
10
  */
@@ -77,7 +69,7 @@ export interface PerformDeploymentResponse {
77
69
  deploymentId: string;
78
70
  /** Status message */
79
71
  message: string;
80
- /** List of tenant domains */
72
+ /** SiteDomain hostnames returned through the compatibility tenant_domains key */
81
73
  tenantDomains: string[];
82
74
  }
83
75
  export interface PerformDeploymentApiResponse {
@@ -5,22 +5,12 @@
5
5
  */ import { getAuthHeaders } from '../auth/credentials.js';
6
6
  import { getEnvConfig } from '../constants.js';
7
7
  import * as log from '../utils/log.js';
8
- import { parseControlPlaneApiError } from './error-response.js';
8
+ import { controlPlaneFetch } from './control-plane-fetch.js';
9
9
  /**
10
10
  * Get the Control Plane API base URL based on environment
11
11
  */ function getControlPlaneBaseUrl() {
12
12
  return getEnvConfig().apiBaseUrl;
13
13
  }
14
- /**
15
- * Error thrown when Control Plane API calls fail
16
- */ export class ControlPlaneError extends Error {
17
- statusCode;
18
- cause;
19
- constructor(message, statusCode, cause){
20
- super(message), this.statusCode = statusCode, this.cause = cause;
21
- this.name = 'ControlPlaneError';
22
- }
23
- }
24
14
  /**
25
15
  * List all tenant instances for the authenticated user
26
16
  * Maps to: GET /v1/tenant
@@ -234,7 +224,7 @@ import { parseControlPlaneApiError } from './error-response.js';
234
224
  deploymentId: options.deploymentId,
235
225
  message: 'Deployment initiated successfully',
236
226
  tenantDomains: [
237
- 'example.figmasource.site'
227
+ 'example.figma.site'
238
228
  ]
239
229
  };
240
230
  }
@@ -316,39 +306,3 @@ import { parseControlPlaneApiError } from './error-response.js';
316
306
  const data = await response.json();
317
307
  return data.meta.cms_resource_id;
318
308
  }
319
- const MAX_RETRIES = 3;
320
- const INITIAL_RETRY_DELAY = 1000;
321
- function sleep(ms) {
322
- return new Promise((resolve)=>setTimeout(resolve, ms));
323
- }
324
- async function controlPlaneFetch(params) {
325
- const { context, options, url } = params;
326
- let lastError;
327
- for(let attempt = 0; attempt < MAX_RETRIES; attempt++){
328
- try {
329
- const response = await fetch(url, options);
330
- if (response.ok) {
331
- return response;
332
- }
333
- if (response.status < 500) {
334
- throw new ControlPlaneError(await parseControlPlaneApiError({
335
- context,
336
- response
337
- }), response.status);
338
- }
339
- lastError = new ControlPlaneError(await parseControlPlaneApiError({
340
- context,
341
- response
342
- }), response.status);
343
- } catch (error) {
344
- if (error instanceof ControlPlaneError) {
345
- throw error;
346
- }
347
- lastError = error instanceof Error ? error : new Error('Unknown error');
348
- }
349
- if (attempt < MAX_RETRIES - 1) {
350
- await sleep(INITIAL_RETRY_DELAY * Math.pow(2, attempt));
351
- }
352
- }
353
- throw new ControlPlaneError(`Network error while ${context}: ${lastError?.message || 'Unknown error'}`, undefined, lastError);
354
- }
@@ -0,0 +1,18 @@
1
+ import type { AuthCredential } from '../auth/credentials.js';
2
+ import type { ProjectResourceType } from './project-resource-type.js';
3
+ interface CreateProjectArgs {
4
+ credential: AuthCredential;
5
+ description: string;
6
+ name: string;
7
+ parentPlanKey: string;
8
+ region: string;
9
+ resourceType: ProjectResourceType;
10
+ subdomain: string;
11
+ }
12
+ interface CreateProjectResponse {
13
+ domainName: string;
14
+ id: string;
15
+ name: string;
16
+ }
17
+ export declare function createProject({ name, credential, description, parentPlanKey, region, resourceType, subdomain, }: CreateProjectArgs): Promise<CreateProjectResponse>;
18
+ export {};
@@ -0,0 +1,37 @@
1
+ import { getAuthHeaders } from '../auth/credentials.js';
2
+ import { getEnvConfig } from '../constants.js';
3
+ import { controlPlaneFetch } from './control-plane-fetch.js';
4
+ export async function createProject({ name, credential, description, parentPlanKey, region, resourceType, subdomain }) {
5
+ if (process.env.FIGMA_MOCK_CONTROL_PLANE === 'true') {
6
+ return {
7
+ id: `cms_${Math.random().toString(36).substring(2, 11)}`,
8
+ name,
9
+ domainName: `${subdomain}.figmasource.site`
10
+ };
11
+ }
12
+ const response = await controlPlaneFetch({
13
+ context: 'create project',
14
+ options: {
15
+ body: JSON.stringify({
16
+ name,
17
+ description,
18
+ parent_plan_key: parentPlanKey,
19
+ region,
20
+ resource_type: resourceType,
21
+ subdomain
22
+ }),
23
+ headers: {
24
+ ...getAuthHeaders(credential),
25
+ 'Content-Type': 'application/json'
26
+ },
27
+ method: 'POST'
28
+ },
29
+ url: `${getEnvConfig().apiBaseUrl}/v1/cms`
30
+ });
31
+ const projectResponse = await response.json();
32
+ return {
33
+ id: projectResponse.meta.tenant.id,
34
+ name: projectResponse.meta.tenant.name,
35
+ domainName: projectResponse.meta.tenant.domain_name
36
+ };
37
+ }
@@ -0,0 +1,8 @@
1
+ import type { AuthCredential } from '../auth/credentials.js';
2
+ interface ProjectWorkspace {
3
+ isDefault: boolean;
4
+ name: string;
5
+ planKey: string;
6
+ }
7
+ export declare function listProjectWorkspaces(credential: AuthCredential): Promise<ProjectWorkspace[]>;
8
+ export {};
@@ -0,0 +1,28 @@
1
+ import { getAuthHeaders } from '../auth/credentials.js';
2
+ import { getEnvConfig } from '../constants.js';
3
+ import { controlPlaneFetch } from './control-plane-fetch.js';
4
+ export async function listProjectWorkspaces(credential) {
5
+ if (process.env.FIGMA_MOCK_CONTROL_PLANE === 'true') {
6
+ return [
7
+ {
8
+ name: 'Mock workspace',
9
+ isDefault: true,
10
+ planKey: 'team::mock-workspace'
11
+ }
12
+ ];
13
+ }
14
+ const response = await controlPlaneFetch({
15
+ context: 'list project workspaces',
16
+ options: {
17
+ headers: getAuthHeaders(credential),
18
+ method: 'POST'
19
+ },
20
+ url: `${getEnvConfig().apiBaseUrl}/v1/cms/workspaces`
21
+ });
22
+ const workspaceResponse = await response.json();
23
+ return workspaceResponse.meta.workspaces.map((workspace)=>({
24
+ name: workspace.name,
25
+ isDefault: workspace.is_default,
26
+ planKey: workspace.plan_key
27
+ }));
28
+ }
@@ -0,0 +1 @@
1
+ export type ProjectResourceType = 'payload' | 'vite';
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,23 @@
1
+ import type { TokenStore } from './token-store.js';
2
+ export interface StartHeadlessOAuthFlowResult {
3
+ authorizationUrl: string;
4
+ expiresAt: number;
5
+ sessionId: string;
6
+ }
7
+ export declare class HeadlessOAuthFlowError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ /** Start OAuth without a callback listener so another process can resume it. */
11
+ export declare function startHeadlessOAuthFlow(tokenStore: TokenStore, options?: {
12
+ now?: number;
13
+ }): StartHeadlessOAuthFlowResult;
14
+ /** Complete a previously started headless OAuth flow and store its tokens. */
15
+ export declare function completeHeadlessOAuthFlow({ callbackUrl, now, sessionId, tokenStore, }: {
16
+ callbackUrl: string;
17
+ now?: number;
18
+ sessionId: string;
19
+ tokenStore: TokenStore;
20
+ }): Promise<{
21
+ tokens: import("./types.js").FigmaTokens;
22
+ userId: string | undefined;
23
+ }>;
@@ -0,0 +1,69 @@
1
+ import crypto from 'node:crypto';
2
+ import { getOAuthConfig } from '../config/oauth.js';
3
+ import { buildAuthorizationUrl } from './browser.js';
4
+ import { parsePastedCode } from './paste-code.js';
5
+ import { generatePKCEPair } from './pkce.js';
6
+ import { exchangeCodeForTokens } from './refresh.js';
7
+ const HEADLESS_OAUTH_SESSION_TTL_MS = 10 * 60 * 1000;
8
+ export class HeadlessOAuthFlowError extends Error {
9
+ constructor(message){
10
+ super(message);
11
+ this.name = 'HeadlessOAuthFlowError';
12
+ }
13
+ }
14
+ /** Start OAuth without a callback listener so another process can resume it. */ export function startHeadlessOAuthFlow(tokenStore, options = {}) {
15
+ const oauthConfig = getOAuthConfig();
16
+ const { codeChallenge, codeChallengeMethod, codeVerifier } = generatePKCEPair();
17
+ const now = options.now ?? Date.now();
18
+ const session = {
19
+ id: crypto.randomBytes(32).toString('base64url'),
20
+ clientId: oauthConfig.clientId,
21
+ codeVerifier,
22
+ expiresAt: now + HEADLESS_OAUTH_SESSION_TTL_MS,
23
+ redirectUri: oauthConfig.redirectUri,
24
+ state: crypto.randomBytes(32).toString('base64url')
25
+ };
26
+ tokenStore.setHeadlessOAuthSession(session);
27
+ return {
28
+ authorizationUrl: buildAuthorizationUrl({
29
+ authorizationUrl: oauthConfig.authorizationUrl,
30
+ clientId: session.clientId,
31
+ codeChallenge,
32
+ codeChallengeMethod,
33
+ redirectUri: session.redirectUri,
34
+ scopes: oauthConfig.scopes,
35
+ state: session.state
36
+ }),
37
+ expiresAt: session.expiresAt,
38
+ sessionId: session.id
39
+ };
40
+ }
41
+ /** Complete a previously started headless OAuth flow and store its tokens. */ export async function completeHeadlessOAuthFlow({ callbackUrl, now = Date.now(), sessionId, tokenStore }) {
42
+ const session = tokenStore.getHeadlessOAuthSession();
43
+ if (!session) {
44
+ throw new HeadlessOAuthFlowError('No pending login found. Start login again with --headless.');
45
+ }
46
+ if (session.id !== sessionId) {
47
+ throw new HeadlessOAuthFlowError('Login session does not match. Start login again with --headless.');
48
+ }
49
+ if (now >= session.expiresAt) {
50
+ tokenStore.clearHeadlessOAuthSession();
51
+ throw new HeadlessOAuthFlowError('Login session expired. Start login again with --headless.');
52
+ }
53
+ try {
54
+ try {
55
+ new URL(callbackUrl);
56
+ } catch {
57
+ throw new HeadlessOAuthFlowError('Paste the full redirected URL so the login state can be verified.');
58
+ }
59
+ const code = parsePastedCode(callbackUrl, session.state);
60
+ const tokens = await exchangeCodeForTokens(code, session.codeVerifier, session.redirectUri, session.clientId);
61
+ tokenStore.setTokens(tokens);
62
+ return {
63
+ tokens,
64
+ userId: tokens.userId
65
+ };
66
+ } finally{
67
+ tokenStore.clearHeadlessOAuthSession();
68
+ }
69
+ }
@@ -16,6 +16,8 @@ export interface OAuthFlowOptions {
16
16
  clientId?: string;
17
17
  /** Callback server fallback ports to try after port */
18
18
  fallbackPorts?: number[];
19
+ /** Open the browser without asking for confirmation */
20
+ openBrowserWithoutPrompt?: boolean;
19
21
  /** First callback server port to try */
20
22
  port?: number;
21
23
  /** Redirect URI (defaults to config) */
@@ -54,7 +54,7 @@ import { exchangeCodeForTokens, refreshAccessToken, TokenRefreshError } from './
54
54
  };
55
55
  }
56
56
  // REAL OAUTH IMPLEMENTATION
57
- const { clientId = oauthConfig.clientId, fallbackPorts, port, redirectUri = oauthConfig.redirectUri, scopes = oauthConfig.scopes, timeoutMs = 120000 } = options;
57
+ const { clientId = oauthConfig.clientId, fallbackPorts, openBrowserWithoutPrompt = false, port, redirectUri = oauthConfig.redirectUri, scopes = oauthConfig.scopes, timeoutMs = 120000 } = options;
58
58
  // Generate PKCE pair for enhanced security
59
59
  const { codeChallenge, codeChallengeMethod, codeVerifier } = generatePKCEPair();
60
60
  // Generate random state for CSRF protection
@@ -85,13 +85,18 @@ import { exchangeCodeForTokens, refreshAccessToken, TokenRefreshError } from './
85
85
  scopes,
86
86
  state
87
87
  });
88
- // Prompt user to open browser
89
- const shouldOpenBrowser = await p.confirm({
90
- initialValue: true,
91
- message: 'Open browser to authenticate with Figma?'
92
- });
93
- if (p.isCancel(shouldOpenBrowser)) {
94
- throw new OAuthFlowError('Authentication cancelled by user');
88
+ // Ask interactive callers before opening a browser. Automated callers have
89
+ // already accepted defaults with -y, so proceed directly to authorization.
90
+ let shouldOpenBrowser = openBrowserWithoutPrompt;
91
+ if (!openBrowserWithoutPrompt) {
92
+ const browserConfirmation = await p.confirm({
93
+ initialValue: true,
94
+ message: 'Open browser to authenticate with Figma?'
95
+ });
96
+ if (p.isCancel(browserConfirmation)) {
97
+ throw new OAuthFlowError('Authentication cancelled by user');
98
+ }
99
+ shouldOpenBrowser = browserConfirmation;
95
100
  }
96
101
  let browserOpened = false;
97
102
  if (shouldOpenBrowser) {
@@ -1,5 +1,5 @@
1
1
  import type { Environment } from '../constants.js';
2
- import type { BootstrapData, FigmaTokens, ProjectStoreScope, ProjectToken, TokenStoreConfig } from './types.js';
2
+ import type { BootstrapData, FigmaTokens, HeadlessOAuthSession, ProjectStoreScope, ProjectToken, TokenStoreConfig } from './types.js';
3
3
  /**
4
4
  * Get the singleton TokenStore instance for an environment.
5
5
  */
@@ -23,6 +23,9 @@ export declare class TokenStore {
23
23
  getOauthInfo(): FigmaTokens | null;
24
24
  setTokens(tokens: FigmaTokens): void;
25
25
  clearTokens(): void;
26
+ getHeadlessOAuthSession(): HeadlessOAuthSession | null;
27
+ setHeadlessOAuthSession(session: HeadlessOAuthSession): void;
28
+ clearHeadlessOAuthSession(): void;
26
29
  hasValidOauthToken(): boolean;
27
30
  isOauthExpired(): boolean;
28
31
  getCurrentOauthToken(): null | string;
@@ -186,11 +186,25 @@ const PROJECT_STORE_SCHEMA_VERSION = 1;
186
186
  clearTokens() {
187
187
  this.oauthConfig.delete('accessToken');
188
188
  this.oauthConfig.delete('expiresAt');
189
+ this.oauthConfig.delete('headlessOAuthSession');
189
190
  this.oauthConfig.delete('refreshToken');
190
191
  this.oauthConfig.delete('scopes');
191
192
  this.oauthConfig.delete('tokenType');
192
193
  this.oauthConfig.delete('userId');
193
194
  }
195
+ getHeadlessOAuthSession() {
196
+ return this.safeGet({
197
+ config: this.oauthConfig,
198
+ key: 'headlessOAuthSession'
199
+ }) ?? null;
200
+ }
201
+ setHeadlessOAuthSession(session) {
202
+ this.oauthConfig.set('_schemaVersion', OAUTH_STORE_SCHEMA_VERSION);
203
+ this.oauthConfig.set('headlessOAuthSession', session);
204
+ }
205
+ clearHeadlessOAuthSession() {
206
+ this.oauthConfig.delete('headlessOAuthSession');
207
+ }
194
208
  hasValidOauthToken() {
195
209
  const tokens = this.getOauthInfo();
196
210
  if (!tokens) {
@@ -32,6 +32,18 @@ export interface FigmaTokens {
32
32
  /** Figma user ID string */
33
33
  userId?: string;
34
34
  }
35
+ /**
36
+ * Temporary state for a resumable OAuth login. Stored encrypted on the machine
37
+ * that generated the PKCE verifier and removed after completion or expiry.
38
+ */
39
+ export interface HeadlessOAuthSession {
40
+ clientId: string;
41
+ codeVerifier: string;
42
+ expiresAt: number;
43
+ id: string;
44
+ redirectUri: string;
45
+ state: string;
46
+ }
35
47
  /**
36
48
  * Raw token response from Figma OAuth2 token endpoint
37
49
  * Response from POST https://api.figma.com/v1/oauth/token
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,42 @@
1
+ export declare const cliArgSpec: {
2
+ readonly '--adapter': StringConstructor;
3
+ readonly '--all': BooleanConstructor;
4
+ readonly '--callback-url': StringConstructor;
5
+ readonly '--complete': StringConstructor;
6
+ readonly '--debug': BooleanConstructor;
7
+ readonly '--description': StringConstructor;
8
+ readonly '--dry-run': BooleanConstructor;
9
+ readonly '--env': StringConstructor;
10
+ readonly '--force': BooleanConstructor;
11
+ readonly '--global': BooleanConstructor;
12
+ readonly '--headless': BooleanConstructor;
13
+ readonly '--help': BooleanConstructor;
14
+ readonly '--id': StringConstructor;
15
+ readonly '--infra-env': StringConstructor;
16
+ readonly '--json': BooleanConstructor;
17
+ readonly '--name': StringConstructor;
18
+ readonly '--no-agent': BooleanConstructor;
19
+ readonly '--output': StringConstructor;
20
+ readonly '--payload-version': StringConstructor;
21
+ readonly '--project': BooleanConstructor;
22
+ readonly '--region': StringConstructor;
23
+ readonly '--skip-auth': BooleanConstructor;
24
+ readonly '--skip-build': BooleanConstructor;
25
+ readonly '--skip-size-check': BooleanConstructor;
26
+ readonly '--subdomain': StringConstructor;
27
+ readonly '--template': StringConstructor;
28
+ readonly '--version': BooleanConstructor;
29
+ readonly '--workspace': StringConstructor;
30
+ readonly '--yes': BooleanConstructor;
31
+ readonly '--environment': "--env";
32
+ readonly '-e': "--env";
33
+ readonly '-f': "--force";
34
+ readonly '-h': "--help";
35
+ readonly '-n': "--name";
36
+ readonly '-t': "--template";
37
+ readonly '-v': "--version";
38
+ readonly '-y': "--yes";
39
+ };
1
40
  /**
2
41
  * Entrypoint for bin/cli.js
3
42
  */