From cb6a73e1b44d448e96ac6a23016aa00dac89c710 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 10 Jul 2025 16:00:26 +0100 Subject: [PATCH] feat(storage-*): include modified headers into the response headers of files when using adapters (#12096) This PR makes it so that `modifyResponseHeaders` is supported in our adapters when set on the collection config. Previously it would be ignored. This means that users can now modify or append new headers to what's returned by each service. ```ts import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { modifyResponseHeaders: ({ headers }) => { const newHeaders = new Headers(headers) // Copy existing headers newHeaders.set('X-Frame-Options', 'DENY') // Set new header return newHeaders }, }, } ``` Also adds support for `void` return on the `modifyResponseHeaders` function in the case where the user just wants to use existing headers and doesn't need more control. eg: ```ts import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { modifyResponseHeaders: ({ headers }) => { headers.set('X-Frame-Options', 'DENY') // You can directly set headers without returning }, }, } ``` Manual testing checklist (no CI e2es setup for these envs yet): - [x] GCS - [x] S3 - [x] Azure - [x] UploadThing - [x] Vercel Blob --------- Co-authored-by: James --- docs/upload/overview.mdx | 46 ++++++++++++++++++- .../payload/src/uploads/endpoints/getFile.ts | 5 +- packages/payload/src/uploads/types.ts | 3 +- packages/plugin-cloud-storage/src/types.ts | 1 + packages/storage-azure/src/staticHandler.ts | 30 ++++++++++-- packages/storage-gcs/src/staticHandler.ts | 28 ++++++----- packages/storage-s3/src/staticHandler.ts | 35 ++++++++------ .../storage-uploadthing/src/staticHandler.ts | 36 ++++++++++----- .../storage-vercel-blob/src/staticHandler.ts | 40 ++++++++-------- test/storage-azure/collections/Media.ts | 3 ++ test/storage-azure/payload-types.ts | 38 ++++++++++----- test/storage-gcs/collections/Media.ts | 3 ++ test/storage-s3/collections/Media.ts | 3 ++ test/storage-uploadthing/collections/Media.ts | 3 ++ test/storage-uploadthing/payload-types.ts | 38 ++++++++++----- test/storage-vercel-blob/collections/Media.ts | 3 ++ test/storage-vercel-blob/payload-types.ts | 40 +++++++++++----- 17 files changed, 256 insertions(+), 99 deletions(-) diff --git a/docs/upload/overview.mdx b/docs/upload/overview.mdx index 07adf66bb..2c8218eba 100644 --- a/docs/upload/overview.mdx +++ b/docs/upload/overview.mdx @@ -116,6 +116,7 @@ _An asterisk denotes that an option is required._ | **`withMetadata`** | If specified, appends metadata to the output image file. Accepts a boolean or a function that receives `metadata` and `req`, returning a boolean. | | **`hideFileInputOnCreate`** | Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation. | | **`hideRemoveFile`** | Set to `true` to prevent the admin UI having a way to remove an existing file while editing. | +| **`modifyResponseHeaders`** | Accepts an object with existing `headers` and allows you to manipulate the response headers for media files. [More](#modifying-response-headers) | ### Payload-wide Upload Options @@ -453,7 +454,7 @@ To fetch files from **restricted URLs** that would otherwise be blocked by CORS, Here’s how to configure the pasteURL option to control remote URL fetching: -``` +```ts import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { @@ -466,7 +467,7 @@ export const Media: CollectionConfig = { pathname: '', port: '', protocol: 'https', - search: '' + search: '', }, { hostname: 'example.com', @@ -519,3 +520,44 @@ _An asterisk denotes that an option is required._ ## Access Control All files that are uploaded to each Collection automatically support the `read` [Access Control](/docs/access-control/overview) function from the Collection itself. You can use this to control who should be allowed to see your uploads, and who should not. + +## Modifying response headers + +You can modify the response headers for files by specifying the `modifyResponseHeaders` option in your upload config. This option accepts an object with existing headers and allows you to manipulate the response headers for media files. + +### Modifying existing headers + +With this method you can directly interface with the `Headers` object and modify the existing headers to append or remove headers. + +```ts +import type { CollectionConfig } from 'payload' + +export const Media: CollectionConfig = { + slug: 'media', + upload: { + modifyResponseHeaders: ({ headers }) => { + headers.set('X-Frame-Options', 'DENY') // You can directly set headers without returning + }, + }, +} +``` + +### Return new headers + +You can also return a new `Headers` object with the modified headers. This is useful if you want to set new headers or remove existing ones. + +```ts +import type { CollectionConfig } from 'payload' + +export const Media: CollectionConfig = { + slug: 'media', + upload: { + modifyResponseHeaders: ({ headers }) => { + const newHeaders = new Headers(headers) // Copy existing headers + newHeaders.set('X-Frame-Options', 'DENY') // Set new header + + return newHeaders + }, + }, +} +``` diff --git a/packages/payload/src/uploads/endpoints/getFile.ts b/packages/payload/src/uploads/endpoints/getFile.ts index 69a3bfea1..e7b39c079 100644 --- a/packages/payload/src/uploads/endpoints/getFile.ts +++ b/packages/payload/src/uploads/endpoints/getFile.ts @@ -38,9 +38,12 @@ export const getFileHandler: PayloadHandler = async (req) => { if (collection.config.upload.handlers?.length) { let customResponse: null | Response | void = null + const headers = new Headers() + for (const handler of collection.config.upload.handlers) { customResponse = await handler(req, { doc: accessResult, + headers, params: { collection: collection.config.slug, filename, @@ -95,7 +98,7 @@ export const getFileHandler: PayloadHandler = async (req) => { headers.set('Content-Type', fileTypeResult.mime) headers.set('Content-Length', stats.size + '') headers = collection.config.upload?.modifyResponseHeaders - ? collection.config.upload.modifyResponseHeaders({ headers }) + ? collection.config.upload.modifyResponseHeaders({ headers }) || headers : headers return new Response(data, { diff --git a/packages/payload/src/uploads/types.ts b/packages/payload/src/uploads/types.ts index 5674f5588..ff4963833 100644 --- a/packages/payload/src/uploads/types.ts +++ b/packages/payload/src/uploads/types.ts @@ -211,6 +211,7 @@ export type UploadConfig = { req: PayloadRequest, args: { doc: TypeWithID + headers?: Headers params: { clientUploadContext?: unknown; collection: string; filename: string } }, ) => Promise | Promise | Response | void)[] @@ -233,7 +234,7 @@ export type UploadConfig = { * Ability to modify the response headers fetching a file. * @default undefined */ - modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers + modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers | void /** * Controls the behavior of pasting/uploading files from URLs. * If set to `false`, fetching from remote URLs is disabled. diff --git a/packages/plugin-cloud-storage/src/types.ts b/packages/plugin-cloud-storage/src/types.ts index 8558ccf72..8b8823113 100644 --- a/packages/plugin-cloud-storage/src/types.ts +++ b/packages/plugin-cloud-storage/src/types.ts @@ -58,6 +58,7 @@ export type StaticHandler = ( req: PayloadRequest, args: { doc?: TypeWithID + headers?: Headers params: { clientUploadContext?: unknown; collection: string; filename: string } }, ) => Promise | Response diff --git a/packages/storage-azure/src/staticHandler.ts b/packages/storage-azure/src/staticHandler.ts index 915c7de94..625b4640d 100644 --- a/packages/storage-azure/src/staticHandler.ts +++ b/packages/storage-azure/src/staticHandler.ts @@ -14,7 +14,7 @@ interface Args { } export const getHandler = ({ collection, getStorageClient }: Args): StaticHandler => { - return async (req, { params: { clientUploadContext, filename } }) => { + return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => { try { const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req }) const blockBlobClient = getStorageClient().getBlockBlobClient( @@ -30,14 +30,34 @@ export const getHandler = ({ collection, getStorageClient }: Args): StaticHandle const response = blob._response + let initHeaders: Headers = { + ...(response.headers.rawHeaders() as unknown as Headers), + } + + // Typescript is difficult here with merging these types from Azure + if (incomingHeaders) { + initHeaders = { + ...initHeaders, + ...incomingHeaders, + } + } + + let headers = new Headers(initHeaders) + const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match') const objectEtag = response.headers.get('etag') + if ( + collection.upload && + typeof collection.upload === 'object' && + typeof collection.upload.modifyResponseHeaders === 'function' + ) { + headers = collection.upload.modifyResponseHeaders({ headers }) || headers + } + if (etagFromHeaders && etagFromHeaders === objectEtag) { return new Response(null, { - headers: new Headers({ - ...response.headers.rawHeaders(), - }), + headers, status: 304, }) } @@ -63,7 +83,7 @@ export const getHandler = ({ collection, getStorageClient }: Args): StaticHandle }) return new Response(readableStream, { - headers: response.headers.rawHeaders(), + headers, status: response.status, }) } catch (err: unknown) { diff --git a/packages/storage-gcs/src/staticHandler.ts b/packages/storage-gcs/src/staticHandler.ts index 258fee971..bceb1b730 100644 --- a/packages/storage-gcs/src/staticHandler.ts +++ b/packages/storage-gcs/src/staticHandler.ts @@ -12,7 +12,7 @@ interface Args { } export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => { - return async (req, { params: { clientUploadContext, filename } }) => { + return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => { try { const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req }) const file = getStorageClient().bucket(bucket).file(path.posix.join(prefix, filename)) @@ -22,13 +22,23 @@ export const getHandler = ({ bucket, collection, getStorageClient }: Args): Stat const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match') const objectEtag = metadata.etag + let headers = new Headers(incomingHeaders) + + headers.append('Content-Length', String(metadata.size)) + headers.append('Content-Type', String(metadata.contentType)) + headers.append('ETag', String(metadata.etag)) + + if ( + collection.upload && + typeof collection.upload === 'object' && + typeof collection.upload.modifyResponseHeaders === 'function' + ) { + headers = collection.upload.modifyResponseHeaders({ headers }) || headers + } + if (etagFromHeaders && etagFromHeaders === objectEtag) { return new Response(null, { - headers: new Headers({ - 'Content-Length': String(metadata.size), - 'Content-Type': String(metadata.contentType), - ETag: String(metadata.etag), - }), + headers, status: 304, }) } @@ -50,11 +60,7 @@ export const getHandler = ({ bucket, collection, getStorageClient }: Args): Stat }) return new Response(readableStream, { - headers: new Headers({ - 'Content-Length': String(metadata.size), - 'Content-Type': String(metadata.contentType), - ETag: String(metadata.etag), - }), + headers, status: 200, }) } catch (err: unknown) { diff --git a/packages/storage-s3/src/staticHandler.ts b/packages/storage-s3/src/staticHandler.ts index 2f068fd65..08d528eca 100644 --- a/packages/storage-s3/src/staticHandler.ts +++ b/packages/storage-s3/src/staticHandler.ts @@ -61,7 +61,7 @@ export const getHandler = ({ getStorageClient, signedDownloads, }: Args): StaticHandler => { - return async (req, { params: { clientUploadContext, filename } }) => { + return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => { let object: AWS.GetObjectOutput | undefined = undefined try { const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req }) @@ -94,17 +94,31 @@ export const getHandler = ({ Key: key, }) + if (!object.Body) { + return new Response(null, { status: 404, statusText: 'Not Found' }) + } + + let headers = new Headers(incomingHeaders) + + headers.append('Content-Length', String(object.ContentLength)) + headers.append('Content-Type', String(object.ContentType)) + headers.append('Accept-Ranges', String(object.AcceptRanges)) + headers.append('ETag', String(object.ETag)) + const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match') const objectEtag = object.ETag + if ( + collection.upload && + typeof collection.upload === 'object' && + typeof collection.upload.modifyResponseHeaders === 'function' + ) { + headers = collection.upload.modifyResponseHeaders({ headers }) || headers + } + if (etagFromHeaders && etagFromHeaders === objectEtag) { return new Response(null, { - headers: new Headers({ - 'Accept-Ranges': String(object.AcceptRanges), - 'Content-Length': String(object.ContentLength), - 'Content-Type': String(object.ContentType), - ETag: String(object.ETag), - }), + headers, status: 304, }) } @@ -125,12 +139,7 @@ export const getHandler = ({ const bodyBuffer = await streamToBuffer(object.Body) return new Response(bodyBuffer, { - headers: new Headers({ - 'Accept-Ranges': String(object.AcceptRanges), - 'Content-Length': String(object.ContentLength), - 'Content-Type': String(object.ContentType), - ETag: String(object.ETag), - }), + headers, status: 200, }) } catch (err) { diff --git a/packages/storage-uploadthing/src/staticHandler.ts b/packages/storage-uploadthing/src/staticHandler.ts index 3321184f1..a3475e7d1 100644 --- a/packages/storage-uploadthing/src/staticHandler.ts +++ b/packages/storage-uploadthing/src/staticHandler.ts @@ -9,9 +9,13 @@ type Args = { } export const getHandler = ({ utApi }: Args): StaticHandler => { - return async (req, { doc, params: { clientUploadContext, collection, filename } }) => { + return async ( + req, + { doc, headers: incomingHeaders, params: { clientUploadContext, collection, filename } }, + ) => { try { let key: string + const collectionConfig = req.payload.collections[collection]?.config if ( clientUploadContext && @@ -21,7 +25,6 @@ export const getHandler = ({ utApi }: Args): StaticHandler => { ) { key = clientUploadContext.key } else { - const collectionConfig = req.payload.collections[collection]?.config let retrievedDoc = doc if (!retrievedDoc) { @@ -82,23 +85,32 @@ export const getHandler = ({ utApi }: Args): StaticHandler => { const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match') const objectEtag = response.headers.get('etag') + let headers = new Headers(incomingHeaders) + + headers.append('Content-Length', String(blob.size)) + headers.append('Content-Type', blob.type) + + if (objectEtag) { + headers.append('ETag', objectEtag) + } + + if ( + collectionConfig?.upload && + typeof collectionConfig.upload === 'object' && + typeof collectionConfig.upload.modifyResponseHeaders === 'function' + ) { + headers = collectionConfig.upload.modifyResponseHeaders({ headers }) || headers + } + if (etagFromHeaders && etagFromHeaders === objectEtag) { return new Response(null, { - headers: new Headers({ - 'Content-Length': String(blob.size), - 'Content-Type': blob.type, - ETag: objectEtag, - }), + headers, status: 304, }) } return new Response(blob, { - headers: new Headers({ - 'Content-Length': String(blob.size), - 'Content-Type': blob.type, - ETag: objectEtag!, - }), + headers, status: 200, }) } catch (err) { diff --git a/packages/storage-vercel-blob/src/staticHandler.ts b/packages/storage-vercel-blob/src/staticHandler.ts index 153bbb220..074443492 100644 --- a/packages/storage-vercel-blob/src/staticHandler.ts +++ b/packages/storage-vercel-blob/src/staticHandler.ts @@ -15,27 +15,36 @@ export const getStaticHandler = ( { baseUrl, cacheControlMaxAge = 0, token }: StaticHandlerArgs, collection: CollectionConfig, ): StaticHandler => { - return async (req, { params: { clientUploadContext, filename } }) => { + return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => { try { const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req }) const fileKey = path.posix.join(prefix, encodeURIComponent(filename)) const fileUrl = `${baseUrl}/${fileKey}` const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match') const blobMetadata = await head(fileUrl, { token }) - const uploadedAtString = blobMetadata.uploadedAt.toISOString() + const { contentDisposition, contentType, size, uploadedAt } = blobMetadata + const uploadedAtString = uploadedAt.toISOString() const ETag = `"${fileKey}-${uploadedAtString}"` - const { contentDisposition, contentType, size } = blobMetadata + let headers = new Headers(incomingHeaders) + + headers.append('Cache-Control', `public, max-age=${cacheControlMaxAge}`) + headers.append('Content-Disposition', contentDisposition) + headers.append('Content-Length', String(size)) + headers.append('Content-Type', contentType) + headers.append('ETag', ETag) + + if ( + collection.upload && + typeof collection.upload === 'object' && + typeof collection.upload.modifyResponseHeaders === 'function' + ) { + headers = collection.upload.modifyResponseHeaders({ headers }) || headers + } if (etagFromHeaders && etagFromHeaders === ETag) { return new Response(null, { - headers: new Headers({ - 'Cache-Control': `public, max-age=${cacheControlMaxAge}`, - 'Content-Disposition': contentDisposition, - 'Content-Length': String(size), - 'Content-Type': contentType, - ETag, - }), + headers, status: 304, }) } @@ -55,15 +64,10 @@ export const getStaticHandler = ( const bodyBuffer = await blob.arrayBuffer() + headers.append('Last-Modified', uploadedAtString) + return new Response(bodyBuffer, { - headers: new Headers({ - 'Cache-Control': `public, max-age=${cacheControlMaxAge}`, - 'Content-Disposition': contentDisposition, - 'Content-Length': String(size), - 'Content-Type': contentType, - ETag, - 'Last-Modified': blobMetadata.uploadedAt.toUTCString(), - }), + headers, status: 200, }) } catch (err: unknown) { diff --git a/test/storage-azure/collections/Media.ts b/test/storage-azure/collections/Media.ts index c5997222c..fa2bcf69a 100644 --- a/test/storage-azure/collections/Media.ts +++ b/test/storage-azure/collections/Media.ts @@ -3,6 +3,9 @@ import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { + modifyResponseHeaders({ headers }) { + headers.set('X-Universal-Truth', 'Set') + }, disableLocalStorage: true, resizeOptions: { position: 'center', diff --git a/test/storage-azure/payload-types.ts b/test/storage-azure/payload-types.ts index 7311e4ebb..463543e45 100644 --- a/test/storage-azure/payload-types.ts +++ b/test/storage-azure/payload-types.ts @@ -84,7 +84,7 @@ export interface Config { 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; globals: {}; globalsSelect: {}; @@ -120,7 +120,7 @@ export interface UserAuthOperations { * via the `definition` "media". */ export interface Media { - id: string; + id: number; alt?: string | null; updatedAt: string; createdAt: string; @@ -157,7 +157,7 @@ export interface Media { * via the `definition` "media-with-prefix". */ export interface MediaWithPrefix { - id: string; + id: number; prefix?: string | null; updatedAt: string; createdAt: string; @@ -176,7 +176,7 @@ export interface MediaWithPrefix { * via the `definition` "users". */ export interface User { - id: string; + id: number; updatedAt: string; createdAt: string; email: string; @@ -186,6 +186,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -193,24 +200,24 @@ export interface User { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'media'; - value: string | Media; + value: number | Media; } | null) | ({ relationTo: 'media-with-prefix'; - value: string | MediaWithPrefix; + value: number | MediaWithPrefix; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -220,10 +227,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -243,7 +250,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -323,6 +330,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/storage-gcs/collections/Media.ts b/test/storage-gcs/collections/Media.ts index c5997222c..fa2bcf69a 100644 --- a/test/storage-gcs/collections/Media.ts +++ b/test/storage-gcs/collections/Media.ts @@ -3,6 +3,9 @@ import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { + modifyResponseHeaders({ headers }) { + headers.set('X-Universal-Truth', 'Set') + }, disableLocalStorage: true, resizeOptions: { position: 'center', diff --git a/test/storage-s3/collections/Media.ts b/test/storage-s3/collections/Media.ts index c5997222c..fa2bcf69a 100644 --- a/test/storage-s3/collections/Media.ts +++ b/test/storage-s3/collections/Media.ts @@ -3,6 +3,9 @@ import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { + modifyResponseHeaders({ headers }) { + headers.set('X-Universal-Truth', 'Set') + }, disableLocalStorage: true, resizeOptions: { position: 'center', diff --git a/test/storage-uploadthing/collections/Media.ts b/test/storage-uploadthing/collections/Media.ts index c5997222c..fa2bcf69a 100644 --- a/test/storage-uploadthing/collections/Media.ts +++ b/test/storage-uploadthing/collections/Media.ts @@ -3,6 +3,9 @@ import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { + modifyResponseHeaders({ headers }) { + headers.set('X-Universal-Truth', 'Set') + }, disableLocalStorage: true, resizeOptions: { position: 'center', diff --git a/test/storage-uploadthing/payload-types.ts b/test/storage-uploadthing/payload-types.ts index e797a2f87..f98b3f62d 100644 --- a/test/storage-uploadthing/payload-types.ts +++ b/test/storage-uploadthing/payload-types.ts @@ -84,7 +84,7 @@ export interface Config { 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; globals: {}; globalsSelect: {}; @@ -120,7 +120,7 @@ export interface UserAuthOperations { * via the `definition` "media". */ export interface Media { - id: string; + id: number; alt?: string | null; _key?: string | null; updatedAt: string; @@ -160,7 +160,7 @@ export interface Media { * via the `definition` "media-with-prefix". */ export interface MediaWithPrefix { - id: string; + id: number; updatedAt: string; createdAt: string; url?: string | null; @@ -178,7 +178,7 @@ export interface MediaWithPrefix { * via the `definition` "users". */ export interface User { - id: string; + id: number; updatedAt: string; createdAt: string; email: string; @@ -188,6 +188,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -195,24 +202,24 @@ export interface User { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'media'; - value: string | Media; + value: number | Media; } | null) | ({ relationTo: 'media-with-prefix'; - value: string | MediaWithPrefix; + value: number | MediaWithPrefix; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -222,10 +229,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -245,7 +252,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -327,6 +334,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/storage-vercel-blob/collections/Media.ts b/test/storage-vercel-blob/collections/Media.ts index 93ece25a9..1d2076fd6 100644 --- a/test/storage-vercel-blob/collections/Media.ts +++ b/test/storage-vercel-blob/collections/Media.ts @@ -3,6 +3,9 @@ import type { CollectionConfig } from 'payload' export const Media: CollectionConfig = { slug: 'media', upload: { + modifyResponseHeaders({ headers }) { + headers.set('X-Universal-Truth', 'Set') + }, resizeOptions: { position: 'center', width: 200, diff --git a/test/storage-vercel-blob/payload-types.ts b/test/storage-vercel-blob/payload-types.ts index 83f98d11f..463543e45 100644 --- a/test/storage-vercel-blob/payload-types.ts +++ b/test/storage-vercel-blob/payload-types.ts @@ -84,7 +84,7 @@ export interface Config { 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; globals: {}; globalsSelect: {}; @@ -120,7 +120,7 @@ export interface UserAuthOperations { * via the `definition` "media". */ export interface Media { - id: string; + id: number; alt?: string | null; updatedAt: string; createdAt: string; @@ -157,7 +157,8 @@ export interface Media { * via the `definition` "media-with-prefix". */ export interface MediaWithPrefix { - id: string; + id: number; + prefix?: string | null; updatedAt: string; createdAt: string; url?: string | null; @@ -175,7 +176,7 @@ export interface MediaWithPrefix { * via the `definition` "users". */ export interface User { - id: string; + id: number; updatedAt: string; createdAt: string; email: string; @@ -185,6 +186,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -192,24 +200,24 @@ export interface User { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'media'; - value: string | Media; + value: number | Media; } | null) | ({ relationTo: 'media-with-prefix'; - value: string | MediaWithPrefix; + value: number | MediaWithPrefix; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -219,10 +227,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -242,7 +250,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -295,6 +303,7 @@ export interface MediaSelect { * via the `definition` "media-with-prefix_select". */ export interface MediaWithPrefixSelect { + prefix?: T; updatedAt?: T; createdAt?: T; url?: T; @@ -321,6 +330,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema