diff --git a/packages/next/src/server/lib/incremental-cache/fetch-cache.ts b/packages/next/src/server/lib/incremental-cache/fetch-cache.ts index 2c6783f8a5a5b..9e8467f3176e1 100644 --- a/packages/next/src/server/lib/incremental-cache/fetch-cache.ts +++ b/packages/next/src/server/lib/incremental-cache/fetch-cache.ts @@ -1,6 +1,14 @@ import type { CacheHandler, CacheHandlerContext, CacheHandlerValue } from './' +import type { + CachedFetchValue, + IncrementalCacheValue, +} from '../../response-cache' import LRUCache from 'next/dist/compiled/lru-cache' + +import { z } from 'next/dist/compiled/zod' +import type zod from 'next/dist/compiled/zod' + import { CACHE_ONE_YEAR, NEXT_CACHE_SOFT_TAGS_HEADER, @@ -23,6 +31,18 @@ const CACHE_REVALIDATE_HEADER = 'x-vercel-revalidate' as const const CACHE_FETCH_URL_HEADER = 'x-vercel-cache-item-name' as const const CACHE_CONTROL_VALUE_HEADER = 'x-vercel-cache-control' as const +const zCachedFetchValue: zod.ZodType = z.object({ + kind: z.literal('FETCH'), + data: z.object({ + headers: z.record(z.string()), + body: z.string(), + url: z.string(), + status: z.number().optional(), + }), + tags: z.array(z.string()).optional(), + revalidate: z.number(), +}) + export default class FetchCache implements CacheHandler { private headers: Record private cacheEndpoint?: string @@ -233,19 +253,22 @@ export default class FetchCache implements CacheHandler { throw new Error(`invalid response from cache ${res.status}`) } - const cached = await res.json() + const json: IncrementalCacheValue = await res.json() + const parsed = zCachedFetchValue.safeParse(json) - if (!cached || cached.kind !== 'FETCH') { - this.debug && console.log({ cached }) - throw new Error(`invalid cache value`) + if (!parsed.success) { + this.debug && console.log({ json }) + throw new Error('invalid cache value') } + const { data: cached } = parsed + // if new tags were specified, merge those tags to the existing tags if (cached.kind === 'FETCH') { cached.tags ??= [] for (const tag of tags ?? []) { - if (!cached.tags.include(tag)) { - cached.tag.push(tag) + if (!cached.tags.includes(tag)) { + cached.tags.push(tag) } } }