@payloadcms/figma 0.0.1-alpha.29 → 0.0.1-alpha.30
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/figma-api.d.ts.map +1 -1
- package/dist/api/figma-api.js +4 -0
- package/dist/api/figma-api.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +32 -50
- package/dist/commands/deploy.js.map +1 -1
- package/dist/db-content-api/README.md +108 -0
- package/dist/db-content-api/generated/content-api-types.d.ts +763 -190
- package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -1
- package/dist/db-content-api/generated/content-api-types.js.map +1 -1
- package/dist/db-content-api/index.d.ts +6 -19
- package/dist/db-content-api/index.d.ts.map +1 -1
- package/dist/db-content-api/index.js +396 -687
- package/dist/db-content-api/index.js.map +1 -1
- package/dist/db-content-api/temp-utilities/pagination.d.ts +13 -0
- package/dist/db-content-api/temp-utilities/pagination.d.ts.map +1 -0
- package/dist/db-content-api/temp-utilities/pagination.js +45 -0
- package/dist/db-content-api/temp-utilities/pagination.js.map +1 -0
- package/dist/db-content-api/temp-utilities/slug.d.ts +2 -0
- package/dist/db-content-api/temp-utilities/slug.d.ts.map +1 -0
- package/dist/db-content-api/temp-utilities/slug.js +3 -0
- package/dist/db-content-api/temp-utilities/slug.js.map +1 -0
- package/dist/db-content-api/temp-utilities/sorting.d.ts +7 -0
- package/dist/db-content-api/temp-utilities/sorting.d.ts.map +1 -0
- package/dist/db-content-api/temp-utilities/sorting.js +71 -0
- package/dist/db-content-api/temp-utilities/sorting.js.map +1 -0
- package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +4 -0
- package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts.map +1 -0
- package/dist/db-content-api/temp-utilities/unwrapDocument.js +45 -0
- package/dist/db-content-api/temp-utilities/unwrapDocument.js.map +1 -0
- package/dist/db-content-api/utilities/auth.d.ts +30 -0
- package/dist/db-content-api/utilities/auth.d.ts.map +1 -0
- package/dist/db-content-api/utilities/auth.js +81 -0
- package/dist/db-content-api/utilities/auth.js.map +1 -0
- package/dist/db-content-api/utilities/data.d.ts +24 -0
- package/dist/db-content-api/utilities/data.d.ts.map +1 -0
- package/dist/db-content-api/utilities/data.js +118 -0
- package/dist/db-content-api/utilities/data.js.map +1 -0
- package/dist/db-content-api/utilities/joins.d.ts +55 -0
- package/dist/db-content-api/utilities/joins.d.ts.map +1 -0
- package/dist/db-content-api/utilities/joins.js +130 -0
- package/dist/db-content-api/utilities/joins.js.map +1 -0
- package/dist/db-content-api/utilities/where.d.ts +12 -0
- package/dist/db-content-api/utilities/where.d.ts.map +1 -0
- package/dist/db-content-api/utilities/where.js +63 -0
- package/dist/db-content-api/utilities/where.js.map +1 -0
- package/dist/plugin/build-config.d.ts +1 -0
- package/dist/plugin/build-config.d.ts.map +1 -1
- package/dist/plugin/build-config.js +38 -0
- package/dist/plugin/build-config.js.map +1 -1
- package/dist/storage-content-api/api-types.d.ts +161 -0
- package/dist/storage-content-api/api-types.d.ts.map +1 -0
- package/dist/storage-content-api/api-types.js +6 -0
- package/dist/storage-content-api/api-types.js.map +1 -0
- package/dist/storage-content-api/client.d.ts +6 -0
- package/dist/storage-content-api/client.d.ts.map +1 -0
- package/dist/storage-content-api/client.js +36 -0
- package/dist/storage-content-api/client.js.map +1 -0
- package/dist/storage-content-api/generateURL.d.ts +7 -0
- package/dist/storage-content-api/generateURL.d.ts.map +1 -0
- package/dist/storage-content-api/generateURL.js +7 -0
- package/dist/storage-content-api/generateURL.js.map +1 -0
- package/dist/storage-content-api/handleDelete.d.ts +8 -0
- package/dist/storage-content-api/handleDelete.d.ts.map +1 -0
- package/dist/storage-content-api/handleDelete.js +15 -0
- package/dist/storage-content-api/handleDelete.js.map +1 -0
- package/dist/storage-content-api/handleUpload.d.ts +11 -0
- package/dist/storage-content-api/handleUpload.d.ts.map +1 -0
- package/dist/storage-content-api/handleUpload.js +126 -0
- package/dist/storage-content-api/handleUpload.js.map +1 -0
- package/dist/storage-content-api/index.d.ts +5 -0
- package/dist/storage-content-api/index.d.ts.map +1 -0
- package/dist/storage-content-api/index.js +31 -0
- package/dist/storage-content-api/index.js.map +1 -0
- package/dist/storage-content-api/staticHandler.d.ts +10 -0
- package/dist/storage-content-api/staticHandler.d.ts.map +1 -0
- package/dist/storage-content-api/staticHandler.js +35 -0
- package/dist/storage-content-api/staticHandler.js.map +1 -0
- package/dist/storage-content-api/types.d.ts +10 -0
- package/dist/storage-content-api/types.d.ts.map +1 -0
- package/dist/storage-content-api/types.js +3 -0
- package/dist/storage-content-api/types.js.map +1 -0
- package/dist/utils/lambda-config.d.ts.map +1 -1
- package/dist/utils/lambda-config.js +1 -0
- package/dist/utils/lambda-config.js.map +1 -1
- package/package.json +5 -2
- 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
|
@@ -1,33 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import createClient from 'openapi-fetch';
|
|
2
|
+
import { createDatabaseAdapter } from 'payload';
|
|
2
3
|
import { v4 as uuid } from 'uuid';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
}
|
|
4
|
+
import { getPaginationData } from './temp-utilities/pagination.js';
|
|
5
|
+
import { getGlobalSlug } from './temp-utilities/slug.js';
|
|
6
|
+
import { addFallbackSort, convertPayloadSortToContentAPI } from './temp-utilities/sorting.js';
|
|
7
|
+
import { unwrapDocument } from './temp-utilities/unwrapDocument.js';
|
|
8
|
+
import { createAuthMiddleware, createErrorMiddleware } from './utilities/auth.js';
|
|
9
|
+
import { dataToContentAPI } from './utilities/data.js';
|
|
10
|
+
import { convertPayloadJoinsToContentAPI } from './utilities/joins.js';
|
|
11
|
+
import { convertPayloadWhereToContentAPI } from './utilities/where.js';
|
|
29
12
|
async function init() {
|
|
30
|
-
// Log which auth mode is being used
|
|
31
13
|
if (this.auth.mode === 'apiKey') {
|
|
32
14
|
this.payload.logger.info('Using API Key authentication');
|
|
33
15
|
} else if (this.auth.mode === 'tokenStore') {
|
|
@@ -35,13 +17,15 @@ async function init() {
|
|
|
35
17
|
} else {
|
|
36
18
|
this.payload.logger.info('Using Dev JWT authentication (testing)');
|
|
37
19
|
}
|
|
38
|
-
// Drop database if PAYLOAD_DROP_DATABASE is set (for tests)
|
|
39
20
|
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
|
40
21
|
this.payload.logger.info(`---- DROPPING CONTENT API SYSTEM (${this.contentSystemId}) ----`);
|
|
41
22
|
try {
|
|
42
|
-
await this.
|
|
43
|
-
body: {
|
|
23
|
+
await fetch(`${this.url}/dev/clear-db`, {
|
|
24
|
+
body: JSON.stringify({
|
|
44
25
|
contentSystemId: this.contentSystemId
|
|
26
|
+
}),
|
|
27
|
+
headers: {
|
|
28
|
+
'Content-Type': 'application/json'
|
|
45
29
|
},
|
|
46
30
|
method: 'POST'
|
|
47
31
|
});
|
|
@@ -50,793 +34,518 @@ async function init() {
|
|
|
50
34
|
this.payload.logger.warn(`Failed to drop content system: ${error.message}`);
|
|
51
35
|
}
|
|
52
36
|
}
|
|
53
|
-
|
|
54
|
-
let existingKeys;
|
|
37
|
+
let existingIds;
|
|
55
38
|
try {
|
|
56
|
-
const response = await this.
|
|
57
|
-
|
|
39
|
+
const { data: response, error } = await this.client.GET('/api/v0/content_systems/{contentSystemId}/collections', {
|
|
40
|
+
params: {
|
|
41
|
+
path: {
|
|
42
|
+
contentSystemId: this.contentSystemId
|
|
43
|
+
}
|
|
44
|
+
}
|
|
58
45
|
});
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
if (error) {
|
|
47
|
+
throw new Error(JSON.stringify(error));
|
|
48
|
+
}
|
|
49
|
+
if (!response) {
|
|
50
|
+
throw new Error('No response from collections endpoint');
|
|
51
|
+
}
|
|
52
|
+
existingIds = new Set(response.data.map((c)=>c.id));
|
|
53
|
+
this.payload.logger.info(`Found ${existingIds.size} existing collections`);
|
|
61
54
|
} catch (error) {
|
|
62
55
|
this.payload.logger.warn(`Failed to fetch collections, will attempt to create all: ${error.message}`);
|
|
63
|
-
|
|
56
|
+
existingIds = new Set();
|
|
64
57
|
}
|
|
65
|
-
// Create only missing collections
|
|
66
58
|
for (const collection of this.payload.config.collections){
|
|
67
|
-
if (!
|
|
59
|
+
if (!existingIds.has(collection.slug)) {
|
|
68
60
|
await createCollection.call(this, collection.slug);
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
|
-
// Create only missing global collections
|
|
72
63
|
for (const global of this.payload.config.globals || []){
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
75
|
-
await createCollection.call(this,
|
|
64
|
+
const globalId = `_global-${global.slug}`;
|
|
65
|
+
if (!existingIds.has(globalId)) {
|
|
66
|
+
await createCollection.call(this, globalId);
|
|
76
67
|
}
|
|
77
68
|
}
|
|
78
|
-
return;
|
|
79
69
|
}
|
|
80
|
-
|
|
81
|
-
async function createCollection(collectionKey) {
|
|
70
|
+
async function createCollection(collectionId) {
|
|
82
71
|
try {
|
|
83
|
-
await this.
|
|
72
|
+
const { error } = await this.client.POST('/api/v0/content_systems/{contentSystemId}/collections', {
|
|
84
73
|
body: {
|
|
85
|
-
|
|
86
|
-
contentSystemId: this.contentSystemId,
|
|
87
|
-
key: collectionKey
|
|
74
|
+
id: collectionId
|
|
88
75
|
},
|
|
89
|
-
|
|
76
|
+
params: {
|
|
77
|
+
path: {
|
|
78
|
+
contentSystemId: this.contentSystemId
|
|
79
|
+
}
|
|
80
|
+
}
|
|
90
81
|
});
|
|
91
|
-
|
|
82
|
+
if (error) {
|
|
83
|
+
throw new Error(JSON.stringify(error));
|
|
84
|
+
}
|
|
85
|
+
this.payload.logger.info(`Created collection: ${collectionId}`);
|
|
92
86
|
} catch (error) {
|
|
93
87
|
const errorMessage = error.message;
|
|
94
|
-
// Still handle 409 gracefully in case of race conditions
|
|
95
88
|
if (!errorMessage.includes('already exists') && !errorMessage.includes('409')) {
|
|
96
|
-
this.payload.logger.warn(`Failed to create collection ${
|
|
89
|
+
this.payload.logger.warn(`Failed to create collection ${collectionId}: ${errorMessage}`);
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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}`);
|
|
93
|
+
async function findMany({ collection, joins, limit, page, pagination, sort, where }) {
|
|
94
|
+
const collectionConfig = this.payload.config.collections.find((c)=>c.slug === collection);
|
|
95
|
+
const sortWithFallback = addFallbackSort(sort, collectionConfig);
|
|
96
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:find', {
|
|
97
|
+
body: {
|
|
98
|
+
collectionId: collection,
|
|
99
|
+
contentSystemId: this.contentSystemId,
|
|
100
|
+
join: collectionConfig ? convertPayloadJoinsToContentAPI(this.payload, collectionConfig, joins) : undefined,
|
|
101
|
+
limit,
|
|
102
|
+
page: page ?? 1,
|
|
103
|
+
sort: convertPayloadSortToContentAPI(sortWithFallback),
|
|
104
|
+
where: convertPayloadWhereToContentAPI(where ?? {})
|
|
124
105
|
}
|
|
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
106
|
});
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
});
|
|
107
|
+
if (error) {
|
|
108
|
+
throw new Error(`Content API findMany error: ${JSON.stringify(error)}`);
|
|
149
109
|
}
|
|
150
|
-
|
|
151
|
-
|
|
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];
|
|
110
|
+
if (!response) {
|
|
111
|
+
throw new Error('No response from findMany');
|
|
239
112
|
}
|
|
240
113
|
return {
|
|
241
|
-
|
|
114
|
+
docs: response.result.data.map((doc)=>unwrapDocument(this.payload, doc, collection)),
|
|
115
|
+
...getPaginationData(response.result.pagination, pagination)
|
|
242
116
|
};
|
|
243
117
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
|
118
|
+
async function find(args) {
|
|
119
|
+
const collectionConfig = this.payload.config.collections.find((c)=>c.slug === args.collection);
|
|
120
|
+
return findMany.call(this, {
|
|
121
|
+
collection: args.collection,
|
|
122
|
+
joins: args.joins,
|
|
123
|
+
limit: args.limit ?? 0,
|
|
124
|
+
page: args.page ?? 1,
|
|
125
|
+
pagination: args.pagination,
|
|
126
|
+
sort: args.sort || collectionConfig?.defaultSort,
|
|
127
|
+
where: args.where
|
|
357
128
|
});
|
|
358
|
-
return transformed;
|
|
359
129
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
|
130
|
+
// TODO: remove Omit when this PR is released: https://github.com/payloadcms/payload/pull/15183
|
|
131
|
+
async function findVersions(args) {
|
|
132
|
+
const whereClause = convertPayloadWhereToContentAPI(args.where ?? {}, {
|
|
133
|
+
parentToDocumentId: true
|
|
410
134
|
});
|
|
411
|
-
|
|
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', {
|
|
135
|
+
const { data: response, error } = await this.client.POST('/api/v0/document_versions:find', {
|
|
444
136
|
body: {
|
|
445
|
-
|
|
137
|
+
collectionId: args.collection,
|
|
446
138
|
contentSystemId: this.contentSystemId,
|
|
447
|
-
limit:
|
|
448
|
-
|
|
449
|
-
sort: convertPayloadSortToContentAPI(
|
|
450
|
-
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'
|
|
139
|
+
limit: args.limit ?? 0,
|
|
140
|
+
page: args.page ?? 1,
|
|
141
|
+
sort: convertPayloadSortToContentAPI(args.sort),
|
|
142
|
+
where: whereClause
|
|
143
|
+
}
|
|
493
144
|
});
|
|
145
|
+
if (error) {
|
|
146
|
+
throw new Error(`Content API findVersions error: ${JSON.stringify(error)}`);
|
|
147
|
+
}
|
|
148
|
+
if (!response) {
|
|
149
|
+
throw new Error('No response from findVersions');
|
|
150
|
+
}
|
|
151
|
+
const docs = response.result.data.map((doc)=>unwrapDocument(this.payload, doc, args.collection));
|
|
494
152
|
return {
|
|
495
|
-
docs
|
|
496
|
-
|
|
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
|
|
153
|
+
docs,
|
|
154
|
+
...getPaginationData(response.result.pagination, args.pagination)
|
|
505
155
|
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
collection: collectionSlug,
|
|
515
|
-
limit,
|
|
516
|
-
page,
|
|
517
|
-
pagination,
|
|
518
|
-
sort,
|
|
156
|
+
}
|
|
157
|
+
async function queryDrafts(args) {
|
|
158
|
+
return this.findVersions({
|
|
159
|
+
collection: args.collection,
|
|
160
|
+
limit: args.limit,
|
|
161
|
+
page: args.page,
|
|
162
|
+
pagination: args.pagination,
|
|
163
|
+
sort: args.sort,
|
|
519
164
|
where: {
|
|
520
|
-
...where,
|
|
521
|
-
// Query non-latest versions as "drafts"
|
|
165
|
+
...args.where,
|
|
522
166
|
latest: {
|
|
523
|
-
equals:
|
|
167
|
+
equals: true
|
|
524
168
|
}
|
|
525
169
|
}
|
|
526
170
|
});
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
const createVersion = async function createVersion({ autosave, collectionSlug, parent, versionData }) {
|
|
531
|
-
const response = await this.makeRequest('/api/v0/document_versions:create', {
|
|
171
|
+
}
|
|
172
|
+
async function createVersion(args) {
|
|
173
|
+
const { data: response, error } = await this.client.POST('/api/v0/document_versions:create', {
|
|
532
174
|
body: {
|
|
533
|
-
|
|
175
|
+
collectionId: args.collectionSlug,
|
|
534
176
|
contentSystemId: this.contentSystemId,
|
|
535
|
-
data: dataToContentAPI
|
|
536
|
-
|
|
537
|
-
latest: !autosave
|
|
538
|
-
}
|
|
539
|
-
method: 'POST'
|
|
177
|
+
data: dataToContentAPI(this.payload, args.collectionSlug, args.versionData),
|
|
178
|
+
documentId: String(args.parent),
|
|
179
|
+
latest: !args.autosave
|
|
180
|
+
}
|
|
540
181
|
});
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
|
|
182
|
+
if (error) {
|
|
183
|
+
throw new Error(`Content API createVersion error: ${JSON.stringify(error)}`);
|
|
184
|
+
}
|
|
185
|
+
if (!response) {
|
|
186
|
+
throw new Error('No response from createVersion');
|
|
187
|
+
}
|
|
188
|
+
if (!('data' in response.result)) {
|
|
189
|
+
throw new Error('Unexpected response format from createVersion');
|
|
190
|
+
}
|
|
191
|
+
return unwrapDocument(this.payload, response.result.data, args.collectionSlug);
|
|
192
|
+
}
|
|
193
|
+
async function updateVersion(args) {
|
|
194
|
+
const { data: response, error } = await this.client.POST('/api/v0/document_versions:update', {
|
|
549
195
|
body: {
|
|
550
|
-
|
|
196
|
+
collectionId: args.collection,
|
|
551
197
|
contentSystemId: this.contentSystemId,
|
|
552
198
|
createOnMissing: false,
|
|
553
|
-
data: dataToContentAPI
|
|
554
|
-
where: convertPayloadWhereToContentAPI(where ?? {
|
|
199
|
+
data: dataToContentAPI(this.payload, args.collection, args.versionData),
|
|
200
|
+
where: convertPayloadWhereToContentAPI(args.where ?? {
|
|
555
201
|
id: {
|
|
556
|
-
equals: id
|
|
202
|
+
equals: args.id
|
|
557
203
|
}
|
|
558
204
|
})
|
|
559
|
-
}
|
|
560
|
-
method: 'POST'
|
|
205
|
+
}
|
|
561
206
|
});
|
|
562
|
-
|
|
207
|
+
if (error) {
|
|
208
|
+
throw new Error(`Content API updateVersion error: ${JSON.stringify(error)}`);
|
|
209
|
+
}
|
|
563
210
|
if (!response?.result || !('data' in response.result)) {
|
|
564
211
|
throw new Error('No document data in updateVersion response');
|
|
565
212
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
213
|
+
const doc = response.result.data[0];
|
|
214
|
+
if (!doc) {
|
|
215
|
+
throw new Error('No document version matched the where clause');
|
|
216
|
+
}
|
|
217
|
+
return unwrapDocument(this.payload, doc, args.collection);
|
|
218
|
+
}
|
|
219
|
+
async function deleteVersions(args) {
|
|
220
|
+
if (!args.collection) {
|
|
221
|
+
throw new Error('deleteVersions requires a collection');
|
|
222
|
+
}
|
|
223
|
+
const { error } = await this.client.POST('/api/v0/document_versions:delete', {
|
|
570
224
|
body: {
|
|
571
|
-
|
|
225
|
+
collectionId: args.collection,
|
|
572
226
|
contentSystemId: this.contentSystemId,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
},
|
|
576
|
-
method: 'POST'
|
|
227
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
228
|
+
}
|
|
577
229
|
});
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
230
|
+
if (error) {
|
|
231
|
+
throw new Error(`Content API deleteVersions error: ${JSON.stringify(error)}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function findOne(args) {
|
|
235
|
+
const { docs } = await this.find({
|
|
236
|
+
collection: args.collection,
|
|
237
|
+
joins: args.joins,
|
|
582
238
|
limit: 1,
|
|
583
239
|
pagination: false,
|
|
584
|
-
where
|
|
240
|
+
where: args.where
|
|
585
241
|
});
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
const response = await this.makeRequest('/api/v0/documents:update', {
|
|
242
|
+
return docs[0] ?? null;
|
|
243
|
+
}
|
|
244
|
+
async function updateMany(args) {
|
|
245
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:update', {
|
|
591
246
|
body: {
|
|
592
|
-
|
|
247
|
+
collectionId: args.collection,
|
|
593
248
|
contentSystemId: this.contentSystemId,
|
|
594
249
|
createOnMissing: false,
|
|
595
|
-
data: dataToContentAPI
|
|
250
|
+
data: dataToContentAPI(this.payload, args.collection, args.data),
|
|
596
251
|
returning: {},
|
|
597
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
598
|
-
}
|
|
599
|
-
method: 'POST'
|
|
252
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
253
|
+
}
|
|
600
254
|
});
|
|
601
|
-
|
|
255
|
+
if (error) {
|
|
256
|
+
throw new Error(`Content API updateMany error: ${JSON.stringify(error)}`);
|
|
257
|
+
}
|
|
258
|
+
if (!response) {
|
|
259
|
+
throw new Error('No response from updateMany');
|
|
260
|
+
}
|
|
602
261
|
if (response.result && 'data' in response.result) {
|
|
603
|
-
return response.result.data.map((doc)=>unwrapDocument
|
|
262
|
+
return response.result.data.map((doc)=>unwrapDocument(this.payload, doc, args.collection));
|
|
604
263
|
}
|
|
605
264
|
return null;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
const response = await this.
|
|
265
|
+
}
|
|
266
|
+
async function updateOne(args) {
|
|
267
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:update', {
|
|
609
268
|
body: {
|
|
610
|
-
|
|
269
|
+
collectionId: args.collection,
|
|
611
270
|
contentSystemId: this.contentSystemId,
|
|
612
271
|
createOnMissing: false,
|
|
613
|
-
data: dataToContentAPI
|
|
614
|
-
|
|
272
|
+
data: dataToContentAPI(this.payload, args.collection, args.data),
|
|
273
|
+
returning: {},
|
|
274
|
+
where: convertPayloadWhereToContentAPI(args.where ?? {
|
|
615
275
|
id: {
|
|
616
|
-
equals: id
|
|
276
|
+
equals: args.id
|
|
617
277
|
}
|
|
618
278
|
})
|
|
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
279
|
}
|
|
628
|
-
|
|
280
|
+
});
|
|
281
|
+
if (error) {
|
|
282
|
+
throw new Error(`Content API updateOne error: ${JSON.stringify(error)}`);
|
|
283
|
+
}
|
|
284
|
+
if (!response) {
|
|
285
|
+
throw new Error('No response from updateOne');
|
|
286
|
+
}
|
|
287
|
+
if (!response.result || !('data' in response.result)) {
|
|
288
|
+
throw new Error('Unexpected response format from updateOne');
|
|
289
|
+
}
|
|
290
|
+
const doc = response.result.data[0];
|
|
291
|
+
if (!doc) {
|
|
292
|
+
throw new Error('No document matched the where clause for update');
|
|
629
293
|
}
|
|
630
|
-
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
await this.
|
|
294
|
+
return unwrapDocument(this.payload, doc, args.collection);
|
|
295
|
+
}
|
|
296
|
+
async function deleteMany(args) {
|
|
297
|
+
const { error } = await this.client.POST('/api/v0/documents:delete', {
|
|
634
298
|
body: {
|
|
635
|
-
|
|
299
|
+
collectionId: args.collection,
|
|
636
300
|
contentSystemId: this.contentSystemId,
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
},
|
|
640
|
-
method: 'POST'
|
|
301
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
302
|
+
}
|
|
641
303
|
});
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
304
|
+
if (error) {
|
|
305
|
+
throw new Error(`Content API deleteMany error: ${JSON.stringify(error)}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async function deleteOne(args) {
|
|
309
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:delete', {
|
|
645
310
|
body: {
|
|
646
|
-
|
|
311
|
+
collectionId: args.collection,
|
|
647
312
|
contentSystemId: this.contentSystemId,
|
|
648
|
-
returning:
|
|
649
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
650
|
-
}
|
|
651
|
-
method: 'POST'
|
|
313
|
+
returning: {},
|
|
314
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
315
|
+
}
|
|
652
316
|
});
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
317
|
+
if (error) {
|
|
318
|
+
throw new Error(`Content API deleteOne error: ${JSON.stringify(error)}`);
|
|
319
|
+
}
|
|
320
|
+
if (!response?.result || !('data' in response.result)) {
|
|
321
|
+
throw new Error('No document data in deleteOne response');
|
|
322
|
+
}
|
|
323
|
+
const doc = response.result.data[0];
|
|
324
|
+
if (!doc) {
|
|
325
|
+
throw new Error('No document matched the where clause for deletion');
|
|
326
|
+
}
|
|
327
|
+
return unwrapDocument(this.payload, doc, args.collection);
|
|
328
|
+
}
|
|
329
|
+
async function create(args) {
|
|
330
|
+
const id = args.data.id || uuid();
|
|
331
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:create', {
|
|
663
332
|
body: {
|
|
664
|
-
|
|
333
|
+
id: String(id),
|
|
334
|
+
collectionId: args.collection,
|
|
665
335
|
contentSystemId: this.contentSystemId,
|
|
666
|
-
data: dataToContentAPI
|
|
667
|
-
|
|
668
|
-
},
|
|
669
|
-
method: 'POST'
|
|
336
|
+
data: dataToContentAPI(this.payload, args.collection, args.data)
|
|
337
|
+
}
|
|
670
338
|
});
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
|
|
339
|
+
if (error) {
|
|
340
|
+
throw new Error(`Content API create error: ${JSON.stringify(error)}`);
|
|
341
|
+
}
|
|
342
|
+
if (!response) {
|
|
343
|
+
throw new Error('No response from create');
|
|
344
|
+
}
|
|
345
|
+
if (!('data' in response.result)) {
|
|
346
|
+
throw new Error('Unexpected response format from create');
|
|
347
|
+
}
|
|
348
|
+
return unwrapDocument(this.payload, response.result.data, args.collection);
|
|
349
|
+
}
|
|
350
|
+
async function count(args) {
|
|
351
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:count', {
|
|
679
352
|
body: {
|
|
680
|
-
|
|
353
|
+
collectionId: args.collection,
|
|
681
354
|
contentSystemId: this.contentSystemId,
|
|
682
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
683
|
-
}
|
|
684
|
-
method: 'POST'
|
|
355
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
356
|
+
}
|
|
685
357
|
});
|
|
358
|
+
if (error) {
|
|
359
|
+
throw new Error(`Content API count error: ${JSON.stringify(error)}`);
|
|
360
|
+
}
|
|
361
|
+
if (!response) {
|
|
362
|
+
throw new Error('No response from count');
|
|
363
|
+
}
|
|
686
364
|
return {
|
|
687
365
|
totalDocs: response.result.count
|
|
688
366
|
};
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
const response = await this.
|
|
367
|
+
}
|
|
368
|
+
async function countVersions(args) {
|
|
369
|
+
const { data: response, error } = await this.client.POST('/api/v0/document_versions:count', {
|
|
692
370
|
body: {
|
|
693
|
-
|
|
371
|
+
collectionId: args.collection,
|
|
694
372
|
contentSystemId: this.contentSystemId,
|
|
695
|
-
where: convertPayloadWhereToContentAPI(where)
|
|
696
|
-
}
|
|
697
|
-
method: 'POST'
|
|
373
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
374
|
+
}
|
|
698
375
|
});
|
|
376
|
+
if (error) {
|
|
377
|
+
throw new Error(`Content API countVersions error: ${JSON.stringify(error)}`);
|
|
378
|
+
}
|
|
379
|
+
if (!response) {
|
|
380
|
+
throw new Error('No response from countVersions');
|
|
381
|
+
}
|
|
699
382
|
return {
|
|
700
383
|
totalDocs: response.result.count
|
|
701
384
|
};
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
|
|
385
|
+
}
|
|
386
|
+
async function upsert(args) {
|
|
387
|
+
let documentId = args.data.id;
|
|
388
|
+
if (!documentId && args.where && 'id' in args.where) {
|
|
389
|
+
const idClause = args.where.id;
|
|
390
|
+
if (idClause && 'equals' in idClause) {
|
|
391
|
+
documentId = idClause.equals;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!documentId) {
|
|
395
|
+
documentId = uuid();
|
|
396
|
+
}
|
|
397
|
+
const { data: response, error } = await this.client.POST('/api/v0/documents:update', {
|
|
705
398
|
body: {
|
|
706
|
-
|
|
399
|
+
collectionId: args.collection,
|
|
707
400
|
contentSystemId: this.contentSystemId,
|
|
708
|
-
createOnMissing:
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
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');
|
|
401
|
+
createOnMissing: {
|
|
402
|
+
id: documentId
|
|
403
|
+
},
|
|
404
|
+
data: dataToContentAPI(this.payload, args.collection, args.data),
|
|
405
|
+
where: convertPayloadWhereToContentAPI(args.where)
|
|
719
406
|
}
|
|
720
|
-
|
|
407
|
+
});
|
|
408
|
+
if (error) {
|
|
409
|
+
throw new Error(`Content API upsert error: ${JSON.stringify(error)}`);
|
|
410
|
+
}
|
|
411
|
+
if (!response) {
|
|
412
|
+
throw new Error('No response from upsert');
|
|
413
|
+
}
|
|
414
|
+
if (!response.result || !('data' in response.result)) {
|
|
415
|
+
throw new Error('Unexpected response format from upsert');
|
|
416
|
+
}
|
|
417
|
+
const doc = response.result.data[0];
|
|
418
|
+
if (!doc) {
|
|
419
|
+
throw new Error('No document data in upsert response');
|
|
721
420
|
}
|
|
722
|
-
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const getGlobalSlug = (slug)=>`_global-${slug}`;
|
|
726
|
-
const createGlobal = function({ slug, data }) {
|
|
421
|
+
return unwrapDocument(this.payload, doc, args.collection);
|
|
422
|
+
}
|
|
423
|
+
function createGlobal(args) {
|
|
727
424
|
return this.create({
|
|
728
|
-
collection: getGlobalSlug(slug),
|
|
425
|
+
collection: getGlobalSlug(args.slug),
|
|
729
426
|
data: {
|
|
730
|
-
...data,
|
|
731
|
-
globalType: slug
|
|
427
|
+
...args.data,
|
|
428
|
+
globalType: args.slug
|
|
732
429
|
}
|
|
733
430
|
});
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
431
|
+
}
|
|
432
|
+
function findGlobal(args) {
|
|
737
433
|
return this.findOne({
|
|
738
|
-
collection: getGlobalSlug(slug),
|
|
739
|
-
where
|
|
434
|
+
collection: getGlobalSlug(args.slug),
|
|
435
|
+
where: args.where ?? {}
|
|
740
436
|
});
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
437
|
+
}
|
|
438
|
+
async function updateGlobal(args) {
|
|
439
|
+
// Use upsert to ensure the global exists
|
|
440
|
+
// Use slug as the consistent document ID for globals
|
|
441
|
+
return this.upsert({
|
|
442
|
+
collection: getGlobalSlug(args.slug),
|
|
443
|
+
data: args.data,
|
|
444
|
+
where: {
|
|
445
|
+
id: {
|
|
446
|
+
equals: args.slug
|
|
447
|
+
}
|
|
448
|
+
}
|
|
747
449
|
});
|
|
748
|
-
}
|
|
749
|
-
|
|
450
|
+
}
|
|
451
|
+
// TODO: remove Omit when this PR is released: https://github.com/payloadcms/payload/pull/15183
|
|
452
|
+
function findGlobalVersions(args) {
|
|
750
453
|
return this.findVersions({
|
|
751
|
-
collection: getGlobalSlug(
|
|
752
|
-
limit,
|
|
753
|
-
page,
|
|
754
|
-
pagination,
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
where
|
|
454
|
+
collection: getGlobalSlug(args.global),
|
|
455
|
+
limit: args.limit,
|
|
456
|
+
page: args.page,
|
|
457
|
+
pagination: args.pagination,
|
|
458
|
+
sort: args.sort,
|
|
459
|
+
where: args.where
|
|
758
460
|
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
|
|
461
|
+
}
|
|
462
|
+
function createGlobalVersion(args) {
|
|
463
|
+
// For globals, use the globalSlug as the consistent document ID
|
|
464
|
+
// This matches what we do in updateGlobal
|
|
762
465
|
return this.createVersion({
|
|
763
|
-
autosave,
|
|
764
|
-
collectionSlug: getGlobalSlug(globalSlug),
|
|
765
|
-
createdAt,
|
|
766
|
-
parent:
|
|
767
|
-
updatedAt,
|
|
768
|
-
versionData
|
|
466
|
+
autosave: args.autosave,
|
|
467
|
+
collectionSlug: getGlobalSlug(args.globalSlug),
|
|
468
|
+
createdAt: args.createdAt,
|
|
469
|
+
parent: args.globalSlug,
|
|
470
|
+
updatedAt: args.updatedAt,
|
|
471
|
+
versionData: args.versionData
|
|
769
472
|
});
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// UpdateVersion
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
args.
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
};
|
|
786
|
-
|
|
473
|
+
}
|
|
474
|
+
function updateGlobalVersion(args) {
|
|
475
|
+
// UpdateVersion requires either id OR where, not both
|
|
476
|
+
if (args.id !== undefined) {
|
|
477
|
+
return this.updateVersion({
|
|
478
|
+
id: args.id,
|
|
479
|
+
collection: getGlobalSlug(args.global),
|
|
480
|
+
versionData: args.versionData
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
// args.where is guaranteed by Payload when args.id is undefined
|
|
484
|
+
return this.updateVersion({
|
|
485
|
+
collection: getGlobalSlug(args.global),
|
|
486
|
+
versionData: args.versionData,
|
|
487
|
+
where: args.where
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function countGlobalVersions(args) {
|
|
787
491
|
return this.countVersions({
|
|
788
|
-
collection: getGlobalSlug(
|
|
789
|
-
where
|
|
492
|
+
collection: getGlobalSlug(args.global),
|
|
493
|
+
where: args.where
|
|
790
494
|
});
|
|
791
|
-
}
|
|
792
|
-
export const contentAPIAdapter = (opts)=>{
|
|
793
|
-
return {
|
|
495
|
+
}
|
|
496
|
+
export const contentAPIAdapter = (opts)=>({
|
|
794
497
|
name: 'content_api',
|
|
795
498
|
defaultIDType: 'text',
|
|
796
499
|
init: ({ payload })=>{
|
|
500
|
+
const client = createClient({
|
|
501
|
+
baseUrl: opts.url
|
|
502
|
+
});
|
|
503
|
+
const middlewareOpts = {
|
|
504
|
+
auth: opts.auth,
|
|
505
|
+
contentSystemId: opts.contentSystemId,
|
|
506
|
+
logger: payload.logger,
|
|
507
|
+
url: opts.url
|
|
508
|
+
};
|
|
509
|
+
client.use(createAuthMiddleware(middlewareOpts));
|
|
510
|
+
client.use(createErrorMiddleware(middlewareOpts));
|
|
797
511
|
return createDatabaseAdapter({
|
|
798
512
|
name: 'content_api',
|
|
799
513
|
auth: opts.auth,
|
|
800
|
-
beginTransaction: ()=>
|
|
801
|
-
|
|
802
|
-
},
|
|
514
|
+
beginTransaction: ()=>Promise.resolve('no-op-transaction'),
|
|
515
|
+
client,
|
|
803
516
|
commitTransaction: async ()=>{},
|
|
804
517
|
contentSystemId: opts.contentSystemId,
|
|
805
|
-
count,
|
|
806
|
-
countGlobalVersions,
|
|
807
|
-
countVersions,
|
|
808
|
-
create,
|
|
809
|
-
createGlobal,
|
|
810
|
-
createGlobalVersion,
|
|
811
|
-
createVersion,
|
|
518
|
+
count: count,
|
|
519
|
+
countGlobalVersions: countGlobalVersions,
|
|
520
|
+
countVersions: countVersions,
|
|
521
|
+
create: create,
|
|
522
|
+
createGlobal: createGlobal,
|
|
523
|
+
createGlobalVersion: createGlobalVersion,
|
|
524
|
+
createVersion: createVersion,
|
|
812
525
|
defaultIDType: 'text',
|
|
813
|
-
deleteMany,
|
|
814
|
-
deleteOne,
|
|
815
|
-
deleteVersions,
|
|
816
|
-
find,
|
|
817
|
-
findDistinct: ()=>
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
findOne,
|
|
823
|
-
findVersions,
|
|
526
|
+
deleteMany: deleteMany,
|
|
527
|
+
deleteOne: deleteOne,
|
|
528
|
+
deleteVersions: deleteVersions,
|
|
529
|
+
find: find,
|
|
530
|
+
findDistinct: ()=>Promise.reject(new Error('findDistinct is not yet implemented for Content API adapter')),
|
|
531
|
+
findGlobal: findGlobal,
|
|
532
|
+
findGlobalVersions: findGlobalVersions,
|
|
533
|
+
findOne: findOne,
|
|
534
|
+
findVersions: findVersions,
|
|
824
535
|
init,
|
|
825
|
-
makeRequest,
|
|
826
536
|
packageName: '@payloadcms/db-content-api',
|
|
827
537
|
payload,
|
|
828
|
-
queryDrafts,
|
|
538
|
+
queryDrafts: queryDrafts,
|
|
829
539
|
rollbackTransaction: async ()=>{},
|
|
830
|
-
updateGlobal,
|
|
831
|
-
updateGlobalVersion,
|
|
832
|
-
updateMany,
|
|
833
|
-
updateOne,
|
|
834
|
-
updateVersion,
|
|
835
|
-
upsert,
|
|
540
|
+
updateGlobal: updateGlobal,
|
|
541
|
+
updateGlobalVersion: updateGlobalVersion,
|
|
542
|
+
updateMany: updateMany,
|
|
543
|
+
updateOne: updateOne,
|
|
544
|
+
updateVersion: updateVersion,
|
|
545
|
+
upsert: upsert,
|
|
836
546
|
url: opts.url
|
|
837
547
|
});
|
|
838
548
|
}
|
|
839
|
-
};
|
|
840
|
-
};
|
|
549
|
+
});
|
|
841
550
|
|
|
842
551
|
//# sourceMappingURL=index.js.map
|