@payloadcms/figma 0.0.1-alpha.57 → 0.0.1-alpha.59
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 +8 -7
- package/dist/api/control-plane.js +16 -23
- package/dist/api/figma-api.d.ts +3 -2
- package/dist/api/figma-api.js +6 -9
- package/dist/auth/credentials.d.ts +21 -0
- package/dist/auth/credentials.js +21 -0
- package/dist/auth/oauth-flow.d.ts +13 -4
- package/dist/auth/oauth-flow.js +34 -8
- package/dist/auth/project-token.js +5 -5
- package/dist/cli.js +5 -0
- package/dist/commands/deploy.d.ts +3 -0
- package/dist/commands/deploy.js +67 -37
- package/dist/commands/env.js +4 -4
- package/dist/commands/init.js +10 -25
- package/dist/commands/login.js +3 -3
- package/dist/commands/upgrade.js +11 -11
- package/dist/db-content-api/index.js +48 -11
- package/dist/db-content-api/temp-utilities/sorting.d.ts +1 -1
- package/dist/db-content-api/temp-utilities/sorting.js +4 -1
- package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +7 -2
- package/dist/db-content-api/temp-utilities/unwrapDocument.js +11 -5
- package/dist/db-content-api/utilities/data/castFieldValue.js +11 -12
- package/dist/db-content-api/utilities/data/index.d.ts +1 -1
- package/dist/db-content-api/utilities/data/index.js +45 -20
- package/dist/db-content-api/utilities/joins.js +10 -4
- package/dist/db-content-api/utilities/meta/buildLocalizedPaths.js +14 -6
- package/dist/db-content-api/utilities/meta/buildPathTypes.js +19 -2
- package/dist/db-content-api/utilities/where.js +15 -45
- package/dist/oauth/endpoints/getLoginEndpoint.js +10 -2
- package/dist/oauth/utilities/refreshTokens.js +4 -1
- package/dist/plugin/build-config.js +4 -4
- package/dist/utils/adapters/nextjs.d.ts +9 -0
- package/dist/utils/adapters/nextjs.js +59 -0
- package/dist/utils/adapters/nitro.d.ts +9 -0
- package/dist/utils/adapters/nitro.js +164 -0
- package/dist/utils/adapters/vite.d.ts +10 -0
- package/dist/utils/adapters/vite.js +32 -0
- package/dist/utils/asset-collection.d.ts +24 -0
- package/dist/utils/asset-collection.js +53 -0
- package/dist/utils/build-detection.d.ts +5 -11
- package/dist/utils/build-detection.js +74 -11
- package/dist/utils/deploy-adapter.d.ts +38 -0
- package/dist/utils/deploy-adapter.js +58 -0
- package/dist/utils/download-template.js +3 -2
- package/dist/utils/fs-utils.d.ts +6 -0
- package/dist/utils/fs-utils.js +27 -0
- package/dist/utils/s3-upload.d.ts +7 -1
- package/dist/utils/s3-upload.js +4 -3
- package/package.json +1 -1
package/dist/commands/deploy.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import spawn from 'cross-spawn';
|
|
3
|
-
import path from 'path';
|
|
4
3
|
import pc from 'picocolors';
|
|
5
4
|
import { ControlPlaneError, createDeployment, getBootstrapInfo, performDeployment } from '../api/control-plane.js';
|
|
6
|
-
import {
|
|
5
|
+
import { tryGetCredential } from '../auth/oauth-flow.js';
|
|
7
6
|
import { getTokenStore } from '../auth/token-store.js';
|
|
8
7
|
import { getInfraEnvironment, getProjectNotFoundMessage } from '../constants.js';
|
|
9
|
-
import {
|
|
8
|
+
import { getFileSize } from '../utils/asset-collection.js';
|
|
10
9
|
import { detectBuild, getBuildCommand } from '../utils/build-detection.js';
|
|
10
|
+
import { detectAdapter } from '../utils/deploy-adapter.js';
|
|
11
11
|
import { getEnvVar } from '../utils/env-management.js';
|
|
12
12
|
import * as log from '../utils/log.js';
|
|
13
13
|
import { getPackageManager } from '../utils/package-manager.js';
|
|
@@ -71,12 +71,12 @@ import { loginCommand } from './login.js';
|
|
|
71
71
|
}
|
|
72
72
|
// Check authentication
|
|
73
73
|
const tokenStore = getTokenStore();
|
|
74
|
-
let
|
|
75
|
-
if (!
|
|
74
|
+
let credential = await tryGetCredential(tokenStore);
|
|
75
|
+
if (!credential) {
|
|
76
76
|
p.log.message('Please log in to continue');
|
|
77
77
|
await loginCommand();
|
|
78
|
-
|
|
79
|
-
if (!
|
|
78
|
+
credential = await tryGetCredential(tokenStore);
|
|
79
|
+
if (!credential) {
|
|
80
80
|
p.log.error(pc.red('✗ Authentication failed'));
|
|
81
81
|
process.exit(1);
|
|
82
82
|
}
|
|
@@ -85,7 +85,7 @@ import { loginCommand } from './login.js';
|
|
|
85
85
|
spinner.start('Resolving deployment target...');
|
|
86
86
|
let tenantInstanceId;
|
|
87
87
|
try {
|
|
88
|
-
const bootstrapInfo = await getBootstrapInfo(
|
|
88
|
+
const bootstrapInfo = await getBootstrapInfo(credential, projectId);
|
|
89
89
|
const resolvedEnv = resolveEnvironment({
|
|
90
90
|
environmentName,
|
|
91
91
|
environments: bootstrapInfo.environments
|
|
@@ -183,68 +183,98 @@ import { loginCommand } from './login.js';
|
|
|
183
183
|
// Verify build output
|
|
184
184
|
buildInfo = await detectBuild(projectPath);
|
|
185
185
|
if (!buildInfo) {
|
|
186
|
-
p.log.error(pc.red('✗ Build completed but
|
|
187
|
-
p.note('Ensure
|
|
186
|
+
p.log.error(pc.red('✗ Build completed but build output not found'));
|
|
187
|
+
p.note('Ensure your build produces a valid output directory.', 'Check Build Configuration');
|
|
188
188
|
process.exit(1);
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
// ===== DEPLOYMENT PREPARATION =====
|
|
192
|
-
//
|
|
192
|
+
// Detect framework adapter
|
|
193
|
+
spinner.start('Detecting framework...');
|
|
194
|
+
const adapter = await detectAdapter(projectPath, options.adapter);
|
|
195
|
+
spinner.stop(pc.green(`✓ Detected ${adapter.name} adapter`));
|
|
196
|
+
// Collect pages and assets
|
|
197
|
+
spinner.start('Collecting assets...');
|
|
198
|
+
const pages = await adapter.collectPages(projectPath);
|
|
199
|
+
const assets = await adapter.collectAssets(projectPath);
|
|
200
|
+
const allAssetKeys = [
|
|
201
|
+
...pages.uploadKeys,
|
|
202
|
+
...assets.uploadKeys
|
|
203
|
+
];
|
|
204
|
+
const combinedPathMap = {
|
|
205
|
+
...pages.pathMap,
|
|
206
|
+
...assets.pathMap
|
|
207
|
+
};
|
|
208
|
+
spinner.stop(pc.green(`✓ ${pages.routes.length} pages, ${assets.routes.length} assets detected`));
|
|
209
|
+
// Create deployment package (if server adapter)
|
|
210
|
+
let zipPath = null;
|
|
211
|
+
let zipSize = 0;
|
|
193
212
|
spinner.start('Creating deployment package...');
|
|
194
213
|
try {
|
|
195
|
-
await
|
|
196
|
-
|
|
214
|
+
zipPath = await adapter.prepareLambdaBundle(projectPath);
|
|
215
|
+
if (zipPath) {
|
|
216
|
+
zipSize = await getFileSize(zipPath);
|
|
217
|
+
spinner.stop(pc.green(`✓ Deployment package created (${formatBytes(zipSize)})`));
|
|
218
|
+
} else {
|
|
219
|
+
spinner.stop(pc.green('✓ Static site — no server package needed'));
|
|
220
|
+
}
|
|
197
221
|
} catch (error) {
|
|
198
222
|
spinner.stop(pc.red('✗ Failed to create deployment package'));
|
|
199
223
|
throw error;
|
|
200
224
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
log.debug(`Lambda zip size: ${formatBytes(zipSize)}`);
|
|
208
|
-
log.debug(`Static assets: ${staticAssets.length} files`);
|
|
225
|
+
log.debug(`Adapter: ${adapter.name}`);
|
|
226
|
+
if (zipPath) {
|
|
227
|
+
log.debug(`Lambda zip size: ${formatBytes(zipSize)}`);
|
|
228
|
+
}
|
|
229
|
+
log.debug(`Pages: ${pages.routes.length} routes`);
|
|
230
|
+
log.debug(`Assets: ${assets.routes.length} files`);
|
|
209
231
|
// ===== DEPLOYMENT CONFIRMATION =====
|
|
210
232
|
if (!options.yes) {
|
|
211
233
|
p.note([
|
|
234
|
+
`${pc.cyan('Adapter:')} ${adapter.name}`,
|
|
212
235
|
`${pc.cyan('Build ID:')} ${buildInfo.buildId}`,
|
|
213
|
-
`${pc.cyan('
|
|
214
|
-
`${pc.cyan('
|
|
215
|
-
`${pc.cyan('
|
|
236
|
+
zipPath ? `${pc.cyan('Code size:')} ${formatBytes(zipSize)}` : `${pc.cyan('Code:')} No server`,
|
|
237
|
+
`${pc.cyan('Pages:')} ${pages.routes.length} routes`,
|
|
238
|
+
`${pc.cyan('Assets:')} ${assets.routes.length} files`
|
|
216
239
|
].join('\n'), 'Details');
|
|
217
240
|
}
|
|
218
241
|
// ===== DEPLOYMENT EXECUTION =====
|
|
219
242
|
// Step 1: Create deployment
|
|
220
243
|
spinner.start('Creating deployment...');
|
|
221
|
-
const createResponse = await createDeployment(
|
|
222
|
-
staticAssets
|
|
244
|
+
const createResponse = await createDeployment(credential, tenantInstanceId, {
|
|
245
|
+
staticAssets: allAssetKeys
|
|
223
246
|
});
|
|
224
247
|
const deploymentId = createResponse.deploymentId;
|
|
225
248
|
const codeUploadUrl = createResponse.codeUploadUrl;
|
|
226
249
|
const staticAssetUploadUrls = createResponse.staticAssetUploadUrls;
|
|
227
250
|
log.debug(`Deployment ID: ${deploymentId}`);
|
|
228
|
-
// Step 2: Upload code
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
251
|
+
// Step 2: Upload code (skip for static sites)
|
|
252
|
+
if (zipPath) {
|
|
253
|
+
spinner.message(`Uploading code (${formatBytes(zipSize)})...`);
|
|
254
|
+
await uploadLambdaZip(zipPath, codeUploadUrl);
|
|
255
|
+
spinner.stop(pc.green(`✓ Code uploaded (${formatBytes(zipSize)})`));
|
|
256
|
+
}
|
|
232
257
|
// Step 3: Upload static assets
|
|
233
|
-
if (
|
|
234
|
-
spinner.start('Uploading
|
|
235
|
-
const uploadResults = await uploadStaticAssets(
|
|
236
|
-
|
|
258
|
+
if (allAssetKeys.length > 0) {
|
|
259
|
+
spinner.start('Uploading assets...');
|
|
260
|
+
const uploadResults = await uploadStaticAssets({
|
|
261
|
+
assetUrls: staticAssetUploadUrls,
|
|
262
|
+
onProgress: (uploaded, total)=>{
|
|
263
|
+
spinner.message(`Uploading assets (${uploaded}/${total})...`);
|
|
264
|
+
},
|
|
265
|
+
pathMap: combinedPathMap,
|
|
266
|
+
projectPath
|
|
237
267
|
});
|
|
238
268
|
if (uploadResults.assetsFailed > 0) {
|
|
239
|
-
spinner.stop(pc.yellow(`⚠ ${uploadResults.assetsUploaded}/${
|
|
269
|
+
spinner.stop(pc.yellow(`⚠ ${uploadResults.assetsUploaded}/${allAssetKeys.length} assets uploaded (${uploadResults.assetsFailed} failed)`));
|
|
240
270
|
p.log.warning(`${uploadResults.assetsFailed} assets failed to upload. Deployment may be incomplete.`);
|
|
241
271
|
} else {
|
|
242
|
-
spinner.stop(pc.green(`✓
|
|
272
|
+
spinner.stop(pc.green(`✓ Assets uploaded (${uploadResults.assetsUploaded} files, ${formatBytes(uploadResults.totalBytesUploaded)})`));
|
|
243
273
|
}
|
|
244
274
|
}
|
|
245
275
|
// Step 4: Perform deployment
|
|
246
276
|
spinner.start('Performing deployment...');
|
|
247
|
-
const result = await performDeployment(
|
|
277
|
+
const result = await performDeployment(credential, tenantInstanceId, {
|
|
248
278
|
deploymentId
|
|
249
279
|
});
|
|
250
280
|
const tenantDomains = result.tenantDomains ?? [];
|
package/dist/commands/env.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import { getBootstrapInfo } from '../api/control-plane.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getValidCredential } from '../auth/oauth-flow.js';
|
|
5
5
|
import { getTokenStore } from '../auth/token-store.js';
|
|
6
6
|
import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
7
7
|
import { addOrUpdateEnvVar, getEnvVar } from '../utils/env-management.js';
|
|
@@ -22,8 +22,8 @@ import * as log from '../utils/log.js';
|
|
|
22
22
|
const currentEnv = await getEnvVar(cwd, 'FIGMA_ENVIRONMENT_NAME');
|
|
23
23
|
// Authenticate
|
|
24
24
|
const tokenStore = getTokenStore();
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
25
|
+
const credential = await getValidCredential(tokenStore);
|
|
26
|
+
if (!credential) {
|
|
27
27
|
p.log.error(pc.red('Not authenticated. Run `@payloadcms/figma login` first.'));
|
|
28
28
|
process.exit(1);
|
|
29
29
|
}
|
|
@@ -32,7 +32,7 @@ import * as log from '../utils/log.js';
|
|
|
32
32
|
spinner.start('Fetching environments...');
|
|
33
33
|
let environments;
|
|
34
34
|
try {
|
|
35
|
-
const bootstrapInfo = await getBootstrapInfo(
|
|
35
|
+
const bootstrapInfo = await getBootstrapInfo(credential, projectId);
|
|
36
36
|
environments = bootstrapInfo.environments;
|
|
37
37
|
cacheAllEnvironments(tokenStore, projectId, bootstrapInfo);
|
|
38
38
|
} catch (error) {
|
package/dist/commands/init.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'path';
|
|
|
4
4
|
import pc from 'picocolors';
|
|
5
5
|
import { ControlPlaneError, getBootstrapInfo } from '../api/control-plane.js';
|
|
6
6
|
import { FigmaApiError } from '../api/figma-api.js';
|
|
7
|
-
import {
|
|
7
|
+
import { tryGetCredential } from '../auth/oauth-flow.js';
|
|
8
8
|
import { getValidProjectToken, ProjectTokenError } from '../auth/project-token.js';
|
|
9
9
|
import { getTokenStore } from '../auth/token-store.js';
|
|
10
10
|
import { getInfraEnvironment, getProjectNotFoundMessage } from '../constants.js';
|
|
@@ -81,14 +81,14 @@ import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
|
81
81
|
if (!tokenStore.hasValidTokens()) {
|
|
82
82
|
// Need to refresh or authenticate - show spinner for API call
|
|
83
83
|
s.start('Checking authentication...');
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
84
|
+
const credential = await tryGetCredential(tokenStore);
|
|
85
|
+
if (!credential) {
|
|
86
86
|
s.stop('Authentication required to continue');
|
|
87
87
|
await loginCommand({
|
|
88
88
|
showNextSteps: false
|
|
89
89
|
});
|
|
90
|
-
const
|
|
91
|
-
if (!
|
|
90
|
+
const newCredential = await tryGetCredential(tokenStore);
|
|
91
|
+
if (!newCredential) {
|
|
92
92
|
p.log.error('Authentication failed');
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
@@ -113,10 +113,10 @@ import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
|
113
113
|
let oauthClientId = null;
|
|
114
114
|
let oauthClientSecret = null;
|
|
115
115
|
if (!options.skipAuth) {
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
116
|
+
const credential = await tryGetCredential(tokenStore);
|
|
117
|
+
if (credential) {
|
|
118
118
|
try {
|
|
119
|
-
bootstrapInfo = await getBootstrapInfo(
|
|
119
|
+
bootstrapInfo = await getBootstrapInfo(credential, cmsResourceId);
|
|
120
120
|
} catch (error) {
|
|
121
121
|
log.debug(`Control Plane Error: ${error.statusCode} - ${error.message}`);
|
|
122
122
|
if (error instanceof ControlPlaneError && (error.statusCode === 404 || error.statusCode === 410)) {
|
|
@@ -217,23 +217,8 @@ import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
|
217
217
|
p.log.warn(pc.yellow(`⚠ Failed to update .env file: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
218
218
|
}
|
|
219
219
|
} else {
|
|
220
|
-
|
|
221
|
-
p.
|
|
222
|
-
const shouldAddPayload = await p.confirm({
|
|
223
|
-
initialValue: true,
|
|
224
|
-
message: 'Would you like to add Payload to this project?'
|
|
225
|
-
});
|
|
226
|
-
if (p.isCancel(shouldAddPayload)) {
|
|
227
|
-
p.cancel('Operation cancelled');
|
|
228
|
-
process.exit(0);
|
|
229
|
-
}
|
|
230
|
-
if (!shouldAddPayload) {
|
|
231
|
-
p.log.error('Payload is required to use Figma CMS');
|
|
232
|
-
process.exit(1);
|
|
233
|
-
}
|
|
234
|
-
// TODO: Add Payload to existing project (future enhancement)
|
|
235
|
-
p.log.error('Adding Payload to existing projects is not yet supported');
|
|
236
|
-
p.note('Create a new project or manually add Payload dependencies', 'Action Required');
|
|
220
|
+
p.log.warn(pc.yellow('⚠ Payload was not detected in this project'));
|
|
221
|
+
p.note('Run this command in a directory without an existing project or in an existing Payload project.', 'Action Required');
|
|
237
222
|
process.exit(1);
|
|
238
223
|
}
|
|
239
224
|
// Generate import map to prevent errors on first dev run
|
package/dist/commands/login.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import { CallbackError } from '../auth/callback-server.js';
|
|
4
|
-
import { executeOAuthFlow,
|
|
4
|
+
import { executeOAuthFlow, getValidCredential, OAuthFlowError } from '../auth/oauth-flow.js';
|
|
5
5
|
import { getTokenStore } from '../auth/token-store.js';
|
|
6
6
|
import { getOAuthConfig } from '../config/oauth.js';
|
|
7
7
|
import { getInfraEnvironment } from '../constants.js';
|
|
@@ -20,8 +20,8 @@ import * as log from '../utils/log.js';
|
|
|
20
20
|
const tokenStore = getTokenStore(env);
|
|
21
21
|
// Check for existing valid tokens
|
|
22
22
|
try {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
23
|
+
const existingCredential = await getValidCredential(tokenStore);
|
|
24
|
+
if (existingCredential) {
|
|
25
25
|
const tokens = tokenStore.getTokens();
|
|
26
26
|
p.log.warn(pc.yellow(`Already logged in${formatEnvSuffix(env)}`));
|
|
27
27
|
if (tokens?.userId) {
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -5,7 +5,7 @@ import pc from 'picocolors';
|
|
|
5
5
|
import { Project } from 'ts-morph';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { getBootstrapInfo, getCmsResourceId } from '../api/control-plane.js';
|
|
8
|
-
import {
|
|
8
|
+
import { getValidCredential } from '../auth/oauth-flow.js';
|
|
9
9
|
import { getTokenStore } from '../auth/token-store.js';
|
|
10
10
|
import { cacheAllEnvironments } from '../utils/cache-bootstrap.js';
|
|
11
11
|
import { addOrUpdateEnvVar, getEnvVar, removeEnvVar } from '../utils/env-management.js';
|
|
@@ -110,16 +110,16 @@ async function migrateProjectId({ changes, cwd, isDryRun, warnings = [] }) {
|
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
const store = getTokenStore();
|
|
113
|
-
const
|
|
114
|
-
if (!
|
|
113
|
+
const credential = await getValidCredential(store);
|
|
114
|
+
if (!credential) {
|
|
115
115
|
warnings.push('Not authenticated — could not resolve FIGMA_PROJECT_ID. Run `npx @payloadcms/figma login` first.');
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
|
-
const cmsResourceId = await getCmsResourceId(
|
|
118
|
+
const cmsResourceId = await getCmsResourceId(credential, oldContentSystemId);
|
|
119
119
|
await addOrUpdateEnvVar(cwd, 'FIGMA_PROJECT_ID', cmsResourceId);
|
|
120
120
|
// Resolve actual environment name from bootstrap API
|
|
121
121
|
try {
|
|
122
|
-
const bootstrapInfo = await getBootstrapInfo(
|
|
122
|
+
const bootstrapInfo = await getBootstrapInfo(credential, cmsResourceId);
|
|
123
123
|
cacheAllEnvironments(store, cmsResourceId, bootstrapInfo);
|
|
124
124
|
const envName = bootstrapInfo.environments[0]?.name ?? 'production';
|
|
125
125
|
await addOrUpdateEnvVar(cwd, 'FIGMA_ENVIRONMENT_NAME', envName);
|
|
@@ -144,11 +144,11 @@ async function ensureBootstrapCached(params) {
|
|
|
144
144
|
if (store.getBootstrapData(projectId, environmentName)) {
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
const
|
|
148
|
-
if (!
|
|
147
|
+
const credential = await getValidCredential(store);
|
|
148
|
+
if (!credential) {
|
|
149
149
|
return;
|
|
150
150
|
}
|
|
151
|
-
const bootstrapInfo = await getBootstrapInfo(
|
|
151
|
+
const bootstrapInfo = await getBootstrapInfo(credential, projectId);
|
|
152
152
|
cacheAllEnvironments(store, projectId, bootstrapInfo);
|
|
153
153
|
// Fix FIGMA_ENVIRONMENT_NAME if it doesn't match any actual environment
|
|
154
154
|
const envNames = bootstrapInfo.environments.map((e)=>e.name);
|
|
@@ -190,10 +190,10 @@ async function migrateRemoveDeprecatedEnvVars({ changes, cwd, isDryRun, warnings
|
|
|
190
190
|
const bootstrapData = store.getBootstrapData(projectId, environmentName);
|
|
191
191
|
if (!bootstrapData) {
|
|
192
192
|
// Try fetching from API
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
193
|
+
const credential = await getValidCredential(store);
|
|
194
|
+
if (credential) {
|
|
195
195
|
try {
|
|
196
|
-
const bootstrapInfo = await getBootstrapInfo(
|
|
196
|
+
const bootstrapInfo = await getBootstrapInfo(credential, projectId);
|
|
197
197
|
cacheAllEnvironments(store, projectId, bootstrapInfo);
|
|
198
198
|
} catch {
|
|
199
199
|
warnings.push('Could not verify bootstrap data — keeping deprecated env vars. Run `npx @payloadcms/figma init` to complete migration.');
|
|
@@ -116,7 +116,7 @@ async function findMany({ collection, joins, limit, locale: localeArg, page, pag
|
|
|
116
116
|
if (!response) {
|
|
117
117
|
throw new Error('No response from findMany');
|
|
118
118
|
}
|
|
119
|
-
return unwrapFindResponse(this.payload, response.result, collection);
|
|
119
|
+
return unwrapFindResponse(this.payload, response.result, collection, localeArg);
|
|
120
120
|
}
|
|
121
121
|
async function find(args) {
|
|
122
122
|
const collectionConfig = this.payload.config.collections.find((c)=>c.slug === args.collection);
|
|
@@ -124,8 +124,11 @@ async function find(args) {
|
|
|
124
124
|
collection: args.collection,
|
|
125
125
|
joins: args.joins,
|
|
126
126
|
// TODO: FindArgs.limit should be 'number' not 'number | undefined'
|
|
127
|
-
//
|
|
128
|
-
|
|
127
|
+
// Payload Core sanitizes limit before calling the adapter when going through findOperation
|
|
128
|
+
// (defaults to 10 or 0 based on pagination), but some callers (e.g. deleteOperation) call
|
|
129
|
+
// db.find() directly without a limit. Default to 0 (unlimited) to avoid the Content API
|
|
130
|
+
// falling back to its own default of 10.
|
|
131
|
+
limit: args.limit ?? 0,
|
|
129
132
|
locale: args.locale,
|
|
130
133
|
page: args.page ?? 1,
|
|
131
134
|
pagination: args.pagination,
|
|
@@ -165,7 +168,7 @@ async function findVersions(args) {
|
|
|
165
168
|
if (!response) {
|
|
166
169
|
throw new Error('No response from findVersions');
|
|
167
170
|
}
|
|
168
|
-
return unwrapFindResponse(this.payload, response.result, args.collection);
|
|
171
|
+
return unwrapFindResponse(this.payload, response.result, args.collection, args.locale);
|
|
169
172
|
}
|
|
170
173
|
async function queryDrafts(args) {
|
|
171
174
|
const versionsResult = await this.findVersions({
|
|
@@ -216,7 +219,11 @@ async function createVersion(args) {
|
|
|
216
219
|
if (!response) {
|
|
217
220
|
throw new Error('No response from createVersion');
|
|
218
221
|
}
|
|
219
|
-
return unwrapDocument(
|
|
222
|
+
return unwrapDocument({
|
|
223
|
+
collectionSlug: args.collectionSlug,
|
|
224
|
+
doc: response.result,
|
|
225
|
+
payload: this.payload
|
|
226
|
+
});
|
|
220
227
|
}
|
|
221
228
|
async function updateVersion(args) {
|
|
222
229
|
const where = args.where ?? {
|
|
@@ -262,7 +269,12 @@ async function updateVersion(args) {
|
|
|
262
269
|
if (!doc) {
|
|
263
270
|
return null;
|
|
264
271
|
}
|
|
265
|
-
return unwrapDocument(
|
|
272
|
+
return unwrapDocument({
|
|
273
|
+
collectionSlug: args.collection,
|
|
274
|
+
doc,
|
|
275
|
+
locale: args.locale,
|
|
276
|
+
payload: this.payload
|
|
277
|
+
});
|
|
266
278
|
}
|
|
267
279
|
async function deleteVersions(args) {
|
|
268
280
|
if (!args.collection) {
|
|
@@ -357,7 +369,12 @@ async function updateMany(args) {
|
|
|
357
369
|
throw new Error('No response from updateMany');
|
|
358
370
|
}
|
|
359
371
|
if (response.result && 'data' in response.result) {
|
|
360
|
-
return response.result.data.map((doc)=>unwrapDocument(
|
|
372
|
+
return response.result.data.map((doc)=>unwrapDocument({
|
|
373
|
+
collectionSlug: args.collection,
|
|
374
|
+
doc,
|
|
375
|
+
locale: args.locale,
|
|
376
|
+
payload: this.payload
|
|
377
|
+
}));
|
|
361
378
|
}
|
|
362
379
|
return null;
|
|
363
380
|
}
|
|
@@ -397,7 +414,12 @@ async function updateOne(args) {
|
|
|
397
414
|
if (!doc) {
|
|
398
415
|
return null;
|
|
399
416
|
}
|
|
400
|
-
return unwrapDocument(
|
|
417
|
+
return unwrapDocument({
|
|
418
|
+
collectionSlug: args.collection,
|
|
419
|
+
doc,
|
|
420
|
+
locale: args.locale,
|
|
421
|
+
payload: this.payload
|
|
422
|
+
});
|
|
401
423
|
}
|
|
402
424
|
async function deleteMany(args) {
|
|
403
425
|
const locale = addFallbackLocale(args.req?.locale, this.payload);
|
|
@@ -444,7 +466,12 @@ async function deleteOne(args) {
|
|
|
444
466
|
if (!doc) {
|
|
445
467
|
return null;
|
|
446
468
|
}
|
|
447
|
-
return unwrapDocument(
|
|
469
|
+
return unwrapDocument({
|
|
470
|
+
collectionSlug: args.collection,
|
|
471
|
+
doc,
|
|
472
|
+
locale: args.req?.locale === null ? undefined : args.req?.locale,
|
|
473
|
+
payload: this.payload
|
|
474
|
+
});
|
|
448
475
|
}
|
|
449
476
|
async function create(args) {
|
|
450
477
|
const isGlobalCollection = args.collection.startsWith('_global-');
|
|
@@ -487,7 +514,12 @@ async function create(args) {
|
|
|
487
514
|
if (!response) {
|
|
488
515
|
throw new Error('No response from create');
|
|
489
516
|
}
|
|
490
|
-
return unwrapDocument(
|
|
517
|
+
return unwrapDocument({
|
|
518
|
+
collectionSlug: args.collection,
|
|
519
|
+
doc: response.result,
|
|
520
|
+
locale: args.locale,
|
|
521
|
+
payload: this.payload
|
|
522
|
+
});
|
|
491
523
|
}
|
|
492
524
|
async function clearDatabase() {
|
|
493
525
|
this.payload.logger.info(`---- CLEARING CONTENT API DATABASE ----`);
|
|
@@ -604,7 +636,12 @@ async function upsert(args) {
|
|
|
604
636
|
if (!doc) {
|
|
605
637
|
throw new Error('No document data in upsert response');
|
|
606
638
|
}
|
|
607
|
-
return unwrapDocument(
|
|
639
|
+
return unwrapDocument({
|
|
640
|
+
collectionSlug: args.collection,
|
|
641
|
+
doc,
|
|
642
|
+
locale: args.locale,
|
|
643
|
+
payload: this.payload
|
|
644
|
+
});
|
|
608
645
|
}
|
|
609
646
|
function createGlobal(args) {
|
|
610
647
|
return this.create({
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Payload } from 'payload';
|
|
2
|
-
export declare function addFallbackSort(sort: string | string[] | undefined, payload: Payload, collectionSlug: string): string | string[] | undefined;
|
|
2
|
+
export declare function addFallbackSort(sort: string | string[] | undefined, payload: Payload, collectionSlug: string, defaultSort?: string | string[]): string | string[] | undefined;
|
|
3
3
|
//# sourceMappingURL=sorting.d.ts.map
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Add fallback sort to ensure consistent ordering when sorting by non-unique fields
|
|
2
2
|
// Matches MongoDB adapter behavior
|
|
3
3
|
// TO-DECIDE: Should this live here or in content-api?
|
|
4
|
-
export function addFallbackSort(sort, payload, collectionSlug) {
|
|
4
|
+
export function addFallbackSort(sort, payload, collectionSlug, defaultSort) {
|
|
5
5
|
const collectionConfig = payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
6
6
|
if (!sort || !collectionConfig) {
|
|
7
|
+
if (defaultSort) {
|
|
8
|
+
return addFallbackSort(defaultSort, payload, collectionSlug);
|
|
9
|
+
}
|
|
7
10
|
return sort;
|
|
8
11
|
}
|
|
9
12
|
const sortArray = Array.isArray(sort) ? sort : [
|
|
@@ -6,8 +6,13 @@ type DocumentResponse = {
|
|
|
6
6
|
type DocumentVersionResponse = {
|
|
7
7
|
id: string;
|
|
8
8
|
} & components['schemas']['DocumentVersion'];
|
|
9
|
-
export declare function unwrapDocument(
|
|
10
|
-
|
|
9
|
+
export declare function unwrapDocument(args: {
|
|
10
|
+
collectionSlug?: string;
|
|
11
|
+
doc: DocumentResponse | DocumentVersionResponse;
|
|
12
|
+
locale?: string;
|
|
13
|
+
payload: Payload;
|
|
14
|
+
}): Record<string, unknown>;
|
|
15
|
+
export declare const unwrapFindResponse: (payload: Payload, response: components["schemas"]["FindDocumentsResponse"]["result"] | components["schemas"]["FindDocumentVersionsResponse"]["result"], collection: string, locale?: string) => {
|
|
11
16
|
totalDocs: number;
|
|
12
17
|
limit: number;
|
|
13
18
|
page: number;
|
|
@@ -6,7 +6,8 @@ import { dataFromContentAPI } from '../utilities/data/index.js';
|
|
|
6
6
|
// Payload expects:
|
|
7
7
|
// - For documents: { id, ...fields, createdAt, updatedAt }
|
|
8
8
|
// - For versions: { id, parent, latest, version: { ...fields }, createdAt, updatedAt }
|
|
9
|
-
export function unwrapDocument(
|
|
9
|
+
export function unwrapDocument(args) {
|
|
10
|
+
const { collectionSlug, doc, locale, payload } = args;
|
|
10
11
|
if (!doc) {
|
|
11
12
|
return doc;
|
|
12
13
|
}
|
|
@@ -21,7 +22,7 @@ export function unwrapDocument(payload, doc, collectionSlug) {
|
|
|
21
22
|
// Transform data from Content API format to Payload format
|
|
22
23
|
if (collectionSlug) {
|
|
23
24
|
// Only transform the nested 'version' field
|
|
24
|
-
baseDoc.version = dataFromContentAPI(payload, collectionSlug, baseDoc.version);
|
|
25
|
+
baseDoc.version = dataFromContentAPI(payload, collectionSlug, baseDoc.version, locale);
|
|
25
26
|
// Also convert version ID if collection uses numeric custom ID
|
|
26
27
|
const customIDType = payload.collections?.[collectionSlug]?.customIDType;
|
|
27
28
|
if (customIDType === 'number') {
|
|
@@ -38,14 +39,19 @@ export function unwrapDocument(payload, doc, collectionSlug) {
|
|
|
38
39
|
};
|
|
39
40
|
// Transform data from Content API format to Payload format
|
|
40
41
|
if (collectionSlug) {
|
|
41
|
-
return dataFromContentAPI(payload, collectionSlug, baseDoc);
|
|
42
|
+
return dataFromContentAPI(payload, collectionSlug, baseDoc, locale);
|
|
42
43
|
}
|
|
43
44
|
return baseDoc;
|
|
44
45
|
}
|
|
45
|
-
export const unwrapFindResponse = (payload, response, collection)=>{
|
|
46
|
+
export const unwrapFindResponse = (payload, response, collection, locale)=>{
|
|
46
47
|
const { data, ...paginationFields } = response;
|
|
47
48
|
return {
|
|
48
|
-
docs: data.map((doc)=>unwrapDocument(
|
|
49
|
+
docs: data.map((doc)=>unwrapDocument({
|
|
50
|
+
collectionSlug: collection,
|
|
51
|
+
doc: doc,
|
|
52
|
+
locale,
|
|
53
|
+
payload
|
|
54
|
+
})),
|
|
49
55
|
...paginationFields
|
|
50
56
|
};
|
|
51
57
|
};
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
return value;
|
|
11
11
|
}
|
|
12
12
|
if (field.type === 'number') {
|
|
13
|
-
// Handle hasMany: true - array of numbers
|
|
14
13
|
if ('hasMany' in field && field.hasMany && Array.isArray(value)) {
|
|
15
14
|
return value.map((item)=>{
|
|
16
15
|
if (typeof item === 'number') {
|
|
@@ -19,20 +18,21 @@
|
|
|
19
18
|
if (typeof item === 'string' || typeof item === 'boolean') {
|
|
20
19
|
return Number(item);
|
|
21
20
|
}
|
|
22
|
-
return item
|
|
23
|
-
;
|
|
21
|
+
return item;
|
|
24
22
|
});
|
|
25
23
|
}
|
|
26
|
-
// Handle single number
|
|
27
24
|
if (typeof value !== 'number') {
|
|
28
25
|
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
29
26
|
return Number(value);
|
|
30
27
|
}
|
|
31
|
-
// For objects/arrays (when not hasMany), return as-is (will likely fail validation later)
|
|
32
28
|
return value;
|
|
33
29
|
}
|
|
34
30
|
}
|
|
35
31
|
if (field.type === 'checkbox' && typeof value !== 'boolean') {
|
|
32
|
+
// Localized fields store locale-keyed objects like { en: true } — don't cast
|
|
33
|
+
if ('localized' in field && field.localized && typeof value === 'object' && value !== null) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
36
|
if (typeof value === 'string') {
|
|
37
37
|
if (value.toLowerCase() === 'true' || value === '1') {
|
|
38
38
|
return true;
|
|
@@ -45,24 +45,23 @@
|
|
|
45
45
|
}
|
|
46
46
|
// Matches Mongoose behavior: stores dates as ISO strings
|
|
47
47
|
if (field.type === 'date' && typeof value !== 'string') {
|
|
48
|
+
// Localized fields store locale-keyed objects like { en: '2024-01-01' } — don't cast
|
|
49
|
+
if ('localized' in field && field.localized && typeof value === 'object' && value !== null) {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
48
52
|
if (value instanceof Date) {
|
|
49
53
|
return value.toISOString();
|
|
50
54
|
}
|
|
51
55
|
if (typeof value === 'number') {
|
|
52
56
|
return new Date(value).toISOString();
|
|
53
57
|
}
|
|
54
|
-
// For other types, return as-is (will likely fail validation)
|
|
55
58
|
return value;
|
|
56
59
|
}
|
|
57
|
-
// Text-like fields: convert non-strings to JSON strings
|
|
58
|
-
//
|
|
59
|
-
// EXCEPTIONS:
|
|
60
|
-
// - Localized fields are stored as objects like {"en": "value", "es": "valor"}
|
|
61
|
-
// - hasMany fields are stored as arrays like ["value1", "value2"]
|
|
60
|
+
// Text-like fields: convert non-strings to JSON strings.
|
|
61
|
+
// Exceptions: localized (stored as locale map) and hasMany (stored as array).
|
|
62
62
|
if ((field.type === 'text' || field.type === 'textarea' || field.type === 'email' || field.type === 'code') && typeof value !== 'string' && !('localized' in field && field.localized) && !('hasMany' in field && field.hasMany && Array.isArray(value))) {
|
|
63
63
|
return JSON.stringify(value);
|
|
64
64
|
}
|
|
65
|
-
// No casting needed for other types or already correct types
|
|
66
65
|
return value;
|
|
67
66
|
}
|
|
68
67
|
|
|
@@ -44,6 +44,6 @@ export declare function dataToContentAPI(payload: Payload, collectionSlug: strin
|
|
|
44
44
|
* object by filtering out known metadata keys.
|
|
45
45
|
*/
|
|
46
46
|
export declare function resolveVersionContent(version: unknown, versionMeta: Record<string, unknown>): unknown;
|
|
47
|
-
export declare function dataFromContentAPI(payload: Payload, collectionSlug: string, data: unknown): unknown;
|
|
47
|
+
export declare function dataFromContentAPI(payload: Payload, collectionSlug: string, data: unknown, locale?: string): unknown;
|
|
48
48
|
export {};
|
|
49
49
|
//# sourceMappingURL=index.d.ts.map
|