diff --git a/.changeset/fast-clouds-shout.md b/.changeset/fast-clouds-shout.md new file mode 100644 index 00000000..2cc6a41e --- /dev/null +++ b/.changeset/fast-clouds-shout.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +decode path params in cache interceptor diff --git a/packages/open-next/src/core/routing/cacheInterceptor.ts b/packages/open-next/src/core/routing/cacheInterceptor.ts index cf441331..8f34f0ae 100644 --- a/packages/open-next/src/core/routing/cacheInterceptor.ts +++ b/packages/open-next/src/core/routing/cacheInterceptor.ts @@ -130,6 +130,39 @@ async function generateResult( }; } +/** + * + * https://github.com/vercel/next.js/blob/34039551d2e5f611c0abde31a197d9985918adaf/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts#L2-L10 + */ +function escapePathDelimiters( + segment: string, + escapeEncoded?: boolean, +): string { + return segment.replace( + new RegExp(`([/#?]${escapeEncoded ? "|%(2f|23|3f|5c)" : ""})`, "gi"), + (char: string) => encodeURIComponent(char), + ); +} + +/** + * + * SSG cache key needs to be decoded, but some characters needs to be properly escaped + * https://github.com/vercel/next.js/blob/34039551d2e5f611c0abde31a197d9985918adaf/packages/next/src/server/lib/router-utils/decode-path-params.ts#L11-L26 + */ +function decodePathParams(pathname: string): string { + return pathname + .split("/") + .map((segment) => { + try { + return escapePathDelimiters(decodeURIComponent(segment), true); + } catch (e) { + // If decodeURIComponent fails, we return the original segment + return segment; + } + }) + .join("/"); +} + export async function cacheInterceptor( event: InternalEvent, ): Promise { @@ -147,6 +180,9 @@ export async function cacheInterceptor( // We also need to remove trailing slash localizedPath = localizedPath.replace(/\/$/, ""); + // Then we decode the path params + localizedPath = decodePathParams(localizedPath); + debug("Checking cache for", localizedPath, PrerenderManifest); const isISR =