@payloadcms/figma 0.0.1-alpha.62 → 0.0.1-alpha.64
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/auth/crypto-utils.d.ts +11 -0
- package/dist/auth/crypto-utils.js +51 -0
- package/dist/auth/oauth-flow.js +4 -3
- package/dist/auth/project-token.d.ts +32 -16
- package/dist/auth/project-token.js +165 -64
- package/dist/auth/token-store-migration.d.ts +58 -0
- package/dist/auth/token-store-migration.js +156 -0
- package/dist/auth/token-store.d.ts +51 -128
- package/dist/auth/token-store.js +326 -187
- package/dist/auth/types.d.ts +12 -1
- package/dist/cli.js +15 -0
- package/dist/commands/bootstrap.d.ts +18 -0
- package/dist/commands/bootstrap.js +90 -0
- package/dist/commands/debug.js +16 -12
- package/dist/commands/dump-tokens.d.ts +12 -0
- package/dist/commands/dump-tokens.js +69 -0
- package/dist/commands/init.js +39 -5
- package/dist/commands/list-tokens.js +2 -2
- package/dist/commands/login.js +1 -1
- package/dist/commands/logout.js +23 -4
- package/dist/db-content-api/index.js +27 -73
- package/dist/db-content-api/utilities/auth.js +4 -1
- package/dist/oauth/defaults.d.ts +3 -1
- package/dist/oauth/defaults.js +6 -5
- package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
- package/dist/oauth/index.js +1 -0
- package/dist/oauth/types.d.ts +10 -0
- package/dist/plugin/auth-preflight.d.ts +8 -0
- package/dist/plugin/auth-preflight.js +20 -0
- package/dist/plugin/bootstrap-preflight.d.ts +23 -0
- package/dist/plugin/bootstrap-preflight.js +45 -0
- package/dist/plugin/build-config.js +135 -58
- package/dist/plugin/dev-cookie-names.d.ts +14 -0
- package/dist/plugin/dev-cookie-names.js +19 -0
- package/dist/storage-content-api/client.js +4 -1
- package/dist/utils/messages.js +7 -0
- package/dist/utils/payload-config-modifier.js +96 -107
- package/dist/utils/payload-package-check.d.ts +21 -1
- package/dist/utils/payload-package-check.js +66 -26
- package/dist/utils/token-display.d.ts +5 -1
- package/dist/utils/token-display.js +47 -26
- package/package.json +2 -1
package/dist/oauth/defaults.js
CHANGED
|
@@ -2,10 +2,11 @@ import { parseCookies } from 'payload';
|
|
|
2
2
|
import { v4 as uuid } from 'uuid';
|
|
3
3
|
import { hasUserTokenPropsChanged } from './utilities/hasUserTokenPropsChanged.js';
|
|
4
4
|
import { isDuplicateKeyError } from './utilities/isDuplicateKeyError.js';
|
|
5
|
-
|
|
5
|
+
export const DEFAULT_USER_INFO_COOKIE_NAME = 'figma-user-info';
|
|
6
|
+
function getFigmaUserInfo(headers, cookieName) {
|
|
6
7
|
try {
|
|
7
8
|
const cookies = parseCookies(headers);
|
|
8
|
-
const encoded = cookies.get(
|
|
9
|
+
const encoded = cookies.get(cookieName);
|
|
9
10
|
if (!encoded) {
|
|
10
11
|
return null;
|
|
11
12
|
}
|
|
@@ -28,7 +29,7 @@ export const defaultUsernameField = {
|
|
|
28
29
|
},
|
|
29
30
|
unique: true
|
|
30
31
|
};
|
|
31
|
-
export const defaultVerify = ({ collection, strategyName, usernameField })=>async ({ headers, payload, token })=>{
|
|
32
|
+
export const defaultVerify = ({ collection, strategyName, userInfoCookieName = DEFAULT_USER_INFO_COOKIE_NAME, usernameField })=>async ({ headers, payload, token })=>{
|
|
32
33
|
let tokenUsername = 'preferred_username';
|
|
33
34
|
if (usernameField.name !== 'preferredUsername') {
|
|
34
35
|
tokenUsername = usernameField.name;
|
|
@@ -38,12 +39,12 @@ export const defaultVerify = ({ collection, strategyName, usernameField })=>asyn
|
|
|
38
39
|
user: null
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
|
-
const figmaUserInfo = getFigmaUserInfo(headers);
|
|
42
|
+
const figmaUserInfo = getFigmaUserInfo(headers, userInfoCookieName);
|
|
42
43
|
let responseHeaders;
|
|
43
44
|
// Clear the cookie after reading
|
|
44
45
|
if (figmaUserInfo) {
|
|
45
46
|
responseHeaders = new Headers();
|
|
46
|
-
responseHeaders.append('Set-Cookie',
|
|
47
|
+
responseHeaders.append('Set-Cookie', `${userInfoCookieName}=; Max-Age=0; Path=/;`);
|
|
47
48
|
}
|
|
48
49
|
let user = null;
|
|
49
50
|
const depth = typeof collection.auth === 'object' ? collection.auth.depth : undefined;
|
|
@@ -262,7 +262,7 @@ export const getLoginEndpoint = ({ collection, collectionOptions, endpointSlug,
|
|
|
262
262
|
})).toString('base64');
|
|
263
263
|
const userInfoCookie = generateCookie({
|
|
264
264
|
...cookieOptions,
|
|
265
|
-
name: 'figma-user-info',
|
|
265
|
+
name: pluginOptions?.userInfoCookieName ?? 'figma-user-info',
|
|
266
266
|
expires: new Date(Date.now() + 60_000),
|
|
267
267
|
returnCookieAsObject: false,
|
|
268
268
|
value: userInfoValue
|
package/dist/oauth/index.js
CHANGED
|
@@ -144,6 +144,7 @@ export const oAuth2Plugin = (pluginOptions)=>(config)=>{
|
|
|
144
144
|
verify: collectionOptions.verify ?? defaultVerify({
|
|
145
145
|
collection: existingCollection,
|
|
146
146
|
strategyName,
|
|
147
|
+
userInfoCookieName: pluginOptions?.userInfoCookieName,
|
|
147
148
|
usernameField
|
|
148
149
|
})
|
|
149
150
|
});
|
package/dist/oauth/types.d.ts
CHANGED
|
@@ -148,6 +148,16 @@ export interface PluginOptions {
|
|
|
148
148
|
* @default 'oauth'
|
|
149
149
|
*/
|
|
150
150
|
strategyName?: string;
|
|
151
|
+
/**
|
|
152
|
+
* The name of the short-lived cookie used to carry Figma user profile
|
|
153
|
+
* info from the login endpoint to `defaultVerify`.
|
|
154
|
+
*
|
|
155
|
+
* Override in local dev when running multiple Payload apps on localhost
|
|
156
|
+
* to avoid cookie collisions (all localhost apps share a cookie jar).
|
|
157
|
+
*
|
|
158
|
+
* @default 'figma-user-info'
|
|
159
|
+
*/
|
|
160
|
+
userInfoCookieName?: string;
|
|
151
161
|
}
|
|
152
162
|
export type CookieOptions = {
|
|
153
163
|
domain?: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TokenStore } from '../auth/token-store.js';
|
|
2
|
+
/**
|
|
3
|
+
* Print a one-shot banner when the plugin is about to use `tokenStore`
|
|
4
|
+
* auth but no valid OAuth credential is present. Keeps the dev loop
|
|
5
|
+
* actionable instead of relying on per-request middleware errors.
|
|
6
|
+
*/
|
|
7
|
+
export declare function logMissingCliAuth(tokenStore: TokenStore): void;
|
|
8
|
+
//# sourceMappingURL=auth-preflight.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
/**
|
|
4
|
+
* Print a one-shot banner when the plugin is about to use `tokenStore`
|
|
5
|
+
* auth but no valid OAuth credential is present. Keeps the dev loop
|
|
6
|
+
* actionable instead of relying on per-request middleware errors.
|
|
7
|
+
*/ export function logMissingCliAuth(tokenStore) {
|
|
8
|
+
if (tokenStore.hasValidOauthToken()) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const lines = [
|
|
12
|
+
'Not logged in to the Figma CLI.',
|
|
13
|
+
'Content API requests will fail until you authenticate.',
|
|
14
|
+
'',
|
|
15
|
+
`Run ${pc.cyan('npx @payloadcms/figma login')} to log in, then restart the dev server.`
|
|
16
|
+
];
|
|
17
|
+
p.note(lines.join('\n'), pc.yellow('Figma authentication required'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=auth-preflight.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reason the Content System ID could not be resolved. Drives the
|
|
3
|
+
* banner's copy so the dev sees the specific remediation step.
|
|
4
|
+
*/
|
|
5
|
+
export type MissingContentSystemIdReason = {
|
|
6
|
+
environmentName: string;
|
|
7
|
+
kind: 'environment-not-found';
|
|
8
|
+
projectId: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'network';
|
|
11
|
+
message: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'no-config';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'unauthenticated';
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Print a banner explaining why Content System ID resolution failed and
|
|
19
|
+
* what to run next. Called just before `buildFigmaConfig` throws, so the
|
|
20
|
+
* actionable step is visible above the stack trace.
|
|
21
|
+
*/
|
|
22
|
+
export declare function logMissingContentSystemId(reason: MissingContentSystemIdReason): void;
|
|
23
|
+
//# sourceMappingURL=bootstrap-preflight.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
/**
|
|
4
|
+
* Print a banner explaining why Content System ID resolution failed and
|
|
5
|
+
* what to run next. Called just before `buildFigmaConfig` throws, so the
|
|
6
|
+
* actionable step is visible above the stack trace.
|
|
7
|
+
*/ export function logMissingContentSystemId(reason) {
|
|
8
|
+
const lines = buildBody(reason);
|
|
9
|
+
p.note(lines.join('\n'), pc.yellow('Figma project not configured'));
|
|
10
|
+
}
|
|
11
|
+
function buildBody(reason) {
|
|
12
|
+
const loginCmd = pc.cyan('npx @payloadcms/figma login');
|
|
13
|
+
const initCmd = pc.cyan('npx @payloadcms/figma init');
|
|
14
|
+
const initForceCmd = pc.cyan('npx @payloadcms/figma init --force');
|
|
15
|
+
if (reason.kind === 'no-config') {
|
|
16
|
+
return [
|
|
17
|
+
'No Figma project configuration found.',
|
|
18
|
+
'',
|
|
19
|
+
`Run ${initCmd} to set up this project.`
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
if (reason.kind === 'unauthenticated') {
|
|
23
|
+
return [
|
|
24
|
+
'Project config found, but you are not logged in.',
|
|
25
|
+
'Cannot fetch bootstrap data without a valid session.',
|
|
26
|
+
'',
|
|
27
|
+
`Run ${loginCmd}, then restart the dev server.`
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
if (reason.kind === 'network') {
|
|
31
|
+
return [
|
|
32
|
+
'Could not reach the Figma API to fetch bootstrap data.',
|
|
33
|
+
`Error: ${reason.message}`,
|
|
34
|
+
'',
|
|
35
|
+
'Check your network, then restart the dev server.'
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
return [
|
|
39
|
+
`Environment ${pc.bold(reason.environmentName)} not found for project ${pc.bold(reason.projectId)}.`,
|
|
40
|
+
'',
|
|
41
|
+
`Run ${initForceCmd} to reconfigure, or set FIGMA_ENVIRONMENT_NAME to a valid environment.`
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=bootstrap-preflight.js.map
|
|
@@ -15,7 +15,11 @@ import { createStorageClient } from '../storage-content-api/client.js';
|
|
|
15
15
|
import { getGenerateSignedURLHandler } from '../storage-content-api/client-uploads/generateSignedURL.js';
|
|
16
16
|
import { contentApiStorageAdapter } from '../storage-content-api/index.js';
|
|
17
17
|
import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
18
|
+
import { getEnvVarSync } from '../utils/env-management.js';
|
|
18
19
|
import * as log from '../utils/log.js';
|
|
20
|
+
import { logMissingCliAuth } from './auth-preflight.js';
|
|
21
|
+
import { logMissingContentSystemId } from './bootstrap-preflight.js';
|
|
22
|
+
import { getDevCookieNames } from './dev-cookie-names.js';
|
|
19
23
|
/**
|
|
20
24
|
* Fields added to users collection for Figma profile info
|
|
21
25
|
*/ const figmaUserFields = [
|
|
@@ -47,20 +51,118 @@ function missingOAuthCredential(name) {
|
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Fetch bootstrap data from the API and cache all environments locally.
|
|
50
|
-
* Returns the requested environment's data, or
|
|
54
|
+
* Returns the requested environment's data, or a typed failure reason.
|
|
51
55
|
*/ async function resolveAndCacheBootstrap(store, projectId, environmentName) {
|
|
56
|
+
let credential;
|
|
57
|
+
try {
|
|
58
|
+
credential = await getValidCredential(store);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
reason: {
|
|
63
|
+
kind: 'network',
|
|
64
|
+
message: messageOf(error)
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (!credential) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
reason: {
|
|
72
|
+
kind: 'unauthenticated'
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
52
76
|
try {
|
|
53
|
-
const credential = await getValidCredential(store);
|
|
54
|
-
if (!credential) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
77
|
const bootstrapInfo = await getBootstrapInfo(credential, projectId);
|
|
58
78
|
cacheAllEnvironments(store, projectId, bootstrapInfo);
|
|
59
|
-
return store.getBootstrapData(projectId, environmentName);
|
|
60
79
|
} catch (error) {
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
reason: {
|
|
83
|
+
kind: 'network',
|
|
84
|
+
message: messageOf(error)
|
|
85
|
+
}
|
|
86
|
+
};
|
|
63
87
|
}
|
|
88
|
+
const data = store.getBootstrapData(projectId, environmentName);
|
|
89
|
+
if (!data) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
reason: {
|
|
93
|
+
environmentName,
|
|
94
|
+
kind: 'environment-not-found',
|
|
95
|
+
projectId
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
data,
|
|
101
|
+
ok: true
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function messageOf(error) {
|
|
105
|
+
return error instanceof Error ? error.message : 'Unknown error';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Creates storage configuration for upload collections
|
|
109
|
+
*/ function createStorageConfig(url, contentSystemId) {
|
|
110
|
+
const storageConfig = process.env.FIGMA_CONTENT_API_ACCESS_KEY ? {
|
|
111
|
+
baseUrl: url,
|
|
112
|
+
contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY
|
|
113
|
+
} : process.env.FIGMA_DEV_JWT === 'true' ? {
|
|
114
|
+
auth: {
|
|
115
|
+
mode: 'devJwt'
|
|
116
|
+
},
|
|
117
|
+
baseUrl: url,
|
|
118
|
+
contentSystemId
|
|
119
|
+
} : {
|
|
120
|
+
auth: {
|
|
121
|
+
mode: 'tokenStore',
|
|
122
|
+
tokenStore: getTokenStore()
|
|
123
|
+
},
|
|
124
|
+
baseUrl: url,
|
|
125
|
+
contentSystemId
|
|
126
|
+
};
|
|
127
|
+
const adapter = contentApiStorageAdapter(storageConfig);
|
|
128
|
+
const storageClient = createStorageClient(storageConfig);
|
|
129
|
+
return {
|
|
130
|
+
adapter,
|
|
131
|
+
storageClient
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Plugin that applies cloud storage configuration to all upload-enabled collections.
|
|
136
|
+
* Runs at the end of the plugin chain so it sees collections added by user plugins too.
|
|
137
|
+
*/ function createStoragePlugin(url, contentSystemId) {
|
|
138
|
+
return (incomingConfig)=>{
|
|
139
|
+
const uploadCollections = (incomingConfig.collections || []).filter((c)=>c.upload);
|
|
140
|
+
if (uploadCollections.length === 0) {
|
|
141
|
+
return incomingConfig;
|
|
142
|
+
}
|
|
143
|
+
const { adapter, storageClient } = createStorageConfig(url, contentSystemId);
|
|
144
|
+
const collectionsMap = uploadCollections.reduce((acc, c)=>{
|
|
145
|
+
acc[c.slug] = {
|
|
146
|
+
adapter,
|
|
147
|
+
disableLocalStorage: true
|
|
148
|
+
};
|
|
149
|
+
return acc;
|
|
150
|
+
}, {});
|
|
151
|
+
initClientUploads({
|
|
152
|
+
clientHandler: '@payloadcms/figma/client#ContentApiClientUploadHandler',
|
|
153
|
+
collections: collectionsMap,
|
|
154
|
+
config: incomingConfig,
|
|
155
|
+
enabled: true,
|
|
156
|
+
serverHandler: getGenerateSignedURLHandler({
|
|
157
|
+
client: storageClient
|
|
158
|
+
}),
|
|
159
|
+
serverHandlerPath: '/content-api-storage-signed-url'
|
|
160
|
+
});
|
|
161
|
+
const storagePlugin = cloudStoragePlugin({
|
|
162
|
+
collections: collectionsMap
|
|
163
|
+
});
|
|
164
|
+
return storagePlugin(incomingConfig);
|
|
165
|
+
};
|
|
64
166
|
}
|
|
65
167
|
export async function buildFigmaConfig(config) {
|
|
66
168
|
const envConfig = getEnvConfig();
|
|
@@ -68,16 +170,27 @@ export async function buildFigmaConfig(config) {
|
|
|
68
170
|
let { contentSystemId } = config.figma;
|
|
69
171
|
contentSystemId ??= process.env.FIGMA_CONTENT_API_CONTENT_SYSTEM_ID;
|
|
70
172
|
let bootstrapData = null;
|
|
173
|
+
let bootstrapReason = null;
|
|
71
174
|
// Local dev: resolve from project ID + bootstrap cache
|
|
175
|
+
// Use getEnvVarSync fallback because Next.js evaluates config before dotenv populates process.env
|
|
72
176
|
if (!contentSystemId) {
|
|
73
|
-
const projectId = process.env.FIGMA_PROJECT_ID;
|
|
74
|
-
const environmentName = process.env.FIGMA_ENVIRONMENT_NAME;
|
|
75
|
-
if (projectId
|
|
177
|
+
const projectId = process.env.FIGMA_PROJECT_ID ?? getEnvVarSync(process.cwd(), 'FIGMA_PROJECT_ID');
|
|
178
|
+
const environmentName = process.env.FIGMA_ENVIRONMENT_NAME ?? getEnvVarSync(process.cwd(), 'FIGMA_ENVIRONMENT_NAME');
|
|
179
|
+
if (!projectId || !environmentName) {
|
|
180
|
+
bootstrapReason = {
|
|
181
|
+
kind: 'no-config'
|
|
182
|
+
};
|
|
183
|
+
} else {
|
|
76
184
|
const store = getTokenStore();
|
|
77
185
|
bootstrapData = store.getBootstrapData(projectId, environmentName);
|
|
78
186
|
// Runtime fallback: fetch from API if not cached (e.g. environment switch without re-init)
|
|
79
187
|
if (!bootstrapData) {
|
|
80
|
-
|
|
188
|
+
const resolution = await resolveAndCacheBootstrap(store, projectId, environmentName);
|
|
189
|
+
if (resolution.ok) {
|
|
190
|
+
bootstrapData = resolution.data;
|
|
191
|
+
} else {
|
|
192
|
+
bootstrapReason = resolution.reason;
|
|
193
|
+
}
|
|
81
194
|
}
|
|
82
195
|
if (bootstrapData) {
|
|
83
196
|
contentSystemId = bootstrapData.contentSystemId;
|
|
@@ -85,10 +198,17 @@ export async function buildFigmaConfig(config) {
|
|
|
85
198
|
}
|
|
86
199
|
}
|
|
87
200
|
if (!contentSystemId) {
|
|
201
|
+
logMissingContentSystemId(bootstrapReason ?? {
|
|
202
|
+
kind: 'no-config'
|
|
203
|
+
});
|
|
88
204
|
throw new Error('Content System ID could not be resolved. ' + 'Run `npx @payloadcms/figma init` to set up your project.');
|
|
89
205
|
}
|
|
90
206
|
const url = process.env.FIGMA_CONTENT_API_URL || envConfig.contentApiUrl;
|
|
91
207
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
208
|
+
const usesTokenStoreAuth = !process.env.FIGMA_CONTENT_API_ACCESS_KEY && process.env.FIGMA_DEV_JWT !== 'true';
|
|
209
|
+
if (usesTokenStoreAuth) {
|
|
210
|
+
logMissingCliAuth(getTokenStore());
|
|
211
|
+
}
|
|
92
212
|
// Determine database adapter based on environment
|
|
93
213
|
let db;
|
|
94
214
|
if (config.figma.useContentSystem === false) {
|
|
@@ -120,50 +240,6 @@ export async function buildFigmaConfig(config) {
|
|
|
120
240
|
url
|
|
121
241
|
});
|
|
122
242
|
}
|
|
123
|
-
// Build storage plugin if there are upload collections and storage is not disabled
|
|
124
|
-
const uploadCollections = (config.collections || []).filter((c)=>c.upload);
|
|
125
|
-
let storagePlugin;
|
|
126
|
-
if (uploadCollections.length > 0 && config.figma.storage !== false) {
|
|
127
|
-
const storageConfig = process.env.FIGMA_CONTENT_API_ACCESS_KEY ? {
|
|
128
|
-
baseUrl: url,
|
|
129
|
-
contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY
|
|
130
|
-
} : process.env.FIGMA_DEV_JWT === 'true' ? {
|
|
131
|
-
auth: {
|
|
132
|
-
mode: 'devJwt'
|
|
133
|
-
},
|
|
134
|
-
baseUrl: url,
|
|
135
|
-
contentSystemId
|
|
136
|
-
} : {
|
|
137
|
-
auth: {
|
|
138
|
-
mode: 'tokenStore',
|
|
139
|
-
tokenStore: getTokenStore()
|
|
140
|
-
},
|
|
141
|
-
baseUrl: url,
|
|
142
|
-
contentSystemId
|
|
143
|
-
};
|
|
144
|
-
const adapter = contentApiStorageAdapter(storageConfig);
|
|
145
|
-
const storageClient = createStorageClient(storageConfig);
|
|
146
|
-
const collectionsMap = uploadCollections.reduce((acc, c)=>{
|
|
147
|
-
acc[c.slug] = {
|
|
148
|
-
adapter,
|
|
149
|
-
disableLocalStorage: true
|
|
150
|
-
};
|
|
151
|
-
return acc;
|
|
152
|
-
}, {});
|
|
153
|
-
initClientUploads({
|
|
154
|
-
clientHandler: '@payloadcms/figma/client#ContentApiClientUploadHandler',
|
|
155
|
-
collections: collectionsMap,
|
|
156
|
-
config: config,
|
|
157
|
-
enabled: true,
|
|
158
|
-
serverHandler: getGenerateSignedURLHandler({
|
|
159
|
-
client: storageClient
|
|
160
|
-
}),
|
|
161
|
-
serverHandlerPath: '/content-api-storage-signed-url'
|
|
162
|
-
});
|
|
163
|
-
storagePlugin = cloudStoragePlugin({
|
|
164
|
-
collections: collectionsMap
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
243
|
// Build complete config with Figma platform defaults
|
|
168
244
|
const configWithFigmaDefaults = {
|
|
169
245
|
...config,
|
|
@@ -197,8 +273,8 @@ export async function buildFigmaConfig(config) {
|
|
|
197
273
|
// Add oauth to plugins if not already present
|
|
198
274
|
plugins: [
|
|
199
275
|
...config.plugins ?? [],
|
|
200
|
-
...
|
|
201
|
-
|
|
276
|
+
...config.figma.storage !== false ? [
|
|
277
|
+
createStoragePlugin(url, contentSystemId)
|
|
202
278
|
] : [],
|
|
203
279
|
oAuth2Plugin({
|
|
204
280
|
collections: [
|
|
@@ -219,6 +295,7 @@ export async function buildFigmaConfig(config) {
|
|
|
219
295
|
usernameField: 'email'
|
|
220
296
|
}
|
|
221
297
|
],
|
|
298
|
+
...isProduction ? {} : getDevCookieNames(contentSystemId),
|
|
222
299
|
debug: !!process.env.DEBUG,
|
|
223
300
|
disabled: false
|
|
224
301
|
}),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespace OAuth cookies per-app in local dev so multiple Payload apps
|
|
3
|
+
* running on localhost (shared cookie jar across ports) don't clobber each
|
|
4
|
+
* other's sessions on logout. Uses projectId so the cookie stays stable when
|
|
5
|
+
* switching environments in the same checkout; falls back to contentSystemId
|
|
6
|
+
* when projectId isn't in `.env`.
|
|
7
|
+
*
|
|
8
|
+
* In production, cookies are isolated by unique hostnames and this is unused.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getDevCookieNames(contentSystemId: string): {
|
|
11
|
+
cookieName: string;
|
|
12
|
+
userInfoCookieName: string;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=dev-cookie-names.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getEnvVarSync } from '../utils/env-management.js';
|
|
2
|
+
/**
|
|
3
|
+
* Namespace OAuth cookies per-app in local dev so multiple Payload apps
|
|
4
|
+
* running on localhost (shared cookie jar across ports) don't clobber each
|
|
5
|
+
* other's sessions on logout. Uses projectId so the cookie stays stable when
|
|
6
|
+
* switching environments in the same checkout; falls back to contentSystemId
|
|
7
|
+
* when projectId isn't in `.env`.
|
|
8
|
+
*
|
|
9
|
+
* In production, cookies are isolated by unique hostnames and this is unused.
|
|
10
|
+
*/ export function getDevCookieNames(contentSystemId) {
|
|
11
|
+
const projectId = process.env.FIGMA_PROJECT_ID ?? getEnvVarSync(process.cwd(), 'FIGMA_PROJECT_ID') ?? contentSystemId;
|
|
12
|
+
const suffix = projectId.slice(0, 8);
|
|
13
|
+
return {
|
|
14
|
+
cookieName: `figma-${suffix}-oauth-token`,
|
|
15
|
+
userInfoCookieName: `figma-${suffix}-user-info`
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=dev-cookie-names.js.map
|
|
@@ -18,7 +18,10 @@ function createStorageAuthMiddleware(config) {
|
|
|
18
18
|
if (auth.mode === 'apiKey') {
|
|
19
19
|
request.headers.set('X-Api-Key', auth.apiKey);
|
|
20
20
|
} else if (auth.mode === 'tokenStore') {
|
|
21
|
-
const token = await getValidProjectToken(
|
|
21
|
+
const token = await getValidProjectToken({
|
|
22
|
+
tenantId: contentSystemId,
|
|
23
|
+
tokenStore: auth.tokenStore
|
|
24
|
+
});
|
|
22
25
|
if (!token) {
|
|
23
26
|
throw new Error('Authentication required. Run `npx @payloadcms/figma login` to authenticate.');
|
|
24
27
|
}
|
package/dist/utils/messages.js
CHANGED
|
@@ -14,6 +14,7 @@ export function helpMessage() {
|
|
|
14
14
|
${pc.cyan('logout')} Clear all stored tokens
|
|
15
15
|
${pc.cyan('list-tokens')} Show stored token information
|
|
16
16
|
${pc.cyan('init')} Initialize a Figma CMS project
|
|
17
|
+
${pc.cyan('bootstrap')} Print bootstrap info (tenant IDs, OAuth creds) for a project
|
|
17
18
|
${pc.cyan('debug')} Show debug info for troubleshooting
|
|
18
19
|
${pc.cyan('env')} Switch active environment
|
|
19
20
|
${pc.cyan('deploy')} Deploy your project to Figma
|
|
@@ -39,6 +40,12 @@ export function helpMessage() {
|
|
|
39
40
|
${pc.dim('--name, -n <name>')} Set project directory name (skips prompt)
|
|
40
41
|
${pc.dim('--force')} Force reconfiguration of existing project
|
|
41
42
|
|
|
43
|
+
${pc.bold('BOOTSTRAP COMMAND')}
|
|
44
|
+
|
|
45
|
+
${pc.cyan('@payloadcms/figma bootstrap --id <cms-resource-id>')} Print bootstrap info
|
|
46
|
+
${pc.dim('--env <environment>')} Filter to a single environment
|
|
47
|
+
${pc.dim('--json')} Output JSON instead of styled note
|
|
48
|
+
|
|
42
49
|
${pc.bold('ENV COMMAND')}
|
|
43
50
|
|
|
44
51
|
${pc.cyan('@payloadcms/figma env')} List and switch environments
|