From 3e1538530a8d8da156096fed04790d4585cf42af Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 25 Nov 2024 09:42:09 +0100 Subject: [PATCH 1/3] fix(cloudflare): cloudflare-streaming do not use the edge runtime --- .changeset/dirty-plums-cheat.md | 5 +++++ .../src/overrides/wrappers/aws-lambda-streaming.ts | 4 ++-- .../src/overrides/wrappers/cloudflare-streaming.ts | 10 +++------- .../open-next/src/overrides/wrappers/cloudflare.ts | 7 +++++-- packages/open-next/src/overrides/wrappers/dummy.ts | 6 +++--- packages/open-next/src/overrides/wrappers/node.ts | 4 ++-- 6 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 .changeset/dirty-plums-cheat.md diff --git a/.changeset/dirty-plums-cheat.md b/.changeset/dirty-plums-cheat.md new file mode 100644 index 000000000..cbac737de --- /dev/null +++ b/.changeset/dirty-plums-cheat.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +fix(cloudflare): cloudflare-streaming do not use the edge runtime diff --git a/packages/open-next/src/overrides/wrappers/aws-lambda-streaming.ts b/packages/open-next/src/overrides/wrappers/aws-lambda-streaming.ts index c0b38051b..315edacc1 100644 --- a/packages/open-next/src/overrides/wrappers/aws-lambda-streaming.ts +++ b/packages/open-next/src/overrides/wrappers/aws-lambda-streaming.ts @@ -3,7 +3,7 @@ import zlib from "node:zlib"; import type { APIGatewayProxyEventV2 } from "aws-lambda"; import type { StreamCreator } from "http/index"; -import type { WrapperHandler } from "types/overrides"; +import type { Wrapper, WrapperHandler } from "types/overrides"; import { debug, error } from "../../adapters/logger"; import type { @@ -119,4 +119,4 @@ export default { wrapper: handler, name: "aws-lambda-streaming", supportStreaming: true, -}; +} satisfies Wrapper; diff --git a/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts b/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts index b4a810d54..6a1ef4510 100644 --- a/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts +++ b/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts @@ -1,14 +1,11 @@ import type { InternalEvent, InternalResult } from "types/open-next"; -import type { WrapperHandler } from "types/overrides"; +import type { Wrapper, WrapperHandler } from "types/overrides"; import { Writable } from "node:stream"; import type { StreamCreator } from "http/index"; import type { MiddlewareOutputEvent } from "../../core/routingHandler"; -const handler: WrapperHandler< - InternalEvent, - InternalResult | ({ type: "middleware" } & MiddlewareOutputEvent) -> = +const handler: WrapperHandler = async (handler, converter) => async ( request: Request, @@ -73,5 +70,4 @@ export default { wrapper: handler, name: "cloudflare-streaming", supportStreaming: true, - edgeRuntime: true, -}; +} satisfies Wrapper; diff --git a/packages/open-next/src/overrides/wrappers/cloudflare.ts b/packages/open-next/src/overrides/wrappers/cloudflare.ts index 1284a7a4b..445d0b13c 100644 --- a/packages/open-next/src/overrides/wrappers/cloudflare.ts +++ b/packages/open-next/src/overrides/wrappers/cloudflare.ts @@ -1,5 +1,5 @@ import type { InternalEvent, InternalResult } from "types/open-next"; -import type { WrapperHandler } from "types/overrides"; +import type { Wrapper, WrapperHandler } from "types/overrides"; import type { MiddlewareOutputEvent } from "../../core/routingHandler"; @@ -65,4 +65,7 @@ export default { name: "cloudflare", supportStreaming: true, edgeRuntime: true, -}; +} satisfies Wrapper< + InternalEvent, + InternalResult | ({ type: "middleware" } & MiddlewareOutputEvent) +>; diff --git a/packages/open-next/src/overrides/wrappers/dummy.ts b/packages/open-next/src/overrides/wrappers/dummy.ts index c6492f8a6..5de347799 100644 --- a/packages/open-next/src/overrides/wrappers/dummy.ts +++ b/packages/open-next/src/overrides/wrappers/dummy.ts @@ -1,9 +1,9 @@ -import type { WrapperHandler } from "types/overrides"; +import type { Wrapper, WrapperHandler } from "types/overrides"; const dummyWrapper: WrapperHandler = async () => async () => undefined; export default { name: "dummy", - handler: dummyWrapper, + wrapper: dummyWrapper, supportStreaming: false, -}; +} satisfies Wrapper; diff --git a/packages/open-next/src/overrides/wrappers/node.ts b/packages/open-next/src/overrides/wrappers/node.ts index c9eb879f9..6f53fd554 100644 --- a/packages/open-next/src/overrides/wrappers/node.ts +++ b/packages/open-next/src/overrides/wrappers/node.ts @@ -1,7 +1,7 @@ import { createServer } from "node:http"; import type { StreamCreator } from "http/index"; -import type { WrapperHandler } from "types/overrides"; +import type { Wrapper, WrapperHandler } from "types/overrides"; import { debug, error } from "../../adapters/logger"; @@ -66,4 +66,4 @@ export default { wrapper, name: "node", supportStreaming: true, -}; +} satisfies Wrapper; From f32e94be5383ff09e056c1a48030e97241a0489b Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 25 Nov 2024 11:12:30 +0100 Subject: [PATCH 2/3] fixup! MiddlewareOutputEvent --- packages/open-next/src/core/requestHandler.ts | 37 ++++++++++--------- .../open-next/src/core/routing/middleware.ts | 19 +++++----- packages/open-next/src/core/routingHandler.ts | 20 +++++----- .../overrides/converters/aws-cloudfront.ts | 6 +-- .../wrappers/cloudflare-streaming.ts | 1 - .../src/overrides/wrappers/cloudflare.ts | 7 +--- 6 files changed, 43 insertions(+), 47 deletions(-) diff --git a/packages/open-next/src/core/requestHandler.ts b/packages/open-next/src/core/requestHandler.ts index 1030581cf..acc7c1a32 100644 --- a/packages/open-next/src/core/requestHandler.ts +++ b/packages/open-next/src/core/requestHandler.ts @@ -34,8 +34,9 @@ export async function openNextHandler( } debug("internalEvent", internalEvent); - let preprocessResult: InternalResult | MiddlewareOutputEvent = { - internalEvent: internalEvent, + let routingResult: InternalResult | MiddlewareOutputEvent = { + type: "middleware", + internalEvent, isExternalRewrite: false, origin: false, isISR: false, @@ -43,16 +44,16 @@ export async function openNextHandler( //#override withRouting try { - preprocessResult = await routingHandler(internalEvent); + routingResult = await routingHandler(internalEvent); } catch (e) { warn("Routing failed.", e); } //#endOverride const headers = - "type" in preprocessResult - ? preprocessResult.headers - : preprocessResult.internalEvent.headers; + routingResult.type === "middleware" + ? routingResult.internalEvent.headers + : routingResult.headers; const overwrittenResponseHeaders: Record = {}; @@ -67,16 +68,17 @@ export async function openNextHandler( } if ( - "isExternalRewrite" in preprocessResult && - preprocessResult.isExternalRewrite === true + routingResult.type === "middleware" && + routingResult.isExternalRewrite === true ) { try { - preprocessResult = await globalThis.proxyExternalRequest.proxy( - preprocessResult.internalEvent, + routingResult = await globalThis.proxyExternalRequest.proxy( + routingResult.internalEvent, ); } catch (e) { error("External request failed.", e); - preprocessResult = { + routingResult = { + type: "middleware", internalEvent: { type: "core", rawPath: "/500", @@ -95,7 +97,7 @@ export async function openNextHandler( } } - if ("type" in preprocessResult) { + if (routingResult.type === "core") { // response is used only in the streaming case if (responseStreaming) { const response = createServerResponse( @@ -103,18 +105,19 @@ export async function openNextHandler( headers, responseStreaming, ); - response.statusCode = preprocessResult.statusCode; + response.statusCode = routingResult.statusCode; response.flushHeaders(); - const [bodyToConsume, bodyToReturn] = preprocessResult.body.tee(); + const [bodyToConsume, bodyToReturn] = routingResult.body.tee(); for await (const chunk of bodyToConsume) { response.write(chunk); } response.end(); - preprocessResult.body = bodyToReturn; + routingResult.body = bodyToReturn; } - return preprocessResult; + return routingResult; } - const preprocessedEvent = preprocessResult.internalEvent; + + const preprocessedEvent = routingResult.internalEvent; debug("preprocessedEvent", preprocessedEvent); const reqProps = { method: preprocessedEvent.method, diff --git a/packages/open-next/src/core/routing/middleware.ts b/packages/open-next/src/core/routing/middleware.ts index b29545596..708beda4d 100644 --- a/packages/open-next/src/core/routing/middleware.ts +++ b/packages/open-next/src/core/routing/middleware.ts @@ -23,9 +23,9 @@ const middlewareManifest = MiddlewareManifest; const middleMatch = getMiddlewareMatch(middlewareManifest); -type MiddlewareOutputEvent = InternalEvent & { +type InternalMiddlewareEvent = InternalEvent & { responseHeaders?: Record; - externalRewrite?: boolean; + isExternalRewrite?: boolean; }; type Middleware = (request: Request) => Response | Promise; @@ -45,7 +45,7 @@ function defaultMiddlewareLoader() { export async function handleMiddleware( internalEvent: InternalEvent, middlewareLoader: MiddlewareLoader = defaultMiddlewareLoader, -): Promise { +): Promise { const headers = internalEvent.headers; // We bypass the middleware if the request is internal @@ -142,14 +142,14 @@ export async function handleMiddleware( statusCode: statusCode, headers: resHeaders, isBase64Encoded: false, - }; + } satisfies InternalResult; } // If the middleware returned a Rewrite, set the `url` to the pathname of the rewrite // NOTE: the header was added to `req` from above const rewriteUrl = responseHeaders.get("x-middleware-rewrite"); let rewritten = false; - let externalRewrite = false; + let isExternalRewrite = false; let middlewareQueryString = internalEvent.query; let newUrl = internalEvent.url; if (rewriteUrl) { @@ -157,7 +157,7 @@ export async function handleMiddleware( if (isExternal(rewriteUrl, internalEvent.headers.host as string)) { newUrl = rewriteUrl; rewritten = true; - externalRewrite = true; + isExternalRewrite = true; } else { const rewriteUrlObject = new URL(rewriteUrl); newUrl = rewriteUrlObject.pathname; @@ -184,14 +184,13 @@ export async function handleMiddleware( // transfer response body to res const body = result.body as ReadableStream; - // await pipeReadable(result.response.body, res); return { type: internalEvent.type, statusCode: statusCode, headers: resHeaders, body, isBase64Encoded: false, - }; + } satisfies InternalResult; } return { @@ -207,6 +206,6 @@ export async function handleMiddleware( query: middlewareQueryString, cookies: internalEvent.cookies, remoteAddress: internalEvent.remoteAddress, - externalRewrite, - }; + isExternalRewrite, + } satisfies InternalMiddlewareEvent; } diff --git a/packages/open-next/src/core/routingHandler.ts b/packages/open-next/src/core/routingHandler.ts index 79c1e030a..55c2a82cd 100644 --- a/packages/open-next/src/core/routingHandler.ts +++ b/packages/open-next/src/core/routingHandler.ts @@ -19,7 +19,9 @@ import { handleMiddleware } from "./routing/middleware"; export const MIDDLEWARE_HEADER_PREFIX = "x-middleware-response-"; export const MIDDLEWARE_HEADER_PREFIX_LEN = MIDDLEWARE_HEADER_PREFIX.length; + export interface MiddlewareOutputEvent { + type: "middleware"; internalEvent: InternalEvent; isExternalRewrite: boolean; origin: Origin | false; @@ -110,17 +112,16 @@ export default async function routingHandler( return redirect; } - const middleware = await handleMiddleware(internalEvent); - let middlewareResponseHeaders: Record = {}; - if ("statusCode" in middleware) { - return middleware; + const middlewareEventOrResult = await handleMiddleware(internalEvent); + const isInternalResult = "statusCode" in middlewareEventOrResult; + if (isInternalResult) { + return middlewareEventOrResult; } - middlewareResponseHeaders = middleware.responseHeaders || {}; - internalEvent = middleware; - - // At this point internalEvent is an InternalEvent or a MiddlewareOutputEvent + const middlewareResponseHeaders = middlewareEventOrResult.responseHeaders; + let isExternalRewrite = middlewareEventOrResult.isExternalRewrite ?? false; + // internalEvent is `InternalEvent | InternalMiddlewareEvent` + internalEvent = middlewareEventOrResult; - let isExternalRewrite = middleware.externalRewrite ?? false; if (!isExternalRewrite) { // First rewrite to be applied const beforeRewrites = handleRewrites( @@ -233,6 +234,7 @@ export default async function routingHandler( }); return { + type: "middleware", internalEvent, isExternalRewrite, origin: false, diff --git a/packages/open-next/src/overrides/converters/aws-cloudfront.ts b/packages/open-next/src/overrides/converters/aws-cloudfront.ts index 494cd84d0..384ca9c53 100644 --- a/packages/open-next/src/overrides/converters/aws-cloudfront.ts +++ b/packages/open-next/src/overrides/converters/aws-cloudfront.ts @@ -111,10 +111,6 @@ async function convertFromCloudFrontRequestEvent( }; } -type MiddlewareEvent = { - type: "middleware"; -} & MiddlewareOutputEvent; - function convertToCloudfrontHeaders( headers: Record, directResponse?: boolean, @@ -150,7 +146,7 @@ function convertToCloudfrontHeaders( } async function convertToCloudFrontRequestResult( - result: InternalResult | MiddlewareEvent, + result: InternalResult | MiddlewareOutputEvent, originalRequest: CloudFrontRequestEvent, ): Promise { if (result.type === "middleware") { diff --git a/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts b/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts index 6a1ef4510..79184c059 100644 --- a/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts +++ b/packages/open-next/src/overrides/wrappers/cloudflare-streaming.ts @@ -3,7 +3,6 @@ import type { Wrapper, WrapperHandler } from "types/overrides"; import { Writable } from "node:stream"; import type { StreamCreator } from "http/index"; -import type { MiddlewareOutputEvent } from "../../core/routingHandler"; const handler: WrapperHandler = async (handler, converter) => diff --git a/packages/open-next/src/overrides/wrappers/cloudflare.ts b/packages/open-next/src/overrides/wrappers/cloudflare.ts index 445d0b13c..0c22f9964 100644 --- a/packages/open-next/src/overrides/wrappers/cloudflare.ts +++ b/packages/open-next/src/overrides/wrappers/cloudflare.ts @@ -17,7 +17,7 @@ interface WorkerContext { const handler: WrapperHandler< InternalEvent, - InternalResult | ({ type: "middleware" } & MiddlewareOutputEvent) + InternalResult | MiddlewareOutputEvent > = async (handler, converter) => async ( @@ -65,7 +65,4 @@ export default { name: "cloudflare", supportStreaming: true, edgeRuntime: true, -} satisfies Wrapper< - InternalEvent, - InternalResult | ({ type: "middleware" } & MiddlewareOutputEvent) ->; +} satisfies Wrapper; From d381220a83148d36859eff43cfa5d4e5bdaafaa5 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Mon, 25 Nov 2024 11:19:28 +0100 Subject: [PATCH 3/3] fixup! test --- packages/tests-unit/tests/core/routing/middleware.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/tests-unit/tests/core/routing/middleware.test.ts b/packages/tests-unit/tests/core/routing/middleware.test.ts index be074b541..541c57579 100644 --- a/packages/tests-unit/tests/core/routing/middleware.test.ts +++ b/packages/tests-unit/tests/core/routing/middleware.test.ts @@ -146,7 +146,7 @@ describe("handleMiddleware", () => { responseHeaders: { "x-middleware-rewrite": "http://localhost/rewrite", }, - externalRewrite: false, + isExternalRewrite: false, }); }); @@ -176,7 +176,7 @@ describe("handleMiddleware", () => { __nextDataReq: "1", newKey: "value", }, - externalRewrite: false, + isExternalRewrite: false, }); }); @@ -201,7 +201,7 @@ describe("handleMiddleware", () => { responseHeaders: { "x-middleware-rewrite": "http://external/rewrite", }, - externalRewrite: true, + isExternalRewrite: true, }); }); @@ -221,7 +221,7 @@ describe("handleMiddleware", () => { "custom-header": "value", }, responseHeaders: {}, - externalRewrite: false, + isExternalRewrite: false, }); });