payload 3.89.0-internal.95c9cba → 3.90.0
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/admin/forms/Field.d.ts +2 -0
- package/dist/admin/forms/Field.d.ts.map +1 -1
- package/dist/admin/forms/Field.js.map +1 -1
- package/dist/admin/forms/Form.d.ts +2 -0
- package/dist/admin/forms/Form.d.ts.map +1 -1
- package/dist/admin/forms/Form.js.map +1 -1
- package/dist/admin/functions/index.d.ts +3 -1
- package/dist/admin/functions/index.d.ts.map +1 -1
- package/dist/admin/functions/index.js.map +1 -1
- package/dist/admin/views/dashboard.d.ts +1 -1
- package/dist/admin/views/dashboard.d.ts.map +1 -1
- package/dist/admin/views/dashboard.js.map +1 -1
- package/dist/auth/applyUserReadAccess.d.ts +15 -0
- package/dist/auth/applyUserReadAccess.d.ts.map +1 -0
- package/dist/auth/applyUserReadAccess.js +41 -0
- package/dist/auth/applyUserReadAccess.js.map +1 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js +20 -0
- package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.js +16 -0
- package/dist/auth/baseFields/apiKey/encryptAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/index.d.ts +6 -0
- package/dist/auth/baseFields/apiKey/index.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/index.js +112 -0
- package/dist/auth/baseFields/apiKey/index.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.js +8 -0
- package/dist/auth/baseFields/apiKey/omitAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js +5 -0
- package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js.map +1 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js +5 -0
- package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js.map +1 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts +4 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts.map +1 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js +17 -0
- package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js.map +1 -0
- package/dist/auth/baseFields/auth.d.ts +1 -0
- package/dist/auth/baseFields/auth.d.ts.map +1 -1
- package/dist/auth/baseFields/auth.js +9 -0
- package/dist/auth/baseFields/auth.js.map +1 -1
- package/dist/auth/defaultUnlockAccess.d.ts +3 -0
- package/dist/auth/defaultUnlockAccess.d.ts.map +1 -0
- package/dist/auth/defaultUnlockAccess.js +8 -0
- package/dist/auth/defaultUnlockAccess.js.map +1 -0
- package/dist/auth/endpoints/index.d.ts +1 -0
- package/dist/auth/endpoints/index.d.ts.map +1 -1
- package/dist/auth/endpoints/index.js +8 -0
- package/dist/auth/endpoints/index.js.map +1 -1
- package/dist/auth/endpoints/revealAPIKey.d.ts +7 -0
- package/dist/auth/endpoints/revealAPIKey.d.ts.map +1 -0
- package/dist/auth/endpoints/revealAPIKey.js +120 -0
- package/dist/auth/endpoints/revealAPIKey.js.map +1 -0
- package/dist/auth/executeAccess.d.ts +3 -1
- package/dist/auth/executeAccess.d.ts.map +1 -1
- package/dist/auth/executeAccess.js +2 -1
- package/dist/auth/executeAccess.js.map +1 -1
- package/dist/auth/getAuthFields.d.ts +1 -1
- package/dist/auth/getAuthFields.d.ts.map +1 -1
- package/dist/auth/getAuthFields.js +7 -4
- package/dist/auth/getAuthFields.js.map +1 -1
- package/dist/auth/getFieldsToSign.d.ts.map +1 -1
- package/dist/auth/getFieldsToSign.js +17 -10
- package/dist/auth/getFieldsToSign.js.map +1 -1
- package/dist/auth/getFieldsToSign.spec.js +114 -0
- package/dist/auth/getFieldsToSign.spec.js.map +1 -0
- package/dist/auth/jwt.d.ts.map +1 -1
- package/dist/auth/jwt.js +2 -0
- package/dist/auth/jwt.js.map +1 -1
- package/dist/auth/jwt.spec.js +24 -0
- package/dist/auth/jwt.spec.js.map +1 -0
- package/dist/auth/jwtAuth.d.ts +9 -0
- package/dist/auth/jwtAuth.d.ts.map +1 -0
- package/dist/auth/jwtAuth.js +8 -0
- package/dist/auth/jwtAuth.js.map +1 -0
- package/dist/auth/operations/auth.d.ts.map +1 -1
- package/dist/auth/operations/auth.js +2 -1
- package/dist/auth/operations/auth.js.map +1 -1
- package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
- package/dist/auth/operations/forgotPassword.js +95 -7
- package/dist/auth/operations/forgotPassword.js.map +1 -1
- package/dist/auth/operations/local/auth.js +3 -1
- package/dist/auth/operations/local/auth.js.map +1 -1
- package/dist/auth/operations/login.d.ts.map +1 -1
- package/dist/auth/operations/login.js +48 -26
- package/dist/auth/operations/login.js.map +1 -1
- package/dist/auth/operations/refresh.d.ts.map +1 -1
- package/dist/auth/operations/refresh.js +32 -9
- package/dist/auth/operations/refresh.js.map +1 -1
- package/dist/auth/operations/registerFirstUser.d.ts.map +1 -1
- package/dist/auth/operations/registerFirstUser.js +3 -4
- package/dist/auth/operations/registerFirstUser.js.map +1 -1
- package/dist/auth/operations/resetPassword.d.ts.map +1 -1
- package/dist/auth/operations/resetPassword.js +31 -22
- package/dist/auth/operations/resetPassword.js.map +1 -1
- package/dist/auth/operations/unlock.d.ts.map +1 -1
- package/dist/auth/operations/unlock.js +1 -0
- package/dist/auth/operations/unlock.js.map +1 -1
- package/dist/auth/strategies/apiKey.d.ts.map +1 -1
- package/dist/auth/strategies/apiKey.js +15 -1
- package/dist/auth/strategies/apiKey.js.map +1 -1
- package/dist/auth/strategies/jwt.d.ts.map +1 -1
- package/dist/auth/strategies/jwt.js +61 -10
- package/dist/auth/strategies/jwt.js.map +1 -1
- package/dist/auth/strategies/jwt.spec.js +281 -0
- package/dist/auth/strategies/jwt.spec.js.map +1 -0
- package/dist/auth/strategies/local/authenticate.d.ts +5 -1
- package/dist/auth/strategies/local/authenticate.d.ts.map +1 -1
- package/dist/auth/strategies/local/authenticate.js +8 -3
- package/dist/auth/strategies/local/authenticate.js.map +1 -1
- package/dist/auth/strategies/local/authenticate.spec.js +37 -10
- package/dist/auth/strategies/local/authenticate.spec.js.map +1 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts +9 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts.map +1 -1
- package/dist/auth/strategies/local/generatePasswordSaltHash.js +61 -34
- package/dist/auth/strategies/local/generatePasswordSaltHash.js.map +1 -1
- package/dist/auth/types.d.ts +16 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/collections/config/client.d.ts +1 -0
- package/dist/collections/config/client.d.ts.map +1 -1
- package/dist/collections/config/client.js +3 -0
- package/dist/collections/config/client.js.map +1 -1
- package/dist/collections/config/defaults.d.ts.map +1 -1
- package/dist/collections/config/defaults.js +4 -2
- package/dist/collections/config/defaults.js.map +1 -1
- package/dist/collections/config/sanitize.d.ts.map +1 -1
- package/dist/collections/config/sanitize.js +17 -6
- package/dist/collections/config/sanitize.js.map +1 -1
- package/dist/collections/endpoints/index.d.ts +1 -0
- package/dist/collections/endpoints/index.d.ts.map +1 -1
- package/dist/collections/endpoints/index.js +6 -5
- package/dist/collections/endpoints/index.js.map +1 -1
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +105 -8
- package/dist/collections/operations/create.js.map +1 -1
- package/dist/collections/operations/deleteByID.js +13 -13
- package/dist/collections/operations/deleteByID.js.map +1 -1
- package/dist/collections/operations/findDistinct.d.ts.map +1 -1
- package/dist/collections/operations/findDistinct.js +96 -18
- package/dist/collections/operations/findDistinct.js.map +1 -1
- package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
- package/dist/collections/operations/restoreVersion.js +47 -13
- package/dist/collections/operations/restoreVersion.js.map +1 -1
- package/dist/collections/operations/update.d.ts.map +1 -1
- package/dist/collections/operations/update.js +123 -23
- package/dist/collections/operations/update.js.map +1 -1
- package/dist/collections/operations/updateByID.d.ts.map +1 -1
- package/dist/collections/operations/updateByID.js +62 -2
- package/dist/collections/operations/updateByID.js.map +1 -1
- package/dist/collections/operations/utilities/update.d.ts.map +1 -1
- package/dist/collections/operations/utilities/update.js +71 -15
- package/dist/collections/operations/utilities/update.js.map +1 -1
- package/dist/config/orderable/index.d.ts.map +1 -1
- package/dist/config/orderable/index.js +67 -14
- package/dist/config/orderable/index.js.map +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/config/sanitize.js +1 -1
- package/dist/config/sanitize.js.map +1 -1
- package/dist/config/types.d.ts +13 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/getLocalizedPaths.d.ts +2 -1
- package/dist/database/getLocalizedPaths.d.ts.map +1 -1
- package/dist/database/getLocalizedPaths.js +12 -3
- package/dist/database/getLocalizedPaths.js.map +1 -1
- package/dist/database/isNestedRelationshipQuery.d.ts +9 -0
- package/dist/database/isNestedRelationshipQuery.d.ts.map +1 -0
- package/dist/database/isNestedRelationshipQuery.js +14 -0
- package/dist/database/isNestedRelationshipQuery.js.map +1 -0
- package/dist/database/prefixWherePaths.d.ts +6 -0
- package/dist/database/prefixWherePaths.d.ts.map +1 -0
- package/dist/database/prefixWherePaths.js +19 -0
- package/dist/database/prefixWherePaths.js.map +1 -0
- package/dist/database/prefixWherePaths.spec.js +46 -0
- package/dist/database/prefixWherePaths.spec.js.map +1 -0
- package/dist/database/queryValidation/validateQueryPaths.d.ts +2 -1
- package/dist/database/queryValidation/validateQueryPaths.d.ts.map +1 -1
- package/dist/database/queryValidation/validateQueryPaths.js +4 -1
- package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.d.ts +2 -1
- package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.js +82 -4
- package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
- package/dist/database/types.d.ts +5 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/database/types.js.map +1 -1
- package/dist/email/normalizeSendEmailOptions.js.map +1 -1
- package/dist/email/types.d.ts +4 -1
- package/dist/email/types.d.ts.map +1 -1
- package/dist/email/types.js.map +1 -1
- package/dist/exports/internal.d.ts +7 -0
- package/dist/exports/internal.d.ts.map +1 -1
- package/dist/exports/internal.js +7 -1
- package/dist/exports/internal.js.map +1 -1
- package/dist/exports/shared.d.ts +3 -0
- package/dist/exports/shared.d.ts.map +1 -1
- package/dist/exports/shared.js +3 -0
- package/dist/exports/shared.js.map +1 -1
- package/dist/fields/config/types.d.ts +7 -5
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/config/types.js.map +1 -1
- package/dist/fields/hooks/beforeChange/index.d.ts +7 -1
- package/dist/fields/hooks/beforeChange/index.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/index.js +4 -2
- package/dist/fields/hooks/beforeChange/index.js.map +1 -1
- package/dist/fields/hooks/beforeChange/index.spec.js +206 -0
- package/dist/fields/hooks/beforeChange/index.spec.js.map +1 -0
- package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/promise.js +51 -9
- package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/beforeChange/traverseFields.js +3 -2
- package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
- package/dist/fields/hooks/beforeDuplicate/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeDuplicate/promise.js +4 -0
- package/dist/fields/hooks/beforeDuplicate/promise.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts +2 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/getFallbackValue.js +2 -2
- package/dist/fields/hooks/beforeValidate/getFallbackValue.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/index.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.js +3 -1
- package/dist/fields/hooks/beforeValidate/index.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/index.spec.js +90 -0
- package/dist/fields/hooks/beforeValidate/index.spec.js.map +1 -0
- package/dist/fields/hooks/beforeValidate/promise.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/promise.js +23 -8
- package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +6 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.js +3 -1
- package/dist/fields/hooks/beforeValidate/traverseFields.js.map +1 -1
- package/dist/fields/validations.d.ts.map +1 -1
- package/dist/fields/validations.js +3 -1
- package/dist/fields/validations.js.map +1 -1
- package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
- package/dist/globals/operations/restoreVersion.js +45 -11
- package/dist/globals/operations/restoreVersion.js.map +1 -1
- package/dist/globals/operations/update.d.ts.map +1 -1
- package/dist/globals/operations/update.js +95 -16
- package/dist/globals/operations/update.js.map +1 -1
- package/dist/index.bundled.d.ts +146 -48
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/preferences/config.d.ts.map +1 -1
- package/dist/preferences/config.js +2 -1
- package/dist/preferences/config.js.map +1 -1
- package/dist/query-presets/access.d.ts.map +1 -1
- package/dist/query-presets/access.js +2 -1
- package/dist/query-presets/access.js.map +1 -1
- package/dist/queues/config/collection.d.ts.map +1 -1
- package/dist/queues/config/collection.js +6 -0
- package/dist/queues/config/collection.js.map +1 -1
- package/dist/queues/config/types/index.d.ts +4 -1
- package/dist/queues/config/types/index.d.ts.map +1 -1
- package/dist/queues/config/types/index.js.map +1 -1
- package/dist/queues/endpoints/handleSchedules.d.ts.map +1 -1
- package/dist/queues/endpoints/handleSchedules.js +2 -1
- package/dist/queues/endpoints/handleSchedules.js.map +1 -1
- package/dist/queues/endpoints/run.d.ts.map +1 -1
- package/dist/queues/endpoints/run.js +2 -1
- package/dist/queues/endpoints/run.js.map +1 -1
- package/dist/uploads/assertClientUploadAccess.d.ts +7 -0
- package/dist/uploads/assertClientUploadAccess.d.ts.map +1 -0
- package/dist/uploads/assertClientUploadAccess.js +27 -0
- package/dist/uploads/assertClientUploadAccess.js.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.d.ts +11 -0
- package/dist/uploads/assertClientUploadAllowed.d.ts.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.js +46 -0
- package/dist/uploads/assertClientUploadAllowed.js.map +1 -0
- package/dist/uploads/assertClientUploadAllowed.spec.js +91 -0
- package/dist/uploads/assertClientUploadAllowed.spec.js.map +1 -0
- package/dist/uploads/checkFileRestrictions.d.ts +4 -1
- package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
- package/dist/uploads/checkFileRestrictions.js +66 -26
- package/dist/uploads/checkFileRestrictions.js.map +1 -1
- package/dist/uploads/clientUploadReceipt.d.ts +23 -0
- package/dist/uploads/clientUploadReceipt.d.ts.map +1 -0
- package/dist/uploads/clientUploadReceipt.js +55 -0
- package/dist/uploads/clientUploadReceipt.js.map +1 -0
- package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
- package/dist/uploads/deleteAssociatedFiles.js +33 -8
- package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
- package/dist/uploads/deleteAssociatedFiles.spec.js +124 -0
- package/dist/uploads/deleteAssociatedFiles.spec.js.map +1 -0
- package/dist/uploads/detectSvgFromXml.d.ts +1 -3
- package/dist/uploads/detectSvgFromXml.d.ts.map +1 -1
- package/dist/uploads/detectSvgFromXml.js +3 -40
- package/dist/uploads/detectSvgFromXml.js.map +1 -1
- package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
- package/dist/uploads/endpoints/getFile.js +5 -3
- package/dist/uploads/endpoints/getFile.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/handlers.d.ts +2 -2
- package/dist/uploads/fetchAPI-multipart/handlers.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/handlers.js +18 -5
- package/dist/uploads/fetchAPI-multipart/handlers.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/index.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/index.js +24 -2
- package/dist/uploads/fetchAPI-multipart/index.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts +0 -6
- package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.js +146 -126
- package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js +663 -0
- package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js.map +1 -0
- package/dist/uploads/generateFileData.d.ts +3 -1
- package/dist/uploads/generateFileData.d.ts.map +1 -1
- package/dist/uploads/generateFileData.js +29 -16
- package/dist/uploads/generateFileData.js.map +1 -1
- package/dist/uploads/getBaseFields.d.ts.map +1 -1
- package/dist/uploads/getBaseFields.js +3 -1
- package/dist/uploads/getBaseFields.js.map +1 -1
- package/dist/uploads/getExternalFile.d.ts +1 -1
- package/dist/uploads/getExternalFile.d.ts.map +1 -1
- package/dist/uploads/getExternalFile.js +60 -15
- package/dist/uploads/getExternalFile.js.map +1 -1
- package/dist/uploads/getFileFromClientUpload.d.ts +2 -2
- package/dist/uploads/getFileFromClientUpload.d.ts.map +1 -1
- package/dist/uploads/getFileFromClientUpload.js +4 -4
- package/dist/uploads/getFileFromClientUpload.js.map +1 -1
- package/dist/uploads/getFileFromClientUpload.spec.js +62 -0
- package/dist/uploads/getFileFromClientUpload.spec.js.map +1 -1
- package/dist/uploads/getFileTypeFallback.d.ts.map +1 -1
- package/dist/uploads/getFileTypeFallback.js +3 -1
- package/dist/uploads/getFileTypeFallback.js.map +1 -1
- package/dist/uploads/getFileTypeIdentity.d.ts +19 -0
- package/dist/uploads/getFileTypeIdentity.d.ts.map +1 -0
- package/dist/uploads/getFileTypeIdentity.js +34 -0
- package/dist/uploads/getFileTypeIdentity.js.map +1 -0
- package/dist/uploads/getFileTypeIdentity.spec.js +43 -0
- package/dist/uploads/getFileTypeIdentity.spec.js.map +1 -0
- package/dist/uploads/isProcessableImage.d.ts +2 -0
- package/dist/uploads/isProcessableImage.d.ts.map +1 -0
- package/dist/uploads/isProcessableImage.js +7 -0
- package/dist/uploads/isProcessableImage.js.map +1 -0
- package/dist/uploads/safeFetch.d.ts.map +1 -1
- package/dist/uploads/safeFetch.js +3 -2
- package/dist/uploads/safeFetch.js.map +1 -1
- package/dist/uploads/sanitizeUploadData.d.ts +26 -0
- package/dist/uploads/sanitizeUploadData.d.ts.map +1 -0
- package/dist/uploads/sanitizeUploadData.js +159 -0
- package/dist/uploads/sanitizeUploadData.js.map +1 -0
- package/dist/uploads/sanitizeUploadData.spec.js +255 -0
- package/dist/uploads/sanitizeUploadData.spec.js.map +1 -0
- package/dist/uploads/types.d.ts +11 -3
- package/dist/uploads/types.d.ts.map +1 -1
- package/dist/uploads/types.js.map +1 -1
- package/dist/uploads/unlinkClientUploadTempFile.d.ts +20 -0
- package/dist/uploads/unlinkClientUploadTempFile.d.ts.map +1 -0
- package/dist/uploads/unlinkClientUploadTempFile.js +30 -0
- package/dist/uploads/unlinkClientUploadTempFile.js.map +1 -0
- package/dist/uploads/unlinkTempFiles.d.ts.map +1 -1
- package/dist/uploads/unlinkTempFiles.js +7 -9
- package/dist/uploads/unlinkTempFiles.js.map +1 -1
- package/dist/uploads/unlinkTempFiles.spec.js +61 -1
- package/dist/uploads/unlinkTempFiles.spec.js.map +1 -1
- package/dist/uploads/uploadContentSecurityPolicy.d.ts +2 -0
- package/dist/uploads/uploadContentSecurityPolicy.d.ts.map +1 -0
- package/dist/uploads/uploadContentSecurityPolicy.js +3 -0
- package/dist/uploads/uploadContentSecurityPolicy.js.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.d.ts +4 -0
- package/dist/uploads/validateISOBaseMediaFile.d.ts.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.js +91 -0
- package/dist/uploads/validateISOBaseMediaFile.js.map +1 -0
- package/dist/uploads/validateISOBaseMediaFile.spec.js +130 -0
- package/dist/uploads/validateISOBaseMediaFile.spec.js.map +1 -0
- package/dist/uploads/validateSvg.d.ts +10 -4
- package/dist/uploads/validateSvg.d.ts.map +1 -1
- package/dist/uploads/validateSvg.js +280 -40
- package/dist/uploads/validateSvg.js.map +1 -1
- package/dist/uploads/validateSvg.spec.js +123 -0
- package/dist/uploads/validateSvg.spec.js.map +1 -0
- package/dist/uploads/validateUploadFilename.d.ts +3 -0
- package/dist/uploads/validateUploadFilename.d.ts.map +1 -0
- package/dist/uploads/validateUploadFilename.js +13 -0
- package/dist/uploads/validateUploadFilename.js.map +1 -0
- package/dist/uploads/validateUploadFilename.spec.js +24 -0
- package/dist/uploads/validateUploadFilename.spec.js.map +1 -0
- package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.js +28 -1
- package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.spec.js +158 -0
- package/dist/utilities/addDataAndFileToRequest.spec.js.map +1 -1
- package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
- package/dist/utilities/createPayloadRequest.js +2 -1
- package/dist/utilities/createPayloadRequest.js.map +1 -1
- package/dist/utilities/deepCopyObject.d.ts.map +1 -1
- package/dist/utilities/deepCopyObject.js +110 -19
- package/dist/utilities/deepCopyObject.js.map +1 -1
- package/dist/utilities/deepCopyObject.spec.js +216 -0
- package/dist/utilities/deepCopyObject.spec.js.map +1 -0
- package/dist/utilities/fieldPath.d.ts +13 -0
- package/dist/utilities/fieldPath.d.ts.map +1 -0
- package/dist/utilities/fieldPath.js +51 -0
- package/dist/utilities/fieldPath.js.map +1 -0
- package/dist/utilities/fieldPath.spec.js +155 -0
- package/dist/utilities/fieldPath.spec.js.map +1 -0
- package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
- package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
- package/dist/utilities/getObjectDotNotation.d.ts.map +1 -1
- package/dist/utilities/getObjectDotNotation.js +7 -1
- package/dist/utilities/getObjectDotNotation.js.map +1 -1
- package/dist/utilities/getObjectDotNotation.spec.js +33 -0
- package/dist/utilities/getObjectDotNotation.spec.js.map +1 -0
- package/dist/utilities/getSafeRedirect.spec.js +14 -0
- package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
- package/dist/utilities/getTopLevelFieldNames.d.ts +2 -0
- package/dist/utilities/getTopLevelFieldNames.d.ts.map +1 -0
- package/dist/utilities/getTopLevelFieldNames.js +3 -0
- package/dist/utilities/getTopLevelFieldNames.js.map +1 -0
- package/dist/utilities/getTopLevelFieldNames.spec.js +18 -0
- package/dist/utilities/getTopLevelFieldNames.spec.js.map +1 -0
- package/dist/utilities/handleEndpoints.js +1 -1
- package/dist/utilities/handleEndpoints.js.map +1 -1
- package/dist/utilities/parseParams/index.d.ts.map +1 -1
- package/dist/utilities/parseParams/index.js +3 -1
- package/dist/utilities/parseParams/index.js.map +1 -1
- package/dist/utilities/parseParams/index.spec.js +8 -0
- package/dist/utilities/parseParams/index.spec.js.map +1 -1
- package/dist/utilities/traverseFields.d.ts.map +1 -1
- package/dist/utilities/traverseFields.js +5 -14
- package/dist/utilities/traverseFields.js.map +1 -1
- package/dist/utilities/unflatten.d.ts.map +1 -1
- package/dist/utilities/unflatten.js +21 -9
- package/dist/utilities/unflatten.js.map +1 -1
- package/dist/utilities/unflatten.spec.js +38 -0
- package/dist/utilities/unflatten.spec.js.map +1 -0
- package/dist/utilities/wrapInternalEndpoints.d.ts.map +1 -1
- package/dist/utilities/wrapInternalEndpoints.js +10 -3
- package/dist/utilities/wrapInternalEndpoints.js.map +1 -1
- package/dist/utilities/wrapInternalEndpoints.spec.js +124 -0
- package/dist/utilities/wrapInternalEndpoints.spec.js.map +1 -0
- package/dist/versions/allLocalesPublicationStatus.d.ts +38 -0
- package/dist/versions/allLocalesPublicationStatus.d.ts.map +1 -0
- package/dist/versions/allLocalesPublicationStatus.js +57 -0
- package/dist/versions/allLocalesPublicationStatus.js.map +1 -0
- package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
- package/dist/versions/getLatestGlobalVersion.js +10 -2
- package/dist/versions/getLatestGlobalVersion.js.map +1 -1
- package/dist/versions/getRestoredStatusesToAuthorize.d.ts +9 -0
- package/dist/versions/getRestoredStatusesToAuthorize.d.ts.map +1 -0
- package/dist/versions/getRestoredStatusesToAuthorize.js +22 -0
- package/dist/versions/getRestoredStatusesToAuthorize.js.map +1 -0
- package/dist/versions/getRestoredStatusesToAuthorize.spec.js +50 -0
- package/dist/versions/getRestoredStatusesToAuthorize.spec.js.map +1 -0
- package/dist/versions/schedule/job.d.ts +2 -2
- package/dist/versions/schedule/job.d.ts.map +1 -1
- package/dist/versions/schedule/job.js +11 -7
- package/dist/versions/schedule/job.js.map +1 -1
- package/dist/versions/schedule/types.d.ts +5 -1
- package/dist/versions/schedule/types.d.ts.map +1 -1
- package/dist/versions/schedule/types.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
import { inspectSvg, inspectSvgFile, validateSvg } from './validateSvg.js';
|
|
7
|
+
const tempFiles = [];
|
|
8
|
+
const writeTempFile = async (content)=>{
|
|
9
|
+
const filePath = path.join(os.tmpdir(), `payload-svg-${randomUUID()}`);
|
|
10
|
+
tempFiles.push(filePath);
|
|
11
|
+
await fs.writeFile(filePath, content);
|
|
12
|
+
return filePath;
|
|
13
|
+
};
|
|
14
|
+
afterEach(async ()=>{
|
|
15
|
+
await Promise.all(tempFiles.splice(0).map((filePath)=>fs.unlink(filePath)));
|
|
16
|
+
});
|
|
17
|
+
describe('SVG inspection', ()=>{
|
|
18
|
+
it.each([
|
|
19
|
+
[
|
|
20
|
+
'script elements',
|
|
21
|
+
'<script>reference()</script>'
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
'event attributes',
|
|
25
|
+
'<g onload="reference()"/>'
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
'embedded HTML',
|
|
29
|
+
'<foreignObject/>'
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
'active links',
|
|
33
|
+
'<a href="javascript:reference()"/>'
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
'nested SVG data',
|
|
37
|
+
'<image href="data:image/svg+xml,<svg/>"/>'
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
'active style attributes',
|
|
41
|
+
'<g style="background:url(javascript:reference())"/>'
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
'active style elements',
|
|
45
|
+
'<style>@import url("reference.css")</style>'
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
'animated active links',
|
|
49
|
+
'<animate attributeName="href" values="https://example.com; javascript:reference()"/>'
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
'assigned active links',
|
|
53
|
+
'<set attributeName="href" to="javascript:reference()"/>'
|
|
54
|
+
]
|
|
55
|
+
])('should reject %s', (_, content)=>{
|
|
56
|
+
expect(validateSvg(Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg">${content}</svg>`))).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('should reject XML-declared SVG event attributes', ()=>{
|
|
59
|
+
expect(validateSvg(Buffer.from('<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" onload="reference()"/>'))).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
it('should inspect complete style content across text and CDATA', ()=>{
|
|
62
|
+
expect(validateSvg(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><style>@im<![CDATA[port]]> url("reference.css")</style></svg>'))).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it('should inspect UTF-16 XML-declared SVG content', ()=>{
|
|
65
|
+
const content = Buffer.concat([
|
|
66
|
+
Buffer.from([
|
|
67
|
+
0xff,
|
|
68
|
+
0xfe
|
|
69
|
+
]),
|
|
70
|
+
Buffer.from('<?xml version="1.0" encoding="UTF-16"?><svg xmlns="http://www.w3.org/2000/svg" onload="reference()"/>', 'utf16le')
|
|
71
|
+
]);
|
|
72
|
+
expect(inspectSvg(content)).toMatchObject({
|
|
73
|
+
isSafe: false,
|
|
74
|
+
isSvg: true,
|
|
75
|
+
isValid: true
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('should accept ordinary SVG content and external resources', ()=>{
|
|
79
|
+
expect(validateSvg(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><text>javascript: reference</text><g aria-label="url(javascript: reference)"/><image href="https://example.com/reference.png"/><animate attributeName="fill" values="red;blue"/></svg>'))).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('should accept large ordinary style content', ()=>{
|
|
82
|
+
expect(validateSvg(Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg"><style>${'.reference { fill: blue; }'.repeat(50_000)}</style></svg>`))).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
it('should stop buffer inspection after a valid non-SVG root is identified', ()=>{
|
|
85
|
+
expect(inspectSvg(Buffer.from('<feed xmlns="urn:example"><entry>'))).toMatchObject({
|
|
86
|
+
isSafe: false,
|
|
87
|
+
isSvg: false,
|
|
88
|
+
isValid: true
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it('should stop streaming after a valid non-SVG root is identified', async ()=>{
|
|
92
|
+
const filePath = await writeTempFile('<feed xmlns="urn:example"><entry>');
|
|
93
|
+
await expect(inspectSvgFile(filePath, {
|
|
94
|
+
highWaterMark: 64
|
|
95
|
+
})).resolves.toMatchObject({
|
|
96
|
+
isSafe: false,
|
|
97
|
+
isSvg: false,
|
|
98
|
+
isValid: true
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
it('should inspect style content across temp-file chunks', async ()=>{
|
|
102
|
+
const filePath = await writeTempFile('<svg xmlns="http://www.w3.org/2000/svg"><style>@import url("reference.css")</style></svg>');
|
|
103
|
+
await expect(inspectSvgFile(filePath, {
|
|
104
|
+
highWaterMark: 3
|
|
105
|
+
})).resolves.toMatchObject({
|
|
106
|
+
isSafe: false,
|
|
107
|
+
isSvg: true,
|
|
108
|
+
isValid: true
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
it('should handle deeply nested namespace declarations', ()=>{
|
|
112
|
+
const depth = 10_000;
|
|
113
|
+
const elements = Array.from({
|
|
114
|
+
length: depth
|
|
115
|
+
}, (_, index)=>`<g xmlns:reference${index}="urn:reference:${index}">`).join('');
|
|
116
|
+
const source = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg">${elements}${'</g>'.repeat(depth)}</svg>`);
|
|
117
|
+
const startedAt = performance.now();
|
|
118
|
+
expect(validateSvg(source)).toBe(true);
|
|
119
|
+
expect(performance.now() - startedAt).toBeLessThan(5_000);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=validateSvg.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/validateSvg.spec.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, describe, expect, it } from 'vitest'\n\nimport { inspectSvg, inspectSvgFile, validateSvg } from './validateSvg.js'\n\nconst tempFiles: string[] = []\n\nconst writeTempFile = async (content: Buffer | string): Promise<string> => {\n const filePath = path.join(os.tmpdir(), `payload-svg-${randomUUID()}`)\n tempFiles.push(filePath)\n await fs.writeFile(filePath, content)\n return filePath\n}\n\nafterEach(async () => {\n await Promise.all(tempFiles.splice(0).map((filePath) => fs.unlink(filePath)))\n})\n\ndescribe('SVG inspection', () => {\n it.each([\n ['script elements', '<script>reference()</script>'],\n ['event attributes', '<g onload=\"reference()\"/>'],\n ['embedded HTML', '<foreignObject/>'],\n ['active links', '<a href=\"javascript:reference()\"/>'],\n ['nested SVG data', '<image href=\"data:image/svg+xml,<svg/>\"/>'],\n ['active style attributes', '<g style=\"background:url(javascript:reference())\"/>'],\n ['active style elements', '<style>@import url(\"reference.css\")</style>'],\n [\n 'animated active links',\n '<animate attributeName=\"href\" values=\"https://example.com; javascript:reference()\"/>',\n ],\n ['assigned active links', '<set attributeName=\"href\" to=\"javascript:reference()\"/>'],\n ])('should reject %s', (_, content) => {\n expect(\n validateSvg(Buffer.from(`<svg xmlns=\"http://www.w3.org/2000/svg\">${content}</svg>`)),\n ).toBe(false)\n })\n\n it('should reject XML-declared SVG event attributes', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<?xml version=\"1.0\"?><svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"reference()\"/>',\n ),\n ),\n ).toBe(false)\n })\n\n it('should inspect complete style content across text and CDATA', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><style>@im<![CDATA[port]]> url(\"reference.css\")</style></svg>',\n ),\n ),\n ).toBe(false)\n })\n\n it('should inspect UTF-16 XML-declared SVG content', () => {\n const content = Buffer.concat([\n Buffer.from([0xff, 0xfe]),\n Buffer.from(\n '<?xml version=\"1.0\" encoding=\"UTF-16\"?><svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"reference()\"/>',\n 'utf16le',\n ),\n ])\n\n expect(inspectSvg(content)).toMatchObject({ isSafe: false, isSvg: true, isValid: true })\n })\n\n it('should accept ordinary SVG content and external resources', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><text>javascript: reference</text><g aria-label=\"url(javascript: reference)\"/><image href=\"https://example.com/reference.png\"/><animate attributeName=\"fill\" values=\"red;blue\"/></svg>',\n ),\n ),\n ).toBe(true)\n })\n\n it('should accept large ordinary style content', () => {\n expect(\n validateSvg(\n Buffer.from(\n `<svg xmlns=\"http://www.w3.org/2000/svg\"><style>${'.reference { fill: blue; }'.repeat(50_000)}</style></svg>`,\n ),\n ),\n ).toBe(true)\n })\n\n it('should stop buffer inspection after a valid non-SVG root is identified', () => {\n expect(inspectSvg(Buffer.from('<feed xmlns=\"urn:example\"><entry>'))).toMatchObject({\n isSafe: false,\n isSvg: false,\n isValid: true,\n })\n })\n\n it('should stop streaming after a valid non-SVG root is identified', async () => {\n const filePath = await writeTempFile('<feed xmlns=\"urn:example\"><entry>')\n\n await expect(inspectSvgFile(filePath, { highWaterMark: 64 })).resolves.toMatchObject({\n isSafe: false,\n isSvg: false,\n isValid: true,\n })\n })\n\n it('should inspect style content across temp-file chunks', async () => {\n const filePath = await writeTempFile(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><style>@import url(\"reference.css\")</style></svg>',\n )\n\n await expect(inspectSvgFile(filePath, { highWaterMark: 3 })).resolves.toMatchObject({\n isSafe: false,\n isSvg: true,\n isValid: true,\n })\n })\n\n it('should handle deeply nested namespace declarations', () => {\n const depth = 10_000\n const elements = Array.from(\n { length: depth },\n (_, index) => `<g xmlns:reference${index}=\"urn:reference:${index}\">`,\n ).join('')\n const source = Buffer.from(\n `<svg xmlns=\"http://www.w3.org/2000/svg\">${elements}${'</g>'.repeat(depth)}</svg>`,\n )\n const startedAt = performance.now()\n\n expect(validateSvg(source)).toBe(true)\n expect(performance.now() - startedAt).toBeLessThan(5_000)\n })\n})\n"],"names":["randomUUID","fs","os","path","afterEach","describe","expect","it","inspectSvg","inspectSvgFile","validateSvg","tempFiles","writeTempFile","content","filePath","join","tmpdir","push","writeFile","Promise","all","splice","map","unlink","each","_","Buffer","from","toBe","concat","toMatchObject","isSafe","isSvg","isValid","repeat","highWaterMark","resolves","depth","elements","Array","length","index","source","startedAt","performance","now","toBeLessThan"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateUploadFilename.d.ts","sourceRoot":"","sources":["../../src/uploads/validateUploadFilename.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAEzD,eAAO,MAAM,sBAAsB,EAAE,QAgBpC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
export const validateUploadFilename = (value)=>{
|
|
3
|
+
if (!value) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
const normalizedFilename = value.replaceAll('\\', '/');
|
|
7
|
+
if (path.posix.isAbsolute(normalizedFilename) || path.win32.isAbsolute(value) || normalizedFilename.split('/').includes('..')) {
|
|
8
|
+
return 'Invalid filename';
|
|
9
|
+
}
|
|
10
|
+
return true;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=validateUploadFilename.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/validateUploadFilename.ts"],"sourcesContent":["import path from 'path'\n\nimport type { Validate } from '../fields/config/types.js'\n\nexport const validateUploadFilename: Validate = (value: null | string | undefined) => {\n if (!value) {\n return true\n }\n\n const normalizedFilename = value.replaceAll('\\\\', '/')\n\n if (\n path.posix.isAbsolute(normalizedFilename) ||\n path.win32.isAbsolute(value) ||\n normalizedFilename.split('/').includes('..')\n ) {\n return 'Invalid filename'\n }\n\n return true\n}\n"],"names":["path","validateUploadFilename","value","normalizedFilename","replaceAll","posix","isAbsolute","win32","split","includes"],"mappings":"AAAA,OAAOA,UAAU,OAAM;AAIvB,OAAO,MAAMC,yBAAmC,CAACC;IAC/C,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,MAAMC,qBAAqBD,MAAME,UAAU,CAAC,MAAM;IAElD,IACEJ,KAAKK,KAAK,CAACC,UAAU,CAACH,uBACtBH,KAAKO,KAAK,CAACD,UAAU,CAACJ,UACtBC,mBAAmBK,KAAK,CAAC,KAAKC,QAAQ,CAAC,OACvC;QACA,OAAO;IACT;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { validateUploadFilename } from './validateUploadFilename.js';
|
|
3
|
+
describe('validateUploadFilename', ()=>{
|
|
4
|
+
it.each([
|
|
5
|
+
'../document.pdf',
|
|
6
|
+
'archive/../document.pdf',
|
|
7
|
+
'..\\document.pdf',
|
|
8
|
+
'archive\\..\\document.pdf',
|
|
9
|
+
'/archive/document.pdf',
|
|
10
|
+
'C:\\archive\\document.pdf'
|
|
11
|
+
])('rejects non-contained filename %s', (filename)=>{
|
|
12
|
+
expect(validateUploadFilename(filename, {})).toBe('Invalid filename');
|
|
13
|
+
});
|
|
14
|
+
it.each([
|
|
15
|
+
'document.pdf',
|
|
16
|
+
'tenant/document.pdf',
|
|
17
|
+
'tenant\\document.pdf',
|
|
18
|
+
'summary..pdf'
|
|
19
|
+
])('accepts contained filename %s', (filename)=>{
|
|
20
|
+
expect(validateUploadFilename(filename, {})).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=validateUploadFilename.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/validateUploadFilename.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { validateUploadFilename } from './validateUploadFilename.js'\n\ndescribe('validateUploadFilename', () => {\n it.each([\n '../document.pdf',\n 'archive/../document.pdf',\n '..\\\\document.pdf',\n 'archive\\\\..\\\\document.pdf',\n '/archive/document.pdf',\n 'C:\\\\archive\\\\document.pdf',\n ])('rejects non-contained filename %s', (filename) => {\n expect(validateUploadFilename(filename, {} as never)).toBe('Invalid filename')\n })\n\n it.each(['document.pdf', 'tenant/document.pdf', 'tenant\\\\document.pdf', 'summary..pdf'])(\n 'accepts contained filename %s',\n (filename) => {\n expect(validateUploadFilename(filename, {} as never)).toBe(true)\n },\n )\n})\n"],"names":["describe","expect","it","validateUploadFilename","each","filename","toBe"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,sBAAsB,QAAQ,8BAA6B;AAEpEH,SAAS,0BAA0B;IACjCE,GAAGE,IAAI,CAAC;QACN;QACA;QACA;QACA;QACA;QACA;KACD,EAAE,qCAAqC,CAACC;QACvCJ,OAAOE,uBAAuBE,UAAU,CAAC,IAAaC,IAAI,CAAC;IAC7D;IAEAJ,GAAGE,IAAI,CAAC;QAAC;QAAgB;QAAuB;QAAwB;KAAe,EACrF,iCACA,CAACC;QACCJ,OAAOE,uBAAuBE,UAAU,CAAC,IAAaC,IAAI,CAAC;IAC7D;AAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addDataAndFileToRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/addDataAndFileToRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"addDataAndFileToRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/addDataAndFileToRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAQvD,KAAK,uBAAuB,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAErE;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,uBAsGrC,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { APIError } from '../errors/APIError.js';
|
|
2
|
+
import { verifyClientUploadReceipt } from '../uploads/clientUploadReceipt.js';
|
|
2
3
|
import { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js';
|
|
3
4
|
import { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js';
|
|
4
5
|
/**
|
|
@@ -57,8 +58,34 @@ import { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js';
|
|
|
57
58
|
} catch {
|
|
58
59
|
throw new APIError('A file name is required.', 400);
|
|
59
60
|
}
|
|
61
|
+
// The collection must come from the route, never from the request body: the body
|
|
62
|
+
// is client-controlled and would select another collection's upload handlers.
|
|
63
|
+
const collectionSlug = typeof req.routeParams?.collection === 'string' ? req.routeParams.collection : undefined;
|
|
64
|
+
const uploadConfig = collectionSlug ? req.payload.collections[collectionSlug]?.config.upload : undefined;
|
|
65
|
+
if (!collectionSlug || !uploadConfig) {
|
|
66
|
+
throw new APIError('Invalid upload collection.', 400);
|
|
67
|
+
}
|
|
68
|
+
if (uploadConfig.requiresClientUploadReceipt) {
|
|
69
|
+
const clientUploadContext = clientUploadFile.clientUploadContext;
|
|
70
|
+
if (!clientUploadContext || typeof clientUploadContext !== 'object' || typeof clientUploadContext.signedReceipt !== 'string') {
|
|
71
|
+
throw new APIError('A verified client upload reference is required.', 400);
|
|
72
|
+
}
|
|
73
|
+
const receipt = verifyClientUploadReceipt({
|
|
74
|
+
collectionSlug,
|
|
75
|
+
req,
|
|
76
|
+
signedReceipt: clientUploadContext.signedReceipt
|
|
77
|
+
});
|
|
78
|
+
if (receipt.filename !== clientUploadFile.filename) {
|
|
79
|
+
throw new APIError('Client upload reference does not match this request.', 400);
|
|
80
|
+
}
|
|
81
|
+
clientUploadFile.clientUploadContext = receipt.context;
|
|
82
|
+
}
|
|
83
|
+
// Pass the route-derived collection to the upload helper, never the body value.
|
|
60
84
|
req.file = await getFileFromClientUpload({
|
|
61
|
-
file:
|
|
85
|
+
file: {
|
|
86
|
+
...clientUploadFile,
|
|
87
|
+
collectionSlug
|
|
88
|
+
},
|
|
62
89
|
req
|
|
63
90
|
});
|
|
64
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js'\nimport { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js'\n\ntype AddDataAndFileToRequest = (req: PayloadRequest) => Promise<void>\n\n/**\n * Mutates the Request, appending 'data' and 'file' if found\n */\nexport const addDataAndFileToRequest: AddDataAndFileToRequest = async (req) => {\n const { body, headers, method, payload } = req\n\n if (method && ['PATCH', 'POST', 'PUT'].includes(method.toUpperCase()) && body) {\n const [contentType] = (headers.get('Content-Type') || '').split(';', 1)\n const bodyByteSize = parseInt(req.headers.get('Content-Length') || '0', 10)\n const hasBodyStream = req.body !== null\n\n if (contentType === 'application/json') {\n try {\n const text = await req.text?.()\n const data = text ? JSON.parse(text) : {}\n req.data = data\n // @ts-expect-error attach json method to request\n req.json = () => Promise.resolve(data)\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new APIError('Invalid JSON', 400)\n }\n req.payload.logger.error(error)\n throw error\n }\n } else if ((bodyByteSize || hasBodyStream) && contentType?.includes('multipart/')) {\n const { error, fields, files } = await processMultipartFormdata({\n options: {\n ...(payload.config.bodyParser || {}),\n ...(payload.config.upload || {}),\n },\n request: req as Request,\n })\n\n if (error) {\n throw new APIError(error.message)\n }\n\n // Set all files on req.files for access by hooks\n if (files) {\n req.files = files\n // Backwards compatibility: set req.file for standard upload collections\n // Guard: if multiple files share the field name \"file\", files.file is an array — skip\n if (files.file && !Array.isArray(files.file)) {\n req.file = files.file\n }\n }\n\n if (fields?._payload && typeof fields._payload === 'string') {\n req.data = JSON.parse(fields._payload)\n }\n\n if (!req.file && fields?.file && typeof fields?.file === 'string') {\n let clientUploadFile: ClientUploadData\n\n try {\n clientUploadFile = JSON.parse(fields.file) as ClientUploadData\n } catch {\n throw new APIError('A file name is required.', 400)\n }\n\n req.file = await getFileFromClientUpload({\n file: clientUploadFile,\n req,\n })\n }\n }\n }\n}\n"],"names":["APIError","processMultipartFormdata","getFileFromClientUpload","addDataAndFileToRequest","req","body","headers","method","payload","includes","toUpperCase","contentType","get","split","bodyByteSize","parseInt","hasBodyStream","text","data","JSON","parse","json","Promise","resolve","error","SyntaxError","logger","fields","files","options","config","bodyParser","upload","request","message","file","Array","isArray","_payload","clientUploadFile"],"mappings":"AAGA,SAASA,QAAQ,QAAQ,wBAAuB;AAChD,SAASC,wBAAwB,QAAQ,yCAAwC;AACjF,SAASC,uBAAuB,QAAQ,wCAAuC;AAI/E;;CAEC,GACD,OAAO,MAAMC,0BAAmD,OAAOC;IACrE,MAAM,EAAEC,IAAI,EAAEC,OAAO,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGJ;IAE3C,IAAIG,UAAU;QAAC;QAAS;QAAQ;KAAM,CAACE,QAAQ,CAACF,OAAOG,WAAW,OAAOL,MAAM;QAC7E,MAAM,CAACM,YAAY,GAAG,AAACL,CAAAA,QAAQM,GAAG,CAAC,mBAAmB,EAAC,EAAGC,KAAK,CAAC,KAAK;QACrE,MAAMC,eAAeC,SAASX,IAAIE,OAAO,CAACM,GAAG,CAAC,qBAAqB,KAAK;QACxE,MAAMI,gBAAgBZ,IAAIC,IAAI,KAAK;QAEnC,IAAIM,gBAAgB,oBAAoB;YACtC,IAAI;gBACF,MAAMM,OAAO,MAAMb,IAAIa,IAAI;gBAC3B,MAAMC,OAAOD,OAAOE,KAAKC,KAAK,CAACH,QAAQ,CAAC;gBACxCb,IAAIc,IAAI,GAAGA;gBACX,iDAAiD;gBACjDd,IAAIiB,IAAI,GAAG,IAAMC,QAAQC,OAAO,CAACL;YACnC,EAAE,OAAOM,OAAO;gBACd,IAAIA,iBAAiBC,aAAa;oBAChC,MAAM,
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { verifyClientUploadReceipt } from '../uploads/clientUploadReceipt.js'\nimport { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js'\nimport { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js'\n\ntype AddDataAndFileToRequest = (req: PayloadRequest) => Promise<void>\n\n/**\n * Mutates the Request, appending 'data' and 'file' if found\n */\nexport const addDataAndFileToRequest: AddDataAndFileToRequest = async (req) => {\n const { body, headers, method, payload } = req\n\n if (method && ['PATCH', 'POST', 'PUT'].includes(method.toUpperCase()) && body) {\n const [contentType] = (headers.get('Content-Type') || '').split(';', 1)\n const bodyByteSize = parseInt(req.headers.get('Content-Length') || '0', 10)\n const hasBodyStream = req.body !== null\n\n if (contentType === 'application/json') {\n try {\n const text = await req.text?.()\n const data = text ? JSON.parse(text) : {}\n req.data = data\n // @ts-expect-error attach json method to request\n req.json = () => Promise.resolve(data)\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new APIError('Invalid JSON', 400)\n }\n req.payload.logger.error(error)\n throw error\n }\n } else if ((bodyByteSize || hasBodyStream) && contentType?.includes('multipart/')) {\n const { error, fields, files } = await processMultipartFormdata({\n options: {\n ...(payload.config.bodyParser || {}),\n ...(payload.config.upload || {}),\n },\n request: req as Request,\n })\n\n if (error) {\n throw new APIError(error.message)\n }\n\n // Set all files on req.files for access by hooks\n if (files) {\n req.files = files\n // Backwards compatibility: set req.file for standard upload collections\n // Guard: if multiple files share the field name \"file\", files.file is an array — skip\n if (files.file && !Array.isArray(files.file)) {\n req.file = files.file\n }\n }\n\n if (fields?._payload && typeof fields._payload === 'string') {\n req.data = JSON.parse(fields._payload)\n }\n\n if (!req.file && fields?.file && typeof fields?.file === 'string') {\n let clientUploadFile: ClientUploadData\n\n try {\n clientUploadFile = JSON.parse(fields.file) as ClientUploadData\n } catch {\n throw new APIError('A file name is required.', 400)\n }\n\n // The collection must come from the route, never from the request body: the body\n // is client-controlled and would select another collection's upload handlers.\n const collectionSlug =\n typeof req.routeParams?.collection === 'string' ? req.routeParams.collection : undefined\n const uploadConfig = collectionSlug\n ? req.payload.collections[collectionSlug]?.config.upload\n : undefined\n\n if (!collectionSlug || !uploadConfig) {\n throw new APIError('Invalid upload collection.', 400)\n }\n\n if (uploadConfig.requiresClientUploadReceipt) {\n const clientUploadContext = clientUploadFile.clientUploadContext\n\n if (\n !clientUploadContext ||\n typeof clientUploadContext !== 'object' ||\n typeof (clientUploadContext as { signedReceipt?: unknown }).signedReceipt !== 'string'\n ) {\n throw new APIError('A verified client upload reference is required.', 400)\n }\n\n const receipt = verifyClientUploadReceipt({\n collectionSlug,\n req,\n signedReceipt: (clientUploadContext as { signedReceipt: string }).signedReceipt,\n })\n\n if (receipt.filename !== clientUploadFile.filename) {\n throw new APIError('Client upload reference does not match this request.', 400)\n }\n\n clientUploadFile.clientUploadContext = receipt.context\n }\n\n // Pass the route-derived collection to the upload helper, never the body value.\n req.file = await getFileFromClientUpload({\n file: { ...clientUploadFile, collectionSlug },\n req,\n })\n }\n }\n }\n}\n"],"names":["APIError","verifyClientUploadReceipt","processMultipartFormdata","getFileFromClientUpload","addDataAndFileToRequest","req","body","headers","method","payload","includes","toUpperCase","contentType","get","split","bodyByteSize","parseInt","hasBodyStream","text","data","JSON","parse","json","Promise","resolve","error","SyntaxError","logger","fields","files","options","config","bodyParser","upload","request","message","file","Array","isArray","_payload","clientUploadFile","collectionSlug","routeParams","collection","undefined","uploadConfig","collections","requiresClientUploadReceipt","clientUploadContext","signedReceipt","receipt","filename","context"],"mappings":"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"}
|
|
@@ -60,6 +60,9 @@ const createClientUploadReq = ({ file, handler, upload })=>{
|
|
|
60
60
|
logger: {
|
|
61
61
|
error: ()=>{}
|
|
62
62
|
}
|
|
63
|
+
},
|
|
64
|
+
routeParams: {
|
|
65
|
+
collection: 'media'
|
|
63
66
|
}
|
|
64
67
|
};
|
|
65
68
|
};
|
|
@@ -72,6 +75,161 @@ describe('addDataAndFileToRequest', ()=>{
|
|
|
72
75
|
expect(req.file?.name).toBe('hello.txt');
|
|
73
76
|
expect(req.file?.mimetype).toBe('text/plain');
|
|
74
77
|
});
|
|
78
|
+
it('should reject unsigned upload instructions before the route handler', async ()=>{
|
|
79
|
+
const formData = new FormData();
|
|
80
|
+
formData.append('file', JSON.stringify({
|
|
81
|
+
collectionSlug: 'private-media',
|
|
82
|
+
clientUploadContext: {
|
|
83
|
+
prefix: 'private'
|
|
84
|
+
},
|
|
85
|
+
filename: 'example.txt',
|
|
86
|
+
mimeType: 'text/plain',
|
|
87
|
+
size: 11
|
|
88
|
+
}));
|
|
89
|
+
const request = new Request('http://localhost/api/public-media', {
|
|
90
|
+
body: formData,
|
|
91
|
+
method: 'POST'
|
|
92
|
+
});
|
|
93
|
+
const privateHandler = vi.fn();
|
|
94
|
+
const publicHandler = vi.fn((_req, args)=>{
|
|
95
|
+
return new Response('hello world', {
|
|
96
|
+
headers: {
|
|
97
|
+
'content-type': 'text/plain',
|
|
98
|
+
'x-collection': args.params.collection
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
const req = {
|
|
103
|
+
body: request.body,
|
|
104
|
+
headers: request.headers,
|
|
105
|
+
method: request.method,
|
|
106
|
+
payload: {
|
|
107
|
+
collections: {
|
|
108
|
+
'private-media': {
|
|
109
|
+
config: {
|
|
110
|
+
upload: {
|
|
111
|
+
handlers: [
|
|
112
|
+
privateHandler
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
'public-media': {
|
|
118
|
+
config: {
|
|
119
|
+
upload: {
|
|
120
|
+
handlers: [
|
|
121
|
+
publicHandler
|
|
122
|
+
],
|
|
123
|
+
requiresClientUploadReceipt: true
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
config: {
|
|
129
|
+
bodyParser: {},
|
|
130
|
+
upload: {}
|
|
131
|
+
},
|
|
132
|
+
logger: {
|
|
133
|
+
error: ()=>{}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
routeParams: {
|
|
137
|
+
collection: 'public-media'
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
await expect(addDataAndFileToRequest(req)).rejects.toThrow('A verified client upload reference is required.');
|
|
141
|
+
expect(privateHandler).not.toHaveBeenCalled();
|
|
142
|
+
expect(publicHandler).not.toHaveBeenCalled();
|
|
143
|
+
expect(req.file).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
it('should require a route collection for upload instructions', async ()=>{
|
|
146
|
+
const formData = new FormData();
|
|
147
|
+
formData.append('file', JSON.stringify({
|
|
148
|
+
collectionSlug: 'media',
|
|
149
|
+
filename: 'example.txt',
|
|
150
|
+
mimeType: 'text/plain',
|
|
151
|
+
size: 11
|
|
152
|
+
}));
|
|
153
|
+
const request = new Request('http://localhost/api/graphql', {
|
|
154
|
+
body: formData,
|
|
155
|
+
method: 'POST'
|
|
156
|
+
});
|
|
157
|
+
const handler = vi.fn(()=>new Response('hello world'));
|
|
158
|
+
const req = {
|
|
159
|
+
body: request.body,
|
|
160
|
+
headers: request.headers,
|
|
161
|
+
method: request.method,
|
|
162
|
+
payload: {
|
|
163
|
+
collections: {
|
|
164
|
+
media: {
|
|
165
|
+
config: {
|
|
166
|
+
upload: {
|
|
167
|
+
handlers: [
|
|
168
|
+
handler
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
config: {
|
|
175
|
+
bodyParser: {},
|
|
176
|
+
upload: {}
|
|
177
|
+
},
|
|
178
|
+
logger: {
|
|
179
|
+
error: ()=>{}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
await expect(addDataAndFileToRequest(req)).rejects.toThrow('Invalid upload collection.');
|
|
184
|
+
expect(handler).not.toHaveBeenCalled();
|
|
185
|
+
});
|
|
186
|
+
it('should require the route collection to support uploads', async ()=>{
|
|
187
|
+
const formData = new FormData();
|
|
188
|
+
formData.append('file', JSON.stringify({
|
|
189
|
+
collectionSlug: 'media',
|
|
190
|
+
filename: 'example.txt',
|
|
191
|
+
mimeType: 'text/plain',
|
|
192
|
+
size: 11
|
|
193
|
+
}));
|
|
194
|
+
const request = new Request('http://localhost/api/posts', {
|
|
195
|
+
body: formData,
|
|
196
|
+
method: 'POST'
|
|
197
|
+
});
|
|
198
|
+
const handler = vi.fn(()=>new Response('hello world'));
|
|
199
|
+
const req = {
|
|
200
|
+
body: request.body,
|
|
201
|
+
headers: request.headers,
|
|
202
|
+
method: request.method,
|
|
203
|
+
payload: {
|
|
204
|
+
collections: {
|
|
205
|
+
media: {
|
|
206
|
+
config: {
|
|
207
|
+
upload: {
|
|
208
|
+
handlers: [
|
|
209
|
+
handler
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
posts: {
|
|
215
|
+
config: {}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
config: {
|
|
219
|
+
bodyParser: {},
|
|
220
|
+
upload: {}
|
|
221
|
+
},
|
|
222
|
+
logger: {
|
|
223
|
+
error: ()=>{}
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
routeParams: {
|
|
227
|
+
collection: 'posts'
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
await expect(addDataAndFileToRequest(req)).rejects.toThrow('Invalid upload collection.');
|
|
231
|
+
expect(handler).not.toHaveBeenCalled();
|
|
232
|
+
});
|
|
75
233
|
describe('client uploads', ()=>{
|
|
76
234
|
const tempFilesToRemove = [];
|
|
77
235
|
afterEach(async ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.spec.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\nimport type { SanitizedUploadConfig } from '../uploads/types.js'\n\nimport fs from 'fs/promises'\nimport { afterEach, describe, expect, it, vi } from 'vitest'\n\nimport { addDataAndFileToRequest } from './addDataAndFileToRequest.js'\n\ntype MinimalReq = Pick<PayloadRequest, 'body' | 'headers' | 'method' | 'payload'> & {\n file?: PayloadRequest['file']\n}\n\nconst createReqWithMultipartBody = (): MinimalReq => {\n const formData = new FormData()\n formData.append('file', new Blob(['hello world'], { type: 'text/plain' }), 'hello.txt')\n\n const request = new Request('http://localhost/api/upload', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {},\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\nconst createClientUploadReq = ({\n file,\n handler,\n upload,\n}: {\n file: ClientUploadData\n handler: NonNullable<SanitizedUploadConfig['handlers']>[number]\n upload?: Partial<SanitizedUploadConfig>\n}): MinimalReq => {\n const formData = new FormData()\n formData.append('file', JSON.stringify(file))\n\n const request = new Request('http://localhost/api/media', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n disableLocalStorage: true,\n handlers: [handler],\n ...upload,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\ndescribe('addDataAndFileToRequest', () => {\n it('should parse multipart form-data even when content-length is absent', async () => {\n const req = createReqWithMultipartBody()\n\n expect(req.headers.get('content-length')).toBeNull()\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(req.file).toBeDefined()\n expect(req.file?.name).toBe('hello.txt')\n expect(req.file?.mimetype).toBe('text/plain')\n })\n\n describe('client uploads', () => {\n const tempFilesToRemove: string[] = []\n\n afterEach(async () => {\n for (const tempFilePath of tempFilesToRemove) {\n await fs.rm(tempFilePath, { force: true })\n }\n tempFilesToRemove.length = 0\n })\n\n it('materializes client-upload metadata without buffering an unused cloud file', async () => {\n const handler = vi.fn(() => {\n throw new Error('No-content handler was invoked')\n })\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'large.mp4',\n mimeType: 'video/mp4',\n size: 5_000_000_000,\n },\n handler,\n upload: { disableLocalStorage: true },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(handler).not.toHaveBeenCalled()\n expect(req.file).toMatchObject({\n clientUploadContext: { prefix: '' },\n mimetype: 'video/mp4',\n name: 'large.mp4',\n size: 5_000_000_000,\n })\n expect(req.file?.data.length).toBe(0)\n })\n\n it('streams a full-content client upload to a temp file without buffering the whole body', async () => {\n const chunks = [Buffer.from('chunk-one-'), Buffer.from('chunk-two')]\n const stream = new ReadableStream({\n start(controller) {\n for (const chunk of chunks) {\n controller.enqueue(chunk)\n }\n controller.close()\n },\n })\n const response = new Response(stream, {\n headers: { 'Content-Type': 'video/mp4' },\n status: 200,\n })\n const arrayBufferTripwire = vi.fn(async () => {\n throw new Error('Unexpected whole-body buffering')\n })\n Object.defineProperty(response, 'arrayBuffer', { value: arrayBufferTripwire })\n\n const handler = vi.fn(async () => response)\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'clip.mp4',\n mimeType: 'video/mp4',\n size: 20,\n },\n handler,\n upload: { disableLocalStorage: true, mimeTypes: ['video/*'] },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n tempFilesToRemove.push(req.file!.tempFilePath!)\n\n expect(arrayBufferTripwire).not.toHaveBeenCalled()\n expect(req.file?.data.length).toBe(0)\n expect(req.file?.tempFilePath).toBeDefined()\n const written = await fs.readFile(req.file!.tempFilePath!)\n expect(written.toString()).toBe(chunks.map((chunk) => chunk.toString()).join(''))\n })\n })\n})\n"],"names":["fs","afterEach","describe","expect","it","vi","addDataAndFileToRequest","createReqWithMultipartBody","formData","FormData","append","Blob","type","request","Request","body","method","headers","payload","collections","config","bodyParser","upload","logger","error","createClientUploadReq","file","handler","JSON","stringify","media","disableLocalStorage","handlers","req","get","toBeNull","toBeDefined","name","toBe","mimetype","tempFilesToRemove","tempFilePath","rm","force","length","fn","Error","clientUploadContext","prefix","collectionSlug","filename","mimeType","size","not","toHaveBeenCalled","toMatchObject","data","chunks","Buffer","from","stream","ReadableStream","start","controller","chunk","enqueue","close","response","Response","status","arrayBufferTripwire","Object","defineProperty","value","mimeTypes","push","written","readFile","toString","map","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.spec.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\nimport type { SanitizedUploadConfig } from '../uploads/types.js'\n\nimport fs from 'fs/promises'\nimport { afterEach, describe, expect, it, vi } from 'vitest'\n\nimport { addDataAndFileToRequest } from './addDataAndFileToRequest.js'\n\ntype MinimalReq = Pick<PayloadRequest, 'body' | 'headers' | 'method' | 'payload'> & {\n file?: PayloadRequest['file']\n routeParams?: PayloadRequest['routeParams']\n}\n\nconst createReqWithMultipartBody = (): MinimalReq => {\n const formData = new FormData()\n formData.append('file', new Blob(['hello world'], { type: 'text/plain' }), 'hello.txt')\n\n const request = new Request('http://localhost/api/upload', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {},\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\nconst createClientUploadReq = ({\n file,\n handler,\n upload,\n}: {\n file: ClientUploadData\n handler: NonNullable<SanitizedUploadConfig['handlers']>[number]\n upload?: Partial<SanitizedUploadConfig>\n}): MinimalReq => {\n const formData = new FormData()\n formData.append('file', JSON.stringify(file))\n\n const request = new Request('http://localhost/api/media', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n disableLocalStorage: true,\n handlers: [handler],\n ...upload,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'media',\n },\n }\n}\n\ndescribe('addDataAndFileToRequest', () => {\n it('should parse multipart form-data even when content-length is absent', async () => {\n const req = createReqWithMultipartBody()\n\n expect(req.headers.get('content-length')).toBeNull()\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(req.file).toBeDefined()\n expect(req.file?.name).toBe('hello.txt')\n expect(req.file?.mimetype).toBe('text/plain')\n })\n\n it('should reject unsigned upload instructions before the route handler', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'private-media',\n clientUploadContext: { prefix: 'private' },\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/public-media', {\n body: formData,\n method: 'POST',\n })\n\n const privateHandler = vi.fn()\n const publicHandler = vi.fn((_req, args) => {\n return new Response('hello world', {\n headers: {\n 'content-type': 'text/plain',\n 'x-collection': args.params.collection,\n },\n })\n })\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n 'private-media': {\n config: {\n upload: {\n handlers: [privateHandler],\n },\n },\n },\n 'public-media': {\n config: {\n upload: {\n handlers: [publicHandler],\n requiresClientUploadReceipt: true,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'public-media',\n },\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'A verified client upload reference is required.',\n )\n\n expect(privateHandler).not.toHaveBeenCalled()\n expect(publicHandler).not.toHaveBeenCalled()\n expect(req.file).toBeUndefined()\n })\n\n it('should require a route collection for upload instructions', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'media',\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/graphql', {\n body: formData,\n method: 'POST',\n })\n const handler = vi.fn(() => new Response('hello world'))\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n handlers: [handler],\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'Invalid upload collection.',\n )\n\n expect(handler).not.toHaveBeenCalled()\n })\n\n it('should require the route collection to support uploads', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'media',\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/posts', {\n body: formData,\n method: 'POST',\n })\n const handler = vi.fn(() => new Response('hello world'))\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n handlers: [handler],\n },\n },\n },\n posts: {\n config: {},\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'posts',\n },\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'Invalid upload collection.',\n )\n\n expect(handler).not.toHaveBeenCalled()\n })\n\n describe('client uploads', () => {\n const tempFilesToRemove: string[] = []\n\n afterEach(async () => {\n for (const tempFilePath of tempFilesToRemove) {\n await fs.rm(tempFilePath, { force: true })\n }\n tempFilesToRemove.length = 0\n })\n\n it('materializes client-upload metadata without buffering an unused cloud file', async () => {\n const handler = vi.fn(() => {\n throw new Error('No-content handler was invoked')\n })\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'large.mp4',\n mimeType: 'video/mp4',\n size: 5_000_000_000,\n },\n handler,\n upload: { disableLocalStorage: true },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(handler).not.toHaveBeenCalled()\n expect(req.file).toMatchObject({\n clientUploadContext: { prefix: '' },\n mimetype: 'video/mp4',\n name: 'large.mp4',\n size: 5_000_000_000,\n })\n expect(req.file?.data.length).toBe(0)\n })\n\n it('streams a full-content client upload to a temp file without buffering the whole body', async () => {\n const chunks = [Buffer.from('chunk-one-'), Buffer.from('chunk-two')]\n const stream = new ReadableStream({\n start(controller) {\n for (const chunk of chunks) {\n controller.enqueue(chunk)\n }\n controller.close()\n },\n })\n const response = new Response(stream, {\n headers: { 'Content-Type': 'video/mp4' },\n status: 200,\n })\n const arrayBufferTripwire = vi.fn(async () => {\n throw new Error('Unexpected whole-body buffering')\n })\n Object.defineProperty(response, 'arrayBuffer', { value: arrayBufferTripwire })\n\n const handler = vi.fn(async () => response)\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'clip.mp4',\n mimeType: 'video/mp4',\n size: 20,\n },\n handler,\n upload: { disableLocalStorage: true, mimeTypes: ['video/*'] },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n tempFilesToRemove.push(req.file!.tempFilePath!)\n\n expect(arrayBufferTripwire).not.toHaveBeenCalled()\n expect(req.file?.data.length).toBe(0)\n expect(req.file?.tempFilePath).toBeDefined()\n const written = await fs.readFile(req.file!.tempFilePath!)\n expect(written.toString()).toBe(chunks.map((chunk) => chunk.toString()).join(''))\n })\n })\n})\n"],"names":["fs","afterEach","describe","expect","it","vi","addDataAndFileToRequest","createReqWithMultipartBody","formData","FormData","append","Blob","type","request","Request","body","method","headers","payload","collections","config","bodyParser","upload","logger","error","createClientUploadReq","file","handler","JSON","stringify","media","disableLocalStorage","handlers","routeParams","collection","req","get","toBeNull","toBeDefined","name","toBe","mimetype","collectionSlug","clientUploadContext","prefix","filename","mimeType","size","privateHandler","fn","publicHandler","_req","args","Response","params","requiresClientUploadReceipt","rejects","toThrow","not","toHaveBeenCalled","toBeUndefined","posts","tempFilesToRemove","tempFilePath","rm","force","length","Error","toMatchObject","data","chunks","Buffer","from","stream","ReadableStream","start","controller","chunk","enqueue","close","response","status","arrayBufferTripwire","Object","defineProperty","value","mimeTypes","push","written","readFile","toString","map","join"],"mappings":"AAIA,OAAOA,QAAQ,cAAa;AAC5B,SAASC,SAAS,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAE5D,SAASC,uBAAuB,QAAQ,+BAA8B;AAOtE,MAAMC,6BAA6B;IACjC,MAAMC,WAAW,IAAIC;IACrBD,SAASE,MAAM,CAAC,QAAQ,IAAIC,KAAK;QAAC;KAAc,EAAE;QAAEC,MAAM;IAAa,IAAI;IAE3E,MAAMC,UAAU,IAAIC,QAAQ,+BAA+B;QACzDC,MAAMP;QACNQ,QAAQ;IACV;IAEA,OAAO;QACLD,MAAMF,QAAQE,IAAI;QAClBE,SAASJ,QAAQI,OAAO;QACxBD,QAAQH,QAAQG,MAAM;QACtBE,SAAS;YACPC,aAAa,CAAC;YACdC,QAAQ;gBACNC,YAAY,CAAC;gBACbC,QAAQ,CAAC;YACX;YACAC,QAAQ;gBACNC,OAAO,KAAO;YAChB;QACF;IACF;AACF;AAEA,MAAMC,wBAAwB,CAAC,EAC7BC,IAAI,EACJC,OAAO,EACPL,MAAM,EAKP;IACC,MAAMd,WAAW,IAAIC;IACrBD,SAASE,MAAM,CAAC,QAAQkB,KAAKC,SAAS,CAACH;IAEvC,MAAMb,UAAU,IAAIC,QAAQ,8BAA8B;QACxDC,MAAMP;QACNQ,QAAQ;IACV;IAEA,OAAO;QACLD,MAAMF,QAAQE,IAAI;QAClBE,SAASJ,QAAQI,OAAO;QACxBD,QAAQH,QAAQG,MAAM;QACtBE,SAAS;YACPC,aAAa;gBACXW,OAAO;oBACLV,QAAQ;wBACNE,QAAQ;4BACNS,qBAAqB;4BACrBC,UAAU;gCAACL;6BAAQ;4BACnB,GAAGL,MAAM;wBACX;oBACF;gBACF;YACF;YACAF,QAAQ;gBACNC,YAAY,CAAC;gBACbC,QAAQ,CAAC;YACX;YACAC,QAAQ;gBACNC,OAAO,KAAO;YAChB;QACF;QACAS,aAAa;YACXC,YAAY;QACd;IACF;AACF;AAEAhC,SAAS,2BAA2B;IAClCE,GAAG,uEAAuE;QACxE,MAAM+B,MAAM5B;QAEZJ,OAAOgC,IAAIlB,OAAO,CAACmB,GAAG,CAAC,mBAAmBC,QAAQ;QAElD,MAAM/B,wBAAwB6B;QAE9BhC,OAAOgC,IAAIT,IAAI,EAAEY,WAAW;QAC5BnC,OAAOgC,IAAIT,IAAI,EAAEa,MAAMC,IAAI,CAAC;QAC5BrC,OAAOgC,IAAIT,IAAI,EAAEe,UAAUD,IAAI,CAAC;IAClC;IAEApC,GAAG,uEAAuE;QACxE,MAAMI,WAAW,IAAIC;QACrBD,SAASE,MAAM,CACb,QACAkB,KAAKC,SAAS,CAAC;YACba,gBAAgB;YAChBC,qBAAqB;gBAAEC,QAAQ;YAAU;YACzCC,UAAU;YACVC,UAAU;YACVC,MAAM;QACR;QAGF,MAAMlC,UAAU,IAAIC,QAAQ,qCAAqC;YAC/DC,MAAMP;YACNQ,QAAQ;QACV;QAEA,MAAMgC,iBAAiB3C,GAAG4C,EAAE;QAC5B,MAAMC,gBAAgB7C,GAAG4C,EAAE,CAAC,CAACE,MAAMC;YACjC,OAAO,IAAIC,SAAS,eAAe;gBACjCpC,SAAS;oBACP,gBAAgB;oBAChB,gBAAgBmC,KAAKE,MAAM,CAACpB,UAAU;gBACxC;YACF;QACF;QAEA,MAAMC,MAAkB;YACtBpB,MAAMF,QAAQE,IAAI;YAClBE,SAASJ,QAAQI,OAAO;YACxBD,QAAQH,QAAQG,MAAM;YACtBE,SAAS;gBACPC,aAAa;oBACX,iBAAiB;wBACfC,QAAQ;4BACNE,QAAQ;gCACNU,UAAU;oCAACgB;iCAAe;4BAC5B;wBACF;oBACF;oBACA,gBAAgB;wBACd5B,QAAQ;4BACNE,QAAQ;gCACNU,UAAU;oCAACkB;iCAAc;gCACzBK,6BAA6B;4BAC/B;wBACF;oBACF;gBACF;gBACAnC,QAAQ;oBACNC,YAAY,CAAC;oBACbC,QAAQ,CAAC;gBACX;gBACAC,QAAQ;oBACNC,OAAO,KAAO;gBAChB;YACF;YACAS,aAAa;gBACXC,YAAY;YACd;QACF;QAEA,MAAM/B,OAAOG,wBAAwB6B,MAAwBqB,OAAO,CAACC,OAAO,CAC1E;QAGFtD,OAAO6C,gBAAgBU,GAAG,CAACC,gBAAgB;QAC3CxD,OAAO+C,eAAeQ,GAAG,CAACC,gBAAgB;QAC1CxD,OAAOgC,IAAIT,IAAI,EAAEkC,aAAa;IAChC;IAEAxD,GAAG,6DAA6D;QAC9D,MAAMI,WAAW,IAAIC;QACrBD,SAASE,MAAM,CACb,QACAkB,KAAKC,SAAS,CAAC;YACba,gBAAgB;YAChBG,UAAU;YACVC,UAAU;YACVC,MAAM;QACR;QAGF,MAAMlC,UAAU,IAAIC,QAAQ,gCAAgC;YAC1DC,MAAMP;YACNQ,QAAQ;QACV;QACA,MAAMW,UAAUtB,GAAG4C,EAAE,CAAC,IAAM,IAAII,SAAS;QAEzC,MAAMlB,MAAkB;YACtBpB,MAAMF,QAAQE,IAAI;YAClBE,SAASJ,QAAQI,OAAO;YACxBD,QAAQH,QAAQG,MAAM;YACtBE,SAAS;gBACPC,aAAa;oBACXW,OAAO;wBACLV,QAAQ;4BACNE,QAAQ;gCACNU,UAAU;oCAACL;iCAAQ;4BACrB;wBACF;oBACF;gBACF;gBACAP,QAAQ;oBACNC,YAAY,CAAC;oBACbC,QAAQ,CAAC;gBACX;gBACAC,QAAQ;oBACNC,OAAO,KAAO;gBAChB;YACF;QACF;QAEA,MAAMrB,OAAOG,wBAAwB6B,MAAwBqB,OAAO,CAACC,OAAO,CAC1E;QAGFtD,OAAOwB,SAAS+B,GAAG,CAACC,gBAAgB;IACtC;IAEAvD,GAAG,0DAA0D;QAC3D,MAAMI,WAAW,IAAIC;QACrBD,SAASE,MAAM,CACb,QACAkB,KAAKC,SAAS,CAAC;YACba,gBAAgB;YAChBG,UAAU;YACVC,UAAU;YACVC,MAAM;QACR;QAGF,MAAMlC,UAAU,IAAIC,QAAQ,8BAA8B;YACxDC,MAAMP;YACNQ,QAAQ;QACV;QACA,MAAMW,UAAUtB,GAAG4C,EAAE,CAAC,IAAM,IAAII,SAAS;QAEzC,MAAMlB,MAAkB;YACtBpB,MAAMF,QAAQE,IAAI;YAClBE,SAASJ,QAAQI,OAAO;YACxBD,QAAQH,QAAQG,MAAM;YACtBE,SAAS;gBACPC,aAAa;oBACXW,OAAO;wBACLV,QAAQ;4BACNE,QAAQ;gCACNU,UAAU;oCAACL;iCAAQ;4BACrB;wBACF;oBACF;oBACAkC,OAAO;wBACLzC,QAAQ,CAAC;oBACX;gBACF;gBACAA,QAAQ;oBACNC,YAAY,CAAC;oBACbC,QAAQ,CAAC;gBACX;gBACAC,QAAQ;oBACNC,OAAO,KAAO;gBAChB;YACF;YACAS,aAAa;gBACXC,YAAY;YACd;QACF;QAEA,MAAM/B,OAAOG,wBAAwB6B,MAAwBqB,OAAO,CAACC,OAAO,CAC1E;QAGFtD,OAAOwB,SAAS+B,GAAG,CAACC,gBAAgB;IACtC;IAEAzD,SAAS,kBAAkB;QACzB,MAAM4D,oBAA8B,EAAE;QAEtC7D,UAAU;YACR,KAAK,MAAM8D,gBAAgBD,kBAAmB;gBAC5C,MAAM9D,GAAGgE,EAAE,CAACD,cAAc;oBAAEE,OAAO;gBAAK;YAC1C;YACAH,kBAAkBI,MAAM,GAAG;QAC7B;QAEA9D,GAAG,8EAA8E;YAC/E,MAAMuB,UAAUtB,GAAG4C,EAAE,CAAC;gBACpB,MAAM,IAAIkB,MAAM;YAClB;YACA,MAAMhC,MAAMV,sBAAsB;gBAChCC,MAAM;oBACJiB,qBAAqB;wBAAEC,QAAQ;oBAAG;oBAClCF,gBAAgB;oBAChBG,UAAU;oBACVC,UAAU;oBACVC,MAAM;gBACR;gBACApB;gBACAL,QAAQ;oBAAES,qBAAqB;gBAAK;YACtC;YAEA,MAAMzB,wBAAwB6B;YAE9BhC,OAAOwB,SAAS+B,GAAG,CAACC,gBAAgB;YACpCxD,OAAOgC,IAAIT,IAAI,EAAE0C,aAAa,CAAC;gBAC7BzB,qBAAqB;oBAAEC,QAAQ;gBAAG;gBAClCH,UAAU;gBACVF,MAAM;gBACNQ,MAAM;YACR;YACA5C,OAAOgC,IAAIT,IAAI,EAAE2C,KAAKH,QAAQ1B,IAAI,CAAC;QACrC;QAEApC,GAAG,wFAAwF;YACzF,MAAMkE,SAAS;gBAACC,OAAOC,IAAI,CAAC;gBAAeD,OAAOC,IAAI,CAAC;aAAa;YACpE,MAAMC,SAAS,IAAIC,eAAe;gBAChCC,OAAMC,UAAU;oBACd,KAAK,MAAMC,SAASP,OAAQ;wBAC1BM,WAAWE,OAAO,CAACD;oBACrB;oBACAD,WAAWG,KAAK;gBAClB;YACF;YACA,MAAMC,WAAW,IAAI3B,SAASoB,QAAQ;gBACpCxD,SAAS;oBAAE,gBAAgB;gBAAY;gBACvCgE,QAAQ;YACV;YACA,MAAMC,sBAAsB7E,GAAG4C,EAAE,CAAC;gBAChC,MAAM,IAAIkB,MAAM;YAClB;YACAgB,OAAOC,cAAc,CAACJ,UAAU,eAAe;gBAAEK,OAAOH;YAAoB;YAE5E,MAAMvD,UAAUtB,GAAG4C,EAAE,CAAC,UAAY+B;YAClC,MAAM7C,MAAMV,sBAAsB;gBAChCC,MAAM;oBACJiB,qBAAqB;wBAAEC,QAAQ;oBAAG;oBAClCF,gBAAgB;oBAChBG,UAAU;oBACVC,UAAU;oBACVC,MAAM;gBACR;gBACApB;gBACAL,QAAQ;oBAAES,qBAAqB;oBAAMuD,WAAW;wBAAC;qBAAU;gBAAC;YAC9D;YAEA,MAAMhF,wBAAwB6B;YAC9B2B,kBAAkByB,IAAI,CAACpD,IAAIT,IAAI,CAAEqC,YAAY;YAE7C5D,OAAO+E,qBAAqBxB,GAAG,CAACC,gBAAgB;YAChDxD,OAAOgC,IAAIT,IAAI,EAAE2C,KAAKH,QAAQ1B,IAAI,CAAC;YACnCrC,OAAOgC,IAAIT,IAAI,EAAEqC,cAAczB,WAAW;YAC1C,MAAMkD,UAAU,MAAMxF,GAAGyF,QAAQ,CAACtD,IAAIT,IAAI,CAAEqC,YAAY;YACxD5D,OAAOqF,QAAQE,QAAQ,IAAIlD,IAAI,CAAC8B,OAAOqB,GAAG,CAAC,CAACd,QAAUA,MAAMa,QAAQ,IAAIE,IAAI,CAAC;QAC/E;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPayloadRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/createPayloadRequest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAkC,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAUvF,KAAK,IAAI,GAAG;IACV,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,oBAAoB,wFAM9B,IAAI,KAAG,OAAO,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"createPayloadRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/createPayloadRequest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAkC,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAUvF,KAAK,IAAI,GAAG;IACV,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,oBAAoB,wFAM9B,IAAI,KAAG,OAAO,CAAC,cAAc,CA4G/B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n allowEmptyArrays: true,\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","allowEmptyArrays","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,2BAA0B;AACnD,YAAYC,QAAQ,SAAQ;AAM5B,SAASC,qBAAqB,QAAQ,mCAAkC;AACxE,SAASC,aAAa,QAAQ,+BAA8B;AAC5D,SAASC,UAAU,QAAQ,cAAa;AACxC,SAASC,eAAe,QAAQ,2BAA0B;AAC1D,SAASC,cAAc,QAAQ,sBAAqB;AACpD,SAASC,kBAAkB,QAAQ,0BAAyB;AAC5D,SAASC,YAAY,QAAQ,oBAAmB;AAYhD,OAAO,MAAMC,uBAAuB,OAAO,EACzCC,aAAa,EACbC,QAAQC,aAAa,EACrBC,MAAM,EACNC,uBAAuB,EACvBC,OAAO,EACF;IACL,MAAMC,UAAUR,aAAaO,QAAQE,OAAO;IAC5C,MAAMC,UAAU,MAAMd,WAAW;QAC/BO,QAAQC;QACRO,MAAM;QACNC,KAAKN;IACP;IAEA,MAAM,EAAEH,MAAM,EAAE,GAAGO;IACnB,MAAMG,eAAeV,OAAOU,YAAY;IAExC,MAAMC,gBAAgB,IAAIC,IAAIR,QAAQS,GAAG;IACzC,MAAM,EAAEC,QAAQ,EAAEC,YAAY,EAAE,GAAGJ;IAEnC,MAAMK,YACJ,CAAChB,OAAOiB,OAAO,CAACC,OAAO,IACvBJ,aACEnB,eAAe;QACbwB,UAAUnB,OAAOoB,MAAM,CAACC,GAAG;QAC3BC,MAAMtB,OAAOoB,MAAM,CAACH,OAAO;IAC7B;IAEJ,MAAMM,WAAW3B,mBAAmB;QAClCI;QACAK;QACAC,SAASF,QAAQE,OAAO;IAC1B;IAEA,MAAMkB,OAAO,MAAMnC,SAAS;QAC1BW,QAAQA,OAAOwB,IAAI;QACnBC,SAAS;QACTF;IACF;IAEA,IAAIG,SAASX,aAAaY,GAAG,CAAC;IAE9B,MAAM,EAAEC,QAAQC,YAAY,EAAE,GAAGlB;IAEjC,MAAMmB,QAAQD,eACVvC,GAAGyC,KAAK,CAACF,cAAc;QACrBG,kBAAkB;QAClBC,YAAY;QACZC,OAAO;QACPC,mBAAmB;IACrB,KACA,CAAC;IAEL,MAAMC,sBAAuBN,MAAMO,cAAc,IAC/CtB,aAAaY,GAAG,CAAC,sBACjBZ,aAAaY,GAAG,CAAC;IAEnB,IAAIU,iBAAiBD;IAErB,IAAI1B,cAAc;QAChB,MAAM4B,UAAU5C,gBAAgB;YAC9B2C,gBAAgBA;YAChBX,QAAQA;YACRhB;QACF;QAEA2B,iBAAiBC,QAAQD,cAAc;QACvCX,SAASY,QAAQZ,MAAM;IACzB;IAEA,MAAMa,gBAAgD;QACpDd,SAAS,CAAC;QACVY,gBAAgBA;QAChBG,MAAM7B,cAAc6B,IAAI;QACxBC,MAAM9B,cAAc8B,IAAI;QACxBC,MAAM/B,cAAc+B,IAAI;QACxBlB;QACAE;QACAiB,QAAQhC,cAAcgC,MAAM;QAC5B7B,UAAUH,cAAcG,QAAQ;QAChCP;QACAqC,YAAY5B,YAAY,YAAY;QACpC6B,mBAAmBC;QACnBC,oBAAoB,CAAC;QACrBC,MAAMrC,cAAcqC,IAAI;QACxBC,UAAUtC,cAAcsC,QAAQ;QAChCnB;QACAoB,aAAahD,UAAU,CAAC;QACxB0B,QAAQjB,cAAciB,MAAM;QAC5Bb,cAAcJ,cAAcI,YAAY;QACxCoC,GAAG3B,KAAK2B,CAAC;QACTC,eAAeN;QACfO,MAAM;IACR;IAEA,MAAMC,MAAsBC,OAAOC,MAAM,CAACpD,SAASmC;IAEnDe,IAAIT,iBAAiB,GAAGrD,cAAc8D;IAEtC,MAAM,EAAEG,eAAe,EAAEJ,IAAI,EAAE,GAAG,MAAM9D,sBAAsB;QAC5DQ;QACAO,SAASgD,IAAIhD,OAAO;QACpBU;QACAT;IACF;
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n allowEmptyArrays: true,\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n req,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","allowEmptyArrays","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepCopyObject.d.ts","sourceRoot":"","sources":["../../src/utilities/deepCopyObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA2DlD,eAAO,MAAM,cAAc,GAAI,CAAC,KAAK,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"deepCopyObject.d.ts","sourceRoot":"","sources":["../../src/utilities/deepCopyObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA2DlD,eAAO,MAAM,cAAc,GAAI,CAAC,KAAK,CAAC,KAAG,CAiDxC,CAAA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,eAAe,UAAQ,GAAG,CAAC,CA6C9F;AAED,wBAAgB,0CAA0C,CAAC,CAAC,SAAS,SAAS,EAC5E,KAAK,EAAE,CAAC,EACR,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,OAAO,CAAA;CAClB,GACL,CAAC,CAyDH;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAiB,GAAG,CAAC,CAyE/F"}
|