@payloadcms/figma 0.0.1-alpha.11 → 0.0.1-alpha.13
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/control-plane.d.ts.map +1 -1
- package/dist/api/control-plane.js +14 -14
- package/dist/api/control-plane.js.map +1 -1
- package/dist/api/figma-api.d.ts.map +1 -1
- package/dist/api/figma-api.js +30 -2
- package/dist/api/figma-api.js.map +1 -1
- package/dist/auth/project-token.d.ts.map +1 -1
- package/dist/auth/project-token.js +3 -2
- package/dist/auth/project-token.js.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/deploy.d.ts +2 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +11 -6
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/config/oauth.d.ts.map +1 -1
- package/dist/config/oauth.js +3 -3
- package/dist/config/oauth.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.js +1 -1
- package/dist/oauth/components/LoginButton/index.js.map +1 -1
- package/dist/utils/payload-config-ast.d.ts +1 -1
- package/dist/utils/payload-config-ast.d.ts.map +1 -1
- package/dist/utils/payload-config-ast.js +7 -7
- package/dist/utils/payload-config-ast.js.map +1 -1
- package/package.json +2 -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;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,
|
|
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,CA6DnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CA2CpC"}
|
|
@@ -8,7 +8,7 @@ import * as log from '../utils/log.js';
|
|
|
8
8
|
* Control Plane API base URLs
|
|
9
9
|
*/ const CONTROL_PLANE_API_URLS = {
|
|
10
10
|
production: 'https://api.figma.com',
|
|
11
|
-
staging: 'https://api.staging.figma.com'
|
|
11
|
+
staging: process.env.FIGMA_API_URL || 'https://api.staging.figma.com'
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
14
|
* Get the Control Plane API base URL based on environment
|
|
@@ -33,11 +33,11 @@ import * as log from '../utils/log.js';
|
|
|
33
33
|
* @returns Array of tenant instances
|
|
34
34
|
*/ export async function listTenants(accessToken) {
|
|
35
35
|
// Check if control plane API should be mocked
|
|
36
|
-
// Default to
|
|
37
|
-
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE
|
|
36
|
+
// Default to true until real API is available
|
|
37
|
+
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
|
|
38
38
|
if (shouldMock) {
|
|
39
39
|
// MOCK IMPLEMENTATION: Return sample tenants for testing
|
|
40
|
-
log.debug('Using mock Control Plane API for listTenants (FIGMA_MOCK_CONTROL_PLANE
|
|
40
|
+
log.debug('Using mock Control Plane API for listTenants (FIGMA_MOCK_CONTROL_PLANE != "false")');
|
|
41
41
|
return [
|
|
42
42
|
{
|
|
43
43
|
id: 'tenant_abc123',
|
|
@@ -77,10 +77,10 @@ import * as log from '../utils/log.js';
|
|
|
77
77
|
* @returns Newly created tenant
|
|
78
78
|
*/ export async function createTenant(accessToken, options) {
|
|
79
79
|
// Check if control plane API should be mocked
|
|
80
|
-
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE
|
|
80
|
+
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
|
|
81
81
|
if (shouldMock) {
|
|
82
82
|
// MOCK IMPLEMENTATION: Generate mock tenant for testing
|
|
83
|
-
log.debug('Using mock Control Plane API for createTenant (FIGMA_MOCK_CONTROL_PLANE
|
|
83
|
+
log.debug('Using mock Control Plane API for createTenant (FIGMA_MOCK_CONTROL_PLANE != "false")');
|
|
84
84
|
const tenantId = `tenant_${Math.random().toString(36).substring(2, 11)}`;
|
|
85
85
|
const slug = options.name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
86
86
|
const domain = `${slug}.figmacms.com`;
|
|
@@ -118,10 +118,10 @@ import * as log from '../utils/log.js';
|
|
|
118
118
|
* @returns Tenant details
|
|
119
119
|
*/ export async function getTenantDetails(accessToken, tenantId) {
|
|
120
120
|
// Check if control plane API should be mocked
|
|
121
|
-
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE
|
|
121
|
+
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
|
|
122
122
|
if (shouldMock) {
|
|
123
123
|
// MOCK IMPLEMENTATION: Return mock tenant details for testing
|
|
124
|
-
log.debug('Using mock Control Plane API for getTenantDetails (FIGMA_MOCK_CONTROL_PLANE
|
|
124
|
+
log.debug('Using mock Control Plane API for getTenantDetails (FIGMA_MOCK_CONTROL_PLANE != "false")');
|
|
125
125
|
return {
|
|
126
126
|
id: tenantId,
|
|
127
127
|
createdAt: '2025-01-15T10:00:00Z',
|
|
@@ -152,10 +152,10 @@ import * as log from '../utils/log.js';
|
|
|
152
152
|
* @returns Deployment ID and upload URLs
|
|
153
153
|
*/ export async function createDeployment(accessToken, tenantId, options) {
|
|
154
154
|
// Check if control plane API should be mocked
|
|
155
|
-
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE
|
|
155
|
+
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
|
|
156
156
|
if (shouldMock) {
|
|
157
157
|
// MOCK IMPLEMENTATION: Generate mock deployment and signed URLs
|
|
158
|
-
log.debug('Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE
|
|
158
|
+
log.debug('Using mock Control Plane API for createDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
|
|
159
159
|
const deploymentId = `deploy_${Math.random().toString(36).substring(2, 11)}`;
|
|
160
160
|
const mockBucket = 'figma-cms-deployments-mock';
|
|
161
161
|
const mockRegion = 'us-west-2';
|
|
@@ -175,7 +175,7 @@ import * as log from '../utils/log.js';
|
|
|
175
175
|
};
|
|
176
176
|
}
|
|
177
177
|
// REAL API IMPLEMENTATION
|
|
178
|
-
const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/create`, {
|
|
178
|
+
const response = await fetch(`${getControlPlaneBaseUrl()}/v1/cms/tenant/${tenantId}/deploy/create`, {
|
|
179
179
|
body: JSON.stringify({
|
|
180
180
|
static_assets: options.staticAssets
|
|
181
181
|
}),
|
|
@@ -206,17 +206,17 @@ import * as log from '../utils/log.js';
|
|
|
206
206
|
* @returns Deployment status and message
|
|
207
207
|
*/ export async function performDeployment(accessToken, tenantId, options) {
|
|
208
208
|
// Check if control plane API should be mocked
|
|
209
|
-
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE
|
|
209
|
+
const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE !== 'false';
|
|
210
210
|
if (shouldMock) {
|
|
211
211
|
// MOCK IMPLEMENTATION: Return mock deployment status
|
|
212
|
-
log.debug('Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE
|
|
212
|
+
log.debug('Using mock Control Plane API for performDeployment (FIGMA_MOCK_CONTROL_PLANE != "false")');
|
|
213
213
|
return {
|
|
214
214
|
deploymentId: options.deploymentId,
|
|
215
215
|
message: 'Deployment initiated successfully'
|
|
216
216
|
};
|
|
217
217
|
}
|
|
218
218
|
// REAL API IMPLEMENTATION
|
|
219
|
-
const response = await fetch(`${getControlPlaneBaseUrl()}/v1/tenant/${tenantId}/deploy/perform`, {
|
|
219
|
+
const response = await fetch(`${getControlPlaneBaseUrl()}/v1/cms/tenant/${tenantId}/deploy/perform`, {
|
|
220
220
|
body: JSON.stringify({
|
|
221
221
|
deployment_id: options.deploymentId
|
|
222
222
|
}),
|
|
@@ -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 * 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 false (real API)\n const shouldMock = process.env.FIGMA_MOCK_CONTROL_PLANE === 'true'\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 = true)')\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 === 'true'\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 = true)')\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 === 'true'\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 = true)',\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 === 'true'\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 = true)',\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 === 'true'\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 = true)',\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,8BAA8B;IAC9B,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"}
|
|
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: process.env.FIGMA_API_URL || '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(\n `${getControlPlaneBaseUrl()}/v1/cms/tenant/${tenantId}/deploy/create`,\n {\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\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(\n `${getControlPlaneBaseUrl()}/v1/cms/tenant/${tenantId}/deploy/perform`,\n {\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\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","process","env","FIGMA_API_URL","getControlPlaneBaseUrl","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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figma-api.d.ts","sourceRoot":"","sources":["../../src/api/figma-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,kBAAkB,CAAA;AAI1E;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAG7B,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;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"figma-api.d.ts","sourceRoot":"","sources":["../../src/api/figma-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,kBAAkB,CAAA;AAI1E;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAG7B,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;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CA+HvB"}
|
package/dist/api/figma-api.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* Base URLs for Figma API
|
|
19
19
|
*/ const API_BASE_URLS = {
|
|
20
20
|
prod: 'https://api.figma.com',
|
|
21
|
-
staging: 'https://api.staging.figma.com'
|
|
21
|
+
staging: process.env.FIGMA_API_URL || 'https://api.staging.figma.com'
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
24
|
* Get the Figma API base URL based on environment
|
|
@@ -41,7 +41,35 @@
|
|
|
41
41
|
* @returns ProjectToken with JWT and expiry information
|
|
42
42
|
* @throws {FigmaApiError} If the API call fails
|
|
43
43
|
*/ export async function getProjectToken(accessToken, tenantId) {
|
|
44
|
-
// Check
|
|
44
|
+
// Priority 1: Check for direct token value from environment
|
|
45
|
+
const envTokenValue = process.env.FIGMA_MOCK_PROJECT_TOKEN_VALUE;
|
|
46
|
+
if (envTokenValue) {
|
|
47
|
+
log.debug('Using direct project token from FIGMA_MOCK_PROJECT_TOKEN_VALUE');
|
|
48
|
+
try {
|
|
49
|
+
// Parse JWT payload to extract claims
|
|
50
|
+
const parts = envTokenValue.split('.');
|
|
51
|
+
if (parts.length !== 3) {
|
|
52
|
+
throw new Error('Invalid JWT format: must have 3 parts (header.payload.signature)');
|
|
53
|
+
}
|
|
54
|
+
const payload = parts[1];
|
|
55
|
+
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
|
|
56
|
+
const paddedBase64 = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '=');
|
|
57
|
+
const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8'));
|
|
58
|
+
if (!decodedPayload.exp || typeof decodedPayload.exp !== 'number') {
|
|
59
|
+
throw new Error('JWT payload missing exp claim');
|
|
60
|
+
}
|
|
61
|
+
// Extract tenant ID from aud claim (use parameter as fallback)
|
|
62
|
+
const extractedTenantId = decodedPayload.aud || tenantId;
|
|
63
|
+
return {
|
|
64
|
+
expiresAt: decodedPayload.exp * 1000,
|
|
65
|
+
tenantId: extractedTenantId,
|
|
66
|
+
token: envTokenValue
|
|
67
|
+
};
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw new FigmaApiError(`Invalid JWT token in FIGMA_MOCK_PROJECT_TOKEN_VALUE: ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, error instanceof Error ? error : undefined);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Priority 2: Check if project token API should be mocked
|
|
45
73
|
// Default to false (use real API)
|
|
46
74
|
const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN === 'true';
|
|
47
75
|
try {
|
|
@@ -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 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
|
+
{"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: process.env.FIGMA_API_URL || '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 // Priority 1: Check for direct token value from environment\n const envTokenValue = process.env.FIGMA_MOCK_PROJECT_TOKEN_VALUE\n if (envTokenValue) {\n log.debug('Using direct project token from FIGMA_MOCK_PROJECT_TOKEN_VALUE')\n try {\n // Parse JWT payload to extract claims\n const parts = envTokenValue.split('.')\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format: must have 3 parts (header.payload.signature)')\n }\n\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 const decodedPayload = JSON.parse(Buffer.from(paddedBase64, 'base64').toString('utf-8')) as {\n aud?: string\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 // Extract tenant ID from aud claim (use parameter as fallback)\n const extractedTenantId = decodedPayload.aud || tenantId\n\n return {\n expiresAt: decodedPayload.exp * 1000, // Convert from seconds to milliseconds\n tenantId: extractedTenantId,\n token: envTokenValue,\n }\n } catch (error) {\n throw new FigmaApiError(\n `Invalid JWT token in FIGMA_MOCK_PROJECT_TOKEN_VALUE: ${error instanceof Error ? error.message : 'Unknown error'}`,\n undefined,\n error instanceof Error ? error : undefined,\n )\n }\n }\n\n // Priority 2: 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","process","env","FIGMA_API_URL","_getApiBaseUrl","FIGMA_API_BASE_URL","getProjectToken","accessToken","tenantId","envTokenValue","FIGMA_MOCK_PROJECT_TOKEN_VALUE","debug","parts","split","length","payload","base64","replace","paddedBase64","padEnd","decodedPayload","JSON","parse","Buffer","from","toString","exp","extractedTenantId","aud","expiresAt","token","error","undefined","shouldMock","FIGMA_MOCK_PROJECT_TOKEN","mockToken","createMockJWT","data","meta","parseJwtExpiry","baseUrl","url","response","fetch","headers","Authorization","method","ok","errorMessage","status","statusText","errorBody","json","expiresInMinutes","header","alg","typ","now","Math","floor","Date","email","iat","sub","encodeBase64Url","obj","stringify","headerEncoded","payloadEncoded","signature","random","substring"],"mappings":"AAAA;;;;;CAKC,GAID,YAAYA,SAAS,kBAAiB;AAEtC;;CAEC,GACD,OAAO,MAAMC,sBAAsBC;;;IACjC,YACEC,OAAe,EACf,AAAOC,UAAmB,EAC1B,AAAOC,KAAa,CACpB;QACA,KAAK,CAACF,eAHCC,aAAAA,iBACAC,QAAAA;QAGP,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA;;CAEC,GACD,MAAMC,gBAAgB;IACpBC,MAAM;IACNC,SAASC,QAAQC,GAAG,CAACC,aAAa,IAAI;AACxC;AAEA;;;CAGC,GACD,SAASC;IACP,oDAAoD;IACpD,OAAOH,QAAQC,GAAG,CAACG,kBAAkB,IAAIP,cAAcE,OAAO;AAChE;AAEA;;;;;;;;;;;;;CAaC,GACD,OAAO,eAAeM,gBACpBC,WAAmB,EACnBC,QAAgB;IAEhB,4DAA4D;IAC5D,MAAMC,gBAAgBR,QAAQC,GAAG,CAACQ,8BAA8B;IAChE,IAAID,eAAe;QACjBlB,IAAIoB,KAAK,CAAC;QACV,IAAI;YACF,sCAAsC;YACtC,MAAMC,QAAQH,cAAcI,KAAK,CAAC;YAClC,IAAID,MAAME,MAAM,KAAK,GAAG;gBACtB,MAAM,IAAIrB,MAAM;YAClB;YAEA,MAAMsB,UAAUH,KAAK,CAAC,EAAE;YACxB,MAAMI,SAASD,QAAQE,OAAO,CAAC,MAAM,KAAKA,OAAO,CAAC,MAAM;YACxD,MAAMC,eAAeF,OAAOG,MAAM,CAACH,OAAOF,MAAM,GAAI,AAAC,CAAA,IAAKE,OAAOF,MAAM,GAAG,CAAC,IAAK,GAAI;YACpF,MAAMM,iBAAiBC,KAAKC,KAAK,CAACC,OAAOC,IAAI,CAACN,cAAc,UAAUO,QAAQ,CAAC;YAK/E,IAAI,CAACL,eAAeM,GAAG,IAAI,OAAON,eAAeM,GAAG,KAAK,UAAU;gBACjE,MAAM,IAAIjC,MAAM;YAClB;YAEA,+DAA+D;YAC/D,MAAMkC,oBAAoBP,eAAeQ,GAAG,IAAIpB;YAEhD,OAAO;gBACLqB,WAAWT,eAAeM,GAAG,GAAG;gBAChClB,UAAUmB;gBACVG,OAAOrB;YACT;QACF,EAAE,OAAOsB,OAAO;YACd,MAAM,IAAIvC,cACR,CAAC,qDAAqD,EAAEuC,iBAAiBtC,QAAQsC,MAAMrC,OAAO,GAAG,iBAAiB,EAClHsC,WACAD,iBAAiBtC,QAAQsC,QAAQC;QAErC;IACF;IAEA,0DAA0D;IAC1D,kCAAkC;IAClC,MAAMC,aAAahC,QAAQC,GAAG,CAACgC,wBAAwB,KAAK;IAE5D,IAAI;QACF,IAAID,YAAY;YACd,6DAA6D;YAC7D1C,IAAIoB,KAAK,CACP;YAEF,MAAMwB,YAAYC,cAAc5B,UAAU,IAAI,oBAAoB;;YAElE,qBAAqB;YACrB,MAAM6B,OAA6B;gBACjCC,MAAM;oBACJR,OAAOK;gBACT;YACF;YAEA,IAAI,CAACE,KAAKC,IAAI,EAAER,OAAO;gBACrB,MAAM,IAAItC,cAAc;YAC1B;YAEA,wDAAwD;YACxD,MAAMqC,YAAYU,eAAeF,KAAKC,IAAI,CAACR,KAAK;YAEhD,OAAO;gBACLD;gBACArB;gBACAsB,OAAOO,KAAKC,IAAI,CAACR,KAAK;YACxB;QACF;QAEA,0BAA0B;QAC1B,MAAMU,UAAUpC;QAChB,MAAMqC,MAAM,GAAGD,QAAQ,QAAQ,EAAEhC,SAAS,OAAO,CAAC;QAElD,MAAMkC,WAAW,MAAMC,MAAMF,KAAK;YAChCG,SAAS;gBACPC,eAAe,CAAC,OAAO,EAAEtC,aAAa;YACxC;YACAuC,QAAQ;QACV;QAEA,IAAI,CAACJ,SAASK,EAAE,EAAE;YAChB,yBAAyB;YACzB,IAAIC,eAAe,CAAC,6BAA6B,EAAEN,SAASO,MAAM,CAAC,CAAC,EAAEP,SAASQ,UAAU,EAAE;YAE3F,IAAI;gBACF,MAAMC,YAAY,MAAMT,SAASU,IAAI;gBACrC,IAAID,UAAUpB,KAAK,IAAIoB,UAAUzD,OAAO,EAAE;oBACxCsD,eAAeG,UAAUpB,KAAK,IAAIoB,UAAUzD,OAAO;gBACrD;YACF,EAAE,OAAM;YACN,0CAA0C;YAC5C;YAEA,MAAM,IAAIF,cAAcwD,cAAcN,SAASO,MAAM;QACvD;QAEA,MAAMZ,OAA6B,MAAMK,SAASU,IAAI;QAEtD,IAAI,CAACf,KAAKC,IAAI,EAAER,OAAO;YACrB,MAAM,IAAItC,cAAc;QAC1B;QAEA,wDAAwD;QACxD,MAAMqC,YAAYU,eAAeF,KAAKC,IAAI,CAACR,KAAK;QAEhD,OAAO;YACLD;YACArB;YACAsB,OAAOO,KAAKC,IAAI,CAACR,KAAK;QACxB;IACF,EAAE,OAAOC,OAAO;QACd,IAAIA,iBAAiBvC,eAAe;YAClC,MAAMuC;QACR;QAEA,oDAAoD;QACpD,MAAM,IAAIvC,cACR,CAAC,6BAA6B,EAAEuC,iBAAiBtC,QAAQsC,MAAMrC,OAAO,GAAG,iBAAiB,EAC1FsC,WACAD,iBAAiBtC,QAAQsC,QAAQC;IAErC;AACF;AAEA;;;CAGC,GACD,SAASI,cAAc5B,QAAgB,EAAE6C,gBAAwB;IAC/D,MAAMC,SAAS;QACbC,KAAK;QACLC,KAAK;IACP;IAEA,MAAMC,MAAMC,KAAKC,KAAK,CAACC,KAAKH,GAAG,KAAK,MAAM,0BAA0B;;IACpE,MAAM/B,MAAM+B,MAAMJ,mBAAmB,GAAG,oBAAoB;;IAE5D,MAAMtC,UAAU;QACda,KAAKpB;QACLqD,OAAO;QACPnC;QACAoC,KAAKL;QACLM,KAAK;IACP;IAEA,mBAAmB;IACnB,MAAMC,kBAAkB,CAACC;QACvB,OAAO1C,OAAOC,IAAI,CAACH,KAAK6C,SAAS,CAACD,MAC/BxC,QAAQ,CAAC,UACTR,OAAO,CAAC,OAAO,KACfA,OAAO,CAAC,OAAO,KACfA,OAAO,CAAC,MAAM;IACnB;IAEA,MAAMkD,gBAAgBH,gBAAgBV;IACtC,MAAMc,iBAAiBJ,gBAAgBjD;IACvC,MAAMsD,YAAY,oBAAoBX,KAAKY,MAAM,GAAG7C,QAAQ,CAAC,IAAI8C,SAAS,CAAC,GAAG;IAE9E,OAAO,GAAGJ,cAAc,CAAC,EAAEC,eAAe,CAAC,EAAEC,WAAW;AAC1D;AAEA;;;;;;;CAOC,GACD,SAAS9B,eAAeT,KAAa;IACnC,IAAI;QACF,uCAAuC;QACvC,MAAMlB,QAAQkB,MAAMjB,KAAK,CAAC;QAC1B,IAAID,MAAME,MAAM,KAAK,GAAG;YACtB,MAAM,IAAIrB,MAAM;QAClB;QAEA,mCAAmC;QACnC,MAAMsB,UAAUH,KAAK,CAAC,EAAE;QACxB,2EAA2E;QAC3E,MAAMI,SAASD,QAAQE,OAAO,CAAC,MAAM,KAAKA,OAAO,CAAC,MAAM;QACxD,MAAMC,eAAeF,OAAOG,MAAM,CAACH,OAAOF,MAAM,GAAI,AAAC,CAAA,IAAKE,OAAOF,MAAM,GAAG,CAAC,IAAK,GAAI;QAEpF,MAAMM,iBAAiBC,KAAKC,KAAK,CAACC,OAAOC,IAAI,CAACN,cAAc,UAAUO,QAAQ,CAAC;QAI/E,IAAI,CAACL,eAAeM,GAAG,IAAI,OAAON,eAAeM,GAAG,KAAK,UAAU;YACjE,MAAM,IAAIjC,MAAM;QAClB;QAEA,uDAAuD;QACvD,OAAO2B,eAAeM,GAAG,GAAG;IAC9B,EAAE,OAAOK,OAAO;QACd,MAAM,IAAIvC,cACR,CAAC,4BAA4B,EAAEuC,iBAAiBtC,QAAQsC,MAAMrC,OAAO,GAAG,iBAAiB,EACzFsC,WACAD,iBAAiBtC,QAAQsC,QAAQC;IAErC;AACF"}
|
|
@@ -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;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,
|
|
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,CAkExB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAMxB"}
|
|
@@ -80,11 +80,12 @@ import { getValidAccessToken } from './oauth-flow.js';
|
|
|
80
80
|
// Fetch a new project token from the Figma API
|
|
81
81
|
const projectToken = await fetchProjectToken(accessToken, tenantId);
|
|
82
82
|
// Validate the JWT signature and claims (skip for mocks)
|
|
83
|
+
const hasEnvToken = !!process.env.FIGMA_MOCK_PROJECT_TOKEN_VALUE;
|
|
83
84
|
const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false';
|
|
84
85
|
let validatedClaims;
|
|
85
|
-
if (shouldMock) {
|
|
86
|
+
if (hasEnvToken || shouldMock) {
|
|
86
87
|
// MOCK: Skip JWT validation and parse claims directly
|
|
87
|
-
log.debug('Skipping JWT validation for mock project token');
|
|
88
|
+
log.debug('Skipping JWT validation for mock/env project token');
|
|
88
89
|
validatedClaims = parseJWTClaims(projectToken.token);
|
|
89
90
|
} else {
|
|
90
91
|
// 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 * 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","
|
|
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 hasEnvToken = !!process.env.FIGMA_MOCK_PROJECT_TOKEN_VALUE\n const shouldMock = process.env.FIGMA_MOCK_PROJECT_TOKEN !== 'false'\n let validatedClaims: JWTPayload\n\n if (hasEnvToken || shouldMock) {\n // MOCK: Skip JWT validation and parse claims directly\n log.debug('Skipping JWT validation for mock/env 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","hasEnvToken","process","env","FIGMA_MOCK_PROJECT_TOKEN_VALUE","shouldMock","FIGMA_MOCK_PROJECT_TOKEN","validatedClaims","debug","validationError","exp","setProjectToken","claims","expiresAt","refreshProjectToken","clearProjectToken"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport arg from 'arg'\nimport pc from 'picocolors'\n\nimport type { CliArgs } from './types.js'\n\nimport { deployCommand } from './commands/deploy.js'\nimport { initCommand } from './commands/init.js'\nimport { listTokensCommand } from './commands/list-tokens.js'\nimport { loginCommand } from './commands/login.js'\nimport { logoutCommand } from './commands/logout.js'\nimport { feedbackOutro, helpMessage } from './utils/messages.js'\n\n/**\n * Entrypoint for bin/cli.js\n */\nexport async function main(): Promise<void> {\n try {\n await new Main().init()\n } catch (e) {\n if (e instanceof Error) {\n // eslint-disable-next-line no-console\n console.error(e.message)\n }\n }\n}\n\nclass Main {\n args: CliArgs\n\n constructor() {\n // @ts-expect-error bad typings\n this.args = arg(\n {\n '--debug': Boolean,\n '--force': Boolean,\n '--help': Boolean,\n '--id': String,\n '--name': String,\n '--skip-auth': Boolean,\n '--yes': Boolean,\n\n // Aliases\n '-f': '--force',\n '-h': '--help',\n '-y': '--yes',\n },\n { permissive: true },\n )\n\n // Set debug flag globally\n if (this.args['--debug']) {\n process.env.DEBUG = 'true'\n }\n }\n\n async init(): Promise<void> {\n try {\n if (this.args['--help']) {\n helpMessage()\n process.exit(0)\n }\n\n // Get the subcommand (first non-flag argument)\n const subcommand = this.args._[0]\n\n // eslint-disable-next-line no-console\n console.log('\\n')\n p.intro(pc.bgCyan(pc.black(' @payloadcms/figma ')))\n\n // Route to appropriate command handler\n switch (subcommand) {\n case 'deploy':\n await deployCommand({\n debug: this.args['--debug'],\n yes: this.args['--yes'],\n })\n break\n\n case 'init':\n await initCommand({\n id: this.args['--id'],\n name: this.args['--name'],\n debug: this.args['--debug'],\n force: this.args['--force'],\n skipAuth: this.args['--skip-auth'],\n })\n break\n\n case 'list-tokens':\n listTokensCommand({\n debug: this.args['--debug'],\n })\n break\n\n case 'login':\n await loginCommand()\n break\n\n case 'logout':\n await logoutCommand({\n debug: this.args['--debug'],\n })\n break\n\n case undefined:\n // No subcommand - show default message\n p.note(\"Let's create a new CMS!\")\n p.outro(feedbackOutro())\n break\n\n default:\n p.log.error(pc.red(`Unknown command: ${subcommand}`))\n p.note('Use --help to see available commands', 'Tip')\n process.exit(1)\n }\n\n process.exit(0)\n } catch (err: unknown) {\n // eslint-disable-next-line no-console\n console.error(err instanceof Error ? err.message : 'An error occurred')\n process.exit(1)\n }\n }\n}\n"],"names":["p","arg","pc","deployCommand","initCommand","listTokensCommand","loginCommand","logoutCommand","feedbackOutro","helpMessage","main","Main","init","e","Error","console","error","message","args","Boolean","String","permissive","process","env","DEBUG","exit","subcommand","_","log","intro","bgCyan","black","
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport arg from 'arg'\nimport pc from 'picocolors'\n\nimport type { CliArgs } from './types.js'\n\nimport { deployCommand } from './commands/deploy.js'\nimport { initCommand } from './commands/init.js'\nimport { listTokensCommand } from './commands/list-tokens.js'\nimport { loginCommand } from './commands/login.js'\nimport { logoutCommand } from './commands/logout.js'\nimport { feedbackOutro, helpMessage } from './utils/messages.js'\n\n/**\n * Entrypoint for bin/cli.js\n */\nexport async function main(): Promise<void> {\n try {\n await new Main().init()\n } catch (e) {\n if (e instanceof Error) {\n // eslint-disable-next-line no-console\n console.error(e.message)\n }\n }\n}\n\nclass Main {\n args: CliArgs\n\n constructor() {\n // @ts-expect-error bad typings\n this.args = arg(\n {\n '--debug': Boolean,\n '--force': Boolean,\n '--help': Boolean,\n '--id': String,\n '--name': String,\n '--skip-auth': Boolean,\n '--yes': Boolean,\n\n // Aliases\n '-f': '--force',\n '-h': '--help',\n '-y': '--yes',\n },\n { permissive: true },\n )\n\n // Set debug flag globally\n if (this.args['--debug']) {\n process.env.DEBUG = 'true'\n }\n }\n\n async init(): Promise<void> {\n try {\n if (this.args['--help']) {\n helpMessage()\n process.exit(0)\n }\n\n // Get the subcommand (first non-flag argument)\n const subcommand = this.args._[0]\n\n // eslint-disable-next-line no-console\n console.log('\\n')\n p.intro(pc.bgCyan(pc.black(' @payloadcms/figma ')))\n\n // Route to appropriate command handler\n switch (subcommand) {\n case 'deploy':\n await deployCommand({\n id: this.args['--id'],\n debug: this.args['--debug'],\n yes: this.args['--yes'],\n })\n break\n\n case 'init':\n await initCommand({\n id: this.args['--id'],\n name: this.args['--name'],\n debug: this.args['--debug'],\n force: this.args['--force'],\n skipAuth: this.args['--skip-auth'],\n })\n break\n\n case 'list-tokens':\n listTokensCommand({\n debug: this.args['--debug'],\n })\n break\n\n case 'login':\n await loginCommand()\n break\n\n case 'logout':\n await logoutCommand({\n debug: this.args['--debug'],\n })\n break\n\n case undefined:\n // No subcommand - show default message\n p.note(\"Let's create a new CMS!\")\n p.outro(feedbackOutro())\n break\n\n default:\n p.log.error(pc.red(`Unknown command: ${subcommand}`))\n p.note('Use --help to see available commands', 'Tip')\n process.exit(1)\n }\n\n process.exit(0)\n } catch (err: unknown) {\n // eslint-disable-next-line no-console\n console.error(err instanceof Error ? err.message : 'An error occurred')\n process.exit(1)\n }\n }\n}\n"],"names":["p","arg","pc","deployCommand","initCommand","listTokensCommand","loginCommand","logoutCommand","feedbackOutro","helpMessage","main","Main","init","e","Error","console","error","message","args","Boolean","String","permissive","process","env","DEBUG","exit","subcommand","_","log","intro","bgCyan","black","id","debug","yes","name","force","skipAuth","undefined","note","outro","red","err"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AA6BD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,gBAAgB;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AA6BD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgUhF"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -51,6 +51,11 @@ import { loginCommand } from './login.js';
|
|
|
51
51
|
*/ export async function deployCommand(options) {
|
|
52
52
|
const projectPath = process.cwd();
|
|
53
53
|
const spinner = p.spinner();
|
|
54
|
+
if (!options.id) {
|
|
55
|
+
p.log.error(pc.red('✗ Tenant ID is required. Use --id <tenant_id> to specify.'));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const tenantId = options.id;
|
|
54
59
|
try {
|
|
55
60
|
// ===== PRE-FLIGHT CHECKS =====
|
|
56
61
|
// Check if in project directory
|
|
@@ -73,7 +78,7 @@ import { loginCommand } from './login.js';
|
|
|
73
78
|
const sourceFile = project.addSourceFileAtPath(configPath);
|
|
74
79
|
// Read figma configuration from buildConfig
|
|
75
80
|
const config = readFigmaConfig(sourceFile);
|
|
76
|
-
if (!config || !config.
|
|
81
|
+
if (!config || !config.contentSystemId) {
|
|
77
82
|
p.log.error(pc.red('✗ No figma configuration found in payload.config.ts'));
|
|
78
83
|
p.note('Run npx @payloadcms/figma init to configure your project.', 'Tip');
|
|
79
84
|
process.exit(1);
|
|
@@ -92,7 +97,7 @@ import { loginCommand } from './login.js';
|
|
|
92
97
|
}
|
|
93
98
|
// Get project token
|
|
94
99
|
try {
|
|
95
|
-
await getValidProjectToken(tokenStore,
|
|
100
|
+
await getValidProjectToken(tokenStore, tenantId);
|
|
96
101
|
} catch (error) {
|
|
97
102
|
p.log.error(pc.yellow('⚠ Project token invalid'));
|
|
98
103
|
throw error;
|
|
@@ -226,7 +231,7 @@ import { loginCommand } from './login.js';
|
|
|
226
231
|
let codeUploadUrl;
|
|
227
232
|
let staticAssetUploadUrls;
|
|
228
233
|
try {
|
|
229
|
-
const createResponse = await createDeployment(accessToken,
|
|
234
|
+
const createResponse = await createDeployment(accessToken, tenantId, {
|
|
230
235
|
staticAssets
|
|
231
236
|
});
|
|
232
237
|
deploymentId = createResponse.deploymentId;
|
|
@@ -267,7 +272,7 @@ import { loginCommand } from './login.js';
|
|
|
267
272
|
// Step 4: Perform deployment
|
|
268
273
|
spinner.start('Performing deployment...');
|
|
269
274
|
try {
|
|
270
|
-
await performDeployment(accessToken,
|
|
275
|
+
await performDeployment(accessToken, tenantId, {
|
|
271
276
|
deploymentId
|
|
272
277
|
});
|
|
273
278
|
spinner.stop(pc.green('✓ Deployment initiated'));
|
|
@@ -282,14 +287,14 @@ import { loginCommand } from './login.js';
|
|
|
282
287
|
p.log.message('This usually takes 2-3 minutes to complete.');
|
|
283
288
|
// Get tenant details for URL
|
|
284
289
|
try {
|
|
285
|
-
const tenant = await getTenantDetails(accessToken,
|
|
290
|
+
const tenant = await getTenantDetails(accessToken, tenantId);
|
|
286
291
|
if (tenant.domain) {
|
|
287
292
|
p.log.message(`View: ${pc.cyan(`https://${tenant.domain}/`)}`);
|
|
288
293
|
}
|
|
289
294
|
} catch {
|
|
290
295
|
// Non-critical - just skip URL display
|
|
291
296
|
}
|
|
292
|
-
p.note(`Manage your deployment at:\n${pc.cyan(`https://cms.figma.com/manage/tenants/${
|
|
297
|
+
p.note(`Manage your deployment at:\n${pc.cyan(`https://cms.figma.com/manage/tenants/${tenantId}`)}`, 'Next Steps');
|
|
293
298
|
} catch (error) {
|
|
294
299
|
spinner.stop(pc.red('✗ Failed'));
|
|
295
300
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport { spawn } from 'child_process'\nimport path from 'path'\nimport pc from 'picocolors'\nimport { Project } from 'ts-morph'\n\nimport { createDeployment, getTenantDetails, performDeployment } from '../api/control-plane.js'\nimport { getValidAccessToken } from '../auth/oauth-flow.js'\nimport { getValidProjectToken } from '../auth/project-token.js'\nimport { TokenStore } from '../auth/token-store.js'\nimport { collectStaticAssets, createLambdaZip, getFileSize } from '../utils/asset-collection.js'\nimport { detectBuild, getBuildCommand } from '../utils/build-detection.js'\nimport * as log from '../utils/log.js'\nimport { getPackageManager } from '../utils/package-manager.js'\nimport { readFigmaConfig } from '../utils/payload-config-ast.js'\nimport { findPayloadConfig } from '../utils/payload-config-finder.js'\nimport { isInProjectDirectory } from '../utils/project.js'\nimport { uploadLambdaZip, uploadStaticAssets } from '../utils/s3-upload.js'\nimport { loginCommand } from './login.js'\n\n/**\n * Options for deploy command\n */\nexport interface DeployCommandOptions {\n /** Enable debug mode */\n debug?: boolean\n /** Skip confirmation prompts */\n yes?: boolean\n}\n\n/**\n * Format bytes to human-readable string\n */\nfunction formatBytes(bytes: number): string {\n if (bytes === 0) {\n return '0 B'\n }\n const k = 1024\n const sizes = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`\n}\n\n/**\n * Format date to human-readable string in local time\n */\nfunction formatDate(date: Date): string {\n return date.toLocaleString('en-US', {\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n month: 'long',\n timeZoneName: 'short',\n year: 'numeric',\n })\n}\n\n/**\n * Execute the deploy command\n *\n * @param options - Command options\n */\nexport async function deployCommand(options: DeployCommandOptions): Promise<void> {\n const projectPath = process.cwd()\n const spinner = p.spinner()\n\n try {\n // ===== PRE-FLIGHT CHECKS =====\n\n // Check if in project directory\n if (!(await isInProjectDirectory(projectPath))) {\n p.log.error(pc.red(\"✗ 'deploy' command is not available outside of a Payload project.\"))\n p.note(\n 'Create a project or connect an existing one to Figma: npx @payloadcms/figma init',\n 'Tip',\n )\n process.exit(1)\n }\n\n // Find and read payload config\n const configPath = await findPayloadConfig(projectPath)\n if (!configPath) {\n p.log.error(pc.red('✗ payload.config.ts not found'))\n p.note('Run npx @payloadcms/figma init to configure your project.', 'Tip')\n process.exit(1)\n }\n\n // Parse config with ts-morph\n const project = new Project({ skipAddingFilesFromTsConfig: true })\n const sourceFile = project.addSourceFileAtPath(configPath)\n\n // Read figma configuration from buildConfig\n const config = readFigmaConfig(sourceFile)\n if (!config || !config.tenantId) {\n p.log.error(pc.red('✗ No figma configuration found in payload.config.ts'))\n p.note('Run npx @payloadcms/figma init to configure your project.', 'Tip')\n process.exit(1)\n }\n\n // Check authentication\n const tokenStore = new TokenStore()\n\n let accessToken = await getValidAccessToken(tokenStore)\n if (!accessToken) {\n p.log.message('Please log in to continue')\n await loginCommand()\n accessToken = await getValidAccessToken(tokenStore)\n if (!accessToken) {\n p.log.error(pc.red('✗ Authentication failed'))\n process.exit(1)\n }\n }\n\n // Get project token\n try {\n await getValidProjectToken(tokenStore, config.tenantId)\n } catch (error) {\n p.log.error(pc.yellow('⚠ Project token invalid'))\n throw error\n }\n\n // ===== BUILD VALIDATION =====\n\n spinner.start('Checking for build...')\n let buildInfo = await detectBuild(projectPath)\n\n if (!buildInfo) {\n spinner.stop(pc.yellow('⚠ No build found for this project.'))\n\n // Try to find build command\n const buildCmd = await getBuildCommand(projectPath)\n\n if (!buildCmd) {\n p.log.error('No build script found in package.json')\n p.note('Add a build script to package.json: \"build\": \"next build\"', 'Tip')\n process.exit(1)\n }\n\n // Prompt to run build\n if (!options.yes) {\n const shouldBuild = await p.confirm({\n initialValue: true,\n message: `Build command found in package.json. Run it?`,\n })\n\n if (p.isCancel(shouldBuild) || !shouldBuild) {\n p.log.message('Cancelling deployment...')\n process.exit(0)\n }\n }\n\n // Run build\n const packageManager = await getPackageManager(projectPath)\n const buildCommand = `${packageManager} run build`\n spinner.stop(`Running ${buildCommand}...\\n`)\n\n try {\n // Stream build output to user with formatting\n const buildProcess = spawn(packageManager, ['run', 'build'], {\n cwd: projectPath,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n // Indent and dim output\n buildProcess.stdout?.on('data', (data) => {\n const lines = data.toString().split('\\n')\n lines.forEach((line: string) => {\n if (line.trim()) {\n // eslint-disable-next-line no-console\n console.log(pc.dim(` ${line}`)) // Standard output\n }\n })\n })\n\n buildProcess.stderr?.on('data', (data) => {\n const lines = data.toString().split('\\n')\n lines.forEach((line: string) => {\n if (line.trim()) {\n // eslint-disable-next-line no-console\n console.log(pc.dim(` ${line}`)) // Standard error\n }\n })\n })\n\n const exitCode = await new Promise<number>((resolve) => {\n buildProcess.on('close', resolve)\n })\n\n if (exitCode !== 0) {\n throw new Error(`Build process exited with code ${exitCode}`)\n }\n\n p.log.success(pc.green('✓ Build completed'))\n } catch (error) {\n p.log.error(pc.red('✗ Build failed'))\n if (error instanceof Error && options.debug) {\n log.error(`Build error: ${error.message}`)\n }\n process.exit(1)\n }\n\n // Re-check for build\n buildInfo = await detectBuild(projectPath)\n if (!buildInfo) {\n p.log.error(pc.red('✗ Build completed but standalone build not found'))\n p.note('Ensure next.config.js has output: \"standalone\"', 'Check Lambda Configuration')\n process.exit(1)\n }\n } else {\n spinner.stop(pc.green('✓ Build found'))\n p.note(\n [\n `${pc.cyan('Build ID:')} ${buildInfo.buildId}`,\n `${pc.cyan('Date:')} ${formatDate(buildInfo.timestamp)}`,\n ].join('\\n'),\n 'Build Details',\n )\n }\n\n // ===== DEPLOYMENT PREPARATION =====\n\n // Create Lambda zip\n spinner.start('Creating deployment package...')\n try {\n await createLambdaZip(projectPath)\n spinner.stop(pc.green('✓ Deployment package created'))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to create deployment package'))\n throw error\n }\n\n // Collect static assets\n spinner.start('Collecting static assets...')\n const staticAssets = await collectStaticAssets(projectPath)\n const zipPath = path.join(projectPath, 'lambda.zip')\n const zipSize = await getFileSize(zipPath)\n spinner.stop(pc.green(`✓ ${staticAssets.length} static assets detected`))\n\n log.debug(`Lambda zip size: ${formatBytes(zipSize)}`)\n log.debug(`Static assets: ${staticAssets.length} files`)\n\n // ===== DEPLOYMENT CONFIRMATION =====\n\n if (!options.yes) {\n p.note(\n [\n `${pc.cyan('Build ID:')} ${buildInfo.buildId}`,\n `${pc.cyan('Date:')} ${formatDate(buildInfo.timestamp)}`,\n `${pc.cyan('Code size:')} ${formatBytes(zipSize)}`,\n `${pc.cyan('Static assets:')} ${staticAssets.length} files`,\n ].join('\\n'),\n 'Details',\n )\n\n const shouldDeploy = await p.confirm({\n initialValue: true,\n message: 'Deploy this build to Figma?',\n })\n\n if (p.isCancel(shouldDeploy) || !shouldDeploy) {\n p.log.message('Cancelling deployment...')\n process.exit(0)\n }\n }\n\n // ===== DEPLOYMENT EXECUTION =====\n\n // Step 1: Create deployment\n spinner.start('Creating deployment...')\n let deploymentId: string\n let codeUploadUrl: string\n let staticAssetUploadUrls: Record<string, string>\n\n try {\n const createResponse = await createDeployment(accessToken, config.tenantId, {\n staticAssets,\n })\n\n deploymentId = createResponse.deploymentId\n codeUploadUrl = createResponse.codeUploadUrl\n staticAssetUploadUrls = createResponse.staticAssetUploadUrls\n\n log.debug(`Deployment ID: ${deploymentId}`)\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to create deployment'))\n throw error\n }\n\n // Step 2: Upload code\n spinner.message(`Uploading code (${formatBytes(zipSize)})...`)\n try {\n await uploadLambdaZip(zipPath, codeUploadUrl)\n spinner.stop(pc.green(`✓ Code uploaded (${formatBytes(zipSize)})`))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to upload code'))\n throw error\n }\n\n // Step 3: Upload static assets\n if (staticAssets.length > 0) {\n spinner.start('Uploading static assets...')\n\n try {\n const uploadResults = await uploadStaticAssets(\n projectPath,\n staticAssetUploadUrls,\n (uploaded, total) => {\n spinner.message(`Uploading static assets (${uploaded}/${total})...`)\n },\n )\n\n if (uploadResults.assetsFailed > 0) {\n spinner.stop(\n pc.yellow(\n `⚠ ${uploadResults.assetsUploaded}/${staticAssets.length} assets uploaded (${uploadResults.assetsFailed} failed)`,\n ),\n )\n p.log.warning(\n `${uploadResults.assetsFailed} assets failed to upload. Deployment may be incomplete.`,\n )\n } else {\n spinner.stop(\n pc.green(\n `✓ Static assets uploaded (${uploadResults.assetsUploaded} files, ${formatBytes(uploadResults.totalBytesUploaded)})`,\n ),\n )\n }\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to upload assets'))\n throw error\n }\n }\n\n // Step 4: Perform deployment\n spinner.start('Performing deployment...')\n try {\n await performDeployment(accessToken, config.tenantId, {\n deploymentId,\n })\n spinner.stop(pc.green('✓ Deployment initiated'))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to perform deployment'))\n throw error\n }\n\n // TODO: Add deployment progress tracking\n // Future: Poll deployment status and show progress\n // API endpoint: GET /v1/tenant/{tenant_id}/deploy/{deployment_id}/status\n\n // Success output\n p.log.message('This usually takes 2-3 minutes to complete.')\n\n // Get tenant details for URL\n try {\n const tenant = await getTenantDetails(accessToken, config.tenantId)\n if (tenant.domain) {\n p.log.message(`View: ${pc.cyan(`https://${tenant.domain}/`)}`)\n }\n } catch {\n // Non-critical - just skip URL display\n }\n\n p.note(\n `Manage your deployment at:\\n${pc.cyan(`https://cms.figma.com/manage/tenants/${config.tenantId}`)}`,\n 'Next Steps',\n )\n } catch (error) {\n spinner.stop(pc.red('✗ Failed'))\n const message = error instanceof Error ? error.message : 'Unknown error'\n p.log.error(pc.red(`✗ ${message}`))\n if (options.debug && error instanceof Error && error.stack) {\n log.error(`Stack trace: ${error.stack}`)\n }\n process.exit(1)\n }\n}\n"],"names":["p","spawn","path","pc","Project","createDeployment","getTenantDetails","performDeployment","getValidAccessToken","getValidProjectToken","TokenStore","collectStaticAssets","createLambdaZip","getFileSize","detectBuild","getBuildCommand","log","getPackageManager","readFigmaConfig","findPayloadConfig","isInProjectDirectory","uploadLambdaZip","uploadStaticAssets","loginCommand","formatBytes","bytes","k","sizes","i","Math","floor","parseFloat","pow","toFixed","formatDate","date","toLocaleString","day","hour","minute","month","timeZoneName","year","deployCommand","options","projectPath","process","cwd","spinner","error","red","note","exit","configPath","project","skipAddingFilesFromTsConfig","sourceFile","addSourceFileAtPath","config","tenantId","tokenStore","accessToken","message","yellow","start","buildInfo","stop","buildCmd","yes","shouldBuild","confirm","initialValue","isCancel","packageManager","buildCommand","buildProcess","stdio","stdout","on","data","lines","toString","split","forEach","line","trim","console","dim","stderr","exitCode","Promise","resolve","Error","success","green","debug","cyan","buildId","timestamp","join","staticAssets","zipPath","zipSize","length","shouldDeploy","deploymentId","codeUploadUrl","staticAssetUploadUrls","createResponse","uploadResults","uploaded","total","assetsFailed","assetsUploaded","warning","totalBytesUploaded","tenant","domain","stack"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport { spawn } from 'child_process'\nimport path from 'path'\nimport pc from 'picocolors'\nimport { Project } from 'ts-morph'\n\nimport { createDeployment, getTenantDetails, performDeployment } from '../api/control-plane.js'\nimport { getValidAccessToken } from '../auth/oauth-flow.js'\nimport { getValidProjectToken } from '../auth/project-token.js'\nimport { TokenStore } from '../auth/token-store.js'\nimport { collectStaticAssets, createLambdaZip, getFileSize } from '../utils/asset-collection.js'\nimport { detectBuild, getBuildCommand } from '../utils/build-detection.js'\nimport * as log from '../utils/log.js'\nimport { getPackageManager } from '../utils/package-manager.js'\nimport { readFigmaConfig } from '../utils/payload-config-ast.js'\nimport { findPayloadConfig } from '../utils/payload-config-finder.js'\nimport { isInProjectDirectory } from '../utils/project.js'\nimport { uploadLambdaZip, uploadStaticAssets } from '../utils/s3-upload.js'\nimport { loginCommand } from './login.js'\n\n/**\n * Options for deploy command\n */\nexport interface DeployCommandOptions {\n /** Enable debug mode */\n debug?: boolean\n /** Tenant ID */\n id?: string\n /** Skip confirmation prompts */\n yes?: boolean\n}\n\n/**\n * Format bytes to human-readable string\n */\nfunction formatBytes(bytes: number): string {\n if (bytes === 0) {\n return '0 B'\n }\n const k = 1024\n const sizes = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`\n}\n\n/**\n * Format date to human-readable string in local time\n */\nfunction formatDate(date: Date): string {\n return date.toLocaleString('en-US', {\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n month: 'long',\n timeZoneName: 'short',\n year: 'numeric',\n })\n}\n\n/**\n * Execute the deploy command\n *\n * @param options - Command options\n */\nexport async function deployCommand(options: DeployCommandOptions): Promise<void> {\n const projectPath = process.cwd()\n const spinner = p.spinner()\n\n if (!options.id) {\n p.log.error(pc.red('✗ Tenant ID is required. Use --id <tenant_id> to specify.'))\n process.exit(1)\n }\n\n const tenantId = options.id\n\n try {\n // ===== PRE-FLIGHT CHECKS =====\n\n // Check if in project directory\n if (!(await isInProjectDirectory(projectPath))) {\n p.log.error(pc.red(\"✗ 'deploy' command is not available outside of a Payload project.\"))\n p.note(\n 'Create a project or connect an existing one to Figma: npx @payloadcms/figma init',\n 'Tip',\n )\n process.exit(1)\n }\n\n // Find and read payload config\n const configPath = await findPayloadConfig(projectPath)\n if (!configPath) {\n p.log.error(pc.red('✗ payload.config.ts not found'))\n p.note('Run npx @payloadcms/figma init to configure your project.', 'Tip')\n process.exit(1)\n }\n\n // Parse config with ts-morph\n const project = new Project({ skipAddingFilesFromTsConfig: true })\n const sourceFile = project.addSourceFileAtPath(configPath)\n\n // Read figma configuration from buildConfig\n const config = readFigmaConfig(sourceFile)\n if (!config || !config.contentSystemId) {\n p.log.error(pc.red('✗ No figma configuration found in payload.config.ts'))\n p.note('Run npx @payloadcms/figma init to configure your project.', 'Tip')\n process.exit(1)\n }\n\n // Check authentication\n const tokenStore = new TokenStore()\n\n let accessToken = await getValidAccessToken(tokenStore)\n if (!accessToken) {\n p.log.message('Please log in to continue')\n await loginCommand()\n accessToken = await getValidAccessToken(tokenStore)\n if (!accessToken) {\n p.log.error(pc.red('✗ Authentication failed'))\n process.exit(1)\n }\n }\n\n // Get project token\n try {\n await getValidProjectToken(tokenStore, tenantId)\n } catch (error) {\n p.log.error(pc.yellow('⚠ Project token invalid'))\n throw error\n }\n\n // ===== BUILD VALIDATION =====\n\n spinner.start('Checking for build...')\n let buildInfo = await detectBuild(projectPath)\n\n if (!buildInfo) {\n spinner.stop(pc.yellow('⚠ No build found for this project.'))\n\n // Try to find build command\n const buildCmd = await getBuildCommand(projectPath)\n\n if (!buildCmd) {\n p.log.error('No build script found in package.json')\n p.note('Add a build script to package.json: \"build\": \"next build\"', 'Tip')\n process.exit(1)\n }\n\n // Prompt to run build\n if (!options.yes) {\n const shouldBuild = await p.confirm({\n initialValue: true,\n message: `Build command found in package.json. Run it?`,\n })\n\n if (p.isCancel(shouldBuild) || !shouldBuild) {\n p.log.message('Cancelling deployment...')\n process.exit(0)\n }\n }\n\n // Run build\n const packageManager = await getPackageManager(projectPath)\n const buildCommand = `${packageManager} run build`\n spinner.stop(`Running ${buildCommand}...\\n`)\n\n try {\n // Stream build output to user with formatting\n const buildProcess = spawn(packageManager, ['run', 'build'], {\n cwd: projectPath,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n // Indent and dim output\n buildProcess.stdout?.on('data', (data) => {\n const lines = data.toString().split('\\n')\n lines.forEach((line: string) => {\n if (line.trim()) {\n // eslint-disable-next-line no-console\n console.log(pc.dim(` ${line}`)) // Standard output\n }\n })\n })\n\n buildProcess.stderr?.on('data', (data) => {\n const lines = data.toString().split('\\n')\n lines.forEach((line: string) => {\n if (line.trim()) {\n // eslint-disable-next-line no-console\n console.log(pc.dim(` ${line}`)) // Standard error\n }\n })\n })\n\n const exitCode = await new Promise<number>((resolve) => {\n buildProcess.on('close', resolve)\n })\n\n if (exitCode !== 0) {\n throw new Error(`Build process exited with code ${exitCode}`)\n }\n\n p.log.success(pc.green('✓ Build completed'))\n } catch (error) {\n p.log.error(pc.red('✗ Build failed'))\n if (error instanceof Error && options.debug) {\n log.error(`Build error: ${error.message}`)\n }\n process.exit(1)\n }\n\n // Re-check for build\n buildInfo = await detectBuild(projectPath)\n if (!buildInfo) {\n p.log.error(pc.red('✗ Build completed but standalone build not found'))\n p.note('Ensure next.config.js has output: \"standalone\"', 'Check Lambda Configuration')\n process.exit(1)\n }\n } else {\n spinner.stop(pc.green('✓ Build found'))\n p.note(\n [\n `${pc.cyan('Build ID:')} ${buildInfo.buildId}`,\n `${pc.cyan('Date:')} ${formatDate(buildInfo.timestamp)}`,\n ].join('\\n'),\n 'Build Details',\n )\n }\n\n // ===== DEPLOYMENT PREPARATION =====\n\n // Create Lambda zip\n spinner.start('Creating deployment package...')\n try {\n await createLambdaZip(projectPath)\n spinner.stop(pc.green('✓ Deployment package created'))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to create deployment package'))\n throw error\n }\n\n // Collect static assets\n spinner.start('Collecting static assets...')\n const staticAssets = await collectStaticAssets(projectPath)\n const zipPath = path.join(projectPath, 'lambda.zip')\n const zipSize = await getFileSize(zipPath)\n spinner.stop(pc.green(`✓ ${staticAssets.length} static assets detected`))\n\n log.debug(`Lambda zip size: ${formatBytes(zipSize)}`)\n log.debug(`Static assets: ${staticAssets.length} files`)\n\n // ===== DEPLOYMENT CONFIRMATION =====\n\n if (!options.yes) {\n p.note(\n [\n `${pc.cyan('Build ID:')} ${buildInfo.buildId}`,\n `${pc.cyan('Date:')} ${formatDate(buildInfo.timestamp)}`,\n `${pc.cyan('Code size:')} ${formatBytes(zipSize)}`,\n `${pc.cyan('Static assets:')} ${staticAssets.length} files`,\n ].join('\\n'),\n 'Details',\n )\n\n const shouldDeploy = await p.confirm({\n initialValue: true,\n message: 'Deploy this build to Figma?',\n })\n\n if (p.isCancel(shouldDeploy) || !shouldDeploy) {\n p.log.message('Cancelling deployment...')\n process.exit(0)\n }\n }\n\n // ===== DEPLOYMENT EXECUTION =====\n\n // Step 1: Create deployment\n spinner.start('Creating deployment...')\n let deploymentId: string\n let codeUploadUrl: string\n let staticAssetUploadUrls: Record<string, string>\n\n try {\n const createResponse = await createDeployment(accessToken, tenantId, {\n staticAssets,\n })\n\n deploymentId = createResponse.deploymentId\n codeUploadUrl = createResponse.codeUploadUrl\n staticAssetUploadUrls = createResponse.staticAssetUploadUrls\n\n log.debug(`Deployment ID: ${deploymentId}`)\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to create deployment'))\n throw error\n }\n\n // Step 2: Upload code\n spinner.message(`Uploading code (${formatBytes(zipSize)})...`)\n try {\n await uploadLambdaZip(zipPath, codeUploadUrl)\n spinner.stop(pc.green(`✓ Code uploaded (${formatBytes(zipSize)})`))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to upload code'))\n throw error\n }\n\n // Step 3: Upload static assets\n if (staticAssets.length > 0) {\n spinner.start('Uploading static assets...')\n\n try {\n const uploadResults = await uploadStaticAssets(\n projectPath,\n staticAssetUploadUrls,\n (uploaded, total) => {\n spinner.message(`Uploading static assets (${uploaded}/${total})...`)\n },\n )\n\n if (uploadResults.assetsFailed > 0) {\n spinner.stop(\n pc.yellow(\n `⚠ ${uploadResults.assetsUploaded}/${staticAssets.length} assets uploaded (${uploadResults.assetsFailed} failed)`,\n ),\n )\n p.log.warning(\n `${uploadResults.assetsFailed} assets failed to upload. Deployment may be incomplete.`,\n )\n } else {\n spinner.stop(\n pc.green(\n `✓ Static assets uploaded (${uploadResults.assetsUploaded} files, ${formatBytes(uploadResults.totalBytesUploaded)})`,\n ),\n )\n }\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to upload assets'))\n throw error\n }\n }\n\n // Step 4: Perform deployment\n spinner.start('Performing deployment...')\n try {\n await performDeployment(accessToken, tenantId, {\n deploymentId,\n })\n spinner.stop(pc.green('✓ Deployment initiated'))\n } catch (error) {\n spinner.stop(pc.red('✗ Failed to perform deployment'))\n throw error\n }\n\n // TODO: Add deployment progress tracking\n // Future: Poll deployment status and show progress\n // API endpoint: GET /v1/tenant/{tenant_id}/deploy/{deployment_id}/status\n\n // Success output\n p.log.message('This usually takes 2-3 minutes to complete.')\n\n // Get tenant details for URL\n try {\n const tenant = await getTenantDetails(accessToken, tenantId)\n if (tenant.domain) {\n p.log.message(`View: ${pc.cyan(`https://${tenant.domain}/`)}`)\n }\n } catch {\n // Non-critical - just skip URL display\n }\n\n p.note(\n `Manage your deployment at:\\n${pc.cyan(`https://cms.figma.com/manage/tenants/${tenantId}`)}`,\n 'Next Steps',\n )\n } catch (error) {\n spinner.stop(pc.red('✗ Failed'))\n const message = error instanceof Error ? error.message : 'Unknown error'\n p.log.error(pc.red(`✗ ${message}`))\n if (options.debug && error instanceof Error && error.stack) {\n log.error(`Stack trace: ${error.stack}`)\n }\n process.exit(1)\n }\n}\n"],"names":["p","spawn","path","pc","Project","createDeployment","getTenantDetails","performDeployment","getValidAccessToken","getValidProjectToken","TokenStore","collectStaticAssets","createLambdaZip","getFileSize","detectBuild","getBuildCommand","log","getPackageManager","readFigmaConfig","findPayloadConfig","isInProjectDirectory","uploadLambdaZip","uploadStaticAssets","loginCommand","formatBytes","bytes","k","sizes","i","Math","floor","parseFloat","pow","toFixed","formatDate","date","toLocaleString","day","hour","minute","month","timeZoneName","year","deployCommand","options","projectPath","process","cwd","spinner","id","error","red","exit","tenantId","note","configPath","project","skipAddingFilesFromTsConfig","sourceFile","addSourceFileAtPath","config","contentSystemId","tokenStore","accessToken","message","yellow","start","buildInfo","stop","buildCmd","yes","shouldBuild","confirm","initialValue","isCancel","packageManager","buildCommand","buildProcess","stdio","stdout","on","data","lines","toString","split","forEach","line","trim","console","dim","stderr","exitCode","Promise","resolve","Error","success","green","debug","cyan","buildId","timestamp","join","staticAssets","zipPath","zipSize","length","shouldDeploy","deploymentId","codeUploadUrl","staticAssetUploadUrls","createResponse","uploadResults","uploaded","total","assetsFailed","assetsUploaded","warning","totalBytesUploaded","tenant","domain","stack"],"mappings":"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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -196,8 +196,8 @@ import { loginCommand } from './login.js';
|
|
|
196
196
|
}
|
|
197
197
|
s.start('Checking Payload configuration...');
|
|
198
198
|
const modResult = await ensurePayloadFigmaConfig(process.cwd(), projectInfo.packageManager || 'pnpm', {
|
|
199
|
+
contentSystemId: selectedTenant.id,
|
|
199
200
|
region: options.region || 'us-east-1',
|
|
200
|
-
tenantId: selectedTenant.id,
|
|
201
201
|
useContentSystem: !options.noContentSystem
|
|
202
202
|
});
|
|
203
203
|
if (!modResult.success) {
|
|
@@ -300,8 +300,8 @@ import { loginCommand } from './login.js';
|
|
|
300
300
|
// Modify Payload configuration
|
|
301
301
|
s.start('Checking Payload configuration...');
|
|
302
302
|
const modResult = await ensurePayloadFigmaConfig(fullPath, 'pnpm', {
|
|
303
|
+
contentSystemId: selectedTenant.id,
|
|
303
304
|
region: options.region || 'us-east-1',
|
|
304
|
-
tenantId: selectedTenant.id,
|
|
305
305
|
useContentSystem: !options.noContentSystem
|
|
306
306
|
});
|
|
307
307
|
if (!modResult.success) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/init.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport fs from 'fs/promises'\nimport path from 'path'\nimport pc from 'picocolors'\n\nimport type { Tenant } from '../types/config.js'\n\nimport { ControlPlaneError, getTenantDetails } from '../api/control-plane.js'\nimport { FigmaApiError } from '../api/figma-api.js'\nimport { getValidAccessToken } from '../auth/oauth-flow.js'\nimport { getValidProjectToken, ProjectTokenError } from '../auth/project-token.js'\nimport { TokenStore } from '../auth/token-store.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\nimport {\n displayManualInstructions,\n ensurePayloadFigmaConfig,\n} from '../utils/payload-config-modifier.js'\nimport {\n detectPayloadProject,\n hasRequiredDependencies,\n initializeGitRepo,\n installDependencies,\n isInProjectDirectory,\n scaffoldProject,\n validatePayloadVersion,\n} from '../utils/project.js'\nimport { loginCommand } from './login.js'\n\n/**\n * Options for init command\n */\nexport interface InitCommandOptions {\n /** Enable debug mode */\n debug?: boolean\n /** Force reconfiguration of existing project */\n force?: boolean\n /** Tenant ID to use (optional - will prompt if not provided) */\n id?: string\n /** Project name (for scaffolding) */\n name?: string\n /** Disable Content System (defaults to enabled) */\n noContentSystem?: boolean\n /** AWS region for deployment (defaults to us-east-1) */\n region?: string\n /** Skip authentication check (for testing/development) */\n skipAuth?: boolean\n /** Skip prompts and use defaults where possible */\n yes?: boolean\n}\n\n/**\n * Generate and store project token for a tenant\n * Non-blocking - will show warning but not exit on failure\n * Only shows feedback if DEBUG mode is enabled, otherwise runs silently\n *\n * @param tokenStore - Token store instance\n * @param tenantId - Tenant ID to generate token for\n * @param spinner - Clack spinner instance for status updates (only used in debug mode)\n */\nasync function generateProjectTokenWithFeedback(\n tokenStore: TokenStore,\n tenantId: string,\n spinner: ReturnType<typeof p.spinner>,\n): Promise<void> {\n if (isDebug()) {\n spinner.start('Generating project token...')\n }\n\n try {\n const projectToken = await getValidProjectToken(tokenStore, tenantId)\n if (isDebug()) {\n if (projectToken) {\n spinner.stop(pc.green('✓ Project token generated'))\n } else {\n spinner.stop(pc.yellow('⚠ Project token not generated (authentication required)'))\n }\n }\n } catch (error) {\n if (isDebug()) {\n spinner.stop(pc.yellow('⚠ Project token generation failed'))\n }\n // Always show failures, even without debug\n if (error instanceof ProjectTokenError || error instanceof FigmaApiError) {\n log.warning(error.message)\n p.note(\n 'Project token is used for authenticating to the Content API.\\nYou can continue without it, but may need to regenerate later.',\n 'Note',\n )\n } else {\n log.warning(\n `Unable to retrieve project token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n // Don't exit - token generation failure shouldn't block initialization\n }\n}\n\n/**\n * Handle the `init` command\n *\n * Sets up a project by:\n * 1. Checking authentication\n * 2. Detecting/scaffolding Payload project\n * 3. Fetching tenant details\n * 4. Storing configuration\n *\n * @param options - Command options\n */\nexport async function initCommand(options: InitCommandOptions): Promise<void> {\n // Check authentication\n const tokenStore = new TokenStore()\n const s = p.spinner()\n\n let accessToken: string\n\n if (options.skipAuth) {\n // Skip authentication for testing/development\n p.log.warn(pc.yellow('Skipping authentication (--skip-auth mode)'))\n accessToken = 'mock-access-token'\n } else {\n try {\n // Check for valid cached tokens first (no API call needed)\n if (tokenStore.hasValidTokens()) {\n // Use cached token silently - no spinner needed\n accessToken = tokenStore.getAccessToken()!\n } else {\n // Need to refresh or authenticate - show spinner for API call\n s.start('Checking authentication...')\n const token = await getValidAccessToken(tokenStore)\n if (!token) {\n s.stop(pc.yellow('⚠ Not authenticated'))\n p.log.info('Authentication required to continue')\n\n // Prompt user to authenticate now\n const shouldAuth = await p.confirm({\n initialValue: true,\n message: 'Would you like to authenticate now?',\n })\n\n if (p.isCancel(shouldAuth) || !shouldAuth) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n // Run login command\n await loginCommand()\n\n // Get token after auth\n const newToken = await getValidAccessToken(tokenStore)\n if (!newToken) {\n p.log.error('Authentication failed')\n process.exit(1)\n }\n accessToken = newToken\n p.log.success(pc.green('✓ Authenticated'))\n } else {\n accessToken = token\n s.stop(pc.green('✓ Authenticated'))\n }\n }\n } catch (error) {\n s.stop(pc.red('✗ Authentication failed'))\n log.error(error instanceof Error ? error.message : 'Unknown error')\n p.note('Run `figma auth` to authenticate', 'Tip')\n process.exit(1)\n }\n }\n\n // Note: We no longer check for figma.config.json here\n // Instead, the AST detection will check if figma object already exists in payload.config.ts\n // and skip modification if it does (unless --force is used)\n\n // Step 3: Get CMS ID with retry loop\n log.debug('Configuring Project...')\n\n let tenantId = options.id\n let selectedTenant: Tenant | undefined\n\n while (!selectedTenant) {\n // Prompt for ID if not provided\n if (!tenantId) {\n const input = await p.text({\n message: 'Enter your CMS ID:',\n placeholder: 'tenant_abc123',\n validate: (value) => {\n if (!value || typeof value !== 'string') {\n return 'CMS ID is required'\n }\n return undefined\n },\n })\n\n if (p.isCancel(input)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n tenantId = input\n }\n\n // Try to fetch tenant details\n try {\n log.debug('Using mock Control Plane API (no real network calls)')\n selectedTenant = await getTenantDetails(accessToken, tenantId)\n log.debug(`Using: ${selectedTenant.domain}`)\n } catch (error) {\n p.log.error(pc.red('✗ Failed to fetch CMS details'))\n\n // Check if permission error (403)\n if (error instanceof ControlPlaneError && error.statusCode === 403) {\n p.log.error('You do not have permission to access the provided CMS ID. Please try again.')\n } else if (error instanceof ControlPlaneError && error.statusCode === 404) {\n p.log.error('Tenant ID not found. Verify the ID is correct.')\n } else {\n p.log.error(error instanceof Error ? error.message : 'Unknown error')\n }\n\n // Clear tenantId to prompt again\n tenantId = undefined\n\n // Ask if they want to retry\n const shouldRetry = await p.confirm({\n initialValue: true,\n message: 'Would you like to try a different CMS ID?',\n })\n\n if (p.isCancel(shouldRetry) || !shouldRetry) {\n p.cancel('Operation cancelled')\n process.exit(1)\n }\n }\n }\n\n // Step 4: Detect or scaffold Payload project\n const isInProject = await isInProjectDirectory()\n\n if (isInProject) {\n // ===== EXISTING PROJECT FLOW =====\n log.debug('Project directory detected')\n\n // Detect Payload\n const projectInfo = await detectPayloadProject()\n\n if (projectInfo.hasPayload) {\n // Validate existing Payload version\n if (projectInfo.payloadVersion && !validatePayloadVersion(projectInfo.payloadVersion)) {\n p.log.warn(\n pc.yellow(\n `Payload version ${projectInfo.payloadVersion} detected. Version 3.x is required.`,\n ),\n )\n p.note('Upgrade to Payload 3.x before continuing', 'Action Required')\n process.exit(1)\n }\n\n p.log.success(pc.green(`✓ Payload ${projectInfo.payloadVersion || 'detected'}`))\n\n // Check dependencies\n s.start('Checking dependencies...')\n const hasDeps = await hasRequiredDependencies(process.cwd())\n s.stop(pc.green('✓ Dependencies checked'))\n\n if (!hasDeps) {\n const shouldInstall = await p.confirm({\n initialValue: true,\n message: 'Install dependencies now?',\n })\n\n if (!p.isCancel(shouldInstall) && shouldInstall) {\n s.start('Installing dependencies...')\n await installDependencies(process.cwd(), projectInfo.packageManager || 'pnpm')\n s.stop(pc.green('✓ Dependencies installed'))\n }\n }\n\n s.start('Checking Payload configuration...')\n const modResult = await ensurePayloadFigmaConfig(\n process.cwd(),\n projectInfo.packageManager || 'pnpm',\n {\n region: options.region || 'us-east-1',\n tenantId: selectedTenant.id,\n useContentSystem: !options.noContentSystem,\n },\n )\n\n if (!modResult.success) {\n s.stop(pc.red('✗ Configuration check failed'))\n displayManualInstructions(modResult.error || 'Unknown error')\n process.exit(1)\n }\n\n if (modResult.modified) {\n s.stop(pc.green('✓ Payload configuration updated'))\n if (modResult.changes.length > 0) {\n modResult.changes.forEach((change) => log.debug(pc.dim(` → ${change}`)))\n }\n } else {\n s.stop(pc.green('✓ Payload configuration valid'))\n }\n\n // Display warnings if any\n if (modResult.warnings && modResult.warnings.length > 0) {\n modResult.warnings.forEach((warning) => {\n p.log.warn(pc.yellow(`⚠ ${warning}`))\n })\n }\n } else {\n // Has package.json but no Payload - offer to add Payload\n p.log.warn(pc.yellow('⚠ No Payload detected in this project'))\n\n const shouldAddPayload = await p.confirm({\n initialValue: true,\n message: 'Would you like to add Payload to this project?',\n })\n\n if (p.isCancel(shouldAddPayload)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n if (!shouldAddPayload) {\n p.log.error('Payload is required to use Figma CMS')\n process.exit(1)\n }\n\n // TODO: Add Payload to existing project (future enhancement)\n p.log.error('Adding Payload to existing projects is not yet supported')\n p.note('Create a new project or manually add Payload dependencies', 'Action Required')\n process.exit(1)\n }\n\n // Generate project token (unless skipping auth)\n if (!options.skipAuth) {\n await generateProjectTokenWithFeedback(tokenStore, selectedTenant.id, s)\n }\n\n // Success message for existing project\n p.outro(pc.green('✓ Project initialized successfully!'))\n\n const nextSteps = [\n selectedTenant.status === 'provisioning'\n ? 'Wait for CMS provisioning to complete (check status with `@payloadcms/figma list`)'\n : undefined,\n 'Start development server: `pnpm dev`',\n `Access your CMS at: ${pc.cyan(`https://${selectedTenant.domain}`)}`,\n ].filter(Boolean)\n\n p.note(nextSteps.join('\\n'), 'Next Steps')\n } else {\n // ===== NEW PROJECT FLOW =====\n // p.log.info('No project detected - Creating New Project')\n\n // Prompt for path\n const projectPathInput = await p.text({\n initialValue: './',\n message: 'Enter path to create project:',\n placeholder: './my-cms-project',\n validate: (value) => {\n if (!value) {\n return 'Path is required'\n }\n // Allow relative or absolute paths\n return undefined\n },\n })\n\n if (p.isCancel(projectPathInput)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n const projectPath = projectPathInput\n const fullPath = path.resolve(process.cwd(), projectPath)\n\n // Get project name from path or prompt\n const projectName = options.name || path.basename(fullPath)\n\n // Create directory\n try {\n await fs.mkdir(fullPath, { recursive: true })\n } catch (error) {\n p.log.error(\n `Failed to create directory: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n process.exit(1)\n }\n\n // Scaffold project\n s.start('Downloading template from GitHub...')\n try {\n await scaffoldProject(fullPath, projectName)\n s.stop(pc.green('✓ Template downloaded'))\n\n s.start('Installing dependencies...')\n await installDependencies(fullPath, 'pnpm')\n s.stop(pc.green('✓ Dependencies installed'))\n } catch (error) {\n s.stop(pc.red('✗ Failed'))\n log.error(error instanceof Error ? error.message : 'Unknown error')\n process.exit(1)\n }\n\n // Modify Payload configuration\n s.start('Checking Payload configuration...')\n const modResult = await ensurePayloadFigmaConfig(fullPath, 'pnpm', {\n region: options.region || 'us-east-1',\n tenantId: selectedTenant.id,\n useContentSystem: !options.noContentSystem,\n })\n\n if (!modResult.success) {\n s.stop(pc.red('✗ Configuration check failed'))\n displayManualInstructions(modResult.error || 'Unknown error')\n process.exit(1)\n }\n\n if (modResult.modified) {\n s.stop(pc.green('✓ Payload configuration updated'))\n if (modResult.changes.length > 0) {\n modResult.changes.forEach((change) => log.debug(pc.dim(` → ${change}`)))\n }\n } else {\n s.stop(pc.green('✓ Payload configuration valid'))\n }\n\n // Display warnings if any\n if (modResult.warnings && modResult.warnings.length > 0) {\n modResult.warnings.forEach((warning) => {\n p.log.warn(pc.yellow(`⚠ ${warning}`))\n })\n }\n\n // Generate project token (unless skipping auth)\n if (!options.skipAuth) {\n await generateProjectTokenWithFeedback(tokenStore, selectedTenant.id, s)\n }\n\n // Initialize git repository (after all files including lock file are ready)\n initializeGitRepo(fullPath)\n\n // Success message for NEW project\n p.log.step(pc.bgGreen(pc.black(' Project created successfully! ')))\n\n const relativePath = path.relative(process.cwd(), fullPath)\n const nextSteps: string[] = []\n\n // Only show cd command if user needs to navigate\n if (relativePath && relativePath !== '.') {\n nextSteps.push(`cd ${relativePath}`)\n }\n\n nextSteps.push(\n 'pnpm dev or follow directions in README.md',\n '',\n 'Documentation:',\n '- Getting Started: https://payloadcms.com/docs/getting-started/what-is-payload',\n '- Configuration: https://payloadcms.com/docs/configuration/overview',\n )\n\n p.note(nextSteps.join('\\n'), 'Next Steps')\n p.outro(pc.green('✓ Done'))\n }\n}\n"],"names":["p","fs","path","pc","ControlPlaneError","getTenantDetails","FigmaApiError","getValidAccessToken","getValidProjectToken","ProjectTokenError","TokenStore","isDebug","log","displayManualInstructions","ensurePayloadFigmaConfig","detectPayloadProject","hasRequiredDependencies","initializeGitRepo","installDependencies","isInProjectDirectory","scaffoldProject","validatePayloadVersion","loginCommand","generateProjectTokenWithFeedback","tokenStore","tenantId","spinner","start","projectToken","stop","green","yellow","error","warning","message","note","Error","initCommand","options","s","accessToken","skipAuth","warn","hasValidTokens","getAccessToken","token","info","shouldAuth","confirm","initialValue","isCancel","cancel","process","exit","newToken","success","red","debug","id","selectedTenant","input","text","placeholder","validate","value","undefined","domain","statusCode","shouldRetry","isInProject","projectInfo","hasPayload","payloadVersion","hasDeps","cwd","shouldInstall","packageManager","modResult","region","useContentSystem","noContentSystem","modified","changes","length","forEach","change","dim","warnings","shouldAddPayload","outro","nextSteps","status","cyan","filter","Boolean","join","projectPathInput","projectPath","fullPath","resolve","projectName","name","basename","mkdir","recursive","step","bgGreen","black","relativePath","relative","push"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/init.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport fs from 'fs/promises'\nimport path from 'path'\nimport pc from 'picocolors'\n\nimport type { Tenant } from '../types/config.js'\n\nimport { ControlPlaneError, getTenantDetails } from '../api/control-plane.js'\nimport { FigmaApiError } from '../api/figma-api.js'\nimport { getValidAccessToken } from '../auth/oauth-flow.js'\nimport { getValidProjectToken, ProjectTokenError } from '../auth/project-token.js'\nimport { TokenStore } from '../auth/token-store.js'\nimport { isDebug } from '../utils/is-debug.js'\nimport * as log from '../utils/log.js'\nimport {\n displayManualInstructions,\n ensurePayloadFigmaConfig,\n} from '../utils/payload-config-modifier.js'\nimport {\n detectPayloadProject,\n hasRequiredDependencies,\n initializeGitRepo,\n installDependencies,\n isInProjectDirectory,\n scaffoldProject,\n validatePayloadVersion,\n} from '../utils/project.js'\nimport { loginCommand } from './login.js'\n\n/**\n * Options for init command\n */\nexport interface InitCommandOptions {\n /** Enable debug mode */\n debug?: boolean\n /** Force reconfiguration of existing project */\n force?: boolean\n /** Tenant ID to use (optional - will prompt if not provided) */\n id?: string\n /** Project name (for scaffolding) */\n name?: string\n /** Disable Content System (defaults to enabled) */\n noContentSystem?: boolean\n /** AWS region for deployment (defaults to us-east-1) */\n region?: string\n /** Skip authentication check (for testing/development) */\n skipAuth?: boolean\n /** Skip prompts and use defaults where possible */\n yes?: boolean\n}\n\n/**\n * Generate and store project token for a tenant\n * Non-blocking - will show warning but not exit on failure\n * Only shows feedback if DEBUG mode is enabled, otherwise runs silently\n *\n * @param tokenStore - Token store instance\n * @param tenantId - Tenant ID to generate token for\n * @param spinner - Clack spinner instance for status updates (only used in debug mode)\n */\nasync function generateProjectTokenWithFeedback(\n tokenStore: TokenStore,\n tenantId: string,\n spinner: ReturnType<typeof p.spinner>,\n): Promise<void> {\n if (isDebug()) {\n spinner.start('Generating project token...')\n }\n\n try {\n const projectToken = await getValidProjectToken(tokenStore, tenantId)\n if (isDebug()) {\n if (projectToken) {\n spinner.stop(pc.green('✓ Project token generated'))\n } else {\n spinner.stop(pc.yellow('⚠ Project token not generated (authentication required)'))\n }\n }\n } catch (error) {\n if (isDebug()) {\n spinner.stop(pc.yellow('⚠ Project token generation failed'))\n }\n // Always show failures, even without debug\n if (error instanceof ProjectTokenError || error instanceof FigmaApiError) {\n log.warning(error.message)\n p.note(\n 'Project token is used for authenticating to the Content API.\\nYou can continue without it, but may need to regenerate later.',\n 'Note',\n )\n } else {\n log.warning(\n `Unable to retrieve project token: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n // Don't exit - token generation failure shouldn't block initialization\n }\n}\n\n/**\n * Handle the `init` command\n *\n * Sets up a project by:\n * 1. Checking authentication\n * 2. Detecting/scaffolding Payload project\n * 3. Fetching tenant details\n * 4. Storing configuration\n *\n * @param options - Command options\n */\nexport async function initCommand(options: InitCommandOptions): Promise<void> {\n // Check authentication\n const tokenStore = new TokenStore()\n const s = p.spinner()\n\n let accessToken: string\n\n if (options.skipAuth) {\n // Skip authentication for testing/development\n p.log.warn(pc.yellow('Skipping authentication (--skip-auth mode)'))\n accessToken = 'mock-access-token'\n } else {\n try {\n // Check for valid cached tokens first (no API call needed)\n if (tokenStore.hasValidTokens()) {\n // Use cached token silently - no spinner needed\n accessToken = tokenStore.getAccessToken()!\n } else {\n // Need to refresh or authenticate - show spinner for API call\n s.start('Checking authentication...')\n const token = await getValidAccessToken(tokenStore)\n if (!token) {\n s.stop(pc.yellow('⚠ Not authenticated'))\n p.log.info('Authentication required to continue')\n\n // Prompt user to authenticate now\n const shouldAuth = await p.confirm({\n initialValue: true,\n message: 'Would you like to authenticate now?',\n })\n\n if (p.isCancel(shouldAuth) || !shouldAuth) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n // Run login command\n await loginCommand()\n\n // Get token after auth\n const newToken = await getValidAccessToken(tokenStore)\n if (!newToken) {\n p.log.error('Authentication failed')\n process.exit(1)\n }\n accessToken = newToken\n p.log.success(pc.green('✓ Authenticated'))\n } else {\n accessToken = token\n s.stop(pc.green('✓ Authenticated'))\n }\n }\n } catch (error) {\n s.stop(pc.red('✗ Authentication failed'))\n log.error(error instanceof Error ? error.message : 'Unknown error')\n p.note('Run `figma auth` to authenticate', 'Tip')\n process.exit(1)\n }\n }\n\n // Note: We no longer check for figma.config.json here\n // Instead, the AST detection will check if figma object already exists in payload.config.ts\n // and skip modification if it does (unless --force is used)\n\n // Step 3: Get CMS ID with retry loop\n log.debug('Configuring Project...')\n\n let tenantId = options.id\n let selectedTenant: Tenant | undefined\n\n while (!selectedTenant) {\n // Prompt for ID if not provided\n if (!tenantId) {\n const input = await p.text({\n message: 'Enter your CMS ID:',\n placeholder: 'tenant_abc123',\n validate: (value) => {\n if (!value || typeof value !== 'string') {\n return 'CMS ID is required'\n }\n return undefined\n },\n })\n\n if (p.isCancel(input)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n tenantId = input\n }\n\n // Try to fetch tenant details\n try {\n log.debug('Using mock Control Plane API (no real network calls)')\n selectedTenant = await getTenantDetails(accessToken, tenantId)\n log.debug(`Using: ${selectedTenant.domain}`)\n } catch (error) {\n p.log.error(pc.red('✗ Failed to fetch CMS details'))\n\n // Check if permission error (403)\n if (error instanceof ControlPlaneError && error.statusCode === 403) {\n p.log.error('You do not have permission to access the provided CMS ID. Please try again.')\n } else if (error instanceof ControlPlaneError && error.statusCode === 404) {\n p.log.error('Tenant ID not found. Verify the ID is correct.')\n } else {\n p.log.error(error instanceof Error ? error.message : 'Unknown error')\n }\n\n // Clear tenantId to prompt again\n tenantId = undefined\n\n // Ask if they want to retry\n const shouldRetry = await p.confirm({\n initialValue: true,\n message: 'Would you like to try a different CMS ID?',\n })\n\n if (p.isCancel(shouldRetry) || !shouldRetry) {\n p.cancel('Operation cancelled')\n process.exit(1)\n }\n }\n }\n\n // Step 4: Detect or scaffold Payload project\n const isInProject = await isInProjectDirectory()\n\n if (isInProject) {\n // ===== EXISTING PROJECT FLOW =====\n log.debug('Project directory detected')\n\n // Detect Payload\n const projectInfo = await detectPayloadProject()\n\n if (projectInfo.hasPayload) {\n // Validate existing Payload version\n if (projectInfo.payloadVersion && !validatePayloadVersion(projectInfo.payloadVersion)) {\n p.log.warn(\n pc.yellow(\n `Payload version ${projectInfo.payloadVersion} detected. Version 3.x is required.`,\n ),\n )\n p.note('Upgrade to Payload 3.x before continuing', 'Action Required')\n process.exit(1)\n }\n\n p.log.success(pc.green(`✓ Payload ${projectInfo.payloadVersion || 'detected'}`))\n\n // Check dependencies\n s.start('Checking dependencies...')\n const hasDeps = await hasRequiredDependencies(process.cwd())\n s.stop(pc.green('✓ Dependencies checked'))\n\n if (!hasDeps) {\n const shouldInstall = await p.confirm({\n initialValue: true,\n message: 'Install dependencies now?',\n })\n\n if (!p.isCancel(shouldInstall) && shouldInstall) {\n s.start('Installing dependencies...')\n await installDependencies(process.cwd(), projectInfo.packageManager || 'pnpm')\n s.stop(pc.green('✓ Dependencies installed'))\n }\n }\n\n s.start('Checking Payload configuration...')\n const modResult = await ensurePayloadFigmaConfig(\n process.cwd(),\n projectInfo.packageManager || 'pnpm',\n {\n contentSystemId: selectedTenant.id,\n region: options.region || 'us-east-1',\n useContentSystem: !options.noContentSystem,\n },\n )\n\n if (!modResult.success) {\n s.stop(pc.red('✗ Configuration check failed'))\n displayManualInstructions(modResult.error || 'Unknown error')\n process.exit(1)\n }\n\n if (modResult.modified) {\n s.stop(pc.green('✓ Payload configuration updated'))\n if (modResult.changes.length > 0) {\n modResult.changes.forEach((change) => log.debug(pc.dim(` → ${change}`)))\n }\n } else {\n s.stop(pc.green('✓ Payload configuration valid'))\n }\n\n // Display warnings if any\n if (modResult.warnings && modResult.warnings.length > 0) {\n modResult.warnings.forEach((warning) => {\n p.log.warn(pc.yellow(`⚠ ${warning}`))\n })\n }\n } else {\n // Has package.json but no Payload - offer to add Payload\n p.log.warn(pc.yellow('⚠ No Payload detected in this project'))\n\n const shouldAddPayload = await p.confirm({\n initialValue: true,\n message: 'Would you like to add Payload to this project?',\n })\n\n if (p.isCancel(shouldAddPayload)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n if (!shouldAddPayload) {\n p.log.error('Payload is required to use Figma CMS')\n process.exit(1)\n }\n\n // TODO: Add Payload to existing project (future enhancement)\n p.log.error('Adding Payload to existing projects is not yet supported')\n p.note('Create a new project or manually add Payload dependencies', 'Action Required')\n process.exit(1)\n }\n\n // Generate project token (unless skipping auth)\n if (!options.skipAuth) {\n await generateProjectTokenWithFeedback(tokenStore, selectedTenant.id, s)\n }\n\n // Success message for existing project\n p.outro(pc.green('✓ Project initialized successfully!'))\n\n const nextSteps = [\n selectedTenant.status === 'provisioning'\n ? 'Wait for CMS provisioning to complete (check status with `@payloadcms/figma list`)'\n : undefined,\n 'Start development server: `pnpm dev`',\n `Access your CMS at: ${pc.cyan(`https://${selectedTenant.domain}`)}`,\n ].filter(Boolean)\n\n p.note(nextSteps.join('\\n'), 'Next Steps')\n } else {\n // ===== NEW PROJECT FLOW =====\n // p.log.info('No project detected - Creating New Project')\n\n // Prompt for path\n const projectPathInput = await p.text({\n initialValue: './',\n message: 'Enter path to create project:',\n placeholder: './my-cms-project',\n validate: (value) => {\n if (!value) {\n return 'Path is required'\n }\n // Allow relative or absolute paths\n return undefined\n },\n })\n\n if (p.isCancel(projectPathInput)) {\n p.cancel('Operation cancelled')\n process.exit(0)\n }\n\n const projectPath = projectPathInput\n const fullPath = path.resolve(process.cwd(), projectPath)\n\n // Get project name from path or prompt\n const projectName = options.name || path.basename(fullPath)\n\n // Create directory\n try {\n await fs.mkdir(fullPath, { recursive: true })\n } catch (error) {\n p.log.error(\n `Failed to create directory: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n process.exit(1)\n }\n\n // Scaffold project\n s.start('Downloading template from GitHub...')\n try {\n await scaffoldProject(fullPath, projectName)\n s.stop(pc.green('✓ Template downloaded'))\n\n s.start('Installing dependencies...')\n await installDependencies(fullPath, 'pnpm')\n s.stop(pc.green('✓ Dependencies installed'))\n } catch (error) {\n s.stop(pc.red('✗ Failed'))\n log.error(error instanceof Error ? error.message : 'Unknown error')\n process.exit(1)\n }\n\n // Modify Payload configuration\n s.start('Checking Payload configuration...')\n const modResult = await ensurePayloadFigmaConfig(fullPath, 'pnpm', {\n contentSystemId: selectedTenant.id,\n region: options.region || 'us-east-1',\n useContentSystem: !options.noContentSystem,\n })\n\n if (!modResult.success) {\n s.stop(pc.red('✗ Configuration check failed'))\n displayManualInstructions(modResult.error || 'Unknown error')\n process.exit(1)\n }\n\n if (modResult.modified) {\n s.stop(pc.green('✓ Payload configuration updated'))\n if (modResult.changes.length > 0) {\n modResult.changes.forEach((change) => log.debug(pc.dim(` → ${change}`)))\n }\n } else {\n s.stop(pc.green('✓ Payload configuration valid'))\n }\n\n // Display warnings if any\n if (modResult.warnings && modResult.warnings.length > 0) {\n modResult.warnings.forEach((warning) => {\n p.log.warn(pc.yellow(`⚠ ${warning}`))\n })\n }\n\n // Generate project token (unless skipping auth)\n if (!options.skipAuth) {\n await generateProjectTokenWithFeedback(tokenStore, selectedTenant.id, s)\n }\n\n // Initialize git repository (after all files including lock file are ready)\n initializeGitRepo(fullPath)\n\n // Success message for NEW project\n p.log.step(pc.bgGreen(pc.black(' Project created successfully! ')))\n\n const relativePath = path.relative(process.cwd(), fullPath)\n const nextSteps: string[] = []\n\n // Only show cd command if user needs to navigate\n if (relativePath && relativePath !== '.') {\n nextSteps.push(`cd ${relativePath}`)\n }\n\n nextSteps.push(\n 'pnpm dev or follow directions in README.md',\n '',\n 'Documentation:',\n '- Getting Started: https://payloadcms.com/docs/getting-started/what-is-payload',\n '- Configuration: https://payloadcms.com/docs/configuration/overview',\n )\n\n p.note(nextSteps.join('\\n'), 'Next Steps')\n p.outro(pc.green('✓ Done'))\n }\n}\n"],"names":["p","fs","path","pc","ControlPlaneError","getTenantDetails","FigmaApiError","getValidAccessToken","getValidProjectToken","ProjectTokenError","TokenStore","isDebug","log","displayManualInstructions","ensurePayloadFigmaConfig","detectPayloadProject","hasRequiredDependencies","initializeGitRepo","installDependencies","isInProjectDirectory","scaffoldProject","validatePayloadVersion","loginCommand","generateProjectTokenWithFeedback","tokenStore","tenantId","spinner","start","projectToken","stop","green","yellow","error","warning","message","note","Error","initCommand","options","s","accessToken","skipAuth","warn","hasValidTokens","getAccessToken","token","info","shouldAuth","confirm","initialValue","isCancel","cancel","process","exit","newToken","success","red","debug","id","selectedTenant","input","text","placeholder","validate","value","undefined","domain","statusCode","shouldRetry","isInProject","projectInfo","hasPayload","payloadVersion","hasDeps","cwd","shouldInstall","packageManager","modResult","contentSystemId","region","useContentSystem","noContentSystem","modified","changes","length","forEach","change","dim","warnings","shouldAddPayload","outro","nextSteps","status","cyan","filter","Boolean","join","projectPathInput","projectPath","fullPath","resolve","projectName","name","basename","mkdir","recursive","step","bgGreen","black","relativePath","relative","push"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/config/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAInD,eAAO,MAAM,IAAI,EAAE,MAAM,CACvB,MAAM,GAAG,SAAS,EAClB,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/config/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAInD,eAAO,MAAM,IAAI,EAAE,MAAM,CACvB,MAAM,GAAG,SAAS,EAClB,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC,CAkBlE,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,WAe1B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAA"}
|
package/dist/config/oauth.js
CHANGED
|
@@ -6,9 +6,9 @@ export const URLS = {
|
|
|
6
6
|
tokenUrl: 'https://api.figma.com/v1/oauth/token'
|
|
7
7
|
},
|
|
8
8
|
staging: {
|
|
9
|
-
authorizationUrl: 'https://staging.figma.com/oauth',
|
|
10
|
-
refreshUrl: 'https://api.staging.figma.com/v1/oauth/refresh',
|
|
11
|
-
tokenUrl: 'https://api.staging.figma.com/v1/oauth/token'
|
|
9
|
+
authorizationUrl: process.env.FIGMA_AUTH_URL ? `${process.env.FIGMA_AUTH_URL}/oauth` : 'https://staging.figma.com/oauth',
|
|
10
|
+
refreshUrl: process.env.FIGMA_API_URL ? `${process.env.FIGMA_API_URL}/v1/oauth/refresh` : 'https://api.staging.figma.com/v1/oauth/refresh',
|
|
11
|
+
tokenUrl: process.env.FIGMA_API_URL ? `${process.env.FIGMA_API_URL}/v1/oauth/token` : 'https://api.staging.figma.com/v1/oauth/token'
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
/**
|
package/dist/config/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/oauth.ts"],"sourcesContent":["import type { OAuthConfig } from '../auth/types.js'\n\nimport { FIGMA_CLIENT_IDS } from '../constants.js'\n\nexport const URLS: Record<\n 'prod' | 'staging',\n Pick<OAuthConfig, 'authorizationUrl' | 'refreshUrl' | 'tokenUrl'>\n> = {\n prod: {\n authorizationUrl: 'https://www.figma.com/oauth',\n refreshUrl: 'https://api.figma.com/v1/oauth/refresh',\n tokenUrl: 'https://api.figma.com/v1/oauth/token',\n },\n staging: {\n authorizationUrl: 'https://staging.figma.com/oauth',\n refreshUrl: 'https://api.staging.figma.com/v1/oauth/refresh',\n tokenUrl: 'https://api.staging.figma.com/v1/oauth/token',\n },\n}\n\n/**\n * Figma OAuth2 configuration for public CLI client\n *\n * This is a PUBLIC OAuth client using PKCE (Proof Key for Code Exchange).\n * No client secret is used because CLIs cannot securely store secrets.\n * PKCE provides security through the code_verifier/code_challenge mechanism.\n *\n * For production use, register a public OAuth app with Figma.\n * To register an OAuth app, visit: https://www.figma.com/developers/api#oauth2\n */\nexport const OAUTH_CONFIG: OAuthConfig = {\n // OAuth client ID (public client)\n // Uses staging client ID by default since we use staging endpoints\n clientId: process.env.FIGMA_CLIENT_ID || FIGMA_CLIENT_IDS.staging,\n\n // No client secret - this is a public OAuth client using PKCE\n // Public clients cannot securely store secrets in CLI environments\n\n redirectUri: process.env.FIGMA_REDIRECT_URI || 'http://localhost:3000/callback',\n\n // Only current_user:read scope is needed for basic user info\n scopes: ['current_user:read'],\n\n // TODO: Dynamically choose between prod and staging based on environment\n ...URLS.staging,\n}\n\n/**\n * Buffer time (in seconds) before token expiration to consider token as expired\n * This helps avoid using tokens that are about to expire\n */\nexport const TOKEN_EXPIRY_BUFFER_SECONDS = 300 // 5 minutes\n"],"names":["FIGMA_CLIENT_IDS","URLS","prod","authorizationUrl","refreshUrl","tokenUrl","staging","
|
|
1
|
+
{"version":3,"sources":["../../src/config/oauth.ts"],"sourcesContent":["import type { OAuthConfig } from '../auth/types.js'\n\nimport { FIGMA_CLIENT_IDS } from '../constants.js'\n\nexport const URLS: Record<\n 'prod' | 'staging',\n Pick<OAuthConfig, 'authorizationUrl' | 'refreshUrl' | 'tokenUrl'>\n> = {\n prod: {\n authorizationUrl: 'https://www.figma.com/oauth',\n refreshUrl: 'https://api.figma.com/v1/oauth/refresh',\n tokenUrl: 'https://api.figma.com/v1/oauth/token',\n },\n staging: {\n authorizationUrl: process.env.FIGMA_AUTH_URL\n ? `${process.env.FIGMA_AUTH_URL}/oauth`\n : 'https://staging.figma.com/oauth',\n refreshUrl: process.env.FIGMA_API_URL\n ? `${process.env.FIGMA_API_URL}/v1/oauth/refresh`\n : 'https://api.staging.figma.com/v1/oauth/refresh',\n tokenUrl: process.env.FIGMA_API_URL\n ? `${process.env.FIGMA_API_URL}/v1/oauth/token`\n : 'https://api.staging.figma.com/v1/oauth/token',\n },\n}\n\n/**\n * Figma OAuth2 configuration for public CLI client\n *\n * This is a PUBLIC OAuth client using PKCE (Proof Key for Code Exchange).\n * No client secret is used because CLIs cannot securely store secrets.\n * PKCE provides security through the code_verifier/code_challenge mechanism.\n *\n * For production use, register a public OAuth app with Figma.\n * To register an OAuth app, visit: https://www.figma.com/developers/api#oauth2\n */\nexport const OAUTH_CONFIG: OAuthConfig = {\n // OAuth client ID (public client)\n // Uses staging client ID by default since we use staging endpoints\n clientId: process.env.FIGMA_CLIENT_ID || FIGMA_CLIENT_IDS.staging,\n\n // No client secret - this is a public OAuth client using PKCE\n // Public clients cannot securely store secrets in CLI environments\n\n redirectUri: process.env.FIGMA_REDIRECT_URI || 'http://localhost:3000/callback',\n\n // Only current_user:read scope is needed for basic user info\n scopes: ['current_user:read'],\n\n // TODO: Dynamically choose between prod and staging based on environment\n ...URLS.staging,\n}\n\n/**\n * Buffer time (in seconds) before token expiration to consider token as expired\n * This helps avoid using tokens that are about to expire\n */\nexport const TOKEN_EXPIRY_BUFFER_SECONDS = 300 // 5 minutes\n"],"names":["FIGMA_CLIENT_IDS","URLS","prod","authorizationUrl","refreshUrl","tokenUrl","staging","process","env","FIGMA_AUTH_URL","FIGMA_API_URL","OAUTH_CONFIG","clientId","FIGMA_CLIENT_ID","redirectUri","FIGMA_REDIRECT_URI","scopes","TOKEN_EXPIRY_BUFFER_SECONDS"],"mappings":"AAEA,SAASA,gBAAgB,QAAQ,kBAAiB;AAElD,OAAO,MAAMC,OAGT;IACFC,MAAM;QACJC,kBAAkB;QAClBC,YAAY;QACZC,UAAU;IACZ;IACAC,SAAS;QACPH,kBAAkBI,QAAQC,GAAG,CAACC,cAAc,GACxC,GAAGF,QAAQC,GAAG,CAACC,cAAc,CAAC,MAAM,CAAC,GACrC;QACJL,YAAYG,QAAQC,GAAG,CAACE,aAAa,GACjC,GAAGH,QAAQC,GAAG,CAACE,aAAa,CAAC,iBAAiB,CAAC,GAC/C;QACJL,UAAUE,QAAQC,GAAG,CAACE,aAAa,GAC/B,GAAGH,QAAQC,GAAG,CAACE,aAAa,CAAC,eAAe,CAAC,GAC7C;IACN;AACF,EAAC;AAED;;;;;;;;;CASC,GACD,OAAO,MAAMC,eAA4B;IACvC,kCAAkC;IAClC,mEAAmE;IACnEC,UAAUL,QAAQC,GAAG,CAACK,eAAe,IAAIb,iBAAiBM,OAAO;IAEjE,8DAA8D;IAC9D,mEAAmE;IAEnEQ,aAAaP,QAAQC,GAAG,CAACO,kBAAkB,IAAI;IAE/C,6DAA6D;IAC7DC,QAAQ;QAAC;KAAoB;IAE7B,yEAAyE;IACzE,GAAGf,KAAKK,OAAO;AACjB,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMW,8BAA8B,IAAI,YAAY;CAAb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useConfig } from '@payloadcms/ui'\nimport { useSearchParams } from 'next/navigation.js'\nimport React, { useEffect, useState } from 'react'\n\nimport './index.scss'\n\nconst baseClass = 'oauth-login'\n\ntype DefaultLoginButtonProps = {\n disabled?: boolean\n endpointSlug: string\n}\n\nexport const DefaultLoginButton: React.FC<DefaultLoginButtonProps> = ({\n disabled,\n endpointSlug,\n}: {\n disabled?: boolean\n endpointSlug: string\n}) => {\n const {\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n const [authorizeURL, setAuthorizeURL] = useState('')\n\n const searchParams = useSearchParams()\n const payloadRedirect = searchParams.get('redirect')\n\n useEffect(() => {\n if (payloadRedirect && !disabled) {\n // set cookie to redirect to the original page\n document.cookie = `payloadRedirect=${payloadRedirect}; path=/`\n }\n }, [payloadRedirect, disabled])\n\n useEffect(() => {\n const getAuthorizeURL = async () => {\n const serverURLFromWindow = window.location.origin\n const data = await fetch(\n `${serverURL}${api}/${userSlug}/${endpointSlug}/meta?serverURL=${serverURLFromWindow}`,\n ).then((res) => res.json())\n\n if (!disabled) {\n setAuthorizeURL(data.authorizeURL)\n }\n }\n\n void getAuthorizeURL()\n }, [api, serverURL, userSlug, disabled, endpointSlug])\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={baseClass}>\n <Button className={`${baseClass}__btn`} el=\"anchor\" url={authorizeURL}>\n Log in\n </Button>\n </div>\n )\n}\n"],"names":["Button","useConfig","useSearchParams","React","useEffect","useState","baseClass","DefaultLoginButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","authorizeURL","setAuthorizeURL","searchParams","payloadRedirect","get","document","cookie","getAuthorizeURL","serverURLFromWindow","window","location","origin","data","fetch","then","res","json","div","className","el","url"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,SAAS,QAAQ,iBAAgB;AAClD,SAASC,eAAe,QAAQ,qBAAoB;AACpD,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAElD,OAAO,eAAc;AAErB,MAAMC,YAAY;AAOlB,OAAO,MAAMC,qBAAwD,CAAC,EACpEC,QAAQ,EACRC,YAAY,EAIb;IACC,MAAM,EACJC,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGf;IACJ,MAAM,CAACgB,cAAcC,gBAAgB,GAAGb,SAAS;IAEjD,MAAMc,eAAejB;IACrB,MAAMkB,kBAAkBD,aAAaE,GAAG,CAAC;IAEzCjB,UAAU;QACR,IAAIgB,mBAAmB,CAACZ,UAAU;YAChC,8CAA8C;YAC9Cc,SAASC,MAAM,GAAG,CAAC,gBAAgB,EAAEH,gBAAgB,QAAQ,CAAC;QAChE;IACF,GAAG;QAACA;QAAiBZ;KAAS;IAE9BJ,UAAU;QACR,MAAMoB,kBAAkB;YACtB,MAAMC,sBAAsBC,OAAOC,QAAQ,CAACC,MAAM;YAClD,MAAMC,OAAO,MAAMC,MACjB,GAAGd,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,gBAAgB,EAAEgB,qBAAqB,EACtFM,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI;YAExB,IAAI,CAACzB,UAAU;gBACbU,gBAAgBW,KAAKZ,YAAY;YACnC;QACF;QAEA,KAAKO;IACP,GAAG;QAACT;QAAKC;QAAWH;QAAUL;QAAUC;KAAa;IAErD,IAAID,UAAU;QACZ,OAAO;IACT;IAEA,qBACE,KAAC0B;QAAIC,WAAW7B;kBACd,cAAA,KAACN;YAAOmC,WAAW,GAAG7B,UAAU,KAAK,CAAC;YAAE8B,IAAG;YAASC,KAAKpB;sBAAc;;;AAK7E,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useConfig } from '@payloadcms/ui'\nimport { useSearchParams } from 'next/navigation.js'\nimport React, { useEffect, useState } from 'react'\n\nimport './index.scss'\n\nconst baseClass = 'oauth-login'\n\ntype DefaultLoginButtonProps = {\n disabled?: boolean\n endpointSlug: string\n}\n\nexport const DefaultLoginButton: React.FC<DefaultLoginButtonProps> = ({\n disabled,\n endpointSlug,\n}: {\n disabled?: boolean\n endpointSlug: string\n}) => {\n const {\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n const [authorizeURL, setAuthorizeURL] = useState('')\n\n const searchParams = useSearchParams()\n const payloadRedirect = searchParams.get('redirect')\n\n useEffect(() => {\n if (payloadRedirect && !disabled) {\n // set cookie to redirect to the original page\n document.cookie = `payloadRedirect=${payloadRedirect}; path=/`\n }\n }, [payloadRedirect, disabled])\n\n useEffect(() => {\n const getAuthorizeURL = async () => {\n const serverURLFromWindow = window.location.origin\n const data = await fetch(\n `${serverURL}${api}/${userSlug}/${endpointSlug}/meta?serverURL=${serverURLFromWindow}`,\n ).then((res) => res.json())\n\n if (!disabled) {\n setAuthorizeURL(data.authorizeURL)\n }\n }\n\n void getAuthorizeURL()\n }, [api, serverURL, userSlug, disabled, endpointSlug])\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={baseClass}>\n <Button className={`${baseClass}__btn`} el=\"anchor\" url={authorizeURL}>\n Log in with Figma\n </Button>\n </div>\n )\n}\n"],"names":["Button","useConfig","useSearchParams","React","useEffect","useState","baseClass","DefaultLoginButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","authorizeURL","setAuthorizeURL","searchParams","payloadRedirect","get","document","cookie","getAuthorizeURL","serverURLFromWindow","window","location","origin","data","fetch","then","res","json","div","className","el","url"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,SAAS,QAAQ,iBAAgB;AAClD,SAASC,eAAe,QAAQ,qBAAoB;AACpD,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAElD,OAAO,eAAc;AAErB,MAAMC,YAAY;AAOlB,OAAO,MAAMC,qBAAwD,CAAC,EACpEC,QAAQ,EACRC,YAAY,EAIb;IACC,MAAM,EACJC,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGf;IACJ,MAAM,CAACgB,cAAcC,gBAAgB,GAAGb,SAAS;IAEjD,MAAMc,eAAejB;IACrB,MAAMkB,kBAAkBD,aAAaE,GAAG,CAAC;IAEzCjB,UAAU;QACR,IAAIgB,mBAAmB,CAACZ,UAAU;YAChC,8CAA8C;YAC9Cc,SAASC,MAAM,GAAG,CAAC,gBAAgB,EAAEH,gBAAgB,QAAQ,CAAC;QAChE;IACF,GAAG;QAACA;QAAiBZ;KAAS;IAE9BJ,UAAU;QACR,MAAMoB,kBAAkB;YACtB,MAAMC,sBAAsBC,OAAOC,QAAQ,CAACC,MAAM;YAClD,MAAMC,OAAO,MAAMC,MACjB,GAAGd,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,gBAAgB,EAAEgB,qBAAqB,EACtFM,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI;YAExB,IAAI,CAACzB,UAAU;gBACbU,gBAAgBW,KAAKZ,YAAY;YACnC;QACF;QAEA,KAAKO;IACP,GAAG;QAACT;QAAKC;QAAWH;QAAUL;QAAUC;KAAa;IAErD,IAAID,UAAU;QACZ,OAAO;IACT;IAEA,qBACE,KAAC0B;QAAIC,WAAW7B;kBACd,cAAA,KAACN;YAAOmC,WAAW,GAAG7B,UAAU,KAAK,CAAC;YAAE8B,IAAG;YAASC,KAAKpB;sBAAc;;;AAK7E,EAAC"}
|
|
@@ -29,8 +29,8 @@ export type ASTModificationResult = {
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function applyModifications(sourceFile: SourceFile, detection: DetectionResult): ASTModificationResult;
|
|
31
31
|
export type FigmaPropertyConfig = {
|
|
32
|
+
contentSystemId: string;
|
|
32
33
|
region: string;
|
|
33
|
-
tenantId: string;
|
|
34
34
|
useContentSystem: boolean;
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-config-ast.d.ts","sourceRoot":"","sources":["../../src/utils/payload-config-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,CAAC,EAAE;QACX,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,cAAc,CAAC,EAAE;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,SAAS,EAAE,OAAO,CAAA;KACnB,CAAA;IACD,iBAAiB,EAAE,OAAO,CAAA;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CAiJ7E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA;AA0CD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,eAAe,GACzB,qBAAqB,CAyJvB;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,
|
|
1
|
+
{"version":3,"file":"payload-config-ast.d.ts","sourceRoot":"","sources":["../../src/utils/payload-config-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAM1C,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,CAAC,EAAE;QACX,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,cAAc,CAAC,EAAE;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,SAAS,EAAE,OAAO,CAAA;KACnB,CAAA;IACD,iBAAiB,EAAE,OAAO,CAAA;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAG,eAAe,CAiJ7E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA;AA0CD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,eAAe,GACzB,qBAAqB,CAyJvB;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,mBAAmB,GAC1B,qBAAqB,CA+CvB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,mBAAmB,GAAG,IAAI,CAoElF"}
|
|
@@ -340,11 +340,11 @@ import * as log from './log.js';
|
|
|
340
340
|
name: 'figma',
|
|
341
341
|
initializer: `{
|
|
342
342
|
region: '${config.region}',
|
|
343
|
-
|
|
343
|
+
contentSystemId: '${config.contentSystemId}',
|
|
344
344
|
useContentSystem: ${config.useContentSystem},
|
|
345
345
|
}`
|
|
346
346
|
});
|
|
347
|
-
changes.push(`Added figma property (region: ${config.region}, tenantId: ${config.
|
|
347
|
+
changes.push(`Added figma property (region: ${config.region}, tenantId: ${config.contentSystemId}, useContentSystem: ${config.useContentSystem})`);
|
|
348
348
|
modified = true;
|
|
349
349
|
return {
|
|
350
350
|
changes,
|
|
@@ -386,24 +386,24 @@ import * as log from './log.js';
|
|
|
386
386
|
}
|
|
387
387
|
// Extract values
|
|
388
388
|
const regionProp = initializer.getProperty('region');
|
|
389
|
-
const
|
|
389
|
+
const contentSystemIdProp = initializer.getProperty('contentSystemId');
|
|
390
390
|
const useContentSystemProp = initializer.getProperty('useContentSystem');
|
|
391
|
-
if (!regionProp || !
|
|
391
|
+
if (!regionProp || !contentSystemIdProp) {
|
|
392
392
|
log.debug('Missing required figma properties (region or tenantId)');
|
|
393
393
|
return null;
|
|
394
394
|
}
|
|
395
395
|
// Extract string values (remove quotes)
|
|
396
396
|
const region = Node.isPropertyAssignment(regionProp) ? regionProp.getInitializer()?.getText().replace(/['"]/g, '') : undefined;
|
|
397
|
-
const
|
|
397
|
+
const contentSystemId = Node.isPropertyAssignment(contentSystemIdProp) ? contentSystemIdProp.getInitializer()?.getText().replace(/['"]/g, '') : undefined;
|
|
398
398
|
const useContentSystem = Node.isPropertyAssignment(useContentSystemProp) ? useContentSystemProp.getInitializer()?.getText() === 'true' : true // Default to true if not specified
|
|
399
399
|
;
|
|
400
|
-
if (!region || !
|
|
400
|
+
if (!region || !contentSystemId) {
|
|
401
401
|
log.debug('Could not extract region or tenantId values');
|
|
402
402
|
return null;
|
|
403
403
|
}
|
|
404
404
|
return {
|
|
405
|
+
contentSystemId,
|
|
405
406
|
region,
|
|
406
|
-
tenantId,
|
|
407
407
|
useContentSystem
|
|
408
408
|
};
|
|
409
409
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/payload-config-ast.ts"],"sourcesContent":["import type { SourceFile } from 'ts-morph'\n\nimport { Node, SyntaxKind } from 'ts-morph'\n\nimport * as log from './log.js'\n\nexport type DetectionResult = {\n dbProperty?: {\n adapter: string\n importSource: string\n }\n editorProperty?: {\n importSource: string\n isDefault: boolean\n }\n figmaObjectExists: boolean\n hasAlias: boolean\n hasBuildConfig?: boolean\n hasOtherPayloadImports: boolean\n needsImportChange: boolean\n secretProperty?: boolean\n}\n\n/**\n * Detect what changes are needed in the payload config file\n */\nexport function detectRequiredChanges(sourceFile: SourceFile): DetectionResult {\n const result: DetectionResult = {\n figmaObjectExists: false,\n hasAlias: false,\n hasOtherPayloadImports: false,\n needsImportChange: false,\n }\n\n // Find buildConfig import\n const imports = sourceFile.getImportDeclarations()\n const payloadImport = imports.find(\n (imp) =>\n imp.getModuleSpecifierValue() === 'payload' ||\n imp.getModuleSpecifierValue() === '@payloadcms/figma',\n )\n\n if (!payloadImport) {\n log.debug('No payload or @payloadcms/figma import found')\n result.hasBuildConfig = false\n return result\n }\n\n log.debug(`Found import from: ${payloadImport.getModuleSpecifierValue()}`)\n\n const moduleSpecifier = payloadImport.getModuleSpecifierValue()\n const namedImports = payloadImport.getNamedImports()\n\n // Check if buildConfig is imported\n const buildConfigImport = namedImports.find((ni) => ni.getName() === 'buildConfig')\n\n if (!buildConfigImport) {\n result.hasBuildConfig = false\n return result\n }\n\n // Check for alias and get the actual name used in code\n const aliasNode = buildConfigImport.getAliasNode()\n const buildConfigName = aliasNode ? aliasNode.getText() : 'buildConfig'\n if (aliasNode) {\n result.hasAlias = true\n }\n\n // Check if import needs change\n if (moduleSpecifier === 'payload') {\n result.needsImportChange = true\n\n // Check if there are other imports from payload\n if (namedImports.length > 1) {\n result.hasOtherPayloadImports = true\n }\n }\n\n // Find buildConfig call in export default\n // First try to find export default with the buildConfig call\n const exportAssignment = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment)\n let buildConfigCall = null\n\n if (exportAssignment) {\n // Look for buildConfig call in the export default\n const callExpressions = exportAssignment.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n // If not found in export default, search all call expressions\n if (!buildConfigCall) {\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n if (!buildConfigCall) {\n result.hasBuildConfig = false\n return result\n }\n\n // Get config object\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n return result\n }\n\n // Check for db property\n const dbProperty = configArg.getProperty('db')\n if (dbProperty) {\n const dbValue = dbProperty.getChildrenOfKind(SyntaxKind.CallExpression)[0]\n if (dbValue) {\n const adapterName = dbValue.getExpression().getText()\n\n // Find the import source for this adapter\n const adapterImport = imports.find((imp) =>\n imp.getNamedImports().some((ni) => ni.getName() === adapterName),\n )\n\n if (adapterImport) {\n result.dbProperty = {\n adapter: adapterName,\n importSource: adapterImport.getModuleSpecifierValue(),\n }\n }\n }\n }\n\n // Check for secret property\n const secretProperty = configArg.getProperty('secret')\n if (secretProperty) {\n result.secretProperty = true\n }\n\n // Check for editor property\n const editorProperty = configArg.getProperty('editor')\n if (editorProperty) {\n const editorValue = editorProperty.getChildrenOfKind(SyntaxKind.CallExpression)[0]\n if (editorValue) {\n const editorName = editorValue.getExpression().getText()\n\n // Find the import source\n const editorImport = imports.find((imp) =>\n imp.getNamedImports().some((ni) => ni.getName() === editorName),\n )\n\n if (editorImport && editorName === 'lexicalEditor') {\n // Check if it has arguments\n const args = editorValue.getArguments()\n const isDefault = args.length === 0\n\n result.editorProperty = {\n importSource: editorImport.getModuleSpecifierValue(),\n isDefault,\n }\n }\n }\n }\n\n // Check for figma property\n const figmaProperty = configArg.getProperty('figma')\n if (figmaProperty) {\n result.figmaObjectExists = true\n }\n\n return result\n}\n\nexport type ASTModificationResult = {\n changes: string[]\n modified: boolean\n}\n\n/**\n * Remove all comments\n * @returns true if any comments were removed\n */\nfunction removeAllComments(sourceFile: SourceFile): boolean {\n const ranges: Array<[number, number]> = []\n\n // Recursively collect comments from node and ALL children (including tokens)\n const collectComments = (node: Node) => {\n node.getLeadingCommentRanges().forEach((range) => {\n ranges.push([range.getPos(), range.getEnd()])\n })\n node.getTrailingCommentRanges().forEach((range) => {\n ranges.push([range.getPos(), range.getEnd()])\n })\n\n // Process ALL children including token nodes (commas, braces, etc.)\n node.getChildren().forEach(collectComments)\n }\n\n collectComments(sourceFile)\n\n if (ranges.length === 0) {\n return false\n }\n\n // Remove duplicates and sort in reverse order to avoid position shifts\n const uniqueRanges = Array.from(new Set(ranges.map((r) => JSON.stringify(r)))).map(\n (r) => JSON.parse(r) as [number, number],\n )\n uniqueRanges.sort((a, b) => b[0] - a[0])\n\n // Remove each comment range\n for (const [pos, end] of uniqueRanges) {\n sourceFile.removeText(pos, end)\n }\n\n return true\n}\n\n/**\n * Apply modifications to the source file based on detection result\n * Modifies the AST in memory - caller must call sourceFile.save()\n */\nexport function applyModifications(\n sourceFile: SourceFile,\n detection: DetectionResult,\n): ASTModificationResult {\n const changes: string[] = []\n let modified = false\n\n if (detection.hasBuildConfig === false || detection.hasAlias) {\n log.debug(\n `Skipping modifications: hasBuildConfig=${detection.hasBuildConfig}, hasAlias=${detection.hasAlias}`,\n )\n return { changes: [], modified: false }\n }\n\n // 1. Remove all comments FIRST (before AST modifications that might shift positions)\n const hadComments = removeAllComments(sourceFile)\n if (hadComments) {\n changes.push('Removed comments')\n modified = true\n }\n\n // Find the import declarations\n const imports = sourceFile.getImportDeclarations()\n const payloadImport = imports.find((imp) => imp.getModuleSpecifierValue() === 'payload')\n\n // Get the buildConfig name (could be aliased)\n let buildConfigName = 'buildConfig'\n if (payloadImport) {\n const buildConfigImport = payloadImport\n .getNamedImports()\n .find((ni) => ni.getName() === 'buildConfig')\n if (buildConfigImport) {\n const aliasNode = buildConfigImport.getAliasNode()\n buildConfigName = aliasNode ? aliasNode.getText() : 'buildConfig'\n }\n }\n\n // Find buildConfig call in export default (prefer export default)\n const exportAssignment = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment)\n let buildConfigCall = null\n\n if (exportAssignment) {\n const callExpressions = exportAssignment.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n // If not found in export default, search all call expressions\n if (!buildConfigCall) {\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n if (!buildConfigCall) {\n return { changes: [], modified: false }\n }\n\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n return { changes: [], modified: false }\n }\n\n // 1. Remove db property\n if (detection.dbProperty) {\n const dbProperty = configArg.getProperty('db')\n if (dbProperty) {\n dbProperty.remove()\n changes.push('Removed db property')\n modified = true\n }\n }\n\n // 2. Remove secret property\n if (detection.secretProperty) {\n const secretProperty = configArg.getProperty('secret')\n if (secretProperty) {\n secretProperty.remove()\n changes.push('Removed secret property')\n modified = true\n }\n }\n\n // 3. Remove editor if default\n if (detection.editorProperty?.isDefault) {\n const editorProperty = configArg.getProperty('editor')\n if (editorProperty) {\n editorProperty.remove()\n changes.push('Removed default editor property')\n modified = true\n }\n }\n\n // 4. Update buildConfig import\n if (detection.needsImportChange) {\n if (payloadImport) {\n if (detection.hasOtherPayloadImports) {\n // Remove buildConfig from payload import, add new figma import\n const namedImports = payloadImport.getNamedImports()\n const buildConfigImport = namedImports.find((ni) => ni.getName() === 'buildConfig')\n if (buildConfigImport) {\n buildConfigImport.remove()\n\n // If payload import is now empty, remove it\n if (payloadImport.getNamedImports().length === 0) {\n payloadImport.remove()\n }\n }\n\n // Add new import at the top\n sourceFile.addImportDeclaration({\n moduleSpecifier: '@payloadcms/figma',\n namedImports: ['buildConfig'],\n })\n\n changes.push('Split buildConfig import to @payloadcms/figma')\n } else {\n // Replace entire import\n payloadImport.setModuleSpecifier('@payloadcms/figma')\n changes.push('Changed buildConfig import to @payloadcms/figma')\n }\n modified = true\n }\n }\n\n // 5. Remove orphaned imports\n // Re-fetch imports after each removal to avoid stale references\n if (detection.dbProperty) {\n const currentImports = sourceFile.getImportDeclarations()\n const dbImport = currentImports.find(\n (imp) => imp.getModuleSpecifierValue() === detection.dbProperty?.importSource,\n )\n if (dbImport) {\n dbImport.remove()\n changes.push(`Removed ${detection.dbProperty.adapter} import`)\n modified = true\n }\n }\n\n if (detection.editorProperty?.isDefault) {\n const currentImports = sourceFile.getImportDeclarations()\n const editorImport = currentImports.find(\n (imp) => imp.getModuleSpecifierValue() === detection.editorProperty?.importSource,\n )\n if (editorImport) {\n editorImport.remove()\n changes.push('Removed lexicalEditor import')\n modified = true\n }\n }\n\n return { changes, modified }\n}\n\nexport type FigmaPropertyConfig = {\n region: string\n tenantId: string\n useContentSystem: boolean\n}\n\n/**\n * Add figma property to buildConfig if it doesn't exist\n * Modifies the AST in memory - caller must call sourceFile.save()\n */\nexport function addFigmaProperty(\n sourceFile: SourceFile,\n config: FigmaPropertyConfig,\n): ASTModificationResult {\n const changes: string[] = []\n let modified = false\n\n // Find buildConfig call\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n const buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n const text = expr.getText()\n return text === 'buildConfig' || text.endsWith('.buildConfig')\n })\n\n if (!buildConfigCall) {\n log.debug('No buildConfig call found')\n return { changes: [], modified: false }\n }\n\n // Get config object argument\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n log.debug('buildConfig argument is not an object literal')\n return { changes: [], modified: false }\n }\n\n // Check if figma property already exists\n const existingFigmaProperty = configArg.getProperty('figma')\n if (existingFigmaProperty) {\n log.debug('figma property already exists, skipping')\n return { changes: ['Skipped: figma property already exists'], modified: false }\n }\n\n // Add figma property\n configArg.addPropertyAssignment({\n name: 'figma',\n initializer: `{\n region: '${config.region}',\n tenantId: '${config.tenantId}',\n useContentSystem: ${config.useContentSystem},\n }`,\n })\n\n changes.push(\n `Added figma property (region: ${config.region}, tenantId: ${config.tenantId}, useContentSystem: ${config.useContentSystem})`,\n )\n modified = true\n\n return { changes, modified }\n}\n\n/**\n * Read figma configuration from payload.config.ts\n * Returns the figma object if it exists, null otherwise\n */\nexport function readFigmaConfig(sourceFile: SourceFile): FigmaPropertyConfig | null {\n // Find buildConfig call\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n const buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n const text = expr.getText()\n return text === 'buildConfig' || text.endsWith('.buildConfig')\n })\n\n if (!buildConfigCall) {\n log.debug('No buildConfig call found')\n return null\n }\n\n // Get config object argument\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n log.debug('buildConfig argument is not an object literal')\n return null\n }\n\n // Find figma property\n const figmaProperty = configArg.getProperty('figma')\n if (!figmaProperty || !Node.isPropertyAssignment(figmaProperty)) {\n log.debug('No figma property found in buildConfig')\n return null\n }\n\n // Get initializer (the object value)\n const initializer = figmaProperty.getInitializer()\n if (!initializer || !Node.isObjectLiteralExpression(initializer)) {\n log.debug('figma property is not an object literal')\n return null\n }\n\n // Extract values\n const regionProp = initializer.getProperty('region')\n const tenantIdProp = initializer.getProperty('tenantId')\n const useContentSystemProp = initializer.getProperty('useContentSystem')\n\n if (!regionProp || !tenantIdProp) {\n log.debug('Missing required figma properties (region or tenantId)')\n return null\n }\n\n // Extract string values (remove quotes)\n const region = Node.isPropertyAssignment(regionProp)\n ? regionProp\n .getInitializer()\n ?.getText()\n .replace(/['\"]/g, '')\n : undefined\n\n const tenantId = Node.isPropertyAssignment(tenantIdProp)\n ? tenantIdProp\n .getInitializer()\n ?.getText()\n .replace(/['\"]/g, '')\n : undefined\n\n const useContentSystem = Node.isPropertyAssignment(useContentSystemProp)\n ? useContentSystemProp.getInitializer()?.getText() === 'true'\n : true // Default to true if not specified\n\n if (!region || !tenantId) {\n log.debug('Could not extract region or tenantId values')\n return null\n }\n\n return {\n region,\n tenantId,\n useContentSystem,\n }\n}\n"],"names":["Node","SyntaxKind","log","detectRequiredChanges","sourceFile","result","figmaObjectExists","hasAlias","hasOtherPayloadImports","needsImportChange","imports","getImportDeclarations","payloadImport","find","imp","getModuleSpecifierValue","debug","hasBuildConfig","moduleSpecifier","namedImports","getNamedImports","buildConfigImport","ni","getName","aliasNode","getAliasNode","buildConfigName","getText","length","exportAssignment","getFirstDescendantByKind","ExportAssignment","buildConfigCall","callExpressions","getDescendantsOfKind","CallExpression","ce","expr","getExpression","configArg","getArguments","isObjectLiteralExpression","dbProperty","getProperty","dbValue","getChildrenOfKind","adapterName","adapterImport","some","adapter","importSource","secretProperty","editorProperty","editorValue","editorName","editorImport","args","isDefault","figmaProperty","removeAllComments","ranges","collectComments","node","getLeadingCommentRanges","forEach","range","push","getPos","getEnd","getTrailingCommentRanges","getChildren","uniqueRanges","Array","from","Set","map","r","JSON","stringify","parse","sort","a","b","pos","end","removeText","applyModifications","detection","changes","modified","hadComments","remove","addImportDeclaration","setModuleSpecifier","currentImports","dbImport","addFigmaProperty","config","text","endsWith","existingFigmaProperty","addPropertyAssignment","name","initializer","region","tenantId","useContentSystem","readFigmaConfig","isPropertyAssignment","getInitializer","regionProp","tenantIdProp","useContentSystemProp","replace","undefined"],"mappings":"AAEA,SAASA,IAAI,EAAEC,UAAU,QAAQ,WAAU;AAE3C,YAAYC,SAAS,WAAU;AAmB/B;;CAEC,GACD,OAAO,SAASC,sBAAsBC,UAAsB;IAC1D,MAAMC,SAA0B;QAC9BC,mBAAmB;QACnBC,UAAU;QACVC,wBAAwB;QACxBC,mBAAmB;IACrB;IAEA,0BAA0B;IAC1B,MAAMC,UAAUN,WAAWO,qBAAqB;IAChD,MAAMC,gBAAgBF,QAAQG,IAAI,CAChC,CAACC,MACCA,IAAIC,uBAAuB,OAAO,aAClCD,IAAIC,uBAAuB,OAAO;IAGtC,IAAI,CAACH,eAAe;QAClBV,IAAIc,KAAK,CAAC;QACVX,OAAOY,cAAc,GAAG;QACxB,OAAOZ;IACT;IAEAH,IAAIc,KAAK,CAAC,CAAC,mBAAmB,EAAEJ,cAAcG,uBAAuB,IAAI;IAEzE,MAAMG,kBAAkBN,cAAcG,uBAAuB;IAC7D,MAAMI,eAAeP,cAAcQ,eAAe;IAElD,mCAAmC;IACnC,MAAMC,oBAAoBF,aAAaN,IAAI,CAAC,CAACS,KAAOA,GAAGC,OAAO,OAAO;IAErE,IAAI,CAACF,mBAAmB;QACtBhB,OAAOY,cAAc,GAAG;QACxB,OAAOZ;IACT;IAEA,uDAAuD;IACvD,MAAMmB,YAAYH,kBAAkBI,YAAY;IAChD,MAAMC,kBAAkBF,YAAYA,UAAUG,OAAO,KAAK;IAC1D,IAAIH,WAAW;QACbnB,OAAOE,QAAQ,GAAG;IACpB;IAEA,+BAA+B;IAC/B,IAAIW,oBAAoB,WAAW;QACjCb,OAAOI,iBAAiB,GAAG;QAE3B,gDAAgD;QAChD,IAAIU,aAAaS,MAAM,GAAG,GAAG;YAC3BvB,OAAOG,sBAAsB,GAAG;QAClC;IACF;IAEA,0CAA0C;IAC1C,6DAA6D;IAC7D,MAAMqB,mBAAmBzB,WAAW0B,wBAAwB,CAAC7B,WAAW8B,gBAAgB;IACxF,IAAIC,kBAAkB;IAEtB,IAAIH,kBAAkB;QACpB,kDAAkD;QAClD,MAAMI,kBAAkBJ,iBAAiBK,oBAAoB,CAACjC,WAAWkC,cAAc;QACvFH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;YACtC,MAAMC,OAAOD,GAAGE,aAAa;YAC7B,OAAOD,KAAKV,OAAO,OAAOD;QAC5B;IACF;IAEA,8DAA8D;IAC9D,IAAI,CAACM,iBAAiB;QACpB,MAAMC,kBAAkB7B,WAAW8B,oBAAoB,CAACjC,WAAWkC,cAAc;QACjFH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;YACtC,MAAMC,OAAOD,GAAGE,aAAa;YAC7B,OAAOD,KAAKV,OAAO,OAAOD;QAC5B;IACF;IAEA,IAAI,CAACM,iBAAiB;QACpB3B,OAAOY,cAAc,GAAG;QACxB,OAAOZ;IACT;IAEA,oBAAoB;IACpB,MAAMkC,YAAYP,gBAAgBQ,YAAY,EAAE,CAAC,EAAE;IACnD,IAAI,CAACD,aAAa,CAACvC,KAAKyC,yBAAyB,CAACF,YAAY;QAC5D,OAAOlC;IACT;IAEA,wBAAwB;IACxB,MAAMqC,aAAaH,UAAUI,WAAW,CAAC;IACzC,IAAID,YAAY;QACd,MAAME,UAAUF,WAAWG,iBAAiB,CAAC5C,WAAWkC,cAAc,CAAC,CAAC,EAAE;QAC1E,IAAIS,SAAS;YACX,MAAME,cAAcF,QAAQN,aAAa,GAAGX,OAAO;YAEnD,0CAA0C;YAC1C,MAAMoB,gBAAgBrC,QAAQG,IAAI,CAAC,CAACC,MAClCA,IAAIM,eAAe,GAAG4B,IAAI,CAAC,CAAC1B,KAAOA,GAAGC,OAAO,OAAOuB;YAGtD,IAAIC,eAAe;gBACjB1C,OAAOqC,UAAU,GAAG;oBAClBO,SAASH;oBACTI,cAAcH,cAAchC,uBAAuB;gBACrD;YACF;QACF;IACF;IAEA,4BAA4B;IAC5B,MAAMoC,iBAAiBZ,UAAUI,WAAW,CAAC;IAC7C,IAAIQ,gBAAgB;QAClB9C,OAAO8C,cAAc,GAAG;IAC1B;IAEA,4BAA4B;IAC5B,MAAMC,iBAAiBb,UAAUI,WAAW,CAAC;IAC7C,IAAIS,gBAAgB;QAClB,MAAMC,cAAcD,eAAeP,iBAAiB,CAAC5C,WAAWkC,cAAc,CAAC,CAAC,EAAE;QAClF,IAAIkB,aAAa;YACf,MAAMC,aAAaD,YAAYf,aAAa,GAAGX,OAAO;YAEtD,yBAAyB;YACzB,MAAM4B,eAAe7C,QAAQG,IAAI,CAAC,CAACC,MACjCA,IAAIM,eAAe,GAAG4B,IAAI,CAAC,CAAC1B,KAAOA,GAAGC,OAAO,OAAO+B;YAGtD,IAAIC,gBAAgBD,eAAe,iBAAiB;gBAClD,4BAA4B;gBAC5B,MAAME,OAAOH,YAAYb,YAAY;gBACrC,MAAMiB,YAAYD,KAAK5B,MAAM,KAAK;gBAElCvB,OAAO+C,cAAc,GAAG;oBACtBF,cAAcK,aAAaxC,uBAAuB;oBAClD0C;gBACF;YACF;QACF;IACF;IAEA,2BAA2B;IAC3B,MAAMC,gBAAgBnB,UAAUI,WAAW,CAAC;IAC5C,IAAIe,eAAe;QACjBrD,OAAOC,iBAAiB,GAAG;IAC7B;IAEA,OAAOD;AACT;AAOA;;;CAGC,GACD,SAASsD,kBAAkBvD,UAAsB;IAC/C,MAAMwD,SAAkC,EAAE;IAE1C,6EAA6E;IAC7E,MAAMC,kBAAkB,CAACC;QACvBA,KAAKC,uBAAuB,GAAGC,OAAO,CAAC,CAACC;YACtCL,OAAOM,IAAI,CAAC;gBAACD,MAAME,MAAM;gBAAIF,MAAMG,MAAM;aAAG;QAC9C;QACAN,KAAKO,wBAAwB,GAAGL,OAAO,CAAC,CAACC;YACvCL,OAAOM,IAAI,CAAC;gBAACD,MAAME,MAAM;gBAAIF,MAAMG,MAAM;aAAG;QAC9C;QAEA,oEAAoE;QACpEN,KAAKQ,WAAW,GAAGN,OAAO,CAACH;IAC7B;IAEAA,gBAAgBzD;IAEhB,IAAIwD,OAAOhC,MAAM,KAAK,GAAG;QACvB,OAAO;IACT;IAEA,uEAAuE;IACvE,MAAM2C,eAAeC,MAAMC,IAAI,CAAC,IAAIC,IAAId,OAAOe,GAAG,CAAC,CAACC,IAAMC,KAAKC,SAAS,CAACF,MAAMD,GAAG,CAChF,CAACC,IAAMC,KAAKE,KAAK,CAACH;IAEpBL,aAAaS,IAAI,CAAC,CAACC,GAAGC,IAAMA,CAAC,CAAC,EAAE,GAAGD,CAAC,CAAC,EAAE;IAEvC,4BAA4B;IAC5B,KAAK,MAAM,CAACE,KAAKC,IAAI,IAAIb,aAAc;QACrCnE,WAAWiF,UAAU,CAACF,KAAKC;IAC7B;IAEA,OAAO;AACT;AAEA;;;CAGC,GACD,OAAO,SAASE,mBACdlF,UAAsB,EACtBmF,SAA0B;IAE1B,MAAMC,UAAoB,EAAE;IAC5B,IAAIC,WAAW;IAEf,IAAIF,UAAUtE,cAAc,KAAK,SAASsE,UAAUhF,QAAQ,EAAE;QAC5DL,IAAIc,KAAK,CACP,CAAC,uCAAuC,EAAEuE,UAAUtE,cAAc,CAAC,WAAW,EAAEsE,UAAUhF,QAAQ,EAAE;QAEtG,OAAO;YAAEiF,SAAS,EAAE;YAAEC,UAAU;QAAM;IACxC;IAEA,qFAAqF;IACrF,MAAMC,cAAc/B,kBAAkBvD;IACtC,IAAIsF,aAAa;QACfF,QAAQtB,IAAI,CAAC;QACbuB,WAAW;IACb;IAEA,+BAA+B;IAC/B,MAAM/E,UAAUN,WAAWO,qBAAqB;IAChD,MAAMC,gBAAgBF,QAAQG,IAAI,CAAC,CAACC,MAAQA,IAAIC,uBAAuB,OAAO;IAE9E,8CAA8C;IAC9C,IAAIW,kBAAkB;IACtB,IAAId,eAAe;QACjB,MAAMS,oBAAoBT,cACvBQ,eAAe,GACfP,IAAI,CAAC,CAACS,KAAOA,GAAGC,OAAO,OAAO;QACjC,IAAIF,mBAAmB;YACrB,MAAMG,YAAYH,kBAAkBI,YAAY;YAChDC,kBAAkBF,YAAYA,UAAUG,OAAO,KAAK;QACtD;IACF;IAEA,kEAAkE;IAClE,MAAME,mBAAmBzB,WAAW0B,wBAAwB,CAAC7B,WAAW8B,gBAAgB;IACxF,IAAIC,kBAAkB;IAEtB,IAAIH,kBAAkB;QACpB,MAAMI,kBAAkBJ,iBAAiBK,oBAAoB,CAACjC,WAAWkC,cAAc;QACvFH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;YACtC,MAAMC,OAAOD,GAAGE,aAAa;YAC7B,OAAOD,KAAKV,OAAO,OAAOD;QAC5B;IACF;IAEA,8DAA8D;IAC9D,IAAI,CAACM,iBAAiB;QACpB,MAAMC,kBAAkB7B,WAAW8B,oBAAoB,CAACjC,WAAWkC,cAAc;QACjFH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;YACtC,MAAMC,OAAOD,GAAGE,aAAa;YAC7B,OAAOD,KAAKV,OAAO,OAAOD;QAC5B;IACF;IAEA,IAAI,CAACM,iBAAiB;QACpB,OAAO;YAAEwD,SAAS,EAAE;YAAEC,UAAU;QAAM;IACxC;IAEA,MAAMlD,YAAYP,gBAAgBQ,YAAY,EAAE,CAAC,EAAE;IACnD,IAAI,CAACD,aAAa,CAACvC,KAAKyC,yBAAyB,CAACF,YAAY;QAC5D,OAAO;YAAEiD,SAAS,EAAE;YAAEC,UAAU;QAAM;IACxC;IAEA,wBAAwB;IACxB,IAAIF,UAAU7C,UAAU,EAAE;QACxB,MAAMA,aAAaH,UAAUI,WAAW,CAAC;QACzC,IAAID,YAAY;YACdA,WAAWiD,MAAM;YACjBH,QAAQtB,IAAI,CAAC;YACbuB,WAAW;QACb;IACF;IAEA,4BAA4B;IAC5B,IAAIF,UAAUpC,cAAc,EAAE;QAC5B,MAAMA,iBAAiBZ,UAAUI,WAAW,CAAC;QAC7C,IAAIQ,gBAAgB;YAClBA,eAAewC,MAAM;YACrBH,QAAQtB,IAAI,CAAC;YACbuB,WAAW;QACb;IACF;IAEA,8BAA8B;IAC9B,IAAIF,UAAUnC,cAAc,EAAEK,WAAW;QACvC,MAAML,iBAAiBb,UAAUI,WAAW,CAAC;QAC7C,IAAIS,gBAAgB;YAClBA,eAAeuC,MAAM;YACrBH,QAAQtB,IAAI,CAAC;YACbuB,WAAW;QACb;IACF;IAEA,+BAA+B;IAC/B,IAAIF,UAAU9E,iBAAiB,EAAE;QAC/B,IAAIG,eAAe;YACjB,IAAI2E,UAAU/E,sBAAsB,EAAE;gBACpC,+DAA+D;gBAC/D,MAAMW,eAAeP,cAAcQ,eAAe;gBAClD,MAAMC,oBAAoBF,aAAaN,IAAI,CAAC,CAACS,KAAOA,GAAGC,OAAO,OAAO;gBACrE,IAAIF,mBAAmB;oBACrBA,kBAAkBsE,MAAM;oBAExB,4CAA4C;oBAC5C,IAAI/E,cAAcQ,eAAe,GAAGQ,MAAM,KAAK,GAAG;wBAChDhB,cAAc+E,MAAM;oBACtB;gBACF;gBAEA,4BAA4B;gBAC5BvF,WAAWwF,oBAAoB,CAAC;oBAC9B1E,iBAAiB;oBACjBC,cAAc;wBAAC;qBAAc;gBAC/B;gBAEAqE,QAAQtB,IAAI,CAAC;YACf,OAAO;gBACL,wBAAwB;gBACxBtD,cAAciF,kBAAkB,CAAC;gBACjCL,QAAQtB,IAAI,CAAC;YACf;YACAuB,WAAW;QACb;IACF;IAEA,6BAA6B;IAC7B,gEAAgE;IAChE,IAAIF,UAAU7C,UAAU,EAAE;QACxB,MAAMoD,iBAAiB1F,WAAWO,qBAAqB;QACvD,MAAMoF,WAAWD,eAAejF,IAAI,CAClC,CAACC,MAAQA,IAAIC,uBAAuB,OAAOwE,UAAU7C,UAAU,EAAEQ;QAEnE,IAAI6C,UAAU;YACZA,SAASJ,MAAM;YACfH,QAAQtB,IAAI,CAAC,CAAC,QAAQ,EAAEqB,UAAU7C,UAAU,CAACO,OAAO,CAAC,OAAO,CAAC;YAC7DwC,WAAW;QACb;IACF;IAEA,IAAIF,UAAUnC,cAAc,EAAEK,WAAW;QACvC,MAAMqC,iBAAiB1F,WAAWO,qBAAqB;QACvD,MAAM4C,eAAeuC,eAAejF,IAAI,CACtC,CAACC,MAAQA,IAAIC,uBAAuB,OAAOwE,UAAUnC,cAAc,EAAEF;QAEvE,IAAIK,cAAc;YAChBA,aAAaoC,MAAM;YACnBH,QAAQtB,IAAI,CAAC;YACbuB,WAAW;QACb;IACF;IAEA,OAAO;QAAED;QAASC;IAAS;AAC7B;AAQA;;;CAGC,GACD,OAAO,SAASO,iBACd5F,UAAsB,EACtB6F,MAA2B;IAE3B,MAAMT,UAAoB,EAAE;IAC5B,IAAIC,WAAW;IAEf,wBAAwB;IACxB,MAAMxD,kBAAkB7B,WAAW8B,oBAAoB,CAACjC,WAAWkC,cAAc;IACjF,MAAMH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;QAC5C,MAAMC,OAAOD,GAAGE,aAAa;QAC7B,MAAM4D,OAAO7D,KAAKV,OAAO;QACzB,OAAOuE,SAAS,iBAAiBA,KAAKC,QAAQ,CAAC;IACjD;IAEA,IAAI,CAACnE,iBAAiB;QACpB9B,IAAIc,KAAK,CAAC;QACV,OAAO;YAAEwE,SAAS,EAAE;YAAEC,UAAU;QAAM;IACxC;IAEA,6BAA6B;IAC7B,MAAMlD,YAAYP,gBAAgBQ,YAAY,EAAE,CAAC,EAAE;IACnD,IAAI,CAACD,aAAa,CAACvC,KAAKyC,yBAAyB,CAACF,YAAY;QAC5DrC,IAAIc,KAAK,CAAC;QACV,OAAO;YAAEwE,SAAS,EAAE;YAAEC,UAAU;QAAM;IACxC;IAEA,yCAAyC;IACzC,MAAMW,wBAAwB7D,UAAUI,WAAW,CAAC;IACpD,IAAIyD,uBAAuB;QACzBlG,IAAIc,KAAK,CAAC;QACV,OAAO;YAAEwE,SAAS;gBAAC;aAAyC;YAAEC,UAAU;QAAM;IAChF;IAEA,qBAAqB;IACrBlD,UAAU8D,qBAAqB,CAAC;QAC9BC,MAAM;QACNC,aAAa,CAAC;aACL,EAAEN,OAAOO,MAAM,CAAC;eACd,EAAEP,OAAOQ,QAAQ,CAAC;sBACX,EAAER,OAAOS,gBAAgB,CAAC;GAC7C,CAAC;IACF;IAEAlB,QAAQtB,IAAI,CACV,CAAC,8BAA8B,EAAE+B,OAAOO,MAAM,CAAC,YAAY,EAAEP,OAAOQ,QAAQ,CAAC,oBAAoB,EAAER,OAAOS,gBAAgB,CAAC,CAAC,CAAC;IAE/HjB,WAAW;IAEX,OAAO;QAAED;QAASC;IAAS;AAC7B;AAEA;;;CAGC,GACD,OAAO,SAASkB,gBAAgBvG,UAAsB;IACpD,wBAAwB;IACxB,MAAM6B,kBAAkB7B,WAAW8B,oBAAoB,CAACjC,WAAWkC,cAAc;IACjF,MAAMH,kBAAkBC,gBAAgBpB,IAAI,CAAC,CAACuB;QAC5C,MAAMC,OAAOD,GAAGE,aAAa;QAC7B,MAAM4D,OAAO7D,KAAKV,OAAO;QACzB,OAAOuE,SAAS,iBAAiBA,KAAKC,QAAQ,CAAC;IACjD;IAEA,IAAI,CAACnE,iBAAiB;QACpB9B,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,6BAA6B;IAC7B,MAAMuB,YAAYP,gBAAgBQ,YAAY,EAAE,CAAC,EAAE;IACnD,IAAI,CAACD,aAAa,CAACvC,KAAKyC,yBAAyB,CAACF,YAAY;QAC5DrC,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,sBAAsB;IACtB,MAAM0C,gBAAgBnB,UAAUI,WAAW,CAAC;IAC5C,IAAI,CAACe,iBAAiB,CAAC1D,KAAK4G,oBAAoB,CAAClD,gBAAgB;QAC/DxD,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,qCAAqC;IACrC,MAAMuF,cAAc7C,cAAcmD,cAAc;IAChD,IAAI,CAACN,eAAe,CAACvG,KAAKyC,yBAAyB,CAAC8D,cAAc;QAChErG,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,iBAAiB;IACjB,MAAM8F,aAAaP,YAAY5D,WAAW,CAAC;IAC3C,MAAMoE,eAAeR,YAAY5D,WAAW,CAAC;IAC7C,MAAMqE,uBAAuBT,YAAY5D,WAAW,CAAC;IAErD,IAAI,CAACmE,cAAc,CAACC,cAAc;QAChC7G,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,wCAAwC;IACxC,MAAMwF,SAASxG,KAAK4G,oBAAoB,CAACE,cACrCA,WACGD,cAAc,IACblF,UACDsF,QAAQ,SAAS,MACpBC;IAEJ,MAAMT,WAAWzG,KAAK4G,oBAAoB,CAACG,gBACvCA,aACGF,cAAc,IACblF,UACDsF,QAAQ,SAAS,MACpBC;IAEJ,MAAMR,mBAAmB1G,KAAK4G,oBAAoB,CAACI,wBAC/CA,qBAAqBH,cAAc,IAAIlF,cAAc,SACrD,KAAK,mCAAmC;;IAE5C,IAAI,CAAC6E,UAAU,CAACC,UAAU;QACxBvG,IAAIc,KAAK,CAAC;QACV,OAAO;IACT;IAEA,OAAO;QACLwF;QACAC;QACAC;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/payload-config-ast.ts"],"sourcesContent":["import type { SourceFile } from 'ts-morph'\n\nimport { Node, SyntaxKind } from 'ts-morph'\n\nimport * as log from './log.js'\n\nexport type DetectionResult = {\n dbProperty?: {\n adapter: string\n importSource: string\n }\n editorProperty?: {\n importSource: string\n isDefault: boolean\n }\n figmaObjectExists: boolean\n hasAlias: boolean\n hasBuildConfig?: boolean\n hasOtherPayloadImports: boolean\n needsImportChange: boolean\n secretProperty?: boolean\n}\n\n/**\n * Detect what changes are needed in the payload config file\n */\nexport function detectRequiredChanges(sourceFile: SourceFile): DetectionResult {\n const result: DetectionResult = {\n figmaObjectExists: false,\n hasAlias: false,\n hasOtherPayloadImports: false,\n needsImportChange: false,\n }\n\n // Find buildConfig import\n const imports = sourceFile.getImportDeclarations()\n const payloadImport = imports.find(\n (imp) =>\n imp.getModuleSpecifierValue() === 'payload' ||\n imp.getModuleSpecifierValue() === '@payloadcms/figma',\n )\n\n if (!payloadImport) {\n log.debug('No payload or @payloadcms/figma import found')\n result.hasBuildConfig = false\n return result\n }\n\n log.debug(`Found import from: ${payloadImport.getModuleSpecifierValue()}`)\n\n const moduleSpecifier = payloadImport.getModuleSpecifierValue()\n const namedImports = payloadImport.getNamedImports()\n\n // Check if buildConfig is imported\n const buildConfigImport = namedImports.find((ni) => ni.getName() === 'buildConfig')\n\n if (!buildConfigImport) {\n result.hasBuildConfig = false\n return result\n }\n\n // Check for alias and get the actual name used in code\n const aliasNode = buildConfigImport.getAliasNode()\n const buildConfigName = aliasNode ? aliasNode.getText() : 'buildConfig'\n if (aliasNode) {\n result.hasAlias = true\n }\n\n // Check if import needs change\n if (moduleSpecifier === 'payload') {\n result.needsImportChange = true\n\n // Check if there are other imports from payload\n if (namedImports.length > 1) {\n result.hasOtherPayloadImports = true\n }\n }\n\n // Find buildConfig call in export default\n // First try to find export default with the buildConfig call\n const exportAssignment = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment)\n let buildConfigCall = null\n\n if (exportAssignment) {\n // Look for buildConfig call in the export default\n const callExpressions = exportAssignment.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n // If not found in export default, search all call expressions\n if (!buildConfigCall) {\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n if (!buildConfigCall) {\n result.hasBuildConfig = false\n return result\n }\n\n // Get config object\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n return result\n }\n\n // Check for db property\n const dbProperty = configArg.getProperty('db')\n if (dbProperty) {\n const dbValue = dbProperty.getChildrenOfKind(SyntaxKind.CallExpression)[0]\n if (dbValue) {\n const adapterName = dbValue.getExpression().getText()\n\n // Find the import source for this adapter\n const adapterImport = imports.find((imp) =>\n imp.getNamedImports().some((ni) => ni.getName() === adapterName),\n )\n\n if (adapterImport) {\n result.dbProperty = {\n adapter: adapterName,\n importSource: adapterImport.getModuleSpecifierValue(),\n }\n }\n }\n }\n\n // Check for secret property\n const secretProperty = configArg.getProperty('secret')\n if (secretProperty) {\n result.secretProperty = true\n }\n\n // Check for editor property\n const editorProperty = configArg.getProperty('editor')\n if (editorProperty) {\n const editorValue = editorProperty.getChildrenOfKind(SyntaxKind.CallExpression)[0]\n if (editorValue) {\n const editorName = editorValue.getExpression().getText()\n\n // Find the import source\n const editorImport = imports.find((imp) =>\n imp.getNamedImports().some((ni) => ni.getName() === editorName),\n )\n\n if (editorImport && editorName === 'lexicalEditor') {\n // Check if it has arguments\n const args = editorValue.getArguments()\n const isDefault = args.length === 0\n\n result.editorProperty = {\n importSource: editorImport.getModuleSpecifierValue(),\n isDefault,\n }\n }\n }\n }\n\n // Check for figma property\n const figmaProperty = configArg.getProperty('figma')\n if (figmaProperty) {\n result.figmaObjectExists = true\n }\n\n return result\n}\n\nexport type ASTModificationResult = {\n changes: string[]\n modified: boolean\n}\n\n/**\n * Remove all comments\n * @returns true if any comments were removed\n */\nfunction removeAllComments(sourceFile: SourceFile): boolean {\n const ranges: Array<[number, number]> = []\n\n // Recursively collect comments from node and ALL children (including tokens)\n const collectComments = (node: Node) => {\n node.getLeadingCommentRanges().forEach((range) => {\n ranges.push([range.getPos(), range.getEnd()])\n })\n node.getTrailingCommentRanges().forEach((range) => {\n ranges.push([range.getPos(), range.getEnd()])\n })\n\n // Process ALL children including token nodes (commas, braces, etc.)\n node.getChildren().forEach(collectComments)\n }\n\n collectComments(sourceFile)\n\n if (ranges.length === 0) {\n return false\n }\n\n // Remove duplicates and sort in reverse order to avoid position shifts\n const uniqueRanges = Array.from(new Set(ranges.map((r) => JSON.stringify(r)))).map(\n (r) => JSON.parse(r) as [number, number],\n )\n uniqueRanges.sort((a, b) => b[0] - a[0])\n\n // Remove each comment range\n for (const [pos, end] of uniqueRanges) {\n sourceFile.removeText(pos, end)\n }\n\n return true\n}\n\n/**\n * Apply modifications to the source file based on detection result\n * Modifies the AST in memory - caller must call sourceFile.save()\n */\nexport function applyModifications(\n sourceFile: SourceFile,\n detection: DetectionResult,\n): ASTModificationResult {\n const changes: string[] = []\n let modified = false\n\n if (detection.hasBuildConfig === false || detection.hasAlias) {\n log.debug(\n `Skipping modifications: hasBuildConfig=${detection.hasBuildConfig}, hasAlias=${detection.hasAlias}`,\n )\n return { changes: [], modified: false }\n }\n\n // 1. Remove all comments FIRST (before AST modifications that might shift positions)\n const hadComments = removeAllComments(sourceFile)\n if (hadComments) {\n changes.push('Removed comments')\n modified = true\n }\n\n // Find the import declarations\n const imports = sourceFile.getImportDeclarations()\n const payloadImport = imports.find((imp) => imp.getModuleSpecifierValue() === 'payload')\n\n // Get the buildConfig name (could be aliased)\n let buildConfigName = 'buildConfig'\n if (payloadImport) {\n const buildConfigImport = payloadImport\n .getNamedImports()\n .find((ni) => ni.getName() === 'buildConfig')\n if (buildConfigImport) {\n const aliasNode = buildConfigImport.getAliasNode()\n buildConfigName = aliasNode ? aliasNode.getText() : 'buildConfig'\n }\n }\n\n // Find buildConfig call in export default (prefer export default)\n const exportAssignment = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment)\n let buildConfigCall = null\n\n if (exportAssignment) {\n const callExpressions = exportAssignment.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n // If not found in export default, search all call expressions\n if (!buildConfigCall) {\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n return expr.getText() === buildConfigName\n })\n }\n\n if (!buildConfigCall) {\n return { changes: [], modified: false }\n }\n\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n return { changes: [], modified: false }\n }\n\n // 1. Remove db property\n if (detection.dbProperty) {\n const dbProperty = configArg.getProperty('db')\n if (dbProperty) {\n dbProperty.remove()\n changes.push('Removed db property')\n modified = true\n }\n }\n\n // 2. Remove secret property\n if (detection.secretProperty) {\n const secretProperty = configArg.getProperty('secret')\n if (secretProperty) {\n secretProperty.remove()\n changes.push('Removed secret property')\n modified = true\n }\n }\n\n // 3. Remove editor if default\n if (detection.editorProperty?.isDefault) {\n const editorProperty = configArg.getProperty('editor')\n if (editorProperty) {\n editorProperty.remove()\n changes.push('Removed default editor property')\n modified = true\n }\n }\n\n // 4. Update buildConfig import\n if (detection.needsImportChange) {\n if (payloadImport) {\n if (detection.hasOtherPayloadImports) {\n // Remove buildConfig from payload import, add new figma import\n const namedImports = payloadImport.getNamedImports()\n const buildConfigImport = namedImports.find((ni) => ni.getName() === 'buildConfig')\n if (buildConfigImport) {\n buildConfigImport.remove()\n\n // If payload import is now empty, remove it\n if (payloadImport.getNamedImports().length === 0) {\n payloadImport.remove()\n }\n }\n\n // Add new import at the top\n sourceFile.addImportDeclaration({\n moduleSpecifier: '@payloadcms/figma',\n namedImports: ['buildConfig'],\n })\n\n changes.push('Split buildConfig import to @payloadcms/figma')\n } else {\n // Replace entire import\n payloadImport.setModuleSpecifier('@payloadcms/figma')\n changes.push('Changed buildConfig import to @payloadcms/figma')\n }\n modified = true\n }\n }\n\n // 5. Remove orphaned imports\n // Re-fetch imports after each removal to avoid stale references\n if (detection.dbProperty) {\n const currentImports = sourceFile.getImportDeclarations()\n const dbImport = currentImports.find(\n (imp) => imp.getModuleSpecifierValue() === detection.dbProperty?.importSource,\n )\n if (dbImport) {\n dbImport.remove()\n changes.push(`Removed ${detection.dbProperty.adapter} import`)\n modified = true\n }\n }\n\n if (detection.editorProperty?.isDefault) {\n const currentImports = sourceFile.getImportDeclarations()\n const editorImport = currentImports.find(\n (imp) => imp.getModuleSpecifierValue() === detection.editorProperty?.importSource,\n )\n if (editorImport) {\n editorImport.remove()\n changes.push('Removed lexicalEditor import')\n modified = true\n }\n }\n\n return { changes, modified }\n}\n\nexport type FigmaPropertyConfig = {\n contentSystemId: string\n region: string\n useContentSystem: boolean\n}\n\n/**\n * Add figma property to buildConfig if it doesn't exist\n * Modifies the AST in memory - caller must call sourceFile.save()\n */\nexport function addFigmaProperty(\n sourceFile: SourceFile,\n config: FigmaPropertyConfig,\n): ASTModificationResult {\n const changes: string[] = []\n let modified = false\n\n // Find buildConfig call\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n const buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n const text = expr.getText()\n return text === 'buildConfig' || text.endsWith('.buildConfig')\n })\n\n if (!buildConfigCall) {\n log.debug('No buildConfig call found')\n return { changes: [], modified: false }\n }\n\n // Get config object argument\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n log.debug('buildConfig argument is not an object literal')\n return { changes: [], modified: false }\n }\n\n // Check if figma property already exists\n const existingFigmaProperty = configArg.getProperty('figma')\n if (existingFigmaProperty) {\n log.debug('figma property already exists, skipping')\n return { changes: ['Skipped: figma property already exists'], modified: false }\n }\n\n // Add figma property\n configArg.addPropertyAssignment({\n name: 'figma',\n initializer: `{\n region: '${config.region}',\n contentSystemId: '${config.contentSystemId}',\n useContentSystem: ${config.useContentSystem},\n }`,\n })\n\n changes.push(\n `Added figma property (region: ${config.region}, tenantId: ${config.contentSystemId}, useContentSystem: ${config.useContentSystem})`,\n )\n modified = true\n\n return { changes, modified }\n}\n\n/**\n * Read figma configuration from payload.config.ts\n * Returns the figma object if it exists, null otherwise\n */\nexport function readFigmaConfig(sourceFile: SourceFile): FigmaPropertyConfig | null {\n // Find buildConfig call\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)\n const buildConfigCall = callExpressions.find((ce) => {\n const expr = ce.getExpression()\n const text = expr.getText()\n return text === 'buildConfig' || text.endsWith('.buildConfig')\n })\n\n if (!buildConfigCall) {\n log.debug('No buildConfig call found')\n return null\n }\n\n // Get config object argument\n const configArg = buildConfigCall.getArguments()[0]\n if (!configArg || !Node.isObjectLiteralExpression(configArg)) {\n log.debug('buildConfig argument is not an object literal')\n return null\n }\n\n // Find figma property\n const figmaProperty = configArg.getProperty('figma')\n if (!figmaProperty || !Node.isPropertyAssignment(figmaProperty)) {\n log.debug('No figma property found in buildConfig')\n return null\n }\n\n // Get initializer (the object value)\n const initializer = figmaProperty.getInitializer()\n if (!initializer || !Node.isObjectLiteralExpression(initializer)) {\n log.debug('figma property is not an object literal')\n return null\n }\n\n // Extract values\n const regionProp = initializer.getProperty('region')\n const contentSystemIdProp = initializer.getProperty('contentSystemId')\n const useContentSystemProp = initializer.getProperty('useContentSystem')\n\n if (!regionProp || !contentSystemIdProp) {\n log.debug('Missing required figma properties (region or tenantId)')\n return null\n }\n\n // Extract string values (remove quotes)\n const region = Node.isPropertyAssignment(regionProp)\n ? regionProp.getInitializer()?.getText().replace(/['\"]/g, '')\n : undefined\n\n const contentSystemId = Node.isPropertyAssignment(contentSystemIdProp)\n ? contentSystemIdProp.getInitializer()?.getText().replace(/['\"]/g, '')\n : undefined\n\n const useContentSystem = Node.isPropertyAssignment(useContentSystemProp)\n ? useContentSystemProp.getInitializer()?.getText() === 'true'\n : true // Default to true if not specified\n\n if (!region || !contentSystemId) {\n log.debug('Could not extract region or tenantId values')\n return null\n }\n\n return {\n contentSystemId,\n region,\n useContentSystem,\n }\n}\n"],"names":["Node","SyntaxKind","log","detectRequiredChanges","sourceFile","result","figmaObjectExists","hasAlias","hasOtherPayloadImports","needsImportChange","imports","getImportDeclarations","payloadImport","find","imp","getModuleSpecifierValue","debug","hasBuildConfig","moduleSpecifier","namedImports","getNamedImports","buildConfigImport","ni","getName","aliasNode","getAliasNode","buildConfigName","getText","length","exportAssignment","getFirstDescendantByKind","ExportAssignment","buildConfigCall","callExpressions","getDescendantsOfKind","CallExpression","ce","expr","getExpression","configArg","getArguments","isObjectLiteralExpression","dbProperty","getProperty","dbValue","getChildrenOfKind","adapterName","adapterImport","some","adapter","importSource","secretProperty","editorProperty","editorValue","editorName","editorImport","args","isDefault","figmaProperty","removeAllComments","ranges","collectComments","node","getLeadingCommentRanges","forEach","range","push","getPos","getEnd","getTrailingCommentRanges","getChildren","uniqueRanges","Array","from","Set","map","r","JSON","stringify","parse","sort","a","b","pos","end","removeText","applyModifications","detection","changes","modified","hadComments","remove","addImportDeclaration","setModuleSpecifier","currentImports","dbImport","addFigmaProperty","config","text","endsWith","existingFigmaProperty","addPropertyAssignment","name","initializer","region","contentSystemId","useContentSystem","readFigmaConfig","isPropertyAssignment","getInitializer","regionProp","contentSystemIdProp","useContentSystemProp","replace","undefined"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/figma",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.13",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/",
|
|
63
63
|
"debug:clear-tokens": "tsx scripts/clear-tokens.ts",
|
|
64
64
|
"debug:expire-token": "tsx scripts/expire-token.ts",
|
|
65
|
+
"debug:get-project-token": "tsx scripts/get-project-token.ts",
|
|
65
66
|
"debug:jwks": "tsx scripts/test-jwks-validation.ts",
|
|
66
67
|
"debug:refresh-token": "tsx scripts/refresh-token.ts",
|
|
67
68
|
"debug:tokens": "tsx scripts/debug-tokens.ts",
|