diff --git a/.changeset/few-planets-attend.md b/.changeset/few-planets-attend.md new file mode 100644 index 00000000000..1777c4cd74f --- /dev/null +++ b/.changeset/few-planets-attend.md @@ -0,0 +1,5 @@ +--- +"@remix-run/architect": patch +--- + +Manually joining headers with semi-colons to avoid differences in Remix and node/undici Headers implementation. diff --git a/contributors.yml b/contributors.yml index a1c32df2763..9317d74d7ce 100644 --- a/contributors.yml +++ b/contributors.yml @@ -114,6 +114,7 @@ - colinhacks - confix - coryhouse +- courey - courtyenn - craigayre - craigglennie diff --git a/packages/remix-architect/__tests__/server-test.ts b/packages/remix-architect/__tests__/server-test.ts index 196f00f9488..243ff5ad99c 100644 --- a/packages/remix-architect/__tests__/server-test.ts +++ b/packages/remix-architect/__tests__/server-test.ts @@ -1,6 +1,7 @@ import fsp from "node:fs/promises"; import path from "node:path"; import { createRequestHandler as createRemixRequestHandler } from "@remix-run/node"; +import { Headers as RemixHeaders } from "@remix-run/web-fetch"; import type { APIGatewayProxyEventV2 } from "aws-lambda"; import lambdaTester from "lambda-tester"; @@ -230,6 +231,18 @@ describe("architect createRemixHeaders", () => { "__session=some_value; __other=some_other_value" ); }); + + it("handles multiple request cookies when using @remix-run/web-fetch", () => { + let headers = createRemixHeaders( + {}, + ["__session=some_value", "__other=some_other_value"], + // @ts-expect-error types don't align since it's not fully spec compliant + RemixHeaders + ); + expect(headers.get("cookie")).toEqual( + "__session=some_value; __other=some_other_value" + ); + }); }); }); diff --git a/packages/remix-architect/package.json b/packages/remix-architect/package.json index e008402bcdd..dcfdffaf0b1 100644 --- a/packages/remix-architect/package.json +++ b/packages/remix-architect/package.json @@ -19,6 +19,7 @@ "dependencies": { "@architect/functions": "^5.2.0", "@remix-run/node": "workspace:*", + "@remix-run/web-fetch": "^4.4.2", "@types/aws-lambda": "^8.10.82" }, "devDependencies": { diff --git a/packages/remix-architect/server.ts b/packages/remix-architect/server.ts index 6ad6c1c692b..52fa5a0bcd3 100644 --- a/packages/remix-architect/server.ts +++ b/packages/remix-architect/server.ts @@ -77,9 +77,15 @@ export function createRemixRequest(event: APIGatewayProxyEventV2): Request { export function createRemixHeaders( requestHeaders: APIGatewayProxyEventHeaders, - requestCookies?: string[] + requestCookies?: string[], + _Headers?: typeof Headers ): Headers { - let headers = new Headers(); + // `_Headers` should only be used for unit testing purposes so we can unit test + // the different behaviors of the @remix-run/web-fetch `Headers` implementation + // and the node/undici implementation. See: + // https://github.com/remix-run/remix/issues/9657 + let HeadersImpl = _Headers || Headers; + let headers = new HeadersImpl(); for (let [header, value] of Object.entries(requestHeaders)) { if (value) { @@ -88,9 +94,7 @@ export function createRemixHeaders( } if (requestCookies) { - for (let cookie of requestCookies) { - headers.append("Cookie", cookie); - } + headers.append("Cookie", requestCookies.join("; ")); } return headers; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e62b78bd283..65b97bab3a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -744,6 +744,9 @@ importers: '@remix-run/node': specifier: workspace:* version: link:../remix-node + '@remix-run/web-fetch': + specifier: ^4.4.2 + version: 4.4.2 '@types/aws-lambda': specifier: ^8.10.82 version: 8.10.133