@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.
Files changed (90) hide show
  1. package/dist/api/figma-api.d.ts.map +1 -1
  2. package/dist/api/figma-api.js +4 -0
  3. package/dist/api/figma-api.js.map +1 -1
  4. package/dist/commands/deploy.d.ts.map +1 -1
  5. package/dist/commands/deploy.js +32 -50
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/db-content-api/README.md +108 -0
  8. package/dist/db-content-api/generated/content-api-types.d.ts +763 -190
  9. package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -1
  10. package/dist/db-content-api/generated/content-api-types.js.map +1 -1
  11. package/dist/db-content-api/index.d.ts +6 -19
  12. package/dist/db-content-api/index.d.ts.map +1 -1
  13. package/dist/db-content-api/index.js +396 -687
  14. package/dist/db-content-api/index.js.map +1 -1
  15. package/dist/db-content-api/temp-utilities/pagination.d.ts +13 -0
  16. package/dist/db-content-api/temp-utilities/pagination.d.ts.map +1 -0
  17. package/dist/db-content-api/temp-utilities/pagination.js +45 -0
  18. package/dist/db-content-api/temp-utilities/pagination.js.map +1 -0
  19. package/dist/db-content-api/temp-utilities/slug.d.ts +2 -0
  20. package/dist/db-content-api/temp-utilities/slug.d.ts.map +1 -0
  21. package/dist/db-content-api/temp-utilities/slug.js +3 -0
  22. package/dist/db-content-api/temp-utilities/slug.js.map +1 -0
  23. package/dist/db-content-api/temp-utilities/sorting.d.ts +7 -0
  24. package/dist/db-content-api/temp-utilities/sorting.d.ts.map +1 -0
  25. package/dist/db-content-api/temp-utilities/sorting.js +71 -0
  26. package/dist/db-content-api/temp-utilities/sorting.js.map +1 -0
  27. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +4 -0
  28. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts.map +1 -0
  29. package/dist/db-content-api/temp-utilities/unwrapDocument.js +45 -0
  30. package/dist/db-content-api/temp-utilities/unwrapDocument.js.map +1 -0
  31. package/dist/db-content-api/utilities/auth.d.ts +30 -0
  32. package/dist/db-content-api/utilities/auth.d.ts.map +1 -0
  33. package/dist/db-content-api/utilities/auth.js +81 -0
  34. package/dist/db-content-api/utilities/auth.js.map +1 -0
  35. package/dist/db-content-api/utilities/data.d.ts +24 -0
  36. package/dist/db-content-api/utilities/data.d.ts.map +1 -0
  37. package/dist/db-content-api/utilities/data.js +118 -0
  38. package/dist/db-content-api/utilities/data.js.map +1 -0
  39. package/dist/db-content-api/utilities/joins.d.ts +55 -0
  40. package/dist/db-content-api/utilities/joins.d.ts.map +1 -0
  41. package/dist/db-content-api/utilities/joins.js +130 -0
  42. package/dist/db-content-api/utilities/joins.js.map +1 -0
  43. package/dist/db-content-api/utilities/where.d.ts +12 -0
  44. package/dist/db-content-api/utilities/where.d.ts.map +1 -0
  45. package/dist/db-content-api/utilities/where.js +63 -0
  46. package/dist/db-content-api/utilities/where.js.map +1 -0
  47. package/dist/plugin/build-config.d.ts +1 -0
  48. package/dist/plugin/build-config.d.ts.map +1 -1
  49. package/dist/plugin/build-config.js +38 -0
  50. package/dist/plugin/build-config.js.map +1 -1
  51. package/dist/storage-content-api/api-types.d.ts +161 -0
  52. package/dist/storage-content-api/api-types.d.ts.map +1 -0
  53. package/dist/storage-content-api/api-types.js +6 -0
  54. package/dist/storage-content-api/api-types.js.map +1 -0
  55. package/dist/storage-content-api/client.d.ts +6 -0
  56. package/dist/storage-content-api/client.d.ts.map +1 -0
  57. package/dist/storage-content-api/client.js +36 -0
  58. package/dist/storage-content-api/client.js.map +1 -0
  59. package/dist/storage-content-api/generateURL.d.ts +7 -0
  60. package/dist/storage-content-api/generateURL.d.ts.map +1 -0
  61. package/dist/storage-content-api/generateURL.js +7 -0
  62. package/dist/storage-content-api/generateURL.js.map +1 -0
  63. package/dist/storage-content-api/handleDelete.d.ts +8 -0
  64. package/dist/storage-content-api/handleDelete.d.ts.map +1 -0
  65. package/dist/storage-content-api/handleDelete.js +15 -0
  66. package/dist/storage-content-api/handleDelete.js.map +1 -0
  67. package/dist/storage-content-api/handleUpload.d.ts +11 -0
  68. package/dist/storage-content-api/handleUpload.d.ts.map +1 -0
  69. package/dist/storage-content-api/handleUpload.js +126 -0
  70. package/dist/storage-content-api/handleUpload.js.map +1 -0
  71. package/dist/storage-content-api/index.d.ts +5 -0
  72. package/dist/storage-content-api/index.d.ts.map +1 -0
  73. package/dist/storage-content-api/index.js +31 -0
  74. package/dist/storage-content-api/index.js.map +1 -0
  75. package/dist/storage-content-api/staticHandler.d.ts +10 -0
  76. package/dist/storage-content-api/staticHandler.d.ts.map +1 -0
  77. package/dist/storage-content-api/staticHandler.js +35 -0
  78. package/dist/storage-content-api/staticHandler.js.map +1 -0
  79. package/dist/storage-content-api/types.d.ts +10 -0
  80. package/dist/storage-content-api/types.d.ts.map +1 -0
  81. package/dist/storage-content-api/types.js +3 -0
  82. package/dist/storage-content-api/types.js.map +1 -0
  83. package/dist/utils/lambda-config.d.ts.map +1 -1
  84. package/dist/utils/lambda-config.js +1 -0
  85. package/dist/utils/lambda-config.js.map +1 -1
  86. package/package.json +5 -2
  87. package/dist/db-content-api/types.d.ts +0 -31
  88. package/dist/db-content-api/types.d.ts.map +0 -1
  89. package/dist/db-content-api/types.js +0 -7
  90. package/dist/db-content-api/types.js.map +0 -1
@@ -1,33 +1,15 @@
1
- import { createDatabaseAdapter, traverseFields } from 'payload';
1
+ import createClient from 'openapi-fetch';
2
+ import { createDatabaseAdapter } from 'payload';
2
3
  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
- }
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.makeRequest('/dev/clear-db', {
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
- // Fetch existing collections once
54
- let existingKeys;
37
+ let existingIds;
55
38
  try {
56
- const response = await this.makeRequest(`/api/v0/collections?contentSystemId=${this.contentSystemId}`, {
57
- method: 'GET'
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
- existingKeys = new Set(response.data.map((c)=>c.key));
60
- this.payload.logger.info(`Found ${existingKeys.size} existing collections`);
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
- existingKeys = new Set();
56
+ existingIds = new Set();
64
57
  }
65
- // Create only missing collections
66
58
  for (const collection of this.payload.config.collections){
67
- if (!existingKeys.has(collection.slug)) {
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 globalKey = `_global-${global.slug}`;
74
- if (!existingKeys.has(globalKey)) {
75
- await createCollection.call(this, globalKey);
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
- // Helper to create a collection
81
- async function createCollection(collectionKey) {
70
+ async function createCollection(collectionId) {
82
71
  try {
83
- await this.makeRequest('/api/v0/collections', {
72
+ const { error } = await this.client.POST('/api/v0/content_systems/{contentSystemId}/collections', {
84
73
  body: {
85
- name: collectionKey,
86
- contentSystemId: this.contentSystemId,
87
- key: collectionKey
74
+ id: collectionId
88
75
  },
89
- method: 'POST'
76
+ params: {
77
+ path: {
78
+ contentSystemId: this.contentSystemId
79
+ }
80
+ }
90
81
  });
91
- this.payload.logger.info(`Created collection: ${collectionKey}`);
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 ${collectionKey}: ${errorMessage}`);
89
+ this.payload.logger.warn(`Failed to create collection ${collectionId}: ${errorMessage}`);
97
90
  }
98
91
  }
99
92
  }
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}`);
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
- // 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
- });
107
+ if (error) {
108
+ throw new Error(`Content API findMany error: ${JSON.stringify(error)}`);
149
109
  }
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];
110
+ if (!response) {
111
+ throw new Error('No response from findMany');
239
112
  }
240
113
  return {
241
- and: conditions
114
+ docs: response.result.data.map((doc)=>unwrapDocument(this.payload, doc, collection)),
115
+ ...getPaginationData(response.result.pagination, pagination)
242
116
  };
243
117
  }
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
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
- * 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
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
- 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', {
135
+ const { data: response, error } = await this.client.POST('/api/v0/document_versions:find', {
444
136
  body: {
445
- collectionKey: collectionSlug,
137
+ collectionId: args.collection,
446
138
  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'
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: 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
153
+ docs,
154
+ ...getPaginationData(response.result.pagination, args.pagination)
505
155
  };
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,
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: false
167
+ equals: true
524
168
  }
525
169
  }
526
170
  });
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', {
171
+ }
172
+ async function createVersion(args) {
173
+ const { data: response, error } = await this.client.POST('/api/v0/document_versions:create', {
532
174
  body: {
533
- collectionKey: collectionSlug,
175
+ collectionId: args.collectionSlug,
534
176
  contentSystemId: this.contentSystemId,
535
- data: dataToContentAPI.call(this, collectionSlug, versionData),
536
- documentKey: parent,
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
- // 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', {
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
- collectionKey: collectionSlug,
196
+ collectionId: args.collection,
551
197
  contentSystemId: this.contentSystemId,
552
198
  createOnMissing: false,
553
- data: dataToContentAPI.call(this, collectionSlug, versionData),
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
- // Handle union type response: { count: number } | { data: DocumentVersion[] }
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
- 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', {
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
- collectionKey: collectionSlug,
225
+ collectionId: args.collection,
572
226
  contentSystemId: this.contentSystemId,
573
- returning: false,
574
- where: convertPayloadWhereToContentAPI(where)
575
- },
576
- method: 'POST'
227
+ where: convertPayloadWhereToContentAPI(args.where)
228
+ }
577
229
  });
578
- };
579
- const findOne = async function findOne({ collection, where }) {
580
- const { docs: [first] } = await this.find({
581
- collection,
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
- // 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', {
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
- collectionKey: collectionSlug,
247
+ collectionId: args.collection,
593
248
  contentSystemId: this.contentSystemId,
594
249
  createOnMissing: false,
595
- data: dataToContentAPI.call(this, collectionSlug, data),
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
- // Handle union type: { count: number } | { data: Document[] }
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.call(this, doc, collectionSlug));
262
+ return response.result.data.map((doc)=>unwrapDocument(this.payload, doc, args.collection));
604
263
  }
605
264
  return null;
606
- };
607
- const updateOne = async function updateOne({ id, collection: collectionSlug, data, where }) {
608
- const response = await this.makeRequest('/api/v0/documents:update', {
265
+ }
266
+ async function updateOne(args) {
267
+ const { data: response, error } = await this.client.POST('/api/v0/documents:update', {
609
268
  body: {
610
- collectionKey: collectionSlug,
269
+ collectionId: args.collection,
611
270
  contentSystemId: this.contentSystemId,
612
271
  createOnMissing: false,
613
- data: dataToContentAPI.call(this, collectionSlug, data),
614
- where: convertPayloadWhereToContentAPI(where ?? {
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
- return unwrapDocument.call(this, doc, collectionSlug);
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
- 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', {
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
- collectionKey: collectionSlug,
299
+ collectionId: args.collection,
636
300
  contentSystemId: this.contentSystemId,
637
- returning: false,
638
- where: convertPayloadWhereToContentAPI(where)
639
- },
640
- method: 'POST'
301
+ where: convertPayloadWhereToContentAPI(args.where)
302
+ }
641
303
  });
642
- };
643
- const deleteOne = async function deleteOne({ collection: collectionSlug, where }) {
644
- await this.makeRequest('/api/v0/documents:delete', {
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
- collectionKey: collectionSlug,
311
+ collectionId: args.collection,
647
312
  contentSystemId: this.contentSystemId,
648
- returning: false,
649
- where: convertPayloadWhereToContentAPI(where)
650
- },
651
- method: 'POST'
313
+ returning: {},
314
+ where: convertPayloadWhereToContentAPI(args.where)
315
+ }
652
316
  });
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', {
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
- collectionKey: collectionSlug,
333
+ id: String(id),
334
+ collectionId: args.collection,
665
335
  contentSystemId: this.contentSystemId,
666
- data: dataToContentAPI.call(this, collectionSlug, data),
667
- key
668
- },
669
- method: 'POST'
336
+ data: dataToContentAPI(this.payload, args.collection, args.data)
337
+ }
670
338
  });
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', {
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
- collectionKey: collectionSlug,
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
- const countVersions = async function countVersions({ collection: collectionSlug, where }) {
691
- const response = await this.makeRequest('/api/v0/document_versions:count', {
367
+ }
368
+ async function countVersions(args) {
369
+ const { data: response, error } = await this.client.POST('/api/v0/document_versions:count', {
692
370
  body: {
693
- collectionKey: collectionSlug,
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
- const upsert = async function upsert({ collection: collectionSlug, data, where }) {
704
- const response = await this.makeRequest('/api/v0/documents:update', {
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
- collectionKey: collectionSlug,
399
+ collectionId: args.collection,
707
400
  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');
401
+ createOnMissing: {
402
+ id: documentId
403
+ },
404
+ data: dataToContentAPI(this.payload, args.collection, args.data),
405
+ where: convertPayloadWhereToContentAPI(args.where)
719
406
  }
720
- return unwrapDocument.call(this, doc, collectionSlug);
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
- 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 }) {
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
- const findGlobal = function({ slug, where = {} }) {
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
- const updateGlobal = function({ slug, data }) {
743
- return this.updateOne({
744
- collection: getGlobalSlug(slug),
745
- data,
746
- where: {}
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
- const findGlobalVersions = function({ global: slug, limit, page, pagination, skip, sort, where }) {
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(slug),
752
- limit,
753
- page,
754
- pagination,
755
- skip,
756
- sort,
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
- const createGlobalVersion = function(// eslint-disable-next-line @typescript-eslint/no-explicit-any
761
- { autosave, createdAt, globalSlug, updatedAt, versionData, ...rest }) {
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: rest.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
- 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 }) {
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(slug),
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
- return Promise.resolve('no-op-transaction');
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
- return Promise.reject(new Error('findDistinct is not yet implemented for Content API adapter'));
819
- },
820
- findGlobal,
821
- findGlobalVersions,
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