fix(fetch-cache): fix additional typo, add type & data validation (#64799)

## Why?

This PR fixes the fetch cache, which currently is not using the fetch
cache when it exists (the tags were not getting set properly), and tags
have not updated.

(Before)


https://github.com/vercel/next.js/assets/28912696/74d8f592-0698-4ae4-be4b-30cffb1ffe11

(After)


https://github.com/vercel/next.js/assets/28912696/af12b13a-46c6-41c3-9ac3-20e1ec44a865

- https://github.com/vercel/next.js/pull/64786
- https://github.com/vercel/next.js/pull/63547

Closes NEXT-3173
This commit is contained in:
Sam Ko 2024-04-22 19:03:10 -04:00 committed by GitHub
parent 3ea57cd725
commit 3d1f3cc1b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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<CachedFetchValue> = 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<string, string>
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.includes(tag)) {
cached.tag.push(tag)
cached.tags.push(tag)
}
}
}