@payloadcms/figma 0.0.1-alpha.42 → 0.0.1-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/control-plane.d.ts +1 -22
- package/dist/api/control-plane.d.ts.map +1 -1
- package/dist/api/control-plane.js +22 -55
- 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 +21 -45
- package/dist/api/figma-api.js.map +1 -1
- package/dist/auth/callback-server.d.ts.map +1 -1
- package/dist/auth/callback-server.js +1 -2
- package/dist/auth/callback-server.js.map +1 -1
- package/dist/auth/crypto-utils.d.ts.map +1 -1
- package/dist/auth/crypto-utils.js +5 -5
- package/dist/auth/crypto-utils.js.map +1 -1
- package/dist/auth/jwt-validator.d.ts +1 -2
- package/dist/auth/jwt-validator.d.ts.map +1 -1
- package/dist/auth/jwt-validator.js +2 -2
- package/dist/auth/jwt-validator.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 +11 -15
- package/dist/auth/oauth-flow.js.map +1 -1
- package/dist/auth/project-token.d.ts.map +1 -1
- package/dist/auth/project-token.js +4 -9
- package/dist/auth/project-token.js.map +1 -1
- package/dist/auth/refresh.d.ts +1 -2
- package/dist/auth/refresh.d.ts.map +1 -1
- package/dist/auth/refresh.js +12 -25
- package/dist/auth/refresh.js.map +1 -1
- package/dist/auth/token-store.d.ts +0 -12
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +5 -28
- package/dist/auth/token-store.js.map +1 -1
- package/dist/auth/types.d.ts +4 -7
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -39
- package/dist/cli.js.map +1 -1
- package/dist/commands/deploy.d.ts +0 -4
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +129 -72
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +85 -105
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list-tokens.d.ts +3 -3
- package/dist/commands/list-tokens.d.ts.map +1 -1
- package/dist/commands/list-tokens.js +7 -22
- package/dist/commands/list-tokens.js.map +1 -1
- package/dist/commands/login.d.ts +1 -8
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +12 -30
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +4 -5
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +13 -56
- package/dist/commands/logout.js.map +1 -1
- package/dist/config/oauth.d.ts +14 -4
- package/dist/config/oauth.d.ts.map +1 -1
- package/dist/config/oauth.js +40 -19
- package/dist/config/oauth.js.map +1 -1
- package/dist/constants.d.ts +18 -26
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +20 -34
- package/dist/constants.js.map +1 -1
- package/dist/exports/client.d.ts +0 -1
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +0 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LoginButton/index.js +6 -50
- package/dist/oauth/components/LoginButton/index.js.map +1 -1
- package/dist/oauth/components/LoginButton/index.scss +3 -50
- package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -1
- package/dist/oauth/components/LogoutButton/index.js +4 -5
- package/dist/oauth/components/LogoutButton/index.js.map +1 -1
- package/dist/oauth/defaults.d.ts.map +1 -1
- package/dist/oauth/defaults.js +5 -29
- package/dist/oauth/defaults.js.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -1
- package/dist/oauth/endpoints/getLoginEndpoint.js +11 -21
- package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
- package/dist/oauth/endpoints/getLogoutEndpoint.d.ts.map +1 -1
- package/dist/oauth/endpoints/getLogoutEndpoint.js +4 -7
- package/dist/oauth/endpoints/getLogoutEndpoint.js.map +1 -1
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +13 -40
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/strategy/index.d.ts +2 -0
- package/dist/oauth/strategy/index.d.ts.map +1 -1
- package/dist/oauth/strategy/index.js +15 -38
- 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/getAdminPath.d.ts +8 -0
- package/dist/oauth/utilities/getAdminPath.d.ts.map +1 -0
- package/dist/oauth/utilities/getAdminPath.js +9 -0
- package/dist/oauth/utilities/getAdminPath.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 +4 -21
- package/dist/plugin/build-config.d.ts.map +1 -1
- package/dist/plugin/build-config.js +7 -113
- package/dist/plugin/build-config.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/asset-collection.d.ts +6 -3
- package/dist/utils/asset-collection.d.ts.map +1 -1
- package/dist/utils/asset-collection.js +34 -10
- package/dist/utils/asset-collection.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/env-management.d.ts +8 -9
- package/dist/utils/env-management.d.ts.map +1 -1
- package/dist/utils/env-management.js +74 -73
- package/dist/utils/env-management.js.map +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +5 -3
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/lambda-config.d.ts +1 -3
- package/dist/utils/lambda-config.d.ts.map +1 -1
- package/dist/utils/lambda-config.js +32 -38
- package/dist/utils/lambda-config.js.map +1 -1
- package/dist/utils/messages.js +8 -8
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/payload-config-ast.d.ts +3 -22
- package/dist/utils/payload-config-ast.d.ts.map +1 -1
- package/dist/utils/payload-config-ast.js +31 -89
- package/dist/utils/payload-config-ast.js.map +1 -1
- package/dist/utils/payload-config-finder.d.ts +2 -2
- package/dist/utils/payload-config-finder.d.ts.map +1 -1
- package/dist/utils/payload-config-finder.js +9 -48
- package/dist/utils/payload-config-finder.js.map +1 -1
- package/dist/utils/payload-config-modifier.d.ts.map +1 -1
- package/dist/utils/payload-config-modifier.js +6 -54
- package/dist/utils/payload-config-modifier.js.map +1 -1
- package/dist/utils/payload-package-check.d.ts +1 -12
- package/dist/utils/payload-package-check.d.ts.map +1 -1
- package/dist/utils/payload-package-check.js +5 -63
- package/dist/utils/payload-package-check.js.map +1 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +5 -8
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/s3-upload.d.ts +1 -0
- package/dist/utils/s3-upload.d.ts.map +1 -1
- package/dist/utils/s3-upload.js +3 -10
- package/dist/utils/s3-upload.js.map +1 -1
- package/dist/utils/token-display.d.ts.map +1 -1
- package/dist/utils/token-display.js +5 -11
- package/dist/utils/token-display.js.map +1 -1
- package/dist/utils/typescript-validator.d.ts.map +1 -1
- package/dist/utils/typescript-validator.js +6 -4
- package/dist/utils/typescript-validator.js.map +1 -1
- package/package.json +9 -27
- package/dist/commands/build-lambda-zip.d.ts +0 -5
- package/dist/commands/build-lambda-zip.d.ts.map +0 -1
- package/dist/commands/build-lambda-zip.js +0 -19
- package/dist/commands/build-lambda-zip.js.map +0 -1
- package/dist/db-content-api/README.md +0 -98
- package/dist/db-content-api/generated/content-api-types.d.ts +0 -3914
- package/dist/db-content-api/generated/content-api-types.d.ts.map +0 -1
- package/dist/db-content-api/generated/content-api-types.js +0 -7
- package/dist/db-content-api/generated/content-api-types.js.map +0 -1
- package/dist/db-content-api/index.d.ts +0 -18
- package/dist/db-content-api/index.d.ts.map +0 -1
- package/dist/db-content-api/index.js +0 -586
- package/dist/db-content-api/index.js.map +0 -1
- package/dist/db-content-api/temp-utilities/slug.d.ts +0 -2
- package/dist/db-content-api/temp-utilities/slug.d.ts.map +0 -1
- package/dist/db-content-api/temp-utilities/slug.js +0 -3
- package/dist/db-content-api/temp-utilities/slug.js.map +0 -1
- package/dist/db-content-api/temp-utilities/sorting.d.ts +0 -3
- package/dist/db-content-api/temp-utilities/sorting.d.ts.map +0 -1
- package/dist/db-content-api/temp-utilities/sorting.js +0 -32
- package/dist/db-content-api/temp-utilities/sorting.js.map +0 -1
- package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +0 -34
- package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts.map +0 -1
- package/dist/db-content-api/temp-utilities/unwrapDocument.js +0 -53
- package/dist/db-content-api/temp-utilities/unwrapDocument.js.map +0 -1
- package/dist/db-content-api/utilities/auth.d.ts +0 -30
- package/dist/db-content-api/utilities/auth.d.ts.map +0 -1
- package/dist/db-content-api/utilities/auth.js +0 -81
- package/dist/db-content-api/utilities/auth.js.map +0 -1
- package/dist/db-content-api/utilities/buildPathTypes.d.ts +0 -12
- package/dist/db-content-api/utilities/buildPathTypes.d.ts.map +0 -1
- package/dist/db-content-api/utilities/buildPathTypes.js +0 -157
- package/dist/db-content-api/utilities/buildPathTypes.js.map +0 -1
- package/dist/db-content-api/utilities/data/applyDefaults.d.ts +0 -7
- package/dist/db-content-api/utilities/data/applyDefaults.d.ts.map +0 -1
- package/dist/db-content-api/utilities/data/applyDefaults.js +0 -59
- package/dist/db-content-api/utilities/data/applyDefaults.js.map +0 -1
- package/dist/db-content-api/utilities/data/castFieldValue.d.ts +0 -11
- package/dist/db-content-api/utilities/data/castFieldValue.d.ts.map +0 -1
- package/dist/db-content-api/utilities/data/castFieldValue.js +0 -66
- package/dist/db-content-api/utilities/data/castFieldValue.js.map +0 -1
- package/dist/db-content-api/utilities/data/index.d.ts +0 -32
- package/dist/db-content-api/utilities/data/index.d.ts.map +0 -1
- package/dist/db-content-api/utilities/data/index.js +0 -190
- package/dist/db-content-api/utilities/data/index.js.map +0 -1
- package/dist/db-content-api/utilities/data/removeVirtualFields.d.ts +0 -12
- package/dist/db-content-api/utilities/data/removeVirtualFields.d.ts.map +0 -1
- package/dist/db-content-api/utilities/data/removeVirtualFields.js +0 -54
- package/dist/db-content-api/utilities/data/removeVirtualFields.js.map +0 -1
- package/dist/db-content-api/utilities/data/stripFields.d.ts +0 -48
- package/dist/db-content-api/utilities/data/stripFields.d.ts.map +0 -1
- package/dist/db-content-api/utilities/data/stripFields.js +0 -195
- package/dist/db-content-api/utilities/data/stripFields.js.map +0 -1
- package/dist/db-content-api/utilities/joins.d.ts +0 -55
- package/dist/db-content-api/utilities/joins.d.ts.map +0 -1
- package/dist/db-content-api/utilities/joins.js +0 -136
- package/dist/db-content-api/utilities/joins.js.map +0 -1
- package/dist/db-content-api/utilities/where.d.ts +0 -12
- package/dist/db-content-api/utilities/where.d.ts.map +0 -1
- package/dist/db-content-api/utilities/where.js +0 -121
- package/dist/db-content-api/utilities/where.js.map +0 -1
- package/dist/endpoints/health.d.ts +0 -3
- package/dist/endpoints/health.d.ts.map +0 -1
- package/dist/endpoints/health.js +0 -11
- package/dist/endpoints/health.js.map +0 -1
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts +0 -7
- package/dist/oauth/utilities/isDuplicateKeyError.d.ts.map +0 -1
- package/dist/oauth/utilities/isDuplicateKeyError.js +0 -14
- package/dist/oauth/utilities/isDuplicateKeyError.js.map +0 -1
- package/dist/storage-content-api/api-types.d.ts +0 -168
- package/dist/storage-content-api/api-types.d.ts.map +0 -1
- package/dist/storage-content-api/api-types.js +0 -6
- package/dist/storage-content-api/api-types.js.map +0 -1
- package/dist/storage-content-api/client-uploads/ClientUploadHandler.d.ts +0 -9
- package/dist/storage-content-api/client-uploads/ClientUploadHandler.d.ts.map +0 -1
- package/dist/storage-content-api/client-uploads/ClientUploadHandler.js +0 -42
- package/dist/storage-content-api/client-uploads/ClientUploadHandler.js.map +0 -1
- package/dist/storage-content-api/client-uploads/generateSignedURL.d.ts +0 -13
- package/dist/storage-content-api/client-uploads/generateSignedURL.d.ts.map +0 -1
- package/dist/storage-content-api/client-uploads/generateSignedURL.js +0 -32
- package/dist/storage-content-api/client-uploads/generateSignedURL.js.map +0 -1
- package/dist/storage-content-api/client.d.ts +0 -6
- package/dist/storage-content-api/client.d.ts.map +0 -1
- package/dist/storage-content-api/client.js +0 -36
- package/dist/storage-content-api/client.js.map +0 -1
- package/dist/storage-content-api/generateURL.d.ts +0 -7
- package/dist/storage-content-api/generateURL.d.ts.map +0 -1
- package/dist/storage-content-api/generateURL.js +0 -8
- package/dist/storage-content-api/generateURL.js.map +0 -1
- package/dist/storage-content-api/handleDelete.d.ts +0 -8
- package/dist/storage-content-api/handleDelete.d.ts.map +0 -1
- package/dist/storage-content-api/handleDelete.js +0 -17
- package/dist/storage-content-api/handleDelete.js.map +0 -1
- package/dist/storage-content-api/handleUpload.d.ts +0 -11
- package/dist/storage-content-api/handleUpload.d.ts.map +0 -1
- package/dist/storage-content-api/handleUpload.js +0 -144
- package/dist/storage-content-api/handleUpload.js.map +0 -1
- package/dist/storage-content-api/index.d.ts +0 -5
- package/dist/storage-content-api/index.d.ts.map +0 -1
- package/dist/storage-content-api/index.js +0 -31
- package/dist/storage-content-api/index.js.map +0 -1
- package/dist/storage-content-api/staticHandler.d.ts +0 -10
- package/dist/storage-content-api/staticHandler.d.ts.map +0 -1
- package/dist/storage-content-api/staticHandler.js +0 -56
- package/dist/storage-content-api/staticHandler.js.map +0 -1
- package/dist/storage-content-api/types.d.ts +0 -10
- package/dist/storage-content-api/types.d.ts.map +0 -1
- package/dist/storage-content-api/types.js +0 -3
- package/dist/storage-content-api/types.js.map +0 -1
- package/dist/templates/README.md +0 -19
- package/dist/utils/build-lambda-zip.d.ts +0 -14
- package/dist/utils/build-lambda-zip.d.ts.map +0 -1
- package/dist/utils/build-lambda-zip.js +0 -81
- package/dist/utils/build-lambda-zip.js.map +0 -1
- package/dist/utils/format-env-suffix.d.ts +0 -12
- package/dist/utils/format-env-suffix.d.ts.map +0 -1
- package/dist/utils/format-env-suffix.js +0 -13
- package/dist/utils/format-env-suffix.js.map +0 -1
- package/dist/utils/version-check.d.ts +0 -3
- package/dist/utils/version-check.d.ts.map +0 -1
- package/dist/utils/version-check.js +0 -38
- package/dist/utils/version-check.js.map +0 -1
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { fieldShouldBeLocalized } from 'payload/shared';
|
|
2
|
-
/**
|
|
3
|
-
* Strips fields from data that are not defined in the schema or are invalid.
|
|
4
|
-
*
|
|
5
|
-
* This function was copied from the MongoDB adapter's implementation:
|
|
6
|
-
* @see packages/db-mongodb/src/utilities/transform.ts (stripFields function)
|
|
7
|
-
*
|
|
8
|
-
* @description
|
|
9
|
-
* This utility performs deep sanitization of document data by:
|
|
10
|
-
* 1. **Removing undefined fields**: Strips any field not present in the collection's schema
|
|
11
|
-
* (e.g., sensitive fields like `password`, `apiKey`, or any extra fields not in config)
|
|
12
|
-
* 2. **Removing invalid locales**: Deletes locale keys that don't exist in `config.localization.localeCodes`
|
|
13
|
-
* (e.g., if data contains `{ "es-MX": "..." }` but only `"en"` is configured)
|
|
14
|
-
* 3. **Removing invalid blocks**: Filters out blocks with unknown `blockType` values
|
|
15
|
-
* (prevents data corruption from blocks that don't exist in the schema)
|
|
16
|
-
* 4. **Recursive sanitization**: Processes nested structures (arrays, groups, blocks, localized fields)
|
|
17
|
-
* to ensure deep data integrity
|
|
18
|
-
*
|
|
19
|
-
* @remarks
|
|
20
|
-
* Unlike MongoDB's adapter which uses Mongoose schemas with `strict: true` (rejecting extra fields
|
|
21
|
-
* on write), Content API uses flexible JSONB storage that accepts any fields. Therefore, this
|
|
22
|
-
* function is called on **both read and write operations** to ensure data consistency.
|
|
23
|
-
*
|
|
24
|
-
* The MongoDB adapter also supports an `allowAdditionalKeys` option that allows reading/writing
|
|
25
|
-
* fields not in the schema. For now, Content API does not support this feature - we always
|
|
26
|
-
* sanitize data. If users request this functionality in the future, we can consider adding it.
|
|
27
|
-
*
|
|
28
|
-
* @todo
|
|
29
|
-
* 1. Consider moving this utility to `payload/shared` so both MongoDB and Content API adapters
|
|
30
|
-
* can use the same implementation, reducing code duplication and maintenance burden.
|
|
31
|
-
*
|
|
32
|
-
* 2. Performance optimization: This function iterates through all fields recursively.
|
|
33
|
-
* The `dataToContentAPI` and `dataFromContentAPI` functions in
|
|
34
|
-
* `packages/figma/src/db-content-api/utilities/data.ts` also iterate through fields
|
|
35
|
-
* to transform richText (object ↔ JSON string), custom IDs (number ↔ string), and dates.
|
|
36
|
-
* Consider combining both traversals into a single abstraction to avoid iterating twice.
|
|
37
|
-
*
|
|
38
|
-
* 3. Feature parity: MongoDB adapter has `allowAdditionalKeys` option. We currently always
|
|
39
|
-
* strip additional keys, but could add this as a configurable option if users need it.
|
|
40
|
-
*/ export const stripFields = ({ config, data, fields, parentIsLocalized = false, reservedKeys = [] })=>{
|
|
41
|
-
for(const k in data){
|
|
42
|
-
if (!fields.some((field)=>field.name === k) && !reservedKeys.includes(k)) {
|
|
43
|
-
delete data[k];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
for (const field of fields){
|
|
47
|
-
reservedKeys = [];
|
|
48
|
-
const fieldData = data[field.name];
|
|
49
|
-
if (!fieldData || typeof fieldData !== 'object') {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const shouldLocalizeField = fieldShouldBeLocalized({
|
|
53
|
-
field,
|
|
54
|
-
parentIsLocalized
|
|
55
|
-
});
|
|
56
|
-
if (field.type === 'blocks') {
|
|
57
|
-
reservedKeys.push('blockType');
|
|
58
|
-
}
|
|
59
|
-
if ('flattenedFields' in field || 'blocks' in field) {
|
|
60
|
-
if (shouldLocalizeField && config.localization) {
|
|
61
|
-
for(const localeKey in fieldData){
|
|
62
|
-
if (!config.localization.localeCodes.some((code)=>code === localeKey)) {
|
|
63
|
-
delete fieldData[localeKey];
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
const localeData = fieldData[localeKey];
|
|
67
|
-
if (!localeData || typeof localeData !== 'object') {
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (field.type === 'array' || field.type === 'blocks') {
|
|
71
|
-
if (!Array.isArray(localeData)) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
let hasNull = false;
|
|
75
|
-
for(let i = 0; i < localeData.length; i++){
|
|
76
|
-
const data = localeData[i];
|
|
77
|
-
let fields = null;
|
|
78
|
-
if (field.type === 'array') {
|
|
79
|
-
fields = field.flattenedFields;
|
|
80
|
-
} else {
|
|
81
|
-
let maybeBlock = undefined;
|
|
82
|
-
if (field.blockReferences) {
|
|
83
|
-
const maybeBlockReference = field.blockReferences.find((each)=>{
|
|
84
|
-
const slug = typeof each === 'string' ? each : each.slug;
|
|
85
|
-
return slug === data.blockType;
|
|
86
|
-
});
|
|
87
|
-
if (maybeBlockReference) {
|
|
88
|
-
if (typeof maybeBlockReference === 'object') {
|
|
89
|
-
maybeBlock = maybeBlockReference;
|
|
90
|
-
} else {
|
|
91
|
-
maybeBlock = config.blocks?.find((each)=>each.slug === maybeBlockReference);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (!maybeBlock) {
|
|
96
|
-
maybeBlock = field.blocks.find((each)=>each.slug === data.blockType);
|
|
97
|
-
}
|
|
98
|
-
if (maybeBlock) {
|
|
99
|
-
fields = maybeBlock.flattenedFields;
|
|
100
|
-
} else {
|
|
101
|
-
localeData[i] = null;
|
|
102
|
-
hasNull = true;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (!fields) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
stripFields({
|
|
109
|
-
config,
|
|
110
|
-
data,
|
|
111
|
-
fields,
|
|
112
|
-
parentIsLocalized: parentIsLocalized || field.localized,
|
|
113
|
-
reservedKeys
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
if (hasNull) {
|
|
117
|
-
fieldData[localeKey] = localeData.filter(Boolean);
|
|
118
|
-
}
|
|
119
|
-
continue;
|
|
120
|
-
} else {
|
|
121
|
-
stripFields({
|
|
122
|
-
config,
|
|
123
|
-
data: localeData,
|
|
124
|
-
fields: field.flattenedFields,
|
|
125
|
-
parentIsLocalized: parentIsLocalized || field.localized,
|
|
126
|
-
reservedKeys
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
if (field.type === 'array' || field.type === 'blocks') {
|
|
133
|
-
if (!Array.isArray(fieldData)) {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
let hasNull = false;
|
|
137
|
-
for(let i = 0; i < fieldData.length; i++){
|
|
138
|
-
const data = fieldData[i];
|
|
139
|
-
let fields = null;
|
|
140
|
-
if (field.type === 'array') {
|
|
141
|
-
fields = field.flattenedFields;
|
|
142
|
-
} else {
|
|
143
|
-
let maybeBlock = undefined;
|
|
144
|
-
if (field.blockReferences) {
|
|
145
|
-
const maybeBlockReference = field.blockReferences.find((each)=>{
|
|
146
|
-
const slug = typeof each === 'string' ? each : each.slug;
|
|
147
|
-
return slug === data.blockType;
|
|
148
|
-
});
|
|
149
|
-
if (maybeBlockReference) {
|
|
150
|
-
if (typeof maybeBlockReference === 'object') {
|
|
151
|
-
maybeBlock = maybeBlockReference;
|
|
152
|
-
} else {
|
|
153
|
-
maybeBlock = config.blocks?.find((each)=>each.slug === maybeBlockReference);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (!maybeBlock) {
|
|
158
|
-
maybeBlock = field.blocks.find((each)=>each.slug === data.blockType);
|
|
159
|
-
}
|
|
160
|
-
if (maybeBlock) {
|
|
161
|
-
fields = maybeBlock.flattenedFields;
|
|
162
|
-
} else {
|
|
163
|
-
fieldData[i] = null;
|
|
164
|
-
hasNull = true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (!fields) {
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
stripFields({
|
|
171
|
-
config,
|
|
172
|
-
data,
|
|
173
|
-
fields,
|
|
174
|
-
parentIsLocalized: parentIsLocalized || field.localized,
|
|
175
|
-
reservedKeys
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
if (hasNull) {
|
|
179
|
-
data[field.name] = fieldData.filter(Boolean);
|
|
180
|
-
}
|
|
181
|
-
continue;
|
|
182
|
-
} else {
|
|
183
|
-
stripFields({
|
|
184
|
-
config,
|
|
185
|
-
data: fieldData,
|
|
186
|
-
fields: field.flattenedFields,
|
|
187
|
-
parentIsLocalized: parentIsLocalized || field.localized,
|
|
188
|
-
reservedKeys
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
//# sourceMappingURL=stripFields.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/db-content-api/utilities/data/stripFields.ts"],"sourcesContent":["import type { FlattenedBlock, FlattenedField, SanitizedConfig } from 'payload'\n\nimport { fieldShouldBeLocalized } from 'payload/shared'\n\n/**\n * Strips fields from data that are not defined in the schema or are invalid.\n *\n * This function was copied from the MongoDB adapter's implementation:\n * @see packages/db-mongodb/src/utilities/transform.ts (stripFields function)\n *\n * @description\n * This utility performs deep sanitization of document data by:\n * 1. **Removing undefined fields**: Strips any field not present in the collection's schema\n * (e.g., sensitive fields like `password`, `apiKey`, or any extra fields not in config)\n * 2. **Removing invalid locales**: Deletes locale keys that don't exist in `config.localization.localeCodes`\n * (e.g., if data contains `{ \"es-MX\": \"...\" }` but only `\"en\"` is configured)\n * 3. **Removing invalid blocks**: Filters out blocks with unknown `blockType` values\n * (prevents data corruption from blocks that don't exist in the schema)\n * 4. **Recursive sanitization**: Processes nested structures (arrays, groups, blocks, localized fields)\n * to ensure deep data integrity\n *\n * @remarks\n * Unlike MongoDB's adapter which uses Mongoose schemas with `strict: true` (rejecting extra fields\n * on write), Content API uses flexible JSONB storage that accepts any fields. Therefore, this\n * function is called on **both read and write operations** to ensure data consistency.\n *\n * The MongoDB adapter also supports an `allowAdditionalKeys` option that allows reading/writing\n * fields not in the schema. For now, Content API does not support this feature - we always\n * sanitize data. If users request this functionality in the future, we can consider adding it.\n *\n * @todo\n * 1. Consider moving this utility to `payload/shared` so both MongoDB and Content API adapters\n * can use the same implementation, reducing code duplication and maintenance burden.\n *\n * 2. Performance optimization: This function iterates through all fields recursively.\n * The `dataToContentAPI` and `dataFromContentAPI` functions in\n * `packages/figma/src/db-content-api/utilities/data.ts` also iterate through fields\n * to transform richText (object ↔ JSON string), custom IDs (number ↔ string), and dates.\n * Consider combining both traversals into a single abstraction to avoid iterating twice.\n *\n * 3. Feature parity: MongoDB adapter has `allowAdditionalKeys` option. We currently always\n * strip additional keys, but could add this as a configurable option if users need it.\n */\nexport const stripFields = ({\n config,\n data,\n fields,\n parentIsLocalized = false,\n reservedKeys = [],\n}: {\n config: SanitizedConfig\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data: any\n fields: FlattenedField[]\n parentIsLocalized?: boolean\n reservedKeys?: string[]\n}) => {\n for (const k in data) {\n if (!fields.some((field) => field.name === k) && !reservedKeys.includes(k)) {\n delete data[k]\n }\n }\n\n for (const field of fields) {\n reservedKeys = []\n const fieldData = data[field.name]\n if (!fieldData || typeof fieldData !== 'object') {\n continue\n }\n\n const shouldLocalizeField = fieldShouldBeLocalized({ field, parentIsLocalized })\n\n if (field.type === 'blocks') {\n reservedKeys.push('blockType')\n }\n\n if ('flattenedFields' in field || 'blocks' in field) {\n if (shouldLocalizeField && config.localization) {\n for (const localeKey in fieldData) {\n if (!config.localization.localeCodes.some((code) => code === localeKey)) {\n delete fieldData[localeKey]\n continue\n }\n\n const localeData = fieldData[localeKey]\n\n if (!localeData || typeof localeData !== 'object') {\n continue\n }\n\n if (field.type === 'array' || field.type === 'blocks') {\n if (!Array.isArray(localeData)) {\n continue\n }\n\n let hasNull = false\n for (let i = 0; i < localeData.length; i++) {\n const data = localeData[i]\n let fields: FlattenedField[] | null = null\n\n if (field.type === 'array') {\n fields = field.flattenedFields\n } else {\n let maybeBlock: FlattenedBlock | undefined = undefined\n\n if (field.blockReferences) {\n const maybeBlockReference = field.blockReferences.find((each) => {\n const slug = typeof each === 'string' ? each : each.slug\n return slug === data.blockType\n })\n\n if (maybeBlockReference) {\n if (typeof maybeBlockReference === 'object') {\n maybeBlock = maybeBlockReference\n } else {\n maybeBlock = config.blocks?.find((each) => each.slug === maybeBlockReference)\n }\n }\n }\n\n if (!maybeBlock) {\n maybeBlock = field.blocks.find((each) => each.slug === data.blockType)\n }\n\n if (maybeBlock) {\n fields = maybeBlock.flattenedFields\n } else {\n localeData[i] = null\n hasNull = true\n }\n }\n\n if (!fields) {\n continue\n }\n\n stripFields({\n config,\n data,\n fields,\n parentIsLocalized: parentIsLocalized || field.localized,\n reservedKeys,\n })\n }\n\n if (hasNull) {\n fieldData[localeKey] = localeData.filter(Boolean)\n }\n\n continue\n } else {\n stripFields({\n config,\n data: localeData,\n fields: field.flattenedFields,\n parentIsLocalized: parentIsLocalized || field.localized,\n reservedKeys,\n })\n }\n }\n continue\n }\n\n if (field.type === 'array' || field.type === 'blocks') {\n if (!Array.isArray(fieldData)) {\n continue\n }\n\n let hasNull = false\n\n for (let i = 0; i < fieldData.length; i++) {\n const data = fieldData[i]\n let fields: FlattenedField[] | null = null\n\n if (field.type === 'array') {\n fields = field.flattenedFields\n } else {\n let maybeBlock: FlattenedBlock | undefined = undefined\n\n if (field.blockReferences) {\n const maybeBlockReference = field.blockReferences.find((each) => {\n const slug = typeof each === 'string' ? each : each.slug\n return slug === data.blockType\n })\n\n if (maybeBlockReference) {\n if (typeof maybeBlockReference === 'object') {\n maybeBlock = maybeBlockReference\n } else {\n maybeBlock = config.blocks?.find((each) => each.slug === maybeBlockReference)\n }\n }\n }\n\n if (!maybeBlock) {\n maybeBlock = field.blocks.find((each) => each.slug === data.blockType)\n }\n\n if (maybeBlock) {\n fields = maybeBlock.flattenedFields\n } else {\n fieldData[i] = null\n hasNull = true\n }\n }\n\n if (!fields) {\n continue\n }\n\n stripFields({\n config,\n data,\n fields,\n parentIsLocalized: parentIsLocalized || field.localized,\n reservedKeys,\n })\n }\n\n if (hasNull) {\n data[field.name] = fieldData.filter(Boolean)\n }\n\n continue\n } else {\n stripFields({\n config,\n data: fieldData,\n fields: field.flattenedFields,\n parentIsLocalized: parentIsLocalized || field.localized,\n reservedKeys,\n })\n }\n }\n }\n}\n"],"names":["fieldShouldBeLocalized","stripFields","config","data","fields","parentIsLocalized","reservedKeys","k","some","field","name","includes","fieldData","shouldLocalizeField","type","push","localization","localeKey","localeCodes","code","localeData","Array","isArray","hasNull","i","length","flattenedFields","maybeBlock","undefined","blockReferences","maybeBlockReference","find","each","slug","blockType","blocks","localized","filter","Boolean"],"mappings":"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"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { JoinQuery, Payload } 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',
|
|
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: '-title',
|
|
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, collectionSlug: string, joins: false | JoinQuery | undefined): ContentAPIJoin[] | undefined;
|
|
54
|
-
export {};
|
|
55
|
-
//# sourceMappingURL=joins.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,MAAM,SAAS,CAAA;AAEjD,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,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GACnC,cAAc,EAAE,GAAG,SAAS,CAyF9B"}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { addFallbackSort } from '../temp-utilities/sorting.js';
|
|
2
|
-
import { convertPayloadWhereToContentAPI } from './where.js';
|
|
3
|
-
/**
|
|
4
|
-
* Convert Payload's JoinQuery to Content API's join format.
|
|
5
|
-
*
|
|
6
|
-
* ## Content API Join Limitations
|
|
7
|
-
*
|
|
8
|
-
* The following Payload join features are NOT YET supported by Content API:
|
|
9
|
-
*
|
|
10
|
-
* 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract
|
|
11
|
-
* a single ID. HasMany relationships store arrays `["id1", "id2"]` which can't match.
|
|
12
|
-
*
|
|
13
|
-
* 2. **Array field relationships** - `on: 'array.category'` expects iteration over array
|
|
14
|
-
* elements, but Content API treats the path as a single JSONB extraction.
|
|
15
|
-
*
|
|
16
|
-
* 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but
|
|
17
|
-
* Content API expects a simple ID string.
|
|
18
|
-
*
|
|
19
|
-
* 4. **Localized relationship fields** - Locale-aware joins not implemented.
|
|
20
|
-
*
|
|
21
|
-
* Note: "Where querying through joins" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)
|
|
22
|
-
* is a separate Payload feature that filters documents based on joined data. This is NOT
|
|
23
|
-
* a join feature but a where clause feature, and would need separate Content API support.
|
|
24
|
-
*
|
|
25
|
-
* Payload's JoinQuery format (at runtime):
|
|
26
|
-
* {
|
|
27
|
-
* 'group.relatedPosts': { // joinPath - where results go in the document
|
|
28
|
-
* sort: '-title',
|
|
29
|
-
* limit: 10,
|
|
30
|
-
* page: 2, // page-based pagination
|
|
31
|
-
* where: { ... }, // Payload where format
|
|
32
|
-
* count: true
|
|
33
|
-
* }
|
|
34
|
-
* }
|
|
35
|
-
*
|
|
36
|
-
* Content API's join format:
|
|
37
|
-
* [{
|
|
38
|
-
* collectionId: 'posts', // collection to join FROM
|
|
39
|
-
* on: 'group.category', // field in joined collection pointing to this doc
|
|
40
|
-
* path: 'group.relatedPosts', // where to put results
|
|
41
|
-
* count: false,
|
|
42
|
-
* where: { ... }, // Content API where format
|
|
43
|
-
* sort: '-title',
|
|
44
|
-
* limit: 10,
|
|
45
|
-
* offset: 10 // offset-based pagination
|
|
46
|
-
* }]
|
|
47
|
-
*
|
|
48
|
-
* The mapping requires the collection config to resolve:
|
|
49
|
-
* - Which collection each join field refers to
|
|
50
|
-
* - What the 'on' field is for each join
|
|
51
|
-
*/ export function convertPayloadJoinsToContentAPI(payload, collectionSlug, joins) {
|
|
52
|
-
const collectionConfig = payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
53
|
-
if (!collectionConfig) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
// joins === false means explicitly disable all joins
|
|
57
|
-
// joins === undefined means use defaults (no custom query params)
|
|
58
|
-
if (joins === false || !joins) {
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
const result = [];
|
|
62
|
-
// Iterate through all join paths in the query
|
|
63
|
-
for (const [joinPath, joinQueryValue] of Object.entries(joins)){
|
|
64
|
-
// joinQuery === false means skip this specific join
|
|
65
|
-
if (joinQueryValue === false) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
// Normalize undefined/empty to empty object
|
|
69
|
-
const joinQuery = joinQueryValue ?? {};
|
|
70
|
-
// Find the SanitizedJoin config for this joinPath
|
|
71
|
-
// SanitizedJoins is indexed by the collection being joined FROM
|
|
72
|
-
let foundJoin;
|
|
73
|
-
// Search through all collections in the joins config
|
|
74
|
-
for (const [collectionSlug, sanitizedJoins] of Object.entries(collectionConfig.joins)){
|
|
75
|
-
for (const sanitizedJoin of sanitizedJoins){
|
|
76
|
-
if (sanitizedJoin.joinPath === joinPath) {
|
|
77
|
-
foundJoin = {
|
|
78
|
-
collectionSlug,
|
|
79
|
-
on: sanitizedJoin.field.on
|
|
80
|
-
};
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (foundJoin) {
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// Also check polymorphic joins
|
|
89
|
-
if (!foundJoin) {
|
|
90
|
-
for (const sanitizedJoin of collectionConfig.polymorphicJoins){
|
|
91
|
-
if (sanitizedJoin.joinPath === joinPath) {
|
|
92
|
-
// For polymorphic joins, collection is an array - use first one
|
|
93
|
-
const collections = sanitizedJoin.field.collection;
|
|
94
|
-
foundJoin = {
|
|
95
|
-
collectionSlug: Array.isArray(collections) ? collections[0] : collections,
|
|
96
|
-
on: sanitizedJoin.field.on
|
|
97
|
-
};
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (!foundJoin) {
|
|
103
|
-
payload.logger.warn(`Join path '${joinPath}' not found in collection config for '${collectionConfig.slug}'`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
// Convert pagination: Payload uses page, Content API JoinClause uses offset
|
|
107
|
-
let offset;
|
|
108
|
-
if (joinQuery.page && joinQuery.page > 1 && joinQuery.limit) {
|
|
109
|
-
offset = (joinQuery.page - 1) * joinQuery.limit;
|
|
110
|
-
}
|
|
111
|
-
// Add fallback sort for the joined collection
|
|
112
|
-
const sortWithFallback = addFallbackSort(joinQuery.sort, payload, foundJoin.collectionSlug);
|
|
113
|
-
const contentAPIJoin = {
|
|
114
|
-
collectionId: foundJoin.collectionSlug,
|
|
115
|
-
count: joinQuery.count ?? false,
|
|
116
|
-
on: foundJoin.on,
|
|
117
|
-
path: joinPath,
|
|
118
|
-
...joinQuery.limit !== undefined && {
|
|
119
|
-
limit: joinQuery.limit
|
|
120
|
-
},
|
|
121
|
-
...offset !== undefined && {
|
|
122
|
-
offset
|
|
123
|
-
},
|
|
124
|
-
...sortWithFallback && {
|
|
125
|
-
sort: sortWithFallback
|
|
126
|
-
},
|
|
127
|
-
...joinQuery.where && {
|
|
128
|
-
where: convertPayloadWhereToContentAPI(joinQuery.where)
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
result.push(contentAPIJoin);
|
|
132
|
-
}
|
|
133
|
-
return result.length > 0 ? result : undefined;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
//# sourceMappingURL=joins.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/db-content-api/utilities/joins.ts"],"sourcesContent":["import type { JoinQuery, Payload } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\nimport { addFallbackSort } from '../temp-utilities/sorting.js'\nimport { convertPayloadWhereToContentAPI } from './where.js'\n\n// JoinClause is an array type, so we extract the element type\ntype ContentAPIJoin = components['schemas']['JoinClause'][number]\n\n/**\n * Convert Payload's JoinQuery to Content API's join format.\n *\n * ## Content API Join Limitations\n *\n * The following Payload join features are NOT YET supported by Content API:\n *\n * 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract\n * a single ID. HasMany relationships store arrays `[\"id1\", \"id2\"]` which can't match.\n *\n * 2. **Array field relationships** - `on: 'array.category'` expects iteration over array\n * elements, but Content API treats the path as a single JSONB extraction.\n *\n * 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but\n * Content API expects a simple ID string.\n *\n * 4. **Localized relationship fields** - Locale-aware joins not implemented.\n *\n * Note: \"Where querying through joins\" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)\n * is a separate Payload feature that filters documents based on joined data. This is NOT\n * a join feature but a where clause feature, and would need separate Content API support.\n *\n * Payload's JoinQuery format (at runtime):\n * {\n * 'group.relatedPosts': { // joinPath - where results go in the document\n * sort: '-title',\n * limit: 10,\n * page: 2, // page-based pagination\n * where: { ... }, // Payload where format\n * count: true\n * }\n * }\n *\n * Content API's join format:\n * [{\n * collectionId: 'posts', // collection to join FROM\n * on: 'group.category', // field in joined collection pointing to this doc\n * path: 'group.relatedPosts', // where to put results\n * count: false,\n * where: { ... }, // Content API where format\n * sort: '-title',\n * limit: 10,\n * offset: 10 // offset-based pagination\n * }]\n *\n * The mapping requires the collection config to resolve:\n * - Which collection each join field refers to\n * - What the 'on' field is for each join\n */\nexport function convertPayloadJoinsToContentAPI(\n payload: Payload,\n collectionSlug: string,\n joins: false | JoinQuery | undefined,\n): ContentAPIJoin[] | undefined {\n const collectionConfig = payload.config.collections.find((c) => c.slug === collectionSlug)\n if (!collectionConfig) {\n return undefined\n }\n // joins === false means explicitly disable all joins\n // joins === undefined means use defaults (no custom query params)\n if (joins === false || !joins) {\n return undefined\n }\n\n const result: ContentAPIJoin[] = []\n\n // Iterate through all join paths in the query\n for (const [joinPath, joinQueryValue] of Object.entries(joins)) {\n // joinQuery === false means skip this specific join\n if (joinQueryValue === false) {\n continue\n }\n\n // Normalize undefined/empty to empty object\n const joinQuery = joinQueryValue ?? {}\n\n // Find the SanitizedJoin config for this joinPath\n // SanitizedJoins is indexed by the collection being joined FROM\n let foundJoin: { collectionSlug: string; on: string } | undefined\n\n // Search through all collections in the joins config\n for (const [collectionSlug, sanitizedJoins] of Object.entries(collectionConfig.joins)) {\n for (const sanitizedJoin of sanitizedJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n foundJoin = {\n collectionSlug,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n if (foundJoin) {\n break\n }\n }\n\n // Also check polymorphic joins\n if (!foundJoin) {\n for (const sanitizedJoin of collectionConfig.polymorphicJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n // For polymorphic joins, collection is an array - use first one\n const collections = sanitizedJoin.field.collection\n foundJoin = {\n collectionSlug: Array.isArray(collections) ? collections[0] : collections,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n }\n\n if (!foundJoin) {\n payload.logger.warn(\n `Join path '${joinPath}' not found in collection config for '${collectionConfig.slug}'`,\n )\n continue\n }\n\n // Convert pagination: Payload uses page, Content API JoinClause uses offset\n let offset: number | undefined\n if (joinQuery.page && joinQuery.page > 1 && joinQuery.limit) {\n offset = (joinQuery.page - 1) * joinQuery.limit\n }\n\n // Add fallback sort for the joined collection\n const sortWithFallback = addFallbackSort(joinQuery.sort, payload, foundJoin.collectionSlug)\n\n const contentAPIJoin: ContentAPIJoin = {\n collectionId: foundJoin.collectionSlug,\n count: joinQuery.count ?? false,\n on: foundJoin.on,\n path: joinPath,\n ...(joinQuery.limit !== undefined && { limit: joinQuery.limit }),\n ...(offset !== undefined && { offset }),\n ...(sortWithFallback && { sort: sortWithFallback }),\n ...(joinQuery.where && { where: convertPayloadWhereToContentAPI(joinQuery.where) }),\n }\n\n result.push(contentAPIJoin)\n }\n\n return result.length > 0 ? result : undefined\n}\n"],"names":["addFallbackSort","convertPayloadWhereToContentAPI","convertPayloadJoinsToContentAPI","payload","collectionSlug","joins","collectionConfig","config","collections","find","c","slug","undefined","result","joinPath","joinQueryValue","Object","entries","joinQuery","foundJoin","sanitizedJoins","sanitizedJoin","on","field","polymorphicJoins","collection","Array","isArray","logger","warn","offset","page","limit","sortWithFallback","sort","contentAPIJoin","collectionId","count","path","where","push","length"],"mappings":"AAIA,SAASA,eAAe,QAAQ,+BAA8B;AAC9D,SAASC,+BAA+B,QAAQ,aAAY;AAK5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDC,GACD,OAAO,SAASC,gCACdC,OAAgB,EAChBC,cAAsB,EACtBC,KAAoC;IAEpC,MAAMC,mBAAmBH,QAAQI,MAAM,CAACC,WAAW,CAACC,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKP;IAC3E,IAAI,CAACE,kBAAkB;QACrB,OAAOM;IACT;IACA,qDAAqD;IACrD,kEAAkE;IAClE,IAAIP,UAAU,SAAS,CAACA,OAAO;QAC7B,OAAOO;IACT;IAEA,MAAMC,SAA2B,EAAE;IAEnC,8CAA8C;IAC9C,KAAK,MAAM,CAACC,UAAUC,eAAe,IAAIC,OAAOC,OAAO,CAACZ,OAAQ;QAC9D,oDAAoD;QACpD,IAAIU,mBAAmB,OAAO;YAC5B;QACF;QAEA,4CAA4C;QAC5C,MAAMG,YAAYH,kBAAkB,CAAC;QAErC,kDAAkD;QAClD,gEAAgE;QAChE,IAAII;QAEJ,qDAAqD;QACrD,KAAK,MAAM,CAACf,gBAAgBgB,eAAe,IAAIJ,OAAOC,OAAO,CAACX,iBAAiBD,KAAK,EAAG;YACrF,KAAK,MAAMgB,iBAAiBD,eAAgB;gBAC1C,IAAIC,cAAcP,QAAQ,KAAKA,UAAU;oBACvCK,YAAY;wBACVf;wBACAkB,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;YACA,IAAIH,WAAW;gBACb;YACF;QACF;QAEA,+BAA+B;QAC/B,IAAI,CAACA,WAAW;YACd,KAAK,MAAME,iBAAiBf,iBAAiBkB,gBAAgB,CAAE;gBAC7D,IAAIH,cAAcP,QAAQ,KAAKA,UAAU;oBACvC,gEAAgE;oBAChE,MAAMN,cAAca,cAAcE,KAAK,CAACE,UAAU;oBAClDN,YAAY;wBACVf,gBAAgBsB,MAAMC,OAAO,CAACnB,eAAeA,WAAW,CAAC,EAAE,GAAGA;wBAC9Dc,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;QACF;QAEA,IAAI,CAACH,WAAW;YACdhB,QAAQyB,MAAM,CAACC,IAAI,CACjB,CAAC,WAAW,EAAEf,SAAS,sCAAsC,EAAER,iBAAiBK,IAAI,CAAC,CAAC,CAAC;YAEzF;QACF;QAEA,4EAA4E;QAC5E,IAAImB;QACJ,IAAIZ,UAAUa,IAAI,IAAIb,UAAUa,IAAI,GAAG,KAAKb,UAAUc,KAAK,EAAE;YAC3DF,SAAS,AAACZ,CAAAA,UAAUa,IAAI,GAAG,CAAA,IAAKb,UAAUc,KAAK;QACjD;QAEA,8CAA8C;QAC9C,MAAMC,mBAAmBjC,gBAAgBkB,UAAUgB,IAAI,EAAE/B,SAASgB,UAAUf,cAAc;QAE1F,MAAM+B,iBAAiC;YACrCC,cAAcjB,UAAUf,cAAc;YACtCiC,OAAOnB,UAAUmB,KAAK,IAAI;YAC1Bf,IAAIH,UAAUG,EAAE;YAChBgB,MAAMxB;YACN,GAAII,UAAUc,KAAK,KAAKpB,aAAa;gBAAEoB,OAAOd,UAAUc,KAAK;YAAC,CAAC;YAC/D,GAAIF,WAAWlB,aAAa;gBAAEkB;YAAO,CAAC;YACtC,GAAIG,oBAAoB;gBAAEC,MAAMD;YAAiB,CAAC;YAClD,GAAIf,UAAUqB,KAAK,IAAI;gBAAEA,OAAOtC,gCAAgCiB,UAAUqB,KAAK;YAAE,CAAC;QACpF;QAEA1B,OAAO2B,IAAI,CAACL;IACd;IAEA,OAAOtB,OAAO4B,MAAM,GAAG,IAAI5B,SAASD;AACtC"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Where } from 'payload';
|
|
2
|
-
import type { components } from '../generated/content-api-types.js';
|
|
3
|
-
type WhereClause = components['schemas']['WhereClause'];
|
|
4
|
-
type ConvertOptions = {
|
|
5
|
-
/** Internal flag to track if we're inside a logical operator (and/or) */
|
|
6
|
-
insideLogicalOperator?: boolean;
|
|
7
|
-
/** If true, transform 'parent' field to 'documentId' (used for version queries) */
|
|
8
|
-
parentToDocumentId?: boolean;
|
|
9
|
-
};
|
|
10
|
-
export declare function convertPayloadWhereToContentAPI(where: undefined | Where, options?: ConvertOptions): WhereClause;
|
|
11
|
-
export {};
|
|
12
|
-
//# sourceMappingURL=where.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"where.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/utilities/where.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,KAAK,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,CAAA;AASvD,KAAK,cAAc,GAAG;IACpB,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,SAAS,GAAG,KAAK,EACxB,OAAO,GAAE,cAAmB,GAC3B,WAAW,CA6Hb"}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
export function convertPayloadWhereToContentAPI(where, options = {}) {
|
|
2
|
-
// Empty where {} should be { and: [] } not undefined
|
|
3
|
-
// Content API requires a where clause structure even for "no filter"
|
|
4
|
-
if (!where || Object.keys(where).length === 0) {
|
|
5
|
-
return {
|
|
6
|
-
and: []
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
const conditions = [];
|
|
10
|
-
for (const [key, value] of Object.entries(where)){
|
|
11
|
-
if (key === 'and') {
|
|
12
|
-
// Recursively convert nested 'and' conditions, preserving options
|
|
13
|
-
const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, {
|
|
14
|
-
...options,
|
|
15
|
-
insideLogicalOperator: true
|
|
16
|
-
}))// TODO: A better solution would be to make the `where` schema of `zod` in `content-api`
|
|
17
|
-
// more permissive. For now I'll do it this way because I have an idea to simplify
|
|
18
|
-
// everything we're doing with `where` (Post EAP) anyway.
|
|
19
|
-
// Filter out empty conditions { and: [] } that would be invalid
|
|
20
|
-
.filter((condition)=>{
|
|
21
|
-
if ('and' in condition) {
|
|
22
|
-
return condition.and.length > 0;
|
|
23
|
-
}
|
|
24
|
-
if ('or' in condition) {
|
|
25
|
-
return condition.or.length > 0;
|
|
26
|
-
}
|
|
27
|
-
return true // Keep path/operator/value conditions
|
|
28
|
-
;
|
|
29
|
-
});
|
|
30
|
-
// If filtering resulted in no conditions, return empty and
|
|
31
|
-
if (nestedConditions.length === 0) {
|
|
32
|
-
return {
|
|
33
|
-
and: []
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
and: nestedConditions
|
|
38
|
-
};
|
|
39
|
-
} else if (key === 'or') {
|
|
40
|
-
// Recursively convert nested 'or' conditions, preserving options
|
|
41
|
-
const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, {
|
|
42
|
-
...options,
|
|
43
|
-
insideLogicalOperator: true
|
|
44
|
-
}))// Filter out empty conditions { and: [] } or { or: [] } that would be invalid
|
|
45
|
-
.filter((condition)=>{
|
|
46
|
-
if ('and' in condition) {
|
|
47
|
-
return condition.and.length > 0;
|
|
48
|
-
}
|
|
49
|
-
if ('or' in condition) {
|
|
50
|
-
return condition.or.length > 0;
|
|
51
|
-
}
|
|
52
|
-
return true // Keep path/operator/value conditions
|
|
53
|
-
;
|
|
54
|
-
});
|
|
55
|
-
// If filtering resulted in no conditions, return empty and
|
|
56
|
-
if (nestedConditions.length === 0) {
|
|
57
|
-
return {
|
|
58
|
-
and: []
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
or: nestedConditions
|
|
63
|
-
};
|
|
64
|
-
} else {
|
|
65
|
-
// TODO: fix this in content api
|
|
66
|
-
// WORKAROUND: Payload uses 'parent' for version queries, but Content API expects 'documentId'
|
|
67
|
-
let fieldPath = key;
|
|
68
|
-
if (options.parentToDocumentId && key === 'parent') {
|
|
69
|
-
fieldPath = 'documentId';
|
|
70
|
-
}
|
|
71
|
-
// Convert field conditions: { fieldName: { operator: value } }
|
|
72
|
-
// to: { path: fieldName, operator, value }
|
|
73
|
-
// Handle Payload's shorthand: { fieldName: value } → { fieldName: { equals: value } }
|
|
74
|
-
// If value is a primitive (string, number, boolean, null) or not a plain object,
|
|
75
|
-
// treat it as an implicit 'equals' operator
|
|
76
|
-
const isPrimitive = value === null || typeof value !== 'object' || Array.isArray(value);
|
|
77
|
-
if (isPrimitive) {
|
|
78
|
-
// Shorthand format: { id: "some-value" } means { id: { equals: "some-value" } }
|
|
79
|
-
conditions.push({
|
|
80
|
-
operator: 'equals',
|
|
81
|
-
path: fieldPath,
|
|
82
|
-
value
|
|
83
|
-
});
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
const operators = value;
|
|
87
|
-
// Skip empty operator objects { fieldName: {} }
|
|
88
|
-
if (Object.keys(operators).length === 0) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
for (const [op, operatorValue] of Object.entries(operators)){
|
|
92
|
-
// Skip operators with undefined values (e.g., { equals: undefined })
|
|
93
|
-
// This can happen when Payload sends incomplete where clauses
|
|
94
|
-
if (operatorValue === undefined) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
let finalValue = operatorValue;
|
|
98
|
-
// Convert string booleans to actual booleans for exists operator
|
|
99
|
-
// REST API sends "true"/"false" as strings, but Content API requires boolean
|
|
100
|
-
if (op === 'exists' && typeof operatorValue === 'string') {
|
|
101
|
-
finalValue = operatorValue === 'true';
|
|
102
|
-
}
|
|
103
|
-
conditions.push({
|
|
104
|
-
operator: op,
|
|
105
|
-
path: fieldPath,
|
|
106
|
-
value: finalValue
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// If inside a logical operator (and/or), return conditions directly
|
|
112
|
-
// Otherwise, wrap in 'and' to match WhereClause type
|
|
113
|
-
if (options.insideLogicalOperator && conditions.length === 1) {
|
|
114
|
-
return conditions[0];
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
and: conditions
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
//# sourceMappingURL=where.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/db-content-api/utilities/where.ts"],"sourcesContent":["import type { Where } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\ntype WhereClause = components['schemas']['WhereClause']\n\n// Payload's format: { fieldName: { operator: value }, and: [...], or: [...] }\n// Content API expects: { and: [{ path, operator, value }], or: [{ path, operator, value }] }\n//\n// The format stays different. This allows the Content API to evolve its filter schema,\n// for example to support composite types like Point, which are not lexicographically sortable.\n// Semantics must remain identical to Payload.\n\ntype ConvertOptions = {\n /** Internal flag to track if we're inside a logical operator (and/or) */\n insideLogicalOperator?: boolean\n /** If true, transform 'parent' field to 'documentId' (used for version queries) */\n parentToDocumentId?: boolean\n}\n\nexport function convertPayloadWhereToContentAPI(\n where: undefined | Where,\n options: ConvertOptions = {},\n): WhereClause {\n // Empty where {} should be { and: [] } not undefined\n // Content API requires a where clause structure even for \"no filter\"\n if (!where || Object.keys(where).length === 0) {\n return { and: [] }\n }\n\n // Extract the condition type (the variant with 'path', 'operator', 'value') from WhereClause union\n type WhereCondition = Extract<WhereClause, { path: string }>\n const conditions: WhereClause[] = []\n\n for (const [key, value] of Object.entries(where)) {\n if (key === 'and') {\n // Recursively convert nested 'and' conditions, preserving options\n const nestedConditions = (value as Where[])\n .map((item) =>\n convertPayloadWhereToContentAPI(item, { ...options, insideLogicalOperator: true }),\n )\n // TODO: A better solution would be to make the `where` schema of `zod` in `content-api`\n // more permissive. For now I'll do it this way because I have an idea to simplify\n // everything we're doing with `where` (Post EAP) anyway.\n // Filter out empty conditions { and: [] } that would be invalid\n .filter((condition) => {\n if ('and' in condition) {\n return condition.and.length > 0\n }\n if ('or' in condition) {\n return condition.or.length > 0\n }\n return true // Keep path/operator/value conditions\n })\n\n // If filtering resulted in no conditions, return empty and\n if (nestedConditions.length === 0) {\n return { and: [] }\n }\n\n return { and: nestedConditions }\n } else if (key === 'or') {\n // Recursively convert nested 'or' conditions, preserving options\n const nestedConditions = (value as Where[])\n .map((item) =>\n convertPayloadWhereToContentAPI(item, { ...options, insideLogicalOperator: true }),\n )\n // Filter out empty conditions { and: [] } or { or: [] } that would be invalid\n .filter((condition) => {\n if ('and' in condition) {\n return condition.and.length > 0\n }\n if ('or' in condition) {\n return condition.or.length > 0\n }\n return true // Keep path/operator/value conditions\n })\n\n // If filtering resulted in no conditions, return empty and\n if (nestedConditions.length === 0) {\n return { and: [] }\n }\n\n return { or: nestedConditions }\n } else {\n // TODO: fix this in content api\n // WORKAROUND: Payload uses 'parent' for version queries, but Content API expects 'documentId'\n let fieldPath = key\n if (options.parentToDocumentId && key === 'parent') {\n fieldPath = 'documentId'\n }\n\n // Convert field conditions: { fieldName: { operator: value } }\n // to: { path: fieldName, operator, value }\n\n // Handle Payload's shorthand: { fieldName: value } → { fieldName: { equals: value } }\n // If value is a primitive (string, number, boolean, null) or not a plain object,\n // treat it as an implicit 'equals' operator\n const isPrimitive = value === null || typeof value !== 'object' || Array.isArray(value)\n\n if (isPrimitive) {\n // Shorthand format: { id: \"some-value\" } means { id: { equals: \"some-value\" } }\n conditions.push({\n operator: 'equals',\n path: fieldPath,\n value,\n } as WhereCondition)\n continue\n }\n\n const operators = value as Record<string, unknown>\n\n // Skip empty operator objects { fieldName: {} }\n if (Object.keys(operators).length === 0) {\n continue\n }\n\n for (const [op, operatorValue] of Object.entries(operators)) {\n // Skip operators with undefined values (e.g., { equals: undefined })\n // This can happen when Payload sends incomplete where clauses\n if (operatorValue === undefined) {\n continue\n }\n\n let finalValue = operatorValue\n\n // Convert string booleans to actual booleans for exists operator\n // REST API sends \"true\"/\"false\" as strings, but Content API requires boolean\n if (op === 'exists' && typeof operatorValue === 'string') {\n finalValue = operatorValue === 'true'\n }\n\n conditions.push({\n operator: op as WhereCondition['operator'],\n path: fieldPath,\n value: finalValue,\n } as WhereCondition)\n }\n }\n }\n\n // If inside a logical operator (and/or), return conditions directly\n // Otherwise, wrap in 'and' to match WhereClause type\n if (options.insideLogicalOperator && conditions.length === 1) {\n return conditions[0]\n }\n\n return { and: conditions }\n}\n"],"names":["convertPayloadWhereToContentAPI","where","options","Object","keys","length","and","conditions","key","value","entries","nestedConditions","map","item","insideLogicalOperator","filter","condition","or","fieldPath","parentToDocumentId","isPrimitive","Array","isArray","push","operator","path","operators","op","operatorValue","undefined","finalValue"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/endpoints/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,eAAO,MAAM,MAAM,EAAE,QAMpB,CAAA"}
|
package/dist/endpoints/health.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/health.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nexport const health: Endpoint = {\n handler: () => {\n return Response.json({ status: 200 })\n },\n method: 'get',\n path: '/health',\n}\n"],"names":["health","handler","Response","json","status","method","path"],"mappings":"AAEA,OAAO,MAAMA,SAAmB;IAC9BC,SAAS;QACP,OAAOC,SAASC,IAAI,CAAC;YAAEC,QAAQ;QAAI;IACrC;IACAC,QAAQ;IACRC,MAAM;AACR,EAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Check if an error is a duplicate key/unique constraint violation from Content API.
|
|
3
|
-
*
|
|
4
|
-
* Content API returns HTTP 409 with "conflict" or "already exists" in the message.
|
|
5
|
-
*/
|
|
6
|
-
export declare function isDuplicateKeyError(error: unknown): boolean;
|
|
7
|
-
//# sourceMappingURL=isDuplicateKeyError.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"isDuplicateKeyError.d.ts","sourceRoot":"","sources":["../../../src/oauth/utilities/isDuplicateKeyError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAa3D"}
|