diff --git a/.changeset/fix-opennextconfig-null-check.md b/.changeset/fix-opennextconfig-null-check.md new file mode 100644 index 000000000..450c96510 --- /dev/null +++ b/.changeset/fix-opennextconfig-null-check.md @@ -0,0 +1,10 @@ +--- +"@opennextjs/aws": patch +--- + +fix: add null check for globalThis.openNextConfig in cache handler + +Adds optional chaining when accessing globalThis.openNextConfig to prevent +TypeError during Next.js 16 build phase when using the Adapters API. The cache +handler can be instantiated during SSG/prerendering before openNextConfig is +initialized by the runtime handlers. diff --git a/packages/open-next/src/adapters/cache.ts b/packages/open-next/src/adapters/cache.ts index 89f42c480..91d5a9f45 100644 --- a/packages/open-next/src/adapters/cache.ts +++ b/packages/open-next/src/adapters/cache.ts @@ -45,7 +45,7 @@ export default class Cache { kind?: "FETCH"; }, ) { - if (globalThis.openNextConfig.dangerous?.disableIncrementalCache) { + if (globalThis.openNextConfig?.dangerous?.disableIncrementalCache) { return null; } @@ -204,7 +204,7 @@ export default class Cache { data?: IncrementalCacheValue, ctx?: IncrementalCacheContext, ): Promise { - if (globalThis.openNextConfig.dangerous?.disableIncrementalCache) { + if (globalThis.openNextConfig?.dangerous?.disableIncrementalCache) { return; } // This one might not even be necessary anymore @@ -322,7 +322,7 @@ export default class Cache { } public async revalidateTag(tags: string | string[]) { - const config = globalThis.openNextConfig.dangerous; + const config = globalThis.openNextConfig?.dangerous; if (config?.disableTagCache || config?.disableIncrementalCache) { return; } @@ -430,7 +430,7 @@ export default class Cache { ctx?: IncrementalCacheContext, ) { if ( - globalThis.openNextConfig.dangerous?.disableTagCache || + globalThis.openNextConfig?.dangerous?.disableTagCache || globalThis.tagCache.mode === "nextMode" || // Here it means it's a delete !data diff --git a/packages/tests-unit/tests/adapters/cache.test.ts b/packages/tests-unit/tests/adapters/cache.test.ts index 9560f97bd..1bf8d9958 100644 --- a/packages/tests-unit/tests/adapters/cache.test.ts +++ b/packages/tests-unit/tests/adapters/cache.test.ts @@ -85,6 +85,34 @@ describe("CacheHandler", () => { expect(result).toBeNull(); }); + describe("undefined openNextConfig", () => { + it("Should not throw when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + // Should not throw TypeError: Cannot read properties of undefined (reading 'dangerous') + const result = await cache.get("key"); + + expect(result).not.toBeUndefined(); + }); + + it("Should not throw on set when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + await expect( + cache.set("key", { kind: "REDIRECT", props: {} }), + ).resolves.not.toThrow(); + }); + + it("Should not throw on revalidateTag when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + await expect(cache.revalidateTag("tag")).resolves.not.toThrow(); + }); + }); + describe("disableIncrementalCache", () => { beforeEach(() => { globalThis.openNextConfig.dangerous.disableIncrementalCache = true;