@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.
- package/dist/api/check-project-subdomain-availability.d.ts +12 -0
- package/dist/api/check-project-subdomain-availability.js +32 -0
- package/dist/api/control-plane-error.d.ts +6 -0
- package/dist/api/control-plane-error.js +8 -0
- package/dist/api/control-plane-fetch.d.ts +7 -0
- package/dist/api/control-plane-fetch.js +37 -0
- package/dist/api/control-plane.d.ts +1 -9
- package/dist/api/control-plane.js +2 -48
- package/dist/api/create-project.d.ts +18 -0
- package/dist/api/create-project.js +37 -0
- package/dist/api/list-project-workspaces.d.ts +8 -0
- package/dist/api/list-project-workspaces.js +28 -0
- package/dist/api/project-resource-type.d.ts +1 -0
- package/dist/api/project-resource-type.js +1 -0
- package/dist/auth/headless-oauth-flow.d.ts +23 -0
- package/dist/auth/headless-oauth-flow.js +69 -0
- package/dist/auth/oauth-flow.d.ts +2 -0
- package/dist/auth/oauth-flow.js +13 -8
- package/dist/auth/token-store.d.ts +4 -1
- package/dist/auth/token-store.js +14 -0
- package/dist/auth/types.d.ts +12 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.js +71 -36
- package/dist/commands/bootstrap.js +2 -1
- package/dist/commands/deploy.d.ts +12 -0
- package/dist/commands/deploy.js +61 -23
- package/dist/commands/detect-project-resource-type.d.ts +3 -0
- package/dist/commands/detect-project-resource-type.js +28 -0
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.js +163 -78
- package/dist/commands/login.d.ts +11 -1
- package/dist/commands/login.js +66 -4
- package/dist/commands/prompt-to-create-project/format-project-subdomain.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/format-project-subdomain.js +3 -0
- package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/format-unavailable-subdomain-reason.js +7 -0
- package/dist/commands/prompt-to-create-project/get-default-project-name.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/get-default-project-name.js +13 -0
- package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.d.ts +7 -0
- package/dist/commands/prompt-to-create-project/prompt-for-available-subdomain.js +32 -0
- package/dist/commands/prompt-to-create-project/resolve-project-region.d.ts +8 -0
- package/dist/commands/prompt-to-create-project/resolve-project-region.js +27 -0
- package/dist/commands/prompt-to-create-project/resolve-project-subdomain.d.ts +9 -0
- package/dist/commands/prompt-to-create-project/resolve-project-subdomain.js +54 -0
- package/dist/commands/prompt-to-create-project/resolve-text-input.d.ts +9 -0
- package/dist/commands/prompt-to-create-project/resolve-text-input.js +23 -0
- package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.d.ts +12 -0
- package/dist/commands/prompt-to-create-project/resolve-workspace-plan-key.js +36 -0
- package/dist/commands/prompt-to-create-project/validate-subdomain.d.ts +1 -0
- package/dist/commands/prompt-to-create-project/validate-subdomain.js +9 -0
- package/dist/commands/prompt-to-create-project.d.ts +24 -0
- package/dist/commands/prompt-to-create-project.js +69 -0
- package/dist/commands/setup-agent.d.ts +12 -0
- package/dist/commands/setup-agent.js +123 -0
- package/dist/commands/write-project-configuration.d.ts +12 -0
- package/dist/commands/write-project-configuration.js +16 -0
- package/dist/db-content-api/index.d.ts +1 -1
- package/dist/db-content-api/index.js +90 -55
- package/dist/db-content-api/utilities/data/injectGlobalType.d.ts +6 -0
- package/dist/db-content-api/utilities/data/injectGlobalType.js +11 -0
- package/dist/db-content-api/utilities/data/stringifyNumericIds.d.ts +1 -0
- package/dist/db-content-api/utilities/data/stringifyNumericIds.js +19 -0
- package/dist/db-content-api/utilities/isRecord.d.ts +9 -0
- package/dist/db-content-api/utilities/isRecord.js +19 -0
- package/dist/db-content-api/utilities/schema/getDocumentSchema.d.ts +3 -0
- package/dist/db-content-api/utilities/schema/getDocumentSchema.js +24 -0
- package/dist/db-content-api/utilities/where.js +6 -4
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +2 -0
- package/dist/lib/write-agent-config.d.ts +12 -0
- package/dist/lib/write-agent-config.js +52 -0
- package/dist/plugin/build-config.js +32 -3
- package/dist/plugin/cloud-limits/CloudLimitModal/index.d.ts +9 -0
- package/dist/plugin/cloud-limits/CloudLimitModal/index.js +78 -0
- package/dist/plugin/cloud-limits/CloudLimitModal/index.scss +51 -0
- package/dist/plugin/cloud-limits/CloudLimitProvider/index.d.ts +7 -0
- package/dist/plugin/cloud-limits/CloudLimitProvider/index.js +169 -0
- package/dist/plugin/cloud-limits/SlugRegistryContext/index.d.ts +2 -0
- package/dist/plugin/cloud-limits/SlugRegistryContext/index.js +3 -0
- package/dist/plugin/cloud-limits/SlugTracker/index.d.ts +9 -0
- package/dist/plugin/cloud-limits/SlugTracker/index.js +23 -0
- package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.d.ts +2 -0
- package/dist/plugin/cloud-limits/icons/ExternalLinkIcon.js +30 -0
- package/dist/plugin/cloud-limits/shared.d.ts +10 -0
- package/dist/plugin/cloud-limits/shared.js +27 -0
- package/dist/skills/deploy-to-figma/SKILL.md +234 -0
- package/dist/skills/deploy-to-figma/references/cli-reference.md +146 -0
- package/dist/translations/ar.d.ts +12 -0
- package/dist/translations/ar.js +12 -0
- package/dist/translations/az.d.ts +12 -0
- package/dist/translations/az.js +12 -0
- package/dist/translations/bg.d.ts +12 -0
- package/dist/translations/bg.js +12 -0
- package/dist/translations/bnBd.d.ts +12 -0
- package/dist/translations/bnBd.js +12 -0
- package/dist/translations/bnIn.d.ts +12 -0
- package/dist/translations/bnIn.js +12 -0
- package/dist/translations/ca.d.ts +12 -0
- package/dist/translations/ca.js +12 -0
- package/dist/translations/cs.d.ts +12 -0
- package/dist/translations/cs.js +12 -0
- package/dist/translations/da.d.ts +12 -0
- package/dist/translations/da.js +12 -0
- package/dist/translations/de.d.ts +12 -0
- package/dist/translations/de.js +12 -0
- package/dist/translations/en.d.ts +12 -0
- package/dist/translations/en.js +12 -0
- package/dist/translations/es.d.ts +12 -0
- package/dist/translations/es.js +12 -0
- package/dist/translations/et.d.ts +12 -0
- package/dist/translations/et.js +12 -0
- package/dist/translations/fa.d.ts +12 -0
- package/dist/translations/fa.js +12 -0
- package/dist/translations/fr.d.ts +12 -0
- package/dist/translations/fr.js +12 -0
- package/dist/translations/he.d.ts +12 -0
- package/dist/translations/he.js +12 -0
- package/dist/translations/hr.d.ts +12 -0
- package/dist/translations/hr.js +12 -0
- package/dist/translations/hu.d.ts +12 -0
- package/dist/translations/hu.js +12 -0
- package/dist/translations/hy.d.ts +12 -0
- package/dist/translations/hy.js +12 -0
- package/dist/translations/id.d.ts +12 -0
- package/dist/translations/id.js +12 -0
- package/dist/translations/index.d.ts +533 -0
- package/dist/translations/index.js +90 -0
- package/dist/translations/is.d.ts +12 -0
- package/dist/translations/is.js +12 -0
- package/dist/translations/it.d.ts +12 -0
- package/dist/translations/it.js +12 -0
- package/dist/translations/ja.d.ts +12 -0
- package/dist/translations/ja.js +12 -0
- package/dist/translations/ko.d.ts +12 -0
- package/dist/translations/ko.js +12 -0
- package/dist/translations/lt.d.ts +12 -0
- package/dist/translations/lt.js +12 -0
- package/dist/translations/lv.d.ts +12 -0
- package/dist/translations/lv.js +12 -0
- package/dist/translations/my.d.ts +12 -0
- package/dist/translations/my.js +12 -0
- package/dist/translations/nb.d.ts +12 -0
- package/dist/translations/nb.js +12 -0
- package/dist/translations/nl.d.ts +12 -0
- package/dist/translations/nl.js +12 -0
- package/dist/translations/pl.d.ts +12 -0
- package/dist/translations/pl.js +12 -0
- package/dist/translations/pt.d.ts +12 -0
- package/dist/translations/pt.js +12 -0
- package/dist/translations/ro.d.ts +12 -0
- package/dist/translations/ro.js +12 -0
- package/dist/translations/rs.d.ts +12 -0
- package/dist/translations/rs.js +12 -0
- package/dist/translations/rsLatin.d.ts +12 -0
- package/dist/translations/rsLatin.js +12 -0
- package/dist/translations/ru.d.ts +12 -0
- package/dist/translations/ru.js +12 -0
- package/dist/translations/sk.d.ts +12 -0
- package/dist/translations/sk.js +12 -0
- package/dist/translations/sl.d.ts +12 -0
- package/dist/translations/sl.js +12 -0
- package/dist/translations/sv.d.ts +12 -0
- package/dist/translations/sv.js +12 -0
- package/dist/translations/ta.d.ts +12 -0
- package/dist/translations/ta.js +12 -0
- package/dist/translations/th.d.ts +12 -0
- package/dist/translations/th.js +12 -0
- package/dist/translations/tr.d.ts +12 -0
- package/dist/translations/tr.js +12 -0
- package/dist/translations/uk.d.ts +12 -0
- package/dist/translations/uk.js +12 -0
- package/dist/translations/vi.d.ts +12 -0
- package/dist/translations/vi.js +12 -0
- package/dist/translations/zh.d.ts +12 -0
- package/dist/translations/zh.js +12 -0
- package/dist/translations/zhTw.d.ts +12 -0
- package/dist/translations/zhTw.js +12 -0
- package/dist/types.d.ts +11 -0
- package/dist/utils/adapters/nextjs.d.ts +3 -3
- package/dist/utils/adapters/nextjs.js +9 -7
- package/dist/utils/adapters/nitro.d.ts +3 -3
- package/dist/utils/adapters/nitro.js +73 -77
- package/dist/utils/adapters/vite.d.ts +1 -1
- package/dist/utils/adapters/vite.js +8 -7
- package/dist/utils/assert-never.d.ts +1 -0
- package/dist/utils/assert-never.js +3 -0
- package/dist/utils/asset-collection.d.ts +2 -2
- package/dist/utils/asset-collection.js +10 -15
- package/dist/utils/build-detection.d.ts +6 -1
- package/dist/utils/build-detection.js +68 -89
- package/dist/utils/build-lambda-zip.d.ts +5 -6
- package/dist/utils/build-lambda-zip.js +31 -48
- package/dist/utils/deploy-adapter.d.ts +4 -4
- package/dist/utils/deploy-adapter.js +12 -8
- package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.d.ts +1 -0
- package/dist/utils/deploy-output/inspectNextjsOutput/getNextRelativeAppDir.js +15 -0
- package/dist/utils/deploy-output/inspectNextjsOutput.d.ts +12 -0
- package/dist/utils/deploy-output/inspectNextjsOutput.js +28 -0
- package/dist/utils/deploy-output/inspectNitroOutput.d.ts +9 -0
- package/dist/utils/deploy-output/inspectNitroOutput.js +13 -0
- package/dist/utils/deploy-output/isFile.d.ts +1 -0
- package/dist/utils/deploy-output/isFile.js +4 -0
- package/dist/utils/deploy-output/readJson.d.ts +1 -0
- package/dist/utils/deploy-output/readJson.js +9 -0
- package/dist/utils/deploy-output/resolveNitroOutputLayout.d.ts +8 -0
- package/dist/utils/deploy-output/resolveNitroOutputLayout.js +16 -0
- package/dist/utils/deploy-output/resolveOutputPath.d.ts +2 -0
- package/dist/utils/deploy-output/resolveOutputPath.js +9 -0
- package/dist/utils/deploy-output/resolveWithin.d.ts +1 -0
- package/dist/utils/deploy-output/resolveWithin.js +12 -0
- package/dist/utils/lambda-config.js +4 -14
- package/dist/utils/messages.js +24 -3
- package/dist/utils/payload-generate.d.ts +10 -0
- package/dist/utils/payload-generate.js +59 -0
- package/dist/utils/pnpm-builds.d.ts +14 -0
- package/dist/utils/pnpm-builds.js +125 -0
- package/package.json +6 -5
- package/dist/lib/download-skill.d.ts +0 -12
- 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,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
|
-
/**
|
|
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 {
|
|
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.
|
|
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) */
|
package/dist/auth/oauth-flow.js
CHANGED
|
@@ -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
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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;
|
package/dist/auth/token-store.js
CHANGED
|
@@ -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) {
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -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
|
*/
|