|
| 1 | +import fs from "node:fs"; |
| 2 | +import path from "node:path"; |
| 3 | + |
| 4 | +import type { NextModeTagCache } from "types/overrides"; |
| 5 | +import { getMonorepoRelativePath } from "utils/normalize-path"; |
| 6 | +import { debug } from "../../adapters/logger"; |
| 7 | + |
| 8 | +const tagFile = path.join( |
| 9 | + getMonorepoRelativePath(), |
| 10 | + "dynamodb-provider/dynamodb-cache.json", |
| 11 | +); |
| 12 | +const tagContent = fs.readFileSync(tagFile, "utf-8"); |
| 13 | + |
| 14 | +let tags = JSON.parse(tagContent) as { |
| 15 | + tag: { S: string }; |
| 16 | + path: { S: string }; |
| 17 | + revalidatedAt: { N: string }; |
| 18 | +}[]; |
| 19 | + |
| 20 | +function buildKey(key: string) { |
| 21 | + const { NEXT_BUILD_ID } = process.env; |
| 22 | + return path.posix.join(NEXT_BUILD_ID ?? "", key); |
| 23 | +} |
| 24 | + |
| 25 | +function buildObject(tag: string, revalidatedAt?: number) { |
| 26 | + return { |
| 27 | + path: { S: buildKey(tag) }, |
| 28 | + tag: { S: buildKey(tag) }, |
| 29 | + revalidatedAt: { N: `${revalidatedAt ?? Date.now()}` }, |
| 30 | + }; |
| 31 | +} |
| 32 | + |
| 33 | +export default { |
| 34 | + name: "fs-dev-nextMode", |
| 35 | + mode: "nextMode", |
| 36 | + getLastRevalidated: async (tagsToCheck: string[]) => { |
| 37 | + // Not supported for now |
| 38 | + // TODO: Implement getLastRevalidated |
| 39 | + return 0; |
| 40 | + }, |
| 41 | + hasBeenRevalidated: async (tagsToCheck: string[], lastModified?: number) => { |
| 42 | + if (globalThis.openNextConfig.dangerous?.disableTagCache) { |
| 43 | + return false; |
| 44 | + } |
| 45 | + debug("hasBeenRevalidated", { tags: tagsToCheck, lastModified }); |
| 46 | + |
| 47 | + // Build the cache keys for the tags we're checking |
| 48 | + const cacheKeys = tagsToCheck.map((tag) => buildKey(tag)); |
| 49 | + |
| 50 | + // Check if any tag has been revalidated after the lastModified time |
| 51 | + const hasRevalidatedTag = tags.some((tagEntry) => { |
| 52 | + const tagRevalidatedAt = Number.parseInt(tagEntry.revalidatedAt.N); |
| 53 | + return ( |
| 54 | + cacheKeys.includes(tagEntry.tag.S) && |
| 55 | + tagRevalidatedAt > (lastModified ?? Date.now()) |
| 56 | + ); |
| 57 | + }); |
| 58 | + |
| 59 | + debug("hasBeenRevalidated result:", hasRevalidatedTag); |
| 60 | + return hasRevalidatedTag; |
| 61 | + }, |
| 62 | + writeTags: async (tagsToWrite: string[]) => { |
| 63 | + if ( |
| 64 | + globalThis.openNextConfig.dangerous?.disableTagCache || |
| 65 | + tagsToWrite.length === 0 |
| 66 | + ) { |
| 67 | + return Promise.resolve(); |
| 68 | + } |
| 69 | + |
| 70 | + debug("writeTags", { tags: tagsToWrite }); |
| 71 | + |
| 72 | + // Create new tag objects to write |
| 73 | + const newTagObjects = tagsToWrite.map((tag) => |
| 74 | + buildObject(tag, Date.now()), |
| 75 | + ); |
| 76 | + |
| 77 | + // Remove any existing entries for these tags to avoid duplicates |
| 78 | + const existingTagKeys = newTagObjects.map((obj) => obj.tag.S); |
| 79 | + tags = tags.filter((tagEntry) => !existingTagKeys.includes(tagEntry.tag.S)); |
| 80 | + |
| 81 | + // Add the new tags |
| 82 | + tags.push(...newTagObjects); |
| 83 | + |
| 84 | + fs.writeFileSync(tagFile, JSON.stringify(tags)); |
| 85 | + |
| 86 | + debug("writeTags completed, written", newTagObjects.length, "tags"); |
| 87 | + |
| 88 | + return Promise.resolve(); |
| 89 | + }, |
| 90 | +} satisfies NextModeTagCache; |
0 commit comments