@payloadcms/figma 0.0.1-alpha.29 → 0.0.1-alpha.3
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 +1 -22
- package/dist/api/control-plane.d.ts.map +1 -1
- package/dist/api/control-plane.js +15 -54
- 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 +12 -38
- package/dist/api/figma-api.js.map +1 -1
- package/dist/auth/callback-server.d.ts.map +1 -1
- package/dist/auth/callback-server.js +1 -2
- package/dist/auth/callback-server.js.map +1 -1
- package/dist/auth/crypto-utils.d.ts.map +1 -1
- package/dist/auth/crypto-utils.js +5 -5
- package/dist/auth/crypto-utils.js.map +1 -1
- package/dist/auth/oauth-flow.d.ts +1 -1
- package/dist/auth/oauth-flow.d.ts.map +1 -1
- package/dist/auth/oauth-flow.js +5 -5
- package/dist/auth/oauth-flow.js.map +1 -1
- package/dist/auth/project-token.d.ts.map +1 -1
- package/dist/auth/project-token.js +4 -9
- package/dist/auth/project-token.js.map +1 -1
- package/dist/auth/token-store.d.ts +0 -10
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +0 -20
- package/dist/auth/token-store.js.map +1 -1
- package/dist/cli.js +0 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/deploy.d.ts +0 -4
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +81 -41
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +85 -90
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list-tokens.js +2 -2
- package/dist/commands/list-tokens.js.map +1 -1
- package/dist/commands/login.d.ts +1 -8
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +6 -12
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +2 -2
- package/dist/commands/logout.js.map +1 -1
- package/dist/config/oauth.d.ts +0 -5
- package/dist/config/oauth.d.ts.map +1 -1
- package/dist/config/oauth.js +4 -9
- package/dist/config/oauth.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LoginButton/index.js +6 -50
- package/dist/oauth/components/LoginButton/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.scss +3 -50
- package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LogoutButton/index.js +1 -0
- package/dist/oauth/components/LogoutButton/index.js.map +1 -1
- package/dist/oauth/defaults.d.ts.map +1 -1
- package/dist/oauth/defaults.js +5 -29
- package/dist/oauth/defaults.js.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +6 -42
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/strategy/index.d.ts.map +1 -1
- package/dist/oauth/strategy/index.js +2 -6
- package/dist/oauth/strategy/index.js.map +1 -1
- package/dist/oauth/types.d.ts +6 -6
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/oauth/types.js.map +1 -1
- package/dist/oauth/utilities/createCookieOptions.d.ts.map +1 -1
- package/dist/oauth/utilities/createCookieOptions.js.map +1 -1
- package/dist/oauth/utilities/refreshTokens.d.ts.map +1 -1
- package/dist/oauth/utilities/refreshTokens.js +1 -1
- package/dist/oauth/utilities/refreshTokens.js.map +1 -1
- package/dist/plugin/build-config.d.ts +4 -20
- package/dist/plugin/build-config.d.ts.map +1 -1
- package/dist/plugin/build-config.js +9 -51
- package/dist/plugin/build-config.js.map +1 -1
- package/dist/utils/env-management.d.ts +8 -9
- package/dist/utils/env-management.d.ts.map +1 -1
- package/dist/utils/env-management.js +74 -73
- package/dist/utils/env-management.js.map +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +7 -1
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +7 -5
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/payload-config-ast.d.ts +3 -22
- package/dist/utils/payload-config-ast.d.ts.map +1 -1
- package/dist/utils/payload-config-ast.js +31 -89
- package/dist/utils/payload-config-ast.js.map +1 -1
- package/dist/utils/payload-config-finder.d.ts +2 -2
- package/dist/utils/payload-config-finder.d.ts.map +1 -1
- package/dist/utils/payload-config-finder.js +9 -48
- package/dist/utils/payload-config-finder.js.map +1 -1
- package/dist/utils/payload-config-modifier.d.ts.map +1 -1
- package/dist/utils/payload-config-modifier.js +4 -33
- package/dist/utils/payload-config-modifier.js.map +1 -1
- package/dist/utils/payload-package-check.d.ts +0 -5
- package/dist/utils/payload-package-check.d.ts.map +1 -1
- package/dist/utils/payload-package-check.js +4 -48
- package/dist/utils/payload-package-check.js.map +1 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +6 -8
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/s3-upload.d.ts +1 -0
- package/dist/utils/s3-upload.d.ts.map +1 -1
- package/dist/utils/s3-upload.js +3 -10
- package/dist/utils/s3-upload.js.map +1 -1
- package/dist/utils/token-display.d.ts.map +1 -1
- package/dist/utils/token-display.js +5 -11
- package/dist/utils/token-display.js.map +1 -1
- package/dist/utils/typescript-validator.d.ts.map +1 -1
- package/dist/utils/typescript-validator.js +6 -1
- package/dist/utils/typescript-validator.js.map +1 -1
- package/package.json +6 -20
- package/dist/db-content-api/generated/content-api-types.d.ts +0 -3129
- package/dist/db-content-api/generated/content-api-types.d.ts.map +0 -1
- package/dist/db-content-api/generated/content-api-types.js +0 -7
- package/dist/db-content-api/generated/content-api-types.js.map +0 -1
- package/dist/db-content-api/index.d.ts +0 -31
- package/dist/db-content-api/index.d.ts.map +0 -1
- package/dist/db-content-api/index.js +0 -842
- package/dist/db-content-api/index.js.map +0 -1
- package/dist/db-content-api/types.d.ts +0 -31
- package/dist/db-content-api/types.d.ts.map +0 -1
- package/dist/db-content-api/types.js +0 -7
- package/dist/db-content-api/types.js.map +0 -1
- package/dist/endpoints/health.d.ts +0 -3
- package/dist/endpoints/health.d.ts.map +0 -1
- package/dist/endpoints/health.js +0 -11
- package/dist/endpoints/health.js.map +0 -1
- package/dist/exports/client.d.ts +0 -3
- package/dist/exports/client.d.ts.map +0 -1
- package/dist/exports/client.js +0 -4
- package/dist/exports/client.js.map +0 -1
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts +0 -7
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts.map +0 -1
- package/dist/oauth/utilities/isDuplicateKeyError.js +0 -14
- package/dist/oauth/utilities/isDuplicateKeyError.js.map +0 -1
- package/dist/templates/README.md +0 -19
|
@@ -1,842 +0,0 @@
|
|
|
1
|
-
import { createDatabaseAdapter, traverseFields } from 'payload';
|
|
2
|
-
import { v4 as uuid } from 'uuid';
|
|
3
|
-
import { getValidProjectToken } from '../auth/project-token.js';
|
|
4
|
-
// Field name mapping between Payload and Content API
|
|
5
|
-
// TODO: Update these when Content API renames to internal_id/external_id (or similar)
|
|
6
|
-
const PAYLOAD_ID_FIELD = 'id';
|
|
7
|
-
const CONTENT_API_KEY_FIELD = 'key';
|
|
8
|
-
// Module-level cache for devJwt tokens (encapsulated, not exposed on adapter)
|
|
9
|
-
const devJwtCache = new Map();
|
|
10
|
-
// Private helper to fetch JWT from dev endpoint (not exposed on adapter type)
|
|
11
|
-
async function fetchDevJwt(url, contentSystemId) {
|
|
12
|
-
const usesSuperUser = !contentSystemId || contentSystemId === 'test-system' || contentSystemId === '*';
|
|
13
|
-
const contentSystemIdForJWT = usesSuperUser ? '*' : contentSystemId;
|
|
14
|
-
const response = await fetch(`${url}/dev/jwt`, {
|
|
15
|
-
body: JSON.stringify({
|
|
16
|
-
content_system_id: contentSystemIdForJWT
|
|
17
|
-
}),
|
|
18
|
-
headers: {
|
|
19
|
-
'Content-Type': 'application/json'
|
|
20
|
-
},
|
|
21
|
-
method: 'POST'
|
|
22
|
-
});
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
throw new Error(`Failed to get dev JWT: ${response.status} ${response.statusText}`);
|
|
25
|
-
}
|
|
26
|
-
const { token } = await response.json();
|
|
27
|
-
return token;
|
|
28
|
-
}
|
|
29
|
-
async function init() {
|
|
30
|
-
// Log which auth mode is being used
|
|
31
|
-
if (this.auth.mode === 'apiKey') {
|
|
32
|
-
this.payload.logger.info('Using API Key authentication');
|
|
33
|
-
} else if (this.auth.mode === 'tokenStore') {
|
|
34
|
-
this.payload.logger.info('Using TokenStore authentication (local dev)');
|
|
35
|
-
} else {
|
|
36
|
-
this.payload.logger.info('Using Dev JWT authentication (testing)');
|
|
37
|
-
}
|
|
38
|
-
// Drop database if PAYLOAD_DROP_DATABASE is set (for tests)
|
|
39
|
-
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
|
40
|
-
this.payload.logger.info(`---- DROPPING CONTENT API SYSTEM (${this.contentSystemId}) ----`);
|
|
41
|
-
try {
|
|
42
|
-
await this.makeRequest('/dev/clear-db', {
|
|
43
|
-
body: {
|
|
44
|
-
contentSystemId: this.contentSystemId
|
|
45
|
-
},
|
|
46
|
-
method: 'POST'
|
|
47
|
-
});
|
|
48
|
-
this.payload.logger.info('---- DROPPED CONTENT API SYSTEM ----');
|
|
49
|
-
} catch (error) {
|
|
50
|
-
this.payload.logger.warn(`Failed to drop content system: ${error.message}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
// Fetch existing collections once
|
|
54
|
-
let existingKeys;
|
|
55
|
-
try {
|
|
56
|
-
const response = await this.makeRequest(`/api/v0/collections?contentSystemId=${this.contentSystemId}`, {
|
|
57
|
-
method: 'GET'
|
|
58
|
-
});
|
|
59
|
-
existingKeys = new Set(response.data.map((c)=>c.key));
|
|
60
|
-
this.payload.logger.info(`Found ${existingKeys.size} existing collections`);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
this.payload.logger.warn(`Failed to fetch collections, will attempt to create all: ${error.message}`);
|
|
63
|
-
existingKeys = new Set();
|
|
64
|
-
}
|
|
65
|
-
// Create only missing collections
|
|
66
|
-
for (const collection of this.payload.config.collections){
|
|
67
|
-
if (!existingKeys.has(collection.slug)) {
|
|
68
|
-
await createCollection.call(this, collection.slug);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Create only missing global collections
|
|
72
|
-
for (const global of this.payload.config.globals || []){
|
|
73
|
-
const globalKey = `_global-${global.slug}`;
|
|
74
|
-
if (!existingKeys.has(globalKey)) {
|
|
75
|
-
await createCollection.call(this, globalKey);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
// Helper to create a collection
|
|
81
|
-
async function createCollection(collectionKey) {
|
|
82
|
-
try {
|
|
83
|
-
await this.makeRequest('/api/v0/collections', {
|
|
84
|
-
body: {
|
|
85
|
-
name: collectionKey,
|
|
86
|
-
contentSystemId: this.contentSystemId,
|
|
87
|
-
key: collectionKey
|
|
88
|
-
},
|
|
89
|
-
method: 'POST'
|
|
90
|
-
});
|
|
91
|
-
this.payload.logger.info(`Created collection: ${collectionKey}`);
|
|
92
|
-
} catch (error) {
|
|
93
|
-
const errorMessage = error.message;
|
|
94
|
-
// Still handle 409 gracefully in case of race conditions
|
|
95
|
-
if (!errorMessage.includes('already exists') && !errorMessage.includes('409')) {
|
|
96
|
-
this.payload.logger.warn(`Failed to create collection ${collectionKey}: ${errorMessage}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
// Helper function to make HTTP requests to the Content API
|
|
101
|
-
async function makeRequest(path, options = {}) {
|
|
102
|
-
const { body, method = 'POST', retryCount = 0 } = options;
|
|
103
|
-
// Build auth header based on auth mode
|
|
104
|
-
let authHeader;
|
|
105
|
-
if (this.auth.mode === 'apiKey') {
|
|
106
|
-
authHeader = {
|
|
107
|
-
'X-Api-Key': this.auth.apiKey
|
|
108
|
-
};
|
|
109
|
-
} else if (this.auth.mode === 'tokenStore') {
|
|
110
|
-
const token = await getValidProjectToken(this.auth.tokenStore, this.contentSystemId);
|
|
111
|
-
if (!token) {
|
|
112
|
-
throw new Error('Authentication required. Run `npx @payloadcms/figma login` to authenticate.');
|
|
113
|
-
}
|
|
114
|
-
authHeader = {
|
|
115
|
-
Authorization: `Bearer ${token}`
|
|
116
|
-
};
|
|
117
|
-
} else {
|
|
118
|
-
// devJwt - inline cache handling
|
|
119
|
-
let token = devJwtCache.get(this.contentSystemId);
|
|
120
|
-
if (!token) {
|
|
121
|
-
token = await fetchDevJwt(this.url, this.contentSystemId);
|
|
122
|
-
devJwtCache.set(this.contentSystemId, token);
|
|
123
|
-
this.payload.logger.info(`Dev JWT acquired for content system: ${this.contentSystemId}`);
|
|
124
|
-
}
|
|
125
|
-
authHeader = {
|
|
126
|
-
Authorization: `Bearer ${token}`
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
const requestUrl = `${this.url}${path}`;
|
|
130
|
-
const response = await fetch(requestUrl, {
|
|
131
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
132
|
-
headers: {
|
|
133
|
-
'Content-Type': 'application/json',
|
|
134
|
-
...authHeader
|
|
135
|
-
},
|
|
136
|
-
method
|
|
137
|
-
});
|
|
138
|
-
// Read response as text first (better for debugging)
|
|
139
|
-
const text = await response.text();
|
|
140
|
-
// Handle 401 - retry logic differs per mode
|
|
141
|
-
if (response.status === 401 && retryCount === 0 && this.auth.mode === 'devJwt') {
|
|
142
|
-
this.payload.logger.info('Dev JWT expired, refreshing...');
|
|
143
|
-
devJwtCache.delete(this.contentSystemId);
|
|
144
|
-
return this.makeRequest(path, {
|
|
145
|
-
body,
|
|
146
|
-
method,
|
|
147
|
-
retryCount: retryCount + 1
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
// tokenStore handles refresh internally via getValidProjectToken
|
|
151
|
-
// apiKey doesn't expire - 401 means invalid key
|
|
152
|
-
// Check HTTP status
|
|
153
|
-
if (!response.ok) {
|
|
154
|
-
this.payload.logger.error({
|
|
155
|
-
msg: `HTTP ${response.status} from ${path}`,
|
|
156
|
-
response: text
|
|
157
|
-
});
|
|
158
|
-
throw new Error(`Content API HTTP ${response.status}: ${text.substring(0, 200)}`);
|
|
159
|
-
}
|
|
160
|
-
// Parse JSON response
|
|
161
|
-
try {
|
|
162
|
-
const parsed = JSON.parse(text);
|
|
163
|
-
// Check if the response is an error object (HTTP 200 but with error in body)
|
|
164
|
-
if (parsed && typeof parsed === 'object' && 'error' in parsed) {
|
|
165
|
-
throw new Error(`Content API error: ${parsed.message || parsed.error}`);
|
|
166
|
-
}
|
|
167
|
-
return parsed;
|
|
168
|
-
} catch (error) {
|
|
169
|
-
// If it's already our custom error, re-throw it
|
|
170
|
-
if (error instanceof Error && error.message.startsWith('Content API error:')) {
|
|
171
|
-
throw error;
|
|
172
|
-
}
|
|
173
|
-
this.payload.logger.error({
|
|
174
|
-
err: error instanceof Error ? error : new Error(String(error)),
|
|
175
|
-
msg: `Failed to parse JSON response from ${path}`,
|
|
176
|
-
response: text
|
|
177
|
-
});
|
|
178
|
-
throw new Error(`Invalid JSON response from content API: ${text.substring(0, 100)}...`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed
|
|
182
|
-
//
|
|
183
|
-
// TODO: Content API should accept Payload's native Where format instead of requiring conversion.
|
|
184
|
-
// This converter exists because after a GitHub merge, Content API changed to expect a different format.
|
|
185
|
-
//
|
|
186
|
-
// Payload's format: { fieldName: { operator: value }, and: [...], or: [...] }
|
|
187
|
-
// Content API expects: { and: [{ path, operator, value }], or: [{ path, operator, value }] }
|
|
188
|
-
//
|
|
189
|
-
// Once Content API accepts Payload's format:
|
|
190
|
-
// 1. Remove this function entirely
|
|
191
|
-
// 2. Remove all calls to convertPayloadWhereToContentAPI()
|
|
192
|
-
// 3. Pass `where` directly to Content API endpoints
|
|
193
|
-
// 4. Update CONTENT_API_ISSUES.md to mark Workaround #1 as resolved
|
|
194
|
-
function convertPayloadWhereToContentAPI(where, insideLogicalOperator = false) {
|
|
195
|
-
// ⚠️ WORKAROUND: Empty where {} should be { and: [] } not undefined
|
|
196
|
-
// Content API requires a where clause structure even for "no filter"
|
|
197
|
-
if (!where || Object.keys(where).length === 0) {
|
|
198
|
-
return {
|
|
199
|
-
and: []
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const conditions = [];
|
|
203
|
-
for (const [key, value] of Object.entries(where)){
|
|
204
|
-
if (key === 'and') {
|
|
205
|
-
// Recursively convert nested 'and' conditions
|
|
206
|
-
const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, true));
|
|
207
|
-
return {
|
|
208
|
-
and: nestedConditions
|
|
209
|
-
};
|
|
210
|
-
} else if (key === 'or') {
|
|
211
|
-
// Recursively convert nested 'or' conditions
|
|
212
|
-
const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, true));
|
|
213
|
-
return {
|
|
214
|
-
or: nestedConditions
|
|
215
|
-
};
|
|
216
|
-
} else {
|
|
217
|
-
// Convert field conditions: { fieldName: { operator: value } }
|
|
218
|
-
// to: { path: fieldName, operator, value }
|
|
219
|
-
const operators = value;
|
|
220
|
-
for (const [op, operatorValue] of Object.entries(operators)){
|
|
221
|
-
let finalValue = operatorValue;
|
|
222
|
-
// Add wildcards for contains/like operators (Payload doesn't add them)
|
|
223
|
-
if ((op === 'contains' || op === 'like') && typeof operatorValue === 'string') {
|
|
224
|
-
finalValue = `%${operatorValue}%`;
|
|
225
|
-
}
|
|
226
|
-
conditions.push({
|
|
227
|
-
// Map Payload's 'id' field to Content API's 'key' field
|
|
228
|
-
operator: op,
|
|
229
|
-
path: key === PAYLOAD_ID_FIELD ? CONTENT_API_KEY_FIELD : key,
|
|
230
|
-
value: finalValue
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// If inside a logical operator (and/or), return conditions directly
|
|
236
|
-
// Otherwise, wrap in 'and' to match WhereClause type
|
|
237
|
-
if (insideLogicalOperator && conditions.length === 1) {
|
|
238
|
-
return conditions[0];
|
|
239
|
-
}
|
|
240
|
-
return {
|
|
241
|
-
and: conditions
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
// Add fallback sort to ensure consistent ordering when sorting by non-unique fields
|
|
245
|
-
// Matches MongoDB adapter behavior
|
|
246
|
-
function addFallbackSort(sort, collectionConfig) {
|
|
247
|
-
if (!sort || !collectionConfig) {
|
|
248
|
-
return sort;
|
|
249
|
-
}
|
|
250
|
-
const sortArray = Array.isArray(sort) ? sort : [
|
|
251
|
-
sort
|
|
252
|
-
];
|
|
253
|
-
// Determine fallback sort field
|
|
254
|
-
let fallbackSort = '-id';
|
|
255
|
-
if (collectionConfig.timestamps !== false) {
|
|
256
|
-
fallbackSort = '-createdAt';
|
|
257
|
-
}
|
|
258
|
-
// Check if fallback sort is already included
|
|
259
|
-
const hasFallback = sortArray.some((item)=>item === fallbackSort || item === fallbackSort.replace('-', ''));
|
|
260
|
-
if (hasFallback) {
|
|
261
|
-
return sort;
|
|
262
|
-
}
|
|
263
|
-
// Check if all sort fields are unique (then no fallback needed)
|
|
264
|
-
// For simplicity, we'll always add fallback - checking uniqueness requires field traversal
|
|
265
|
-
// which would be expensive. This matches the conservative approach.
|
|
266
|
-
// Add fallback sort - always return array to preserve multiple sort fields
|
|
267
|
-
return [
|
|
268
|
-
...sortArray,
|
|
269
|
-
fallbackSort
|
|
270
|
-
];
|
|
271
|
-
}
|
|
272
|
-
// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed
|
|
273
|
-
//
|
|
274
|
-
// TODO: Content API should accept Payload's native Sort format instead of requiring conversion.
|
|
275
|
-
// This converter exists because Content API expects a different format.
|
|
276
|
-
//
|
|
277
|
-
// Payload's format: "-createdAt" or ["createdAt", "-updatedAt"]
|
|
278
|
-
// Content API expects: [{ path: "createdAt", direction: "dsc" }]
|
|
279
|
-
//
|
|
280
|
-
// Once Content API accepts Payload's format:
|
|
281
|
-
// 1. Remove this function entirely
|
|
282
|
-
// 2. Remove all calls to convertPayloadSortToContentAPI()
|
|
283
|
-
// 3. Pass `sort` directly to Content API endpoints
|
|
284
|
-
function convertPayloadSortToContentAPI(sort) {
|
|
285
|
-
if (!sort) {
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
const sortArray = Array.isArray(sort) ? sort : [
|
|
289
|
-
sort
|
|
290
|
-
];
|
|
291
|
-
return sortArray.map((field)=>{
|
|
292
|
-
let path = field;
|
|
293
|
-
let direction = 'asc';
|
|
294
|
-
// Check if field starts with '-' for descending
|
|
295
|
-
if (field.startsWith('-')) {
|
|
296
|
-
path = field.substring(1); // Remove the '-'
|
|
297
|
-
direction = 'desc';
|
|
298
|
-
}
|
|
299
|
-
// ⚠️ WORKAROUND: Strip "version." prefix from field names
|
|
300
|
-
// Payload sends "-version.createdAt" for version sort fields
|
|
301
|
-
// but Content API expects just "createdAt"
|
|
302
|
-
// TODO: Content API should handle version field paths correctly
|
|
303
|
-
if (path.startsWith('version.')) {
|
|
304
|
-
path = path.substring(8); // Remove "version." prefix
|
|
305
|
-
}
|
|
306
|
-
return {
|
|
307
|
-
direction,
|
|
308
|
-
path
|
|
309
|
-
};
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Transform data before sending to Content API (WRITE operations)
|
|
314
|
-
*
|
|
315
|
-
* Conversions applied:
|
|
316
|
-
* - RichText fields: Objects -> JSON strings
|
|
317
|
-
* - Date fields: Date objects -> Unix timestamps (numbers)
|
|
318
|
-
*/ function dataToContentAPI(collectionSlug, data) {
|
|
319
|
-
if (!data || typeof data !== 'object') {
|
|
320
|
-
return data;
|
|
321
|
-
}
|
|
322
|
-
// Deep clone to avoid mutating original data
|
|
323
|
-
const transformed = JSON.parse(JSON.stringify(data));
|
|
324
|
-
// Get collection config
|
|
325
|
-
const isGlobal = collectionSlug.startsWith('_global-');
|
|
326
|
-
const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug;
|
|
327
|
-
const collectionConfig = isGlobal ? this.payload.config.globals?.find((g)=>g.slug === actualSlug) : this.payload.config.collections.find((c)=>c.slug === actualSlug);
|
|
328
|
-
if (!collectionConfig?.fields) {
|
|
329
|
-
return transformed;
|
|
330
|
-
}
|
|
331
|
-
// Use Payload's traverseFields to iterate over all fields
|
|
332
|
-
const callback = ({ field, ref })=>{
|
|
333
|
-
if (!('name' in field) || !field.name) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
if (!ref || typeof ref !== 'object') {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const current = ref;
|
|
340
|
-
const value = current[field.name];
|
|
341
|
-
if (value !== null && value !== undefined) {
|
|
342
|
-
// RichText: object -> JSON string
|
|
343
|
-
if (field.type === 'richText' && typeof value !== 'string') {
|
|
344
|
-
current[field.name] = JSON.stringify(value);
|
|
345
|
-
} else if (field.type === 'date') {
|
|
346
|
-
const dateValue = value instanceof Date ? value : new Date(value);
|
|
347
|
-
if (!isNaN(dateValue.getTime())) {
|
|
348
|
-
current[field.name] = dateValue.getTime();
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
traverseFields({
|
|
354
|
-
callback,
|
|
355
|
-
fields: collectionConfig.fields,
|
|
356
|
-
ref: transformed
|
|
357
|
-
});
|
|
358
|
-
return transformed;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Transform data received from Content API (READ operations)
|
|
362
|
-
*
|
|
363
|
-
* Conversions applied:
|
|
364
|
-
* - RichText fields: JSON strings -> Objects
|
|
365
|
-
* - Date fields: Unix timestamps (numbers) -> Date objects
|
|
366
|
-
*/ function dataFromContentAPI(collectionSlug, data) {
|
|
367
|
-
if (!data || typeof data !== 'object') {
|
|
368
|
-
return data;
|
|
369
|
-
}
|
|
370
|
-
// Deep clone to avoid mutating original data
|
|
371
|
-
const transformed = JSON.parse(JSON.stringify(data));
|
|
372
|
-
// Get collection config
|
|
373
|
-
const isGlobal = collectionSlug.startsWith('_global-');
|
|
374
|
-
const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug;
|
|
375
|
-
const collectionConfig = isGlobal ? this.payload.config.globals?.find((g)=>g.slug === actualSlug) : this.payload.config.collections.find((c)=>c.slug === actualSlug);
|
|
376
|
-
if (!collectionConfig?.fields) {
|
|
377
|
-
return transformed;
|
|
378
|
-
}
|
|
379
|
-
// Use Payload's traverseFields to iterate over all fields
|
|
380
|
-
const callback = ({ field, parentPath, ref })=>{
|
|
381
|
-
if (!('name' in field) || !field.name) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
if (!ref || typeof ref !== 'object') {
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
const current = ref;
|
|
388
|
-
const value = current[field.name];
|
|
389
|
-
if (value !== null && value !== undefined) {
|
|
390
|
-
// RichText: JSON string -> object
|
|
391
|
-
if (field.type === 'richText' && typeof value === 'string') {
|
|
392
|
-
try {
|
|
393
|
-
current[field.name] = JSON.parse(value);
|
|
394
|
-
} catch (error) {
|
|
395
|
-
const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
|
|
396
|
-
this.payload.logger.warn({
|
|
397
|
-
err: error instanceof Error ? error : new Error(String(error)),
|
|
398
|
-
msg: `Failed to parse richtext field '${fieldPath}' in collection '${collectionSlug}'`
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
} else if (field.type === 'date') {
|
|
402
|
-
current[field.name] = new Date(value);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
traverseFields({
|
|
407
|
-
callback,
|
|
408
|
-
fields: collectionConfig.fields,
|
|
409
|
-
ref: transformed
|
|
410
|
-
});
|
|
411
|
-
return transformed;
|
|
412
|
-
}
|
|
413
|
-
// Helper to unwrap Content API document format to Payload format
|
|
414
|
-
// Content API returns: { id, data: { ...fields }, createdAt, updatedAt }
|
|
415
|
-
// Payload expects: { id, ...fields, createdAt, updatedAt }
|
|
416
|
-
function unwrapDocument(doc, collectionSlug) {
|
|
417
|
-
if (!doc) {
|
|
418
|
-
return doc;
|
|
419
|
-
}
|
|
420
|
-
// TODO
|
|
421
|
-
// Document has 'key', DocumentVersion has 'documentId'
|
|
422
|
-
const docId = CONTENT_API_KEY_FIELD in doc ? doc[CONTENT_API_KEY_FIELD] : doc.documentId;
|
|
423
|
-
const baseDoc = {
|
|
424
|
-
...doc.data,
|
|
425
|
-
createdAt: doc.createdAt,
|
|
426
|
-
[PAYLOAD_ID_FIELD]: docId,
|
|
427
|
-
updatedAt: doc.updatedAt
|
|
428
|
-
};
|
|
429
|
-
// Transform data from Content API format to Payload format
|
|
430
|
-
if (collectionSlug) {
|
|
431
|
-
return dataFromContentAPI.call(this, collectionSlug, baseDoc);
|
|
432
|
-
}
|
|
433
|
-
return baseDoc;
|
|
434
|
-
}
|
|
435
|
-
const findMany = async function findMany({ collectionSlug, limit, page, pagination, skip, sort, where }) {
|
|
436
|
-
// Payload semantics: limit: 0 means "no limit" (get all documents)
|
|
437
|
-
// Pass this through to Content API which follows the same convention
|
|
438
|
-
const effectiveLimit = limit;
|
|
439
|
-
const offset = skip ?? (limit === 0 ? 0 : (page - 1) * limit);
|
|
440
|
-
// Add fallback sort to ensure consistent ordering (matching MongoDB behavior)
|
|
441
|
-
const collectionConfig = this.payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
442
|
-
const sortWithFallback = addFallbackSort(sort, collectionConfig);
|
|
443
|
-
const response = await this.makeRequest('/api/v0/documents:find', {
|
|
444
|
-
body: {
|
|
445
|
-
collectionKey: collectionSlug,
|
|
446
|
-
contentSystemId: this.contentSystemId,
|
|
447
|
-
limit: effectiveLimit,
|
|
448
|
-
offset,
|
|
449
|
-
sort: convertPayloadSortToContentAPI(sortWithFallback),
|
|
450
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
451
|
-
},
|
|
452
|
-
method: 'POST'
|
|
453
|
-
});
|
|
454
|
-
return {
|
|
455
|
-
docs: response.result.data.map((doc)=>unwrapDocument.call(this, doc, collectionSlug)),
|
|
456
|
-
hasNextPage: pagination !== false && limit > 0 && response.result.pagination.total > offset + response.result.data.length,
|
|
457
|
-
hasPrevPage: pagination !== false && offset > 0,
|
|
458
|
-
limit,
|
|
459
|
-
nextPage: pagination !== false && response.result.pagination.total > offset + response.result.data.length ? page + 1 : null,
|
|
460
|
-
page,
|
|
461
|
-
pagingCounter: offset + 1,
|
|
462
|
-
prevPage: pagination !== false && offset > 0 ? page - 1 : null,
|
|
463
|
-
totalDocs: response.result.pagination.total,
|
|
464
|
-
totalPages: limit > 0 ? Math.ceil(response.result.pagination.total / limit) : 1
|
|
465
|
-
};
|
|
466
|
-
};
|
|
467
|
-
const find = async function find({ collection: collectionSlug, limit = 0, page = 1, pagination, skip, sort, where }) {
|
|
468
|
-
// Apply defaultSort from collection config if no sort is provided
|
|
469
|
-
const collectionConfig = this.payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
470
|
-
const effectiveSort = sort || collectionConfig?.defaultSort;
|
|
471
|
-
return findMany.call(this, {
|
|
472
|
-
collectionSlug,
|
|
473
|
-
limit,
|
|
474
|
-
page,
|
|
475
|
-
pagination,
|
|
476
|
-
skip,
|
|
477
|
-
sort: effectiveSort,
|
|
478
|
-
where: where ?? {}
|
|
479
|
-
});
|
|
480
|
-
};
|
|
481
|
-
const findVersions = async function findVersions({ collection: collectionSlug, limit = 0, page = 1, pagination, skip, sort, where }) {
|
|
482
|
-
const offset = skip ?? (page - 1) * limit;
|
|
483
|
-
const response = await this.makeRequest('/api/v0/document_versions:find', {
|
|
484
|
-
body: {
|
|
485
|
-
collectionKey: collectionSlug,
|
|
486
|
-
contentSystemId: this.contentSystemId,
|
|
487
|
-
limit,
|
|
488
|
-
offset,
|
|
489
|
-
sort: convertPayloadSortToContentAPI(sort),
|
|
490
|
-
where: convertPayloadWhereToContentAPI(where ?? {})
|
|
491
|
-
},
|
|
492
|
-
method: 'POST'
|
|
493
|
-
});
|
|
494
|
-
return {
|
|
495
|
-
docs: response.result.data.map((doc)=>unwrapDocument.call(this, doc, collectionSlug)),
|
|
496
|
-
hasNextPage: pagination !== false && limit > 0 && response.result.pagination.total > offset + response.result.data.length,
|
|
497
|
-
hasPrevPage: pagination !== false && offset > 0,
|
|
498
|
-
limit,
|
|
499
|
-
nextPage: pagination !== false && response.result.pagination.total > offset + response.result.data.length ? page + 1 : null,
|
|
500
|
-
page,
|
|
501
|
-
pagingCounter: offset + 1,
|
|
502
|
-
prevPage: pagination !== false && offset > 0 ? page - 1 : null,
|
|
503
|
-
totalDocs: response.result.pagination.total,
|
|
504
|
-
totalPages: limit > 0 ? Math.ceil(response.result.pagination.total / limit) : 1
|
|
505
|
-
};
|
|
506
|
-
};
|
|
507
|
-
const queryDrafts = async function queryDrafts({ collection: collectionSlug, limit, page, pagination, sort, where = {} }) {
|
|
508
|
-
// TODO: review this
|
|
509
|
-
// Content API doesn't have a separate "draft" concept
|
|
510
|
-
// It only has versions with a "latest" flag
|
|
511
|
-
// PayloadCMS drafts would typically be versions where latest=false
|
|
512
|
-
// But this mapping may need adjustment based on your use case
|
|
513
|
-
const result = await this.findVersions({
|
|
514
|
-
collection: collectionSlug,
|
|
515
|
-
limit,
|
|
516
|
-
page,
|
|
517
|
-
pagination,
|
|
518
|
-
sort,
|
|
519
|
-
where: {
|
|
520
|
-
...where,
|
|
521
|
-
// Query non-latest versions as "drafts"
|
|
522
|
-
latest: {
|
|
523
|
-
equals: false
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
});
|
|
527
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
528
|
-
return result;
|
|
529
|
-
};
|
|
530
|
-
const createVersion = async function createVersion({ autosave, collectionSlug, parent, versionData }) {
|
|
531
|
-
const response = await this.makeRequest('/api/v0/document_versions:create', {
|
|
532
|
-
body: {
|
|
533
|
-
collectionKey: collectionSlug,
|
|
534
|
-
contentSystemId: this.contentSystemId,
|
|
535
|
-
data: dataToContentAPI.call(this, collectionSlug, versionData),
|
|
536
|
-
documentKey: parent,
|
|
537
|
-
latest: !autosave
|
|
538
|
-
},
|
|
539
|
-
method: 'POST'
|
|
540
|
-
});
|
|
541
|
-
// Handle union type response: { id: string } | { data: DocumentVersion }
|
|
542
|
-
if ('data' in response.result) {
|
|
543
|
-
return unwrapDocument.call(this, response.result.data, collectionSlug);
|
|
544
|
-
}
|
|
545
|
-
throw new Error('Unexpected response format from createVersion');
|
|
546
|
-
};
|
|
547
|
-
const updateVersion = async function updateVersion({ id, collection: collectionSlug, versionData, where }) {
|
|
548
|
-
const response = await this.makeRequest('/api/v0/document_versions:update', {
|
|
549
|
-
body: {
|
|
550
|
-
collectionKey: collectionSlug,
|
|
551
|
-
contentSystemId: this.contentSystemId,
|
|
552
|
-
createOnMissing: false,
|
|
553
|
-
data: dataToContentAPI.call(this, collectionSlug, versionData),
|
|
554
|
-
where: convertPayloadWhereToContentAPI(where ?? {
|
|
555
|
-
id: {
|
|
556
|
-
equals: id
|
|
557
|
-
}
|
|
558
|
-
})
|
|
559
|
-
},
|
|
560
|
-
method: 'POST'
|
|
561
|
-
});
|
|
562
|
-
// Handle union type response: { count: number } | { data: DocumentVersion[] }
|
|
563
|
-
if (!response?.result || !('data' in response.result)) {
|
|
564
|
-
throw new Error('No document data in updateVersion response');
|
|
565
|
-
}
|
|
566
|
-
return unwrapDocument.call(this, response.result.data[0], collectionSlug);
|
|
567
|
-
};
|
|
568
|
-
const deleteVersions = async function deleteVersions({ collection: collectionSlug, where }) {
|
|
569
|
-
await this.makeRequest('/api/v0/document_versions:delete', {
|
|
570
|
-
body: {
|
|
571
|
-
collectionKey: collectionSlug,
|
|
572
|
-
contentSystemId: this.contentSystemId,
|
|
573
|
-
returning: false,
|
|
574
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
575
|
-
},
|
|
576
|
-
method: 'POST'
|
|
577
|
-
});
|
|
578
|
-
};
|
|
579
|
-
const findOne = async function findOne({ collection, where }) {
|
|
580
|
-
const { docs: [first] } = await this.find({
|
|
581
|
-
collection,
|
|
582
|
-
limit: 1,
|
|
583
|
-
pagination: false,
|
|
584
|
-
where
|
|
585
|
-
});
|
|
586
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
587
|
-
return first ?? null;
|
|
588
|
-
};
|
|
589
|
-
const updateMany = async function updateMany({ collection: collectionSlug, data, where }) {
|
|
590
|
-
const response = await this.makeRequest('/api/v0/documents:update', {
|
|
591
|
-
body: {
|
|
592
|
-
collectionKey: collectionSlug,
|
|
593
|
-
contentSystemId: this.contentSystemId,
|
|
594
|
-
createOnMissing: false,
|
|
595
|
-
data: dataToContentAPI.call(this, collectionSlug, data),
|
|
596
|
-
returning: {},
|
|
597
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
598
|
-
},
|
|
599
|
-
method: 'POST'
|
|
600
|
-
});
|
|
601
|
-
// Handle union type: { count: number } | { data: Document[] }
|
|
602
|
-
if (response.result && 'data' in response.result) {
|
|
603
|
-
return response.result.data.map((doc)=>unwrapDocument.call(this, doc, collectionSlug));
|
|
604
|
-
}
|
|
605
|
-
return null;
|
|
606
|
-
};
|
|
607
|
-
const updateOne = async function updateOne({ id, collection: collectionSlug, data, where }) {
|
|
608
|
-
const response = await this.makeRequest('/api/v0/documents:update', {
|
|
609
|
-
body: {
|
|
610
|
-
collectionKey: collectionSlug,
|
|
611
|
-
contentSystemId: this.contentSystemId,
|
|
612
|
-
createOnMissing: false,
|
|
613
|
-
data: dataToContentAPI.call(this, collectionSlug, data),
|
|
614
|
-
where: convertPayloadWhereToContentAPI(where ?? {
|
|
615
|
-
id: {
|
|
616
|
-
equals: id
|
|
617
|
-
}
|
|
618
|
-
})
|
|
619
|
-
},
|
|
620
|
-
method: 'POST'
|
|
621
|
-
});
|
|
622
|
-
// Handle union type: { count: number } | { data: Document[] }
|
|
623
|
-
if (response.result && 'data' in response.result) {
|
|
624
|
-
const doc = response.result.data[0];
|
|
625
|
-
if (!doc) {
|
|
626
|
-
throw new Error('No document data in updateOne response');
|
|
627
|
-
}
|
|
628
|
-
return unwrapDocument.call(this, doc, collectionSlug);
|
|
629
|
-
}
|
|
630
|
-
throw new Error('Unexpected response format from updateOne');
|
|
631
|
-
};
|
|
632
|
-
const deleteMany = async function deleteMany({ collection: collectionSlug, where }) {
|
|
633
|
-
await this.makeRequest('/api/v0/documents:delete', {
|
|
634
|
-
body: {
|
|
635
|
-
collectionKey: collectionSlug,
|
|
636
|
-
contentSystemId: this.contentSystemId,
|
|
637
|
-
returning: false,
|
|
638
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
639
|
-
},
|
|
640
|
-
method: 'POST'
|
|
641
|
-
});
|
|
642
|
-
};
|
|
643
|
-
const deleteOne = async function deleteOne({ collection: collectionSlug, where }) {
|
|
644
|
-
await this.makeRequest('/api/v0/documents:delete', {
|
|
645
|
-
body: {
|
|
646
|
-
collectionKey: collectionSlug,
|
|
647
|
-
contentSystemId: this.contentSystemId,
|
|
648
|
-
returning: false,
|
|
649
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
650
|
-
},
|
|
651
|
-
method: 'POST'
|
|
652
|
-
});
|
|
653
|
-
};
|
|
654
|
-
const create = async function create({ collection: collectionSlug, data }) {
|
|
655
|
-
// Generate a document key if not provided
|
|
656
|
-
// Content API has two ID fields:
|
|
657
|
-
// - `id` (UUID, auto-generated by DB, internal use only)
|
|
658
|
-
// - `key` (text, public document identifier, maps to Payload's `id`)
|
|
659
|
-
// If Payload doesn't provide an ID, we generate a UUID
|
|
660
|
-
// (same as other SQL-based Payload adapters like db-postgres and db-drizzle)
|
|
661
|
-
const key = data[PAYLOAD_ID_FIELD] || uuid();
|
|
662
|
-
const response = await this.makeRequest('/api/v0/documents:create', {
|
|
663
|
-
body: {
|
|
664
|
-
collectionKey: collectionSlug,
|
|
665
|
-
contentSystemId: this.contentSystemId,
|
|
666
|
-
data: dataToContentAPI.call(this, collectionSlug, data),
|
|
667
|
-
key
|
|
668
|
-
},
|
|
669
|
-
method: 'POST'
|
|
670
|
-
});
|
|
671
|
-
// Handle union type response: { id: string } | { data: Document }
|
|
672
|
-
if ('data' in response.result) {
|
|
673
|
-
return unwrapDocument.call(this, response.result.data, collectionSlug);
|
|
674
|
-
}
|
|
675
|
-
throw new Error('Unexpected response format from create');
|
|
676
|
-
};
|
|
677
|
-
const count = async function count({ collection: collectionSlug, where }) {
|
|
678
|
-
const response = await this.makeRequest('/api/v0/documents:count', {
|
|
679
|
-
body: {
|
|
680
|
-
collectionKey: collectionSlug,
|
|
681
|
-
contentSystemId: this.contentSystemId,
|
|
682
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
683
|
-
},
|
|
684
|
-
method: 'POST'
|
|
685
|
-
});
|
|
686
|
-
return {
|
|
687
|
-
totalDocs: response.result.count
|
|
688
|
-
};
|
|
689
|
-
};
|
|
690
|
-
const countVersions = async function countVersions({ collection: collectionSlug, where }) {
|
|
691
|
-
const response = await this.makeRequest('/api/v0/document_versions:count', {
|
|
692
|
-
body: {
|
|
693
|
-
collectionKey: collectionSlug,
|
|
694
|
-
contentSystemId: this.contentSystemId,
|
|
695
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
696
|
-
},
|
|
697
|
-
method: 'POST'
|
|
698
|
-
});
|
|
699
|
-
return {
|
|
700
|
-
totalDocs: response.result.count
|
|
701
|
-
};
|
|
702
|
-
};
|
|
703
|
-
const upsert = async function upsert({ collection: collectionSlug, data, where }) {
|
|
704
|
-
const response = await this.makeRequest('/api/v0/documents:update', {
|
|
705
|
-
body: {
|
|
706
|
-
collectionKey: collectionSlug,
|
|
707
|
-
contentSystemId: this.contentSystemId,
|
|
708
|
-
createOnMissing: true,
|
|
709
|
-
data: dataToContentAPI.call(this, collectionSlug, data),
|
|
710
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
711
|
-
},
|
|
712
|
-
method: 'POST'
|
|
713
|
-
});
|
|
714
|
-
// Handle union type: { count: number } | { data: Document[] }
|
|
715
|
-
if (response.result && 'data' in response.result) {
|
|
716
|
-
const doc = response.result.data[0];
|
|
717
|
-
if (!doc) {
|
|
718
|
-
throw new Error('No document data in upsert response');
|
|
719
|
-
}
|
|
720
|
-
return unwrapDocument.call(this, doc, collectionSlug);
|
|
721
|
-
}
|
|
722
|
-
throw new Error('Unexpected response format from upsert');
|
|
723
|
-
};
|
|
724
|
-
// TODO: global should be a prefix or a resource in the REST API / Table in the DB?
|
|
725
|
-
const getGlobalSlug = (slug)=>`_global-${slug}`;
|
|
726
|
-
const createGlobal = function({ slug, data }) {
|
|
727
|
-
return this.create({
|
|
728
|
-
collection: getGlobalSlug(slug),
|
|
729
|
-
data: {
|
|
730
|
-
...data,
|
|
731
|
-
globalType: slug
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
};
|
|
735
|
-
const findGlobal = function({ slug, where = {} }) {
|
|
736
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
737
|
-
return this.findOne({
|
|
738
|
-
collection: getGlobalSlug(slug),
|
|
739
|
-
where
|
|
740
|
-
});
|
|
741
|
-
};
|
|
742
|
-
const updateGlobal = function({ slug, data }) {
|
|
743
|
-
return this.updateOne({
|
|
744
|
-
collection: getGlobalSlug(slug),
|
|
745
|
-
data,
|
|
746
|
-
where: {}
|
|
747
|
-
});
|
|
748
|
-
};
|
|
749
|
-
const findGlobalVersions = function({ global: slug, limit, page, pagination, skip, sort, where }) {
|
|
750
|
-
return this.findVersions({
|
|
751
|
-
collection: getGlobalSlug(slug),
|
|
752
|
-
limit,
|
|
753
|
-
page,
|
|
754
|
-
pagination,
|
|
755
|
-
skip,
|
|
756
|
-
sort,
|
|
757
|
-
where
|
|
758
|
-
});
|
|
759
|
-
};
|
|
760
|
-
const createGlobalVersion = function(// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
761
|
-
{ autosave, createdAt, globalSlug, updatedAt, versionData, ...rest }) {
|
|
762
|
-
return this.createVersion({
|
|
763
|
-
autosave,
|
|
764
|
-
collectionSlug: getGlobalSlug(globalSlug),
|
|
765
|
-
createdAt,
|
|
766
|
-
parent: rest.parent,
|
|
767
|
-
updatedAt,
|
|
768
|
-
versionData
|
|
769
|
-
});
|
|
770
|
-
};
|
|
771
|
-
const updateGlobalVersion = function({ id, global: slug, versionData, where, ...rest }) {
|
|
772
|
-
// UpdateVersion accepts either id OR where, not both
|
|
773
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
774
|
-
const args = {
|
|
775
|
-
collection: getGlobalSlug(slug),
|
|
776
|
-
versionData,
|
|
777
|
-
...rest
|
|
778
|
-
};
|
|
779
|
-
if (id !== undefined) {
|
|
780
|
-
args.id = id;
|
|
781
|
-
} else if (where !== undefined) {
|
|
782
|
-
args.where = where;
|
|
783
|
-
}
|
|
784
|
-
return this.updateVersion(args);
|
|
785
|
-
};
|
|
786
|
-
const countGlobalVersions = function({ global: slug, where }) {
|
|
787
|
-
return this.countVersions({
|
|
788
|
-
collection: getGlobalSlug(slug),
|
|
789
|
-
where
|
|
790
|
-
});
|
|
791
|
-
};
|
|
792
|
-
export const contentAPIAdapter = (opts)=>{
|
|
793
|
-
return {
|
|
794
|
-
name: 'content_api',
|
|
795
|
-
defaultIDType: 'text',
|
|
796
|
-
init: ({ payload })=>{
|
|
797
|
-
return createDatabaseAdapter({
|
|
798
|
-
name: 'content_api',
|
|
799
|
-
auth: opts.auth,
|
|
800
|
-
beginTransaction: ()=>{
|
|
801
|
-
return Promise.resolve('no-op-transaction');
|
|
802
|
-
},
|
|
803
|
-
commitTransaction: async ()=>{},
|
|
804
|
-
contentSystemId: opts.contentSystemId,
|
|
805
|
-
count,
|
|
806
|
-
countGlobalVersions,
|
|
807
|
-
countVersions,
|
|
808
|
-
create,
|
|
809
|
-
createGlobal,
|
|
810
|
-
createGlobalVersion,
|
|
811
|
-
createVersion,
|
|
812
|
-
defaultIDType: 'text',
|
|
813
|
-
deleteMany,
|
|
814
|
-
deleteOne,
|
|
815
|
-
deleteVersions,
|
|
816
|
-
find,
|
|
817
|
-
findDistinct: ()=>{
|
|
818
|
-
return Promise.reject(new Error('findDistinct is not yet implemented for Content API adapter'));
|
|
819
|
-
},
|
|
820
|
-
findGlobal,
|
|
821
|
-
findGlobalVersions,
|
|
822
|
-
findOne,
|
|
823
|
-
findVersions,
|
|
824
|
-
init,
|
|
825
|
-
makeRequest,
|
|
826
|
-
packageName: '@payloadcms/db-content-api',
|
|
827
|
-
payload,
|
|
828
|
-
queryDrafts,
|
|
829
|
-
rollbackTransaction: async ()=>{},
|
|
830
|
-
updateGlobal,
|
|
831
|
-
updateGlobalVersion,
|
|
832
|
-
updateMany,
|
|
833
|
-
updateOne,
|
|
834
|
-
updateVersion,
|
|
835
|
-
upsert,
|
|
836
|
-
url: opts.url
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
};
|
|
840
|
-
};
|
|
841
|
-
|
|
842
|
-
//# sourceMappingURL=index.js.map
|