@payloadcms/figma 0.0.1-alpha.3 → 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/control-plane.d.ts +22 -1
- package/dist/api/control-plane.d.ts.map +1 -1
- package/dist/api/control-plane.js +54 -15
- package/dist/api/control-plane.js.map +1 -1
- package/dist/api/figma-api.d.ts.map +1 -1
- package/dist/api/figma-api.js +42 -12
- package/dist/api/figma-api.js.map +1 -1
- package/dist/auth/callback-server.d.ts.map +1 -1
- package/dist/auth/callback-server.js +2 -1
- package/dist/auth/callback-server.js.map +1 -1
- package/dist/auth/crypto-utils.d.ts.map +1 -1
- package/dist/auth/crypto-utils.js +5 -5
- package/dist/auth/crypto-utils.js.map +1 -1
- package/dist/auth/oauth-flow.d.ts +1 -1
- package/dist/auth/oauth-flow.d.ts.map +1 -1
- package/dist/auth/oauth-flow.js +5 -5
- package/dist/auth/oauth-flow.js.map +1 -1
- package/dist/auth/project-token.d.ts.map +1 -1
- package/dist/auth/project-token.js +9 -4
- package/dist/auth/project-token.js.map +1 -1
- package/dist/auth/token-store.d.ts +10 -0
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +20 -0
- package/dist/auth/token-store.js.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/deploy.d.ts +4 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +68 -126
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.d.ts +1 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +90 -85
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list-tokens.js +2 -2
- package/dist/commands/list-tokens.js.map +1 -1
- package/dist/commands/login.d.ts +8 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +12 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +2 -2
- package/dist/commands/logout.js.map +1 -1
- package/dist/config/oauth.d.ts +5 -0
- package/dist/config/oauth.d.ts.map +1 -1
- package/dist/config/oauth.js +9 -4
- package/dist/config/oauth.js.map +1 -1
- package/dist/db-content-api/README.md +108 -0
- package/dist/db-content-api/generated/content-api-types.d.ts +3702 -0
- package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -0
- package/dist/db-content-api/generated/content-api-types.js +7 -0
- package/dist/db-content-api/generated/content-api-types.js.map +1 -0
- package/dist/db-content-api/index.d.ts +18 -0
- package/dist/db-content-api/index.d.ts.map +1 -0
- package/dist/db-content-api/index.js +551 -0
- package/dist/db-content-api/index.js.map +1 -0
- 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/endpoints/health.d.ts +3 -0
- package/dist/endpoints/health.d.ts.map +1 -0
- package/dist/endpoints/health.js +11 -0
- package/dist/endpoints/health.js.map +1 -0
- package/dist/exports/client.d.ts +3 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +4 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LoginButton/index.js +50 -6
- package/dist/oauth/components/LoginButton/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.scss +50 -3
- package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LogoutButton/index.js +0 -1
- package/dist/oauth/components/LogoutButton/index.js.map +1 -1
- package/dist/oauth/defaults.d.ts.map +1 -1
- package/dist/oauth/defaults.js +29 -5
- package/dist/oauth/defaults.js.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +42 -6
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/strategy/index.d.ts.map +1 -1
- package/dist/oauth/strategy/index.js +6 -2
- package/dist/oauth/strategy/index.js.map +1 -1
- package/dist/oauth/types.d.ts +6 -6
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/oauth/types.js.map +1 -1
- package/dist/oauth/utilities/createCookieOptions.d.ts.map +1 -1
- package/dist/oauth/utilities/createCookieOptions.js.map +1 -1
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts +7 -0
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts.map +1 -0
- package/dist/oauth/utilities/isDuplicateKeyError.js +14 -0
- package/dist/oauth/utilities/isDuplicateKeyError.js.map +1 -0
- package/dist/oauth/utilities/refreshTokens.d.ts.map +1 -1
- package/dist/oauth/utilities/refreshTokens.js +1 -1
- package/dist/oauth/utilities/refreshTokens.js.map +1 -1
- package/dist/plugin/build-config.d.ts +21 -4
- package/dist/plugin/build-config.d.ts.map +1 -1
- package/dist/plugin/build-config.js +89 -9
- 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/templates/README.md +19 -0
- package/dist/utils/env-management.d.ts +9 -8
- package/dist/utils/env-management.d.ts.map +1 -1
- package/dist/utils/env-management.js +73 -74
- package/dist/utils/env-management.js.map +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +1 -7
- package/dist/utils/formatter.js.map +1 -1
- 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/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +5 -7
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/payload-config-ast.d.ts +22 -3
- package/dist/utils/payload-config-ast.d.ts.map +1 -1
- package/dist/utils/payload-config-ast.js +89 -31
- package/dist/utils/payload-config-ast.js.map +1 -1
- package/dist/utils/payload-config-finder.d.ts +2 -2
- package/dist/utils/payload-config-finder.d.ts.map +1 -1
- package/dist/utils/payload-config-finder.js +48 -9
- package/dist/utils/payload-config-finder.js.map +1 -1
- package/dist/utils/payload-config-modifier.d.ts.map +1 -1
- package/dist/utils/payload-config-modifier.js +33 -4
- package/dist/utils/payload-config-modifier.js.map +1 -1
- package/dist/utils/payload-package-check.d.ts +5 -0
- package/dist/utils/payload-package-check.d.ts.map +1 -1
- package/dist/utils/payload-package-check.js +48 -4
- package/dist/utils/payload-package-check.js.map +1 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +8 -6
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/s3-upload.d.ts +0 -1
- package/dist/utils/s3-upload.d.ts.map +1 -1
- package/dist/utils/s3-upload.js +10 -3
- package/dist/utils/s3-upload.js.map +1 -1
- package/dist/utils/token-display.d.ts.map +1 -1
- package/dist/utils/token-display.js +11 -5
- package/dist/utils/token-display.js.map +1 -1
- package/dist/utils/typescript-validator.d.ts.map +1 -1
- package/dist/utils/typescript-validator.js +1 -6
- package/dist/utils/typescript-validator.js.map +1 -1
- package/package.json +24 -7
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Convert Content API pagination response to Payload's expected format
|
|
2
|
+
// Content API already calculates next/prev pages, we just need to transform the structure
|
|
3
|
+
//
|
|
4
|
+
// Content API format (nested):
|
|
5
|
+
// {
|
|
6
|
+
// data: [...],
|
|
7
|
+
// pagination: {
|
|
8
|
+
// total: 100,
|
|
9
|
+
// current: { limit: 10, page: 2 },
|
|
10
|
+
// next: { limit: 10, page: 3 },
|
|
11
|
+
// prev: { limit: 10, page: 1 }
|
|
12
|
+
// }
|
|
13
|
+
// }
|
|
14
|
+
//
|
|
15
|
+
// Payload format (flat):
|
|
16
|
+
// {
|
|
17
|
+
// docs: [...],
|
|
18
|
+
// hasNextPage: true,
|
|
19
|
+
// hasPrevPage: true,
|
|
20
|
+
// limit: 10,
|
|
21
|
+
// nextPage: 3,
|
|
22
|
+
// page: 2,
|
|
23
|
+
// pagingCounter: 11,
|
|
24
|
+
// prevPage: 1,
|
|
25
|
+
// totalDocs: 100,
|
|
26
|
+
// totalPages: 10
|
|
27
|
+
// }
|
|
28
|
+
export const getPaginationData = (contentAPIPagination, pagination)=>{
|
|
29
|
+
const { current, next, prev, total } = contentAPIPagination;
|
|
30
|
+
const hasNextPage = pagination !== false && next !== undefined;
|
|
31
|
+
const hasPrevPage = pagination !== false && prev !== undefined;
|
|
32
|
+
return {
|
|
33
|
+
hasNextPage,
|
|
34
|
+
hasPrevPage,
|
|
35
|
+
limit: current.limit,
|
|
36
|
+
nextPage: next?.page ?? null,
|
|
37
|
+
page: current.page,
|
|
38
|
+
pagingCounter: (current.page - 1) * current.limit + 1,
|
|
39
|
+
prevPage: prev?.page ?? null,
|
|
40
|
+
totalDocs: total,
|
|
41
|
+
totalPages: current.limit > 0 ? Math.ceil(total / current.limit) : 1
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/temp-utilities/pagination.ts"],"sourcesContent":["import type { components } from '../generated/content-api-types.js'\n\n// Convert Content API pagination response to Payload's expected format\n// Content API already calculates next/prev pages, we just need to transform the structure\n//\n// Content API format (nested):\n// {\n// data: [...],\n// pagination: {\n// total: 100,\n// current: { limit: 10, page: 2 },\n// next: { limit: 10, page: 3 },\n// prev: { limit: 10, page: 1 }\n// }\n// }\n//\n// Payload format (flat):\n// {\n// docs: [...],\n// hasNextPage: true,\n// hasPrevPage: true,\n// limit: 10,\n// nextPage: 3,\n// page: 2,\n// pagingCounter: 11,\n// prevPage: 1,\n// totalDocs: 100,\n// totalPages: 10\n// }\nexport const getPaginationData = (\n contentAPIPagination: components['schemas']['Pagination'],\n pagination?: boolean,\n) => {\n const { current, next, prev, total } = contentAPIPagination\n const hasNextPage = pagination !== false && next !== undefined\n const hasPrevPage = pagination !== false && prev !== undefined\n\n return {\n hasNextPage,\n hasPrevPage,\n limit: current.limit,\n nextPage: next?.page ?? null,\n page: current.page,\n pagingCounter: (current.page - 1) * current.limit + 1,\n prevPage: prev?.page ?? null,\n totalDocs: total,\n totalPages: current.limit > 0 ? Math.ceil(total / current.limit) : 1,\n }\n}\n"],"names":["getPaginationData","contentAPIPagination","pagination","current","next","prev","total","hasNextPage","undefined","hasPrevPage","limit","nextPage","page","pagingCounter","prevPage","totalDocs","totalPages","Math","ceil"],"mappings":"AAEA,uEAAuE;AACvE,0FAA0F;AAC1F,EAAE;AACF,+BAA+B;AAC/B,IAAI;AACJ,iBAAiB;AACjB,kBAAkB;AAClB,kBAAkB;AAClB,uCAAuC;AACvC,oCAAoC;AACpC,mCAAmC;AACnC,MAAM;AACN,IAAI;AACJ,EAAE;AACF,yBAAyB;AACzB,IAAI;AACJ,iBAAiB;AACjB,uBAAuB;AACvB,uBAAuB;AACvB,eAAe;AACf,iBAAiB;AACjB,aAAa;AACb,uBAAuB;AACvB,iBAAiB;AACjB,oBAAoB;AACpB,mBAAmB;AACnB,IAAI;AACJ,OAAO,MAAMA,oBAAoB,CAC/BC,sBACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,IAAI,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAGL;IACvC,MAAMM,cAAcL,eAAe,SAASE,SAASI;IACrD,MAAMC,cAAcP,eAAe,SAASG,SAASG;IAErD,OAAO;QACLD;QACAE;QACAC,OAAOP,QAAQO,KAAK;QACpBC,UAAUP,MAAMQ,QAAQ;QACxBA,MAAMT,QAAQS,IAAI;QAClBC,eAAe,AAACV,CAAAA,QAAQS,IAAI,GAAG,CAAA,IAAKT,QAAQO,KAAK,GAAG;QACpDI,UAAUT,MAAMO,QAAQ;QACxBG,WAAWT;QACXU,YAAYb,QAAQO,KAAK,GAAG,IAAIO,KAAKC,IAAI,CAACZ,QAAQH,QAAQO,KAAK,IAAI;IACrE;AACF,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/temp-utilities/slug.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,SAAU,MAAM,WAAsB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/temp-utilities/slug.ts"],"sourcesContent":["export const getGlobalSlug = (slug: string) => `_global-${slug}`\n"],"names":["getGlobalSlug","slug"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,CAACC,OAAiB,CAAC,QAAQ,EAAEA,MAAM,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CollectionConfig } from 'payload';
|
|
2
|
+
export declare function addFallbackSort(sort: string | string[] | undefined, collectionConfig: CollectionConfig | undefined): string | string[] | undefined;
|
|
3
|
+
export declare function convertPayloadSortToContentAPI(sort: string | string[] | undefined): Array<{
|
|
4
|
+
direction: 'asc' | 'desc';
|
|
5
|
+
path: string;
|
|
6
|
+
}> | undefined;
|
|
7
|
+
//# sourceMappingURL=sorting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sorting.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/temp-utilities/sorting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAK/C,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EACnC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,GAC7C,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CA4B/B;AAcD,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAClC,KAAK,CAAC;IAAE,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,CA2BhE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Add fallback sort to ensure consistent ordering when sorting by non-unique fields
|
|
2
|
+
// Matches MongoDB adapter behavior
|
|
3
|
+
// TO-DECIDE: Should this live here or in content-api?
|
|
4
|
+
export function addFallbackSort(sort, collectionConfig) {
|
|
5
|
+
if (!sort || !collectionConfig) {
|
|
6
|
+
return sort;
|
|
7
|
+
}
|
|
8
|
+
const sortArray = Array.isArray(sort) ? sort : [
|
|
9
|
+
sort
|
|
10
|
+
];
|
|
11
|
+
// Determine fallback sort field
|
|
12
|
+
let fallbackSort = '-id';
|
|
13
|
+
if (collectionConfig.timestamps !== false) {
|
|
14
|
+
fallbackSort = '-createdAt';
|
|
15
|
+
}
|
|
16
|
+
// Check if fallback sort is already included
|
|
17
|
+
const hasFallback = sortArray.some((item)=>item === fallbackSort || item === fallbackSort.replace('-', ''));
|
|
18
|
+
if (hasFallback) {
|
|
19
|
+
return sort;
|
|
20
|
+
}
|
|
21
|
+
// Check if all sort fields are unique (then no fallback needed)
|
|
22
|
+
// For simplicity, we'll always add fallback - checking uniqueness requires field traversal
|
|
23
|
+
// which would be expensive. This matches the conservative approach.
|
|
24
|
+
// Add fallback sort - always return array to preserve multiple sort fields
|
|
25
|
+
return [
|
|
26
|
+
...sortArray,
|
|
27
|
+
fallbackSort
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed
|
|
31
|
+
//
|
|
32
|
+
// TODO: Content API should accept Payload's native Sort format instead of requiring conversion.
|
|
33
|
+
// This converter exists because Content API expects a different format.
|
|
34
|
+
//
|
|
35
|
+
// Payload's format: "-createdAt" or ["createdAt", "-updatedAt"]
|
|
36
|
+
// Content API expects: [{ path: "createdAt", direction: "dsc" }]
|
|
37
|
+
//
|
|
38
|
+
// Once Content API accepts Payload's format:
|
|
39
|
+
// 1. Remove this function entirely
|
|
40
|
+
// 2. Remove all calls to convertPayloadSortToContentAPI()
|
|
41
|
+
// 3. Pass `sort` directly to Content API endpoints
|
|
42
|
+
export function convertPayloadSortToContentAPI(sort) {
|
|
43
|
+
if (!sort) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const sortArray = Array.isArray(sort) ? sort : [
|
|
47
|
+
sort
|
|
48
|
+
];
|
|
49
|
+
return sortArray.map((field)=>{
|
|
50
|
+
let path = field;
|
|
51
|
+
let direction = 'asc';
|
|
52
|
+
// Check if field starts with '-' for descending
|
|
53
|
+
if (field.startsWith('-')) {
|
|
54
|
+
path = field.substring(1); // Remove the '-'
|
|
55
|
+
direction = 'desc';
|
|
56
|
+
}
|
|
57
|
+
// ⚠️ WORKAROUND: Strip "version." prefix from field names
|
|
58
|
+
// Payload sends "-version.createdAt" for version sort fields
|
|
59
|
+
// but Content API expects just "createdAt"
|
|
60
|
+
// TODO: Content API should handle version field paths correctly
|
|
61
|
+
if (path.startsWith('version.')) {
|
|
62
|
+
path = path.substring(8); // Remove "version." prefix
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
direction,
|
|
66
|
+
path
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=sorting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/temp-utilities/sorting.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\n// Add fallback sort to ensure consistent ordering when sorting by non-unique fields\n// Matches MongoDB adapter behavior\n// TO-DECIDE: Should this live here or in content-api?\nexport function addFallbackSort(\n sort: string | string[] | undefined,\n collectionConfig: CollectionConfig | undefined,\n): string | string[] | undefined {\n if (!sort || !collectionConfig) {\n return sort\n }\n\n const sortArray = Array.isArray(sort) ? sort : [sort]\n\n // Determine fallback sort field\n let fallbackSort = '-id'\n if (collectionConfig.timestamps !== false) {\n fallbackSort = '-createdAt'\n }\n\n // Check if fallback sort is already included\n const hasFallback = sortArray.some(\n (item) => item === fallbackSort || item === fallbackSort.replace('-', ''),\n )\n\n if (hasFallback) {\n return sort\n }\n\n // Check if all sort fields are unique (then no fallback needed)\n // For simplicity, we'll always add fallback - checking uniqueness requires field traversal\n // which would be expensive. This matches the conservative approach.\n\n // Add fallback sort - always return array to preserve multiple sort fields\n return [...sortArray, fallbackSort]\n}\n\n// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed\n//\n// TODO: Content API should accept Payload's native Sort format instead of requiring conversion.\n// This converter exists because Content API expects a different format.\n//\n// Payload's format: \"-createdAt\" or [\"createdAt\", \"-updatedAt\"]\n// Content API expects: [{ path: \"createdAt\", direction: \"dsc\" }]\n//\n// Once Content API accepts Payload's format:\n// 1. Remove this function entirely\n// 2. Remove all calls to convertPayloadSortToContentAPI()\n// 3. Pass `sort` directly to Content API endpoints\nexport function convertPayloadSortToContentAPI(\n sort: string | string[] | undefined,\n): Array<{ direction: 'asc' | 'desc'; path: string }> | undefined {\n if (!sort) {\n return undefined\n }\n\n const sortArray = Array.isArray(sort) ? sort : [sort]\n\n return sortArray.map((field) => {\n let path = field\n let direction: 'asc' | 'desc' = 'asc'\n\n // Check if field starts with '-' for descending\n if (field.startsWith('-')) {\n path = field.substring(1) // Remove the '-'\n direction = 'desc'\n }\n\n // ⚠️ WORKAROUND: Strip \"version.\" prefix from field names\n // Payload sends \"-version.createdAt\" for version sort fields\n // but Content API expects just \"createdAt\"\n // TODO: Content API should handle version field paths correctly\n if (path.startsWith('version.')) {\n path = path.substring(8) // Remove \"version.\" prefix\n }\n\n return { direction, path }\n })\n}\n"],"names":["addFallbackSort","sort","collectionConfig","sortArray","Array","isArray","fallbackSort","timestamps","hasFallback","some","item","replace","convertPayloadSortToContentAPI","undefined","map","field","path","direction","startsWith","substring"],"mappings":"AAEA,oFAAoF;AACpF,mCAAmC;AACnC,sDAAsD;AACtD,OAAO,SAASA,gBACdC,IAAmC,EACnCC,gBAA8C;IAE9C,IAAI,CAACD,QAAQ,CAACC,kBAAkB;QAC9B,OAAOD;IACT;IAEA,MAAME,YAAYC,MAAMC,OAAO,CAACJ,QAAQA,OAAO;QAACA;KAAK;IAErD,gCAAgC;IAChC,IAAIK,eAAe;IACnB,IAAIJ,iBAAiBK,UAAU,KAAK,OAAO;QACzCD,eAAe;IACjB;IAEA,6CAA6C;IAC7C,MAAME,cAAcL,UAAUM,IAAI,CAChC,CAACC,OAASA,SAASJ,gBAAgBI,SAASJ,aAAaK,OAAO,CAAC,KAAK;IAGxE,IAAIH,aAAa;QACf,OAAOP;IACT;IAEA,gEAAgE;IAChE,2FAA2F;IAC3F,oEAAoE;IAEpE,2EAA2E;IAC3E,OAAO;WAAIE;QAAWG;KAAa;AACrC;AAEA,6DAA6D;AAC7D,EAAE;AACF,gGAAgG;AAChG,wEAAwE;AACxE,EAAE;AACF,gEAAgE;AAChE,iEAAiE;AACjE,EAAE;AACF,6CAA6C;AAC7C,mCAAmC;AACnC,0DAA0D;AAC1D,mDAAmD;AACnD,OAAO,SAASM,+BACdX,IAAmC;IAEnC,IAAI,CAACA,MAAM;QACT,OAAOY;IACT;IAEA,MAAMV,YAAYC,MAAMC,OAAO,CAACJ,QAAQA,OAAO;QAACA;KAAK;IAErD,OAAOE,UAAUW,GAAG,CAAC,CAACC;QACpB,IAAIC,OAAOD;QACX,IAAIE,YAA4B;QAEhC,gDAAgD;QAChD,IAAIF,MAAMG,UAAU,CAAC,MAAM;YACzBF,OAAOD,MAAMI,SAAS,CAAC,IAAG,iBAAiB;YAC3CF,YAAY;QACd;QAEA,0DAA0D;QAC1D,6DAA6D;QAC7D,2CAA2C;QAC3C,gEAAgE;QAChE,IAAID,KAAKE,UAAU,CAAC,aAAa;YAC/BF,OAAOA,KAAKG,SAAS,CAAC,IAAG,2BAA2B;QACtD;QAEA,OAAO;YAAEF;YAAWD;QAAK;IAC3B;AACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
import type { components } from '../generated/content-api-types.js';
|
|
3
|
+
export declare function unwrapDocument(payload: Payload, doc: components['schemas']['Document'] | components['schemas']['DocumentVersion'], collectionSlug?: string): Record<string, unknown>;
|
|
4
|
+
//# sourceMappingURL=unwrapDocument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unwrapDocument.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/temp-utilities/unwrapDocument.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAUnE,wBAAgB,cAAc,CAC5B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,EACjF,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6CzB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { dataFromContentAPI } from '../utilities/data.js';
|
|
2
|
+
// Helper to unwrap Content API document format to Payload format
|
|
3
|
+
// Content API returns: { id, data: { ...fields }, createdAt, updatedAt }
|
|
4
|
+
// Payload expects:
|
|
5
|
+
// - For documents: { id, ...fields, createdAt, updatedAt }
|
|
6
|
+
// - For versions: { id, version: { ...fields }, createdAt, updatedAt, ... }
|
|
7
|
+
export function unwrapDocument(payload, doc, collectionSlug) {
|
|
8
|
+
if (!doc) {
|
|
9
|
+
return doc;
|
|
10
|
+
}
|
|
11
|
+
// Check if this is a DocumentVersion (has documentId and latest fields)
|
|
12
|
+
const isVersion = 'documentId' in doc && 'latest' in doc;
|
|
13
|
+
if (isVersion) {
|
|
14
|
+
// For versions, Payload expects nested structure with 'version' field
|
|
15
|
+
const versionDoc = doc;
|
|
16
|
+
const baseDoc = {
|
|
17
|
+
id: versionDoc.id,
|
|
18
|
+
createdAt: versionDoc.createdAt,
|
|
19
|
+
latest: versionDoc.latest,
|
|
20
|
+
updatedAt: versionDoc.updatedAt,
|
|
21
|
+
version: versionDoc.data
|
|
22
|
+
};
|
|
23
|
+
// Transform data from Content API format to Payload format
|
|
24
|
+
if (collectionSlug) {
|
|
25
|
+
// Only transform the nested 'version' field
|
|
26
|
+
baseDoc.version = dataFromContentAPI(payload, collectionSlug, baseDoc.version);
|
|
27
|
+
}
|
|
28
|
+
return baseDoc;
|
|
29
|
+
} else {
|
|
30
|
+
// For regular documents, spread data at root level
|
|
31
|
+
const baseDoc = {
|
|
32
|
+
...doc.data,
|
|
33
|
+
id: doc.id,
|
|
34
|
+
createdAt: doc.createdAt,
|
|
35
|
+
updatedAt: doc.updatedAt
|
|
36
|
+
};
|
|
37
|
+
// Transform data from Content API format to Payload format
|
|
38
|
+
if (collectionSlug) {
|
|
39
|
+
return dataFromContentAPI(payload, collectionSlug, baseDoc);
|
|
40
|
+
}
|
|
41
|
+
return baseDoc;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=unwrapDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/temp-utilities/unwrapDocument.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\nimport { dataFromContentAPI } from '../utilities/data.js'\n\n// Helper to unwrap Content API document format to Payload format\n// Content API returns: { id, data: { ...fields }, createdAt, updatedAt }\n// Payload expects:\n// - For documents: { id, ...fields, createdAt, updatedAt }\n\n// - For versions: { id, version: { ...fields }, createdAt, updatedAt, ... }\nexport function unwrapDocument(\n payload: Payload,\n doc: components['schemas']['Document'] | components['schemas']['DocumentVersion'],\n collectionSlug?: string,\n): Record<string, unknown> {\n if (!doc) {\n return doc as unknown as Record<string, unknown>\n }\n\n // Check if this is a DocumentVersion (has documentId and latest fields)\n const isVersion = 'documentId' in doc && 'latest' in doc\n\n if (isVersion) {\n // For versions, Payload expects nested structure with 'version' field\n const versionDoc = doc\n const baseDoc = {\n id: versionDoc.id,\n createdAt: versionDoc.createdAt,\n latest: versionDoc.latest,\n updatedAt: versionDoc.updatedAt,\n version: versionDoc.data, // Nest data inside 'version'\n }\n\n // Transform data from Content API format to Payload format\n if (collectionSlug) {\n // Only transform the nested 'version' field\n baseDoc.version = dataFromContentAPI(payload, collectionSlug, baseDoc.version) as Record<\n string,\n unknown\n >\n }\n\n return baseDoc as Record<string, unknown>\n } else {\n // For regular documents, spread data at root level\n const baseDoc = {\n ...doc.data, // Spread the actual document fields\n id: doc.id,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n\n // Transform data from Content API format to Payload format\n if (collectionSlug) {\n return dataFromContentAPI(payload, collectionSlug, baseDoc) as Record<string, unknown>\n }\n\n return baseDoc as Record<string, unknown>\n }\n}\n"],"names":["dataFromContentAPI","unwrapDocument","payload","doc","collectionSlug","isVersion","versionDoc","baseDoc","id","createdAt","latest","updatedAt","version","data"],"mappings":"AAIA,SAASA,kBAAkB,QAAQ,uBAAsB;AAEzD,iEAAiE;AACjE,yEAAyE;AACzE,mBAAmB;AACnB,6DAA6D;AAE7D,8EAA8E;AAC9E,OAAO,SAASC,eACdC,OAAgB,EAChBC,GAAiF,EACjFC,cAAuB;IAEvB,IAAI,CAACD,KAAK;QACR,OAAOA;IACT;IAEA,wEAAwE;IACxE,MAAME,YAAY,gBAAgBF,OAAO,YAAYA;IAErD,IAAIE,WAAW;QACb,sEAAsE;QACtE,MAAMC,aAAaH;QACnB,MAAMI,UAAU;YACdC,IAAIF,WAAWE,EAAE;YACjBC,WAAWH,WAAWG,SAAS;YAC/BC,QAAQJ,WAAWI,MAAM;YACzBC,WAAWL,WAAWK,SAAS;YAC/BC,SAASN,WAAWO,IAAI;QAC1B;QAEA,2DAA2D;QAC3D,IAAIT,gBAAgB;YAClB,4CAA4C;YAC5CG,QAAQK,OAAO,GAAGZ,mBAAmBE,SAASE,gBAAgBG,QAAQK,OAAO;QAI/E;QAEA,OAAOL;IACT,OAAO;QACL,mDAAmD;QACnD,MAAMA,UAAU;YACd,GAAGJ,IAAIU,IAAI;YACXL,IAAIL,IAAIK,EAAE;YACVC,WAAWN,IAAIM,SAAS;YACxBE,WAAWR,IAAIQ,SAAS;QAC1B;QAEA,2DAA2D;QAC3D,IAAIP,gBAAgB;YAClB,OAAOJ,mBAAmBE,SAASE,gBAAgBG;QACrD;QAEA,OAAOA;IACT;AACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Middleware } from 'openapi-fetch';
|
|
2
|
+
import type { Payload } from 'payload';
|
|
3
|
+
import type { TokenStore } from '../../auth/token-store.js';
|
|
4
|
+
type ApiKeyAuth = {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
mode: 'apiKey';
|
|
7
|
+
};
|
|
8
|
+
type TokenStoreAuth = {
|
|
9
|
+
mode: 'tokenStore';
|
|
10
|
+
tokenStore: TokenStore;
|
|
11
|
+
};
|
|
12
|
+
type DevJwtAuth = {
|
|
13
|
+
mode: 'devJwt';
|
|
14
|
+
};
|
|
15
|
+
export type AuthMode = ApiKeyAuth | DevJwtAuth | TokenStoreAuth;
|
|
16
|
+
export declare function fetchDevJwt(url: string, contentSystemId: string): Promise<string>;
|
|
17
|
+
export declare function createAuthMiddleware(opts: {
|
|
18
|
+
auth: AuthMode;
|
|
19
|
+
contentSystemId: string;
|
|
20
|
+
logger: Payload['logger'];
|
|
21
|
+
url: string;
|
|
22
|
+
}): Middleware;
|
|
23
|
+
export declare function createErrorMiddleware(opts: {
|
|
24
|
+
auth: AuthMode;
|
|
25
|
+
contentSystemId: string;
|
|
26
|
+
logger: Payload['logger'];
|
|
27
|
+
url: string;
|
|
28
|
+
}): Middleware;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/utilities/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAK3D,KAAK,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AACpD,KAAK,cAAc,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAA;AACpE,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AACpC,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,cAAc,CAAA;AAK/D,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBvF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,QAAQ,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,UAAU,CAyBb;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,QAAQ,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,UAAU,CAqCb"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { getValidProjectToken } from '../../auth/project-token.js';
|
|
2
|
+
// Module-level cache for dev JWT tokens
|
|
3
|
+
const devJwtCache = new Map();
|
|
4
|
+
export async function fetchDevJwt(url, contentSystemId) {
|
|
5
|
+
const usesSuperUser = !contentSystemId || contentSystemId === 'test-system' || contentSystemId === '*';
|
|
6
|
+
const contentSystemIdForJWT = usesSuperUser ? '*' : contentSystemId;
|
|
7
|
+
const response = await fetch(`${url}/dev/jwt`, {
|
|
8
|
+
body: JSON.stringify({
|
|
9
|
+
content_system_id: contentSystemIdForJWT
|
|
10
|
+
}),
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/json'
|
|
13
|
+
},
|
|
14
|
+
method: 'POST'
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
throw new Error(`Failed to get dev JWT: ${response.status} ${response.statusText}`);
|
|
18
|
+
}
|
|
19
|
+
const { token } = await response.json();
|
|
20
|
+
return token;
|
|
21
|
+
}
|
|
22
|
+
export function createAuthMiddleware(opts) {
|
|
23
|
+
return {
|
|
24
|
+
async onRequest ({ request }) {
|
|
25
|
+
if (opts.auth.mode === 'apiKey') {
|
|
26
|
+
request.headers.set('X-Api-Key', opts.auth.apiKey);
|
|
27
|
+
} else if (opts.auth.mode === 'tokenStore') {
|
|
28
|
+
const token = await getValidProjectToken(opts.auth.tokenStore, opts.contentSystemId);
|
|
29
|
+
if (!token) {
|
|
30
|
+
throw new Error('Authentication required. Run `npx @payloadcms/figma login` to authenticate.');
|
|
31
|
+
}
|
|
32
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
33
|
+
} else {
|
|
34
|
+
let token = devJwtCache.get(opts.contentSystemId);
|
|
35
|
+
if (!token) {
|
|
36
|
+
token = await fetchDevJwt(opts.url, opts.contentSystemId);
|
|
37
|
+
devJwtCache.set(opts.contentSystemId, token);
|
|
38
|
+
opts.logger.info(`Dev JWT acquired for content system: ${opts.contentSystemId}`);
|
|
39
|
+
}
|
|
40
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
41
|
+
}
|
|
42
|
+
return request;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function createErrorMiddleware(opts) {
|
|
47
|
+
return {
|
|
48
|
+
async onResponse ({ request, response }) {
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
// Handle 401 retry for dev JWT
|
|
51
|
+
if (response.status === 401 && opts.auth.mode === 'devJwt') {
|
|
52
|
+
const retryCount = parseInt(request.headers.get('X-Retry-Count') || '0', 10);
|
|
53
|
+
if (retryCount < 1) {
|
|
54
|
+
opts.logger.info('Dev JWT expired, refreshing...');
|
|
55
|
+
devJwtCache.delete(opts.contentSystemId);
|
|
56
|
+
const newToken = await fetchDevJwt(opts.url, opts.contentSystemId);
|
|
57
|
+
devJwtCache.set(opts.contentSystemId, newToken);
|
|
58
|
+
// duplex: 'half' is required for Node.js fetch with streaming body
|
|
59
|
+
const newRequest = new Request(request.url, {
|
|
60
|
+
body: request.body,
|
|
61
|
+
duplex: 'half',
|
|
62
|
+
headers: new Headers(request.headers),
|
|
63
|
+
method: request.method
|
|
64
|
+
});
|
|
65
|
+
newRequest.headers.set('X-Retry-Count', '1');
|
|
66
|
+
newRequest.headers.set('Authorization', `Bearer ${newToken}`);
|
|
67
|
+
return fetch(newRequest);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const text = await response.clone().text();
|
|
71
|
+
opts.logger.error({
|
|
72
|
+
msg: `HTTP ${response.status} from ${request.url}`,
|
|
73
|
+
response: text
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return response;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/utilities/auth.ts"],"sourcesContent":["import type { Middleware } from 'openapi-fetch'\nimport type { Payload } from 'payload'\n\nimport type { TokenStore } from '../../auth/token-store.js'\n\nimport { getValidProjectToken } from '../../auth/project-token.js'\n\n// Auth mode types\ntype ApiKeyAuth = { apiKey: string; mode: 'apiKey' }\ntype TokenStoreAuth = { mode: 'tokenStore'; tokenStore: TokenStore }\ntype DevJwtAuth = { mode: 'devJwt' }\nexport type AuthMode = ApiKeyAuth | DevJwtAuth | TokenStoreAuth\n\n// Module-level cache for dev JWT tokens\nconst devJwtCache = new Map<string, string>()\n\nexport async function fetchDevJwt(url: string, contentSystemId: string): Promise<string> {\n const usesSuperUser =\n !contentSystemId || contentSystemId === 'test-system' || contentSystemId === '*'\n const contentSystemIdForJWT = usesSuperUser ? '*' : contentSystemId\n\n const response = await fetch(`${url}/dev/jwt`, {\n body: JSON.stringify({ content_system_id: contentSystemIdForJWT }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to get dev JWT: ${response.status} ${response.statusText}`)\n }\n\n const { token } = await response.json()\n return token\n}\n\nexport function createAuthMiddleware(opts: {\n auth: AuthMode\n contentSystemId: string\n logger: Payload['logger']\n url: string\n}): Middleware {\n return {\n async onRequest({ request }) {\n if (opts.auth.mode === 'apiKey') {\n request.headers.set('X-Api-Key', opts.auth.apiKey)\n } else if (opts.auth.mode === 'tokenStore') {\n const token = await getValidProjectToken(opts.auth.tokenStore, opts.contentSystemId)\n if (!token) {\n throw new Error(\n 'Authentication required. Run `npx @payloadcms/figma login` to authenticate.',\n )\n }\n request.headers.set('Authorization', `Bearer ${token}`)\n } else {\n let token = devJwtCache.get(opts.contentSystemId)\n if (!token) {\n token = await fetchDevJwt(opts.url, opts.contentSystemId)\n devJwtCache.set(opts.contentSystemId, token)\n opts.logger.info(`Dev JWT acquired for content system: ${opts.contentSystemId}`)\n }\n request.headers.set('Authorization', `Bearer ${token}`)\n }\n return request\n },\n }\n}\n\nexport function createErrorMiddleware(opts: {\n auth: AuthMode\n contentSystemId: string\n logger: Payload['logger']\n url: string\n}): Middleware {\n return {\n async onResponse({ request, response }) {\n if (!response.ok) {\n // Handle 401 retry for dev JWT\n if (response.status === 401 && opts.auth.mode === 'devJwt') {\n const retryCount = parseInt(request.headers.get('X-Retry-Count') || '0', 10)\n if (retryCount < 1) {\n opts.logger.info('Dev JWT expired, refreshing...')\n devJwtCache.delete(opts.contentSystemId)\n\n const newToken = await fetchDevJwt(opts.url, opts.contentSystemId)\n devJwtCache.set(opts.contentSystemId, newToken)\n\n // duplex: 'half' is required for Node.js fetch with streaming body\n const newRequest = new Request(request.url, {\n body: request.body,\n duplex: 'half',\n headers: new Headers(request.headers),\n method: request.method,\n } as RequestInit)\n newRequest.headers.set('X-Retry-Count', '1')\n newRequest.headers.set('Authorization', `Bearer ${newToken}`)\n\n return fetch(newRequest)\n }\n }\n\n const text = await response.clone().text()\n opts.logger.error({\n msg: `HTTP ${response.status} from ${request.url}`,\n response: text,\n })\n }\n return response\n },\n }\n}\n"],"names":["getValidProjectToken","devJwtCache","Map","fetchDevJwt","url","contentSystemId","usesSuperUser","contentSystemIdForJWT","response","fetch","body","JSON","stringify","content_system_id","headers","method","ok","Error","status","statusText","token","json","createAuthMiddleware","opts","onRequest","request","auth","mode","set","apiKey","tokenStore","get","logger","info","createErrorMiddleware","onResponse","retryCount","parseInt","delete","newToken","newRequest","Request","duplex","Headers","text","clone","error","msg"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
import type { components } from '../generated/content-api-types.js';
|
|
3
|
+
type DataWithOperations = components['schemas']['DataWithOperations'];
|
|
4
|
+
/**
|
|
5
|
+
* Transform data before sending to Content API (WRITE operations)
|
|
6
|
+
*
|
|
7
|
+
* Conversions applied:
|
|
8
|
+
* - RichText fields: Objects -> JSON strings
|
|
9
|
+
*
|
|
10
|
+
* Note: Date fields are automatically converted to ISO strings by JSON.stringify()
|
|
11
|
+
*/
|
|
12
|
+
export declare function dataToContentAPI(payload: Payload, collectionSlug: string, data: unknown): DataWithOperations;
|
|
13
|
+
/**
|
|
14
|
+
* Transform data received from Content API (READ operations)
|
|
15
|
+
*
|
|
16
|
+
* Conversions applied:
|
|
17
|
+
* - RichText fields: JSON strings -> Objects
|
|
18
|
+
*
|
|
19
|
+
* Note: Date fields come as ISO strings from Content API and stay as strings
|
|
20
|
+
* (matching MongoDB and other adapters' behavior)
|
|
21
|
+
*/
|
|
22
|
+
export declare function dataFromContentAPI(payload: Payload, collectionSlug: string, data: unknown): unknown;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/utilities/data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,OAAO,EAA0B,MAAM,SAAS,CAAA;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,OAAO,GACZ,kBAAkB,CA2CpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,OAAO,GACZ,OAAO,CAgET"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { traverseFields } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Transform data before sending to Content API (WRITE operations)
|
|
4
|
+
*
|
|
5
|
+
* Conversions applied:
|
|
6
|
+
* - RichText fields: Objects -> JSON strings
|
|
7
|
+
*
|
|
8
|
+
* Note: Date fields are automatically converted to ISO strings by JSON.stringify()
|
|
9
|
+
*/ export function dataToContentAPI(payload, collectionSlug, data) {
|
|
10
|
+
if (!data || typeof data !== 'object') {
|
|
11
|
+
return data;
|
|
12
|
+
}
|
|
13
|
+
// Deep clone to avoid mutating original data
|
|
14
|
+
const transformed = JSON.parse(JSON.stringify(data));
|
|
15
|
+
// Get collection config
|
|
16
|
+
const isGlobal = collectionSlug.startsWith('_global-');
|
|
17
|
+
const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug;
|
|
18
|
+
const collectionConfig = isGlobal ? payload.config.globals?.find((g)=>g.slug === actualSlug) : payload.config.collections.find((c)=>c.slug === actualSlug);
|
|
19
|
+
if (!collectionConfig?.fields) {
|
|
20
|
+
return transformed;
|
|
21
|
+
}
|
|
22
|
+
// Use Payload's traverseFields to iterate over all fields
|
|
23
|
+
const callback = ({ field, ref })=>{
|
|
24
|
+
if (!('name' in field) || !field.name) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!ref || typeof ref !== 'object') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const current = ref;
|
|
31
|
+
const value = current[field.name];
|
|
32
|
+
if (value !== null && value !== undefined) {
|
|
33
|
+
// RichText: object -> JSON string
|
|
34
|
+
if (field.type === 'richText' && typeof value !== 'string') {
|
|
35
|
+
current[field.name] = JSON.stringify(value);
|
|
36
|
+
}
|
|
37
|
+
// Date fields are already handled by JSON.stringify() which converts Date -> ISO string
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
traverseFields({
|
|
41
|
+
callback,
|
|
42
|
+
fields: collectionConfig.fields,
|
|
43
|
+
ref: transformed
|
|
44
|
+
});
|
|
45
|
+
return transformed;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Transform data received from Content API (READ operations)
|
|
49
|
+
*
|
|
50
|
+
* Conversions applied:
|
|
51
|
+
* - RichText fields: JSON strings -> Objects
|
|
52
|
+
*
|
|
53
|
+
* Note: Date fields come as ISO strings from Content API and stay as strings
|
|
54
|
+
* (matching MongoDB and other adapters' behavior)
|
|
55
|
+
*/ export function dataFromContentAPI(payload, collectionSlug, data) {
|
|
56
|
+
if (!data || typeof data !== 'object') {
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
// Deep clone to avoid mutating original data
|
|
60
|
+
const transformed = JSON.parse(JSON.stringify(data));
|
|
61
|
+
// Get collection config
|
|
62
|
+
const isGlobal = collectionSlug.startsWith('_global-');
|
|
63
|
+
const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug;
|
|
64
|
+
const collectionConfig = isGlobal ? payload.config.globals?.find((g)=>g.slug === actualSlug) : payload.config.collections.find((c)=>c.slug === actualSlug);
|
|
65
|
+
if (!collectionConfig?.fields) {
|
|
66
|
+
return transformed;
|
|
67
|
+
}
|
|
68
|
+
// Use Payload's traverseFields to iterate over all fields
|
|
69
|
+
const callback = ({ field, parentPath, ref })=>{
|
|
70
|
+
if (!('name' in field) || !field.name) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (!ref || typeof ref !== 'object') {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const current = ref;
|
|
77
|
+
const value = current[field.name];
|
|
78
|
+
if (value !== null && value !== undefined) {
|
|
79
|
+
// RichText: JSON string -> object
|
|
80
|
+
if (field.type === 'richText' && typeof value === 'string') {
|
|
81
|
+
try {
|
|
82
|
+
current[field.name] = JSON.parse(value);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
|
|
85
|
+
payload.logger.warn({
|
|
86
|
+
err: error instanceof Error ? error : new Error(String(error)),
|
|
87
|
+
msg: `Failed to parse richtext field '${fieldPath}' in collection '${collectionSlug}'`
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Date fields: Already ISO strings from Content API, no conversion needed
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
traverseFields({
|
|
95
|
+
callback,
|
|
96
|
+
fields: collectionConfig.fields,
|
|
97
|
+
ref: transformed
|
|
98
|
+
});
|
|
99
|
+
// Handle auth-specific fields that aren't in the field schema
|
|
100
|
+
// When these fields are null in DB, Content API omits them from response (undefined)
|
|
101
|
+
// But Payload expects them to be null, not undefined
|
|
102
|
+
// Only add them if the collection has auth enabled
|
|
103
|
+
if ('auth' in collectionConfig && collectionConfig.auth) {
|
|
104
|
+
const authFields = [
|
|
105
|
+
'resetPasswordExpiration',
|
|
106
|
+
'lockUntil'
|
|
107
|
+
];
|
|
108
|
+
for (const fieldName of authFields){
|
|
109
|
+
if (!(fieldName in transformed)) {
|
|
110
|
+
;
|
|
111
|
+
transformed[fieldName] = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return transformed;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/utilities/data.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig, Payload, TraverseFieldsCallback } from 'payload'\n\nimport { traverseFields } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\ntype DataWithOperations = components['schemas']['DataWithOperations']\n\n/**\n * Transform data before sending to Content API (WRITE operations)\n *\n * Conversions applied:\n * - RichText fields: Objects -> JSON strings\n *\n * Note: Date fields are automatically converted to ISO strings by JSON.stringify()\n */\nexport function dataToContentAPI(\n payload: Payload,\n collectionSlug: string,\n data: unknown,\n): DataWithOperations {\n if (!data || typeof data !== 'object') {\n return data as DataWithOperations\n }\n\n // Deep clone to avoid mutating original data\n const transformed = JSON.parse(JSON.stringify(data))\n\n // Get collection config\n const isGlobal = collectionSlug.startsWith('_global-')\n const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug\n const collectionConfig: CollectionConfig | GlobalConfig | undefined = isGlobal\n ? payload.config.globals?.find((g) => g.slug === actualSlug)\n : payload.config.collections.find((c) => c.slug === actualSlug)\n\n if (!collectionConfig?.fields) {\n return transformed as DataWithOperations\n }\n\n // Use Payload's traverseFields to iterate over all fields\n const callback: TraverseFieldsCallback = ({ field, ref }) => {\n if (!('name' in field) || !field.name) {\n return\n }\n if (!ref || typeof ref !== 'object') {\n return\n }\n\n const current = ref as Record<string, unknown>\n const value = current[field.name]\n\n if (value !== null && value !== undefined) {\n // RichText: object -> JSON string\n if (field.type === 'richText' && typeof value !== 'string') {\n current[field.name] = JSON.stringify(value)\n }\n // Date fields are already handled by JSON.stringify() which converts Date -> ISO string\n }\n }\n\n traverseFields({ callback, fields: collectionConfig.fields, ref: transformed })\n\n return transformed as DataWithOperations\n}\n\n/**\n * Transform data received from Content API (READ operations)\n *\n * Conversions applied:\n * - RichText fields: JSON strings -> Objects\n *\n * Note: Date fields come as ISO strings from Content API and stay as strings\n * (matching MongoDB and other adapters' behavior)\n */\nexport function dataFromContentAPI(\n payload: Payload,\n collectionSlug: string,\n data: unknown,\n): unknown {\n if (!data || typeof data !== 'object') {\n return data\n }\n\n // Deep clone to avoid mutating original data\n const transformed = JSON.parse(JSON.stringify(data))\n\n // Get collection config\n const isGlobal = collectionSlug.startsWith('_global-')\n const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug\n const collectionConfig: CollectionConfig | GlobalConfig | undefined = isGlobal\n ? payload.config.globals?.find((g) => g.slug === actualSlug)\n : payload.config.collections.find((c) => c.slug === actualSlug)\n\n if (!collectionConfig?.fields) {\n return transformed\n }\n\n // Use Payload's traverseFields to iterate over all fields\n const callback: TraverseFieldsCallback = ({ field, parentPath, ref }) => {\n if (!('name' in field) || !field.name) {\n return\n }\n if (!ref || typeof ref !== 'object') {\n return\n }\n\n const current = ref as Record<string, unknown>\n const value = current[field.name]\n\n if (value !== null && value !== undefined) {\n // RichText: JSON string -> object\n if (field.type === 'richText' && typeof value === 'string') {\n try {\n current[field.name] = JSON.parse(value)\n } catch (error) {\n const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name\n payload.logger.warn({\n err: error instanceof Error ? error : new Error(String(error)),\n msg: `Failed to parse richtext field '${fieldPath}' in collection '${collectionSlug}'`,\n })\n }\n }\n // Date fields: Already ISO strings from Content API, no conversion needed\n }\n }\n\n traverseFields({ callback, fields: collectionConfig.fields, ref: transformed })\n\n // Handle auth-specific fields that aren't in the field schema\n // When these fields are null in DB, Content API omits them from response (undefined)\n // But Payload expects them to be null, not undefined\n // Only add them if the collection has auth enabled\n if ('auth' in collectionConfig && collectionConfig.auth) {\n const authFields = ['resetPasswordExpiration', 'lockUntil']\n for (const fieldName of authFields) {\n if (!(fieldName in (transformed as Record<string, unknown>))) {\n ;(transformed as Record<string, unknown>)[fieldName] = null\n }\n }\n }\n\n return transformed\n}\n"],"names":["traverseFields","dataToContentAPI","payload","collectionSlug","data","transformed","JSON","parse","stringify","isGlobal","startsWith","actualSlug","substring","collectionConfig","config","globals","find","g","slug","collections","c","fields","callback","field","ref","name","current","value","undefined","type","dataFromContentAPI","parentPath","error","fieldPath","logger","warn","err","Error","String","msg","auth","authFields","fieldName"],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { JoinQuery, Payload, SanitizedCollectionConfig } from 'payload';
|
|
2
|
+
import type { components } from '../generated/content-api-types.js';
|
|
3
|
+
type ContentAPIJoin = components['schemas']['JoinClause'][number];
|
|
4
|
+
/**
|
|
5
|
+
* Convert Payload's JoinQuery to Content API's join format.
|
|
6
|
+
*
|
|
7
|
+
* ## Content API Join Limitations
|
|
8
|
+
*
|
|
9
|
+
* The following Payload join features are NOT YET supported by Content API:
|
|
10
|
+
*
|
|
11
|
+
* 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract
|
|
12
|
+
* a single ID. HasMany relationships store arrays `["id1", "id2"]` which can't match.
|
|
13
|
+
*
|
|
14
|
+
* 2. **Array field relationships** - `on: 'array.category'` expects iteration over array
|
|
15
|
+
* elements, but Content API treats the path as a single JSONB extraction.
|
|
16
|
+
*
|
|
17
|
+
* 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but
|
|
18
|
+
* Content API expects a simple ID string.
|
|
19
|
+
*
|
|
20
|
+
* 4. **Localized relationship fields** - Locale-aware joins not implemented.
|
|
21
|
+
*
|
|
22
|
+
* Note: "Where querying through joins" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)
|
|
23
|
+
* is a separate Payload feature that filters documents based on joined data. This is NOT
|
|
24
|
+
* a join feature but a where clause feature, and would need separate Content API support.
|
|
25
|
+
*
|
|
26
|
+
* Payload's JoinQuery format (at runtime):
|
|
27
|
+
* {
|
|
28
|
+
* 'group.relatedPosts': { // joinPath - where results go in the document
|
|
29
|
+
* sort: '-title', // Payload sort format
|
|
30
|
+
* limit: 10,
|
|
31
|
+
* page: 2, // page-based pagination
|
|
32
|
+
* where: { ... }, // Payload where format
|
|
33
|
+
* count: true
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* Content API's join format:
|
|
38
|
+
* [{
|
|
39
|
+
* collectionId: 'posts', // collection to join FROM
|
|
40
|
+
* on: 'group.category', // field in joined collection pointing to this doc
|
|
41
|
+
* path: 'group.relatedPosts', // where to put results
|
|
42
|
+
* count: false,
|
|
43
|
+
* where: { ... }, // Content API where format
|
|
44
|
+
* sort: [{ path, direction }], // Content API sort format
|
|
45
|
+
* limit: 10,
|
|
46
|
+
* offset: 10 // offset-based pagination
|
|
47
|
+
* }]
|
|
48
|
+
*
|
|
49
|
+
* The mapping requires the collection config to resolve:
|
|
50
|
+
* - Which collection each join field refers to
|
|
51
|
+
* - What the 'on' field is for each join
|
|
52
|
+
*/
|
|
53
|
+
export declare function convertPayloadJoinsToContentAPI(payload: Payload, collectionConfig: SanitizedCollectionConfig, joins: false | JoinQuery | undefined): ContentAPIJoin[] | undefined;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=joins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"joins.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/utilities/joins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAE5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAMnE,KAAK,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,OAAO,EAChB,gBAAgB,EAAE,yBAAyB,EAC3C,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GACnC,cAAc,EAAE,GAAG,SAAS,CAkF9B"}
|