diff --git a/.changeset/sour-points-bake.md b/.changeset/sour-points-bake.md
new file mode 100644
index 000000000..11f8167f1
--- /dev/null
+++ b/.changeset/sour-points-bake.md
@@ -0,0 +1,5 @@
+---
+"@opennextjs/aws": patch
+---
+
+fix fetch cache for next 15
diff --git a/examples/app-router/app/ssr/page.tsx b/examples/app-router/app/ssr/page.tsx
index 4f57336df..e41137576 100644
--- a/examples/app-router/app/ssr/page.tsx
+++ b/examples/app-router/app/ssr/page.tsx
@@ -14,10 +14,14 @@ async function getTime() {
export default async function SSR() {
const time = await getTime();
const headerList = await headers();
+ const responseOpenNext = await fetch("https://opennext.js.org", {
+ cache: "force-cache",
+ });
return (
Time: {time}
{headerList.get("host")}
+
Cached fetch: {responseOpenNext.headers.get("date")}
);
}
diff --git a/packages/open-next/src/adapters/cache.ts b/packages/open-next/src/adapters/cache.ts
index 82c4e1bcf..b357d0dbc 100644
--- a/packages/open-next/src/adapters/cache.ts
+++ b/packages/open-next/src/adapters/cache.ts
@@ -108,6 +108,28 @@ declare global {
var lastModified: Record;
var isNextAfter15: boolean;
}
+
+function isFetchCache(
+ options?:
+ | boolean
+ | {
+ fetchCache?: boolean;
+ kindHint?: "app" | "pages" | "fetch";
+ kind?: "FETCH";
+ },
+): boolean {
+ if (typeof options === "boolean") {
+ return options;
+ }
+ if (typeof options === "object") {
+ return (
+ options.kindHint === "fetch" ||
+ options.fetchCache ||
+ options.kind === "FETCH"
+ );
+ }
+ return false;
+}
// We need to use globalThis client here as this class can be defined at load time in next 12 but client is not available at load time
export default class S3Cache {
constructor(_ctx: CacheHandlerContext) {}
@@ -122,21 +144,16 @@ export default class S3Cache {
kindHint?: "app" | "pages" | "fetch";
tags?: string[];
softTags?: string[];
+ kind?: "FETCH";
},
) {
if (globalThis.disableIncrementalCache) {
return null;
}
- const isFetchCache =
- typeof options === "object"
- ? options.kindHint
- ? options.kindHint === "fetch"
- : options.fetchCache
- : options;
const softTags = typeof options === "object" ? options.softTags : [];
const tags = typeof options === "object" ? options.tags : [];
- return isFetchCache
+ return isFetchCache(options)
? this.getFetchCache(key, softTags, tags)
: this.getIncrementalCache(key);
}
diff --git a/packages/tests-e2e/tests/appRouter/ssr.test.ts b/packages/tests-e2e/tests/appRouter/ssr.test.ts
index cd472c44f..261189115 100644
--- a/packages/tests-e2e/tests/appRouter/ssr.test.ts
+++ b/packages/tests-e2e/tests/appRouter/ssr.test.ts
@@ -53,3 +53,12 @@ test("Server Side Render and loading.tsx", async ({ page }) => {
// await expect(el).toBeVisible();
// await expect(time).not.toEqual(newTime);
});
+
+test("Fetch cache properly cached", async ({ page }) => {
+ await page.goto("/ssr");
+ const originalDate = await page.getByText("Cached fetch:").textContent();
+ await wait(2000);
+ await page.reload();
+ const newDate = await page.getByText("Cached fetch:").textContent();
+ expect(originalDate).toEqual(newDate);
+});