-
Notifications
You must be signed in to change notification settings - Fork 397
feat: Add Convex Adapter #1235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Add Convex Adapter #1235
Changes from 4 commits
b5b704b
50e71a9
084228b
e20ad2b
b4ab843
6b8145d
45a1f12
2d4bb76
b481f13
de178e7
121f21a
b79d51b
681e127
f840666
75f4383
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "uploadthing": minor | ||
| --- | ||
|
|
||
| Add Convex Adapter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import type { FunctionReference, HttpRouter } from "convex/server"; | ||
| import { httpActionGeneric } from "convex/server"; | ||
|
|
||
| const addCorsHeaders = (headers?: Record<string, string>) => { | ||
| if (!process.env.CLIENT_ORIGIN) { | ||
| throw new Error("Convex deployment doesn't have CLIENT_ORIGIN set"); | ||
| } | ||
|
|
||
| return new Headers({ | ||
| ...headers, | ||
| "Access-Control-Allow-Origin": process.env.CLIENT_ORIGIN, | ||
| "Access-Control-Allow-Methods": "GET, POST, OPTIONS", | ||
| "Access-Control-Allow-Headers": "*", | ||
| "Access-Control-Max-Age": "86400", | ||
| }); | ||
| }; | ||
|
|
||
| export const createRouteHandler = ( | ||
| http: HttpRouter, | ||
| internalAction: FunctionReference< | ||
| "action", | ||
| "internal", | ||
| { | ||
| request: { | ||
| url: string; | ||
| method: string; | ||
| headers: Record<string, string>; | ||
| body?: string; | ||
| }; | ||
| }, | ||
| { | ||
| status: number; | ||
| statusText: string; | ||
| headers: Record<string, string>; | ||
| body: string; | ||
| } | ||
| >, | ||
| ) => { | ||
| const handler = httpActionGeneric(async (ctx, req) => { | ||
| const headers: Record<string, string> = {}; | ||
| req.headers.forEach((value, key) => { | ||
| headers[key] = value; | ||
| }); | ||
| const request = { | ||
| url: req.url, | ||
| method: req.method, | ||
| headers, | ||
| body: await req.text(), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The request body is converted to text with View Details📝 Patch Detailsdiff --git a/packages/uploadthing/src/convex-helpers.ts b/packages/uploadthing/src/convex-helpers.ts
index 444ab16..5065c24 100644
--- a/packages/uploadthing/src/convex-helpers.ts
+++ b/packages/uploadthing/src/convex-helpers.ts
@@ -45,7 +45,12 @@ export const createRouteHandler = (
url: req.url,
method: req.method,
headers,
- body: await req.text(),
+ ...(await req.arrayBuffer().then(buffer => {
+ // Convert binary data to base64 to preserve it through Convex serialization
+ return buffer.byteLength > 0 ?
+ { body: btoa(String.fromCharCode(...new Uint8Array(buffer))) } :
+ {};
+ })),
};
const response = await ctx.runAction(internalAction, { request });
diff --git a/packages/uploadthing/src/convex.ts b/packages/uploadthing/src/convex.ts
index a536096..2e8ec63 100644
--- a/packages/uploadthing/src/convex.ts
+++ b/packages/uploadthing/src/convex.ts
@@ -55,7 +55,15 @@ export const createInternalAction = <TRouter extends FileRouter>(
const request = new Request(args.request.url, {
method: args.request.method,
headers: new Headers(args.request.headers),
- body: args.request.body ? new Blob([args.request.body]) : null,
+ body: args.request.body ? (() => {
+ // Convert base64 back to binary data
+ const binaryString = atob(args.request.body);
+ const bytes = new Uint8Array(binaryString.length);
+ for (let i = 0; i < binaryString.length; i++) {
+ bytes[i] = binaryString.charCodeAt(i);
+ }
+ return new Blob([bytes]);
+ })() : null,
});
const response = await handler(ctx, request);
AnalysisThe Convex adapter attempts to serialize HTTP request bodies as strings using File uploads typically contain multipart/form-data with binary file content that cannot be safely represented as UTF-8 text. When This will cause uploaded files to be corrupted and unusable. The adapter needs to handle binary data properly, potentially using base64 encoding or a similar approach to safely serialize binary content through Convex's action system. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Request bodies are always serialized as strings, but GET requests typically have empty bodies which will result in an empty string being passed instead of undefined. View DetailsAnalysisIn the This creates an inconsistency: GET requests will have The fix is to check if the request method is GET or if the body is empty, and conditionally set the body to undefined: body: req.method === "GET" || !(await req.text()) ? undefined : await req.text(),However, since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code uses View Details📝 Patch Detailsdiff --git a/packages/uploadthing/src/convex-helpers.ts b/packages/uploadthing/src/convex-helpers.ts
index daebba6..56e3480 100644
--- a/packages/uploadthing/src/convex-helpers.ts
+++ b/packages/uploadthing/src/convex-helpers.ts
@@ -46,11 +46,12 @@ export const createRouteHandler = ({
req.headers.forEach((value, key) => {
headers[key] = value;
});
+ const arrayBuffer = await req.arrayBuffer();
const request = {
url: req.url,
method: req.method,
headers,
- body: await req.text(),
+ ...(arrayBuffer.byteLength > 0 && { body: Buffer.from(arrayBuffer).toString('base64') }),
};
const response = await ctx.runAction(internalAction, { request });
diff --git a/packages/uploadthing/src/convex.ts b/packages/uploadthing/src/convex.ts
index 75f60db..3dd4375 100644
--- a/packages/uploadthing/src/convex.ts
+++ b/packages/uploadthing/src/convex.ts
@@ -55,7 +55,7 @@ export const createInternalAction = <TRouter extends FileRouter>(
const request = new Request(args.request.url, {
method: args.request.method,
headers: new Headers(args.request.headers),
- body: args.request.body ? new Blob([args.request.body]) : null,
+ body: args.request.body ? new Blob([Buffer.from(args.request.body, 'base64')]) : null,
});
const response = await handler(ctx, request);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 286ae0b..ff748ef 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -130,7 +130,7 @@ importers:
version: 12.0.6([email protected]([email protected]))([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
next-sitemap:
specifier: ^4.2.3
version: 4.2.3([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]))
@@ -368,7 +368,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -432,6 +432,43 @@ importers:
specifier: 5.8.3
version: 5.8.3
+ examples/minimal-convex:
+ dependencies:
+ '@uploadthing/react':
+ specifier: 7.3.3
+ version: link:../../packages/react
+ convex:
+ specifier: 1.26.2
+ version: 1.26.2(@clerk/[email protected]([email protected]([email protected]))([email protected]))([email protected])
+ next:
+ specifier: 15.3.1
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ react:
+ specifier: 19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: 19.1.0
+ version: 19.1.0([email protected])
+ uploadthing:
+ specifier: 7.7.4
+ version: link:../../packages/uploadthing
+ devDependencies:
+ '@next/bundle-analyzer':
+ specifier: 15.1.3
+ version: 15.1.3
+ '@types/node':
+ specifier: ^22.10.0
+ version: 22.12.0
+ '@types/react':
+ specifier: 19.1.2
+ version: 19.1.2
+ '@types/react-dom':
+ specifier: 19.1.2
+ version: 19.1.2(@types/[email protected])
+ typescript:
+ specifier: 5.8.3
+ version: 5.8.3
+
examples/minimal-expo:
dependencies:
'@bacons/text-decoder':
@@ -572,7 +609,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -723,7 +760,7 @@ importers:
version: 0.469.0([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
next-auth:
specifier: 5.0.0-beta.25
version: 5.0.0-beta.25([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]))([email protected])
@@ -799,7 +836,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -848,7 +885,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1013,7 +1050,7 @@ importers:
version: 0.38.3(@cloudflare/[email protected])(@libsql/[email protected])(@types/[email protected])([email protected])([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1065,7 +1102,7 @@ importers:
version: 0.38.3(@cloudflare/[email protected])(@libsql/[email protected])(@types/[email protected])([email protected])([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1123,7 +1160,7 @@ importers:
version: 0.469.0([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
next-themes:
specifier: ^0.4.6
version: 0.4.6([email protected]([email protected]))([email protected])
@@ -1178,7 +1215,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1209,7 +1246,7 @@ importers:
dependencies:
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1240,7 +1277,7 @@ importers:
version: link:../../packages/react
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1436,7 +1473,7 @@ importers:
version: 2.7.5(@types/[email protected])([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react:
specifier: 19.1.0
version: 19.1.0
@@ -1689,7 +1726,7 @@ importers:
version: 2.7.5(@types/[email protected])([email protected])
next:
specifier: 15.3.1
- version: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ version: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
solid-js:
specifier: ^1.9.3
version: 1.9.3
@@ -4883,12 +4920,6 @@ packages:
cpu: [arm64]
os: [darwin]
- '@img/[email protected]':
- resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [darwin]
-
'@img/[email protected]':
resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -4901,12 +4932,6 @@ packages:
cpu: [x64]
os: [darwin]
- '@img/[email protected]':
- resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [darwin]
-
'@img/[email protected]':
resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -4918,11 +4943,6 @@ packages:
cpu: [arm64]
os: [darwin]
- '@img/[email protected]':
- resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
- cpu: [arm64]
- os: [darwin]
-
'@img/[email protected]':
resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==}
cpu: [arm64]
@@ -4933,11 +4953,6 @@ packages:
cpu: [x64]
os: [darwin]
- '@img/[email protected]':
- resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
- cpu: [x64]
- os: [darwin]
-
'@img/[email protected]':
resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==}
cpu: [x64]
@@ -4948,11 +4963,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
- cpu: [arm64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
cpu: [arm64]
@@ -4963,21 +4973,11 @@ packages:
cpu: [arm]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
- cpu: [arm]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
cpu: [arm]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
- cpu: [ppc64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
cpu: [ppc64]
@@ -4988,11 +4988,6 @@ packages:
cpu: [s390x]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
- cpu: [s390x]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
cpu: [s390x]
@@ -5003,11 +4998,6 @@ packages:
cpu: [x64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
- cpu: [x64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
cpu: [x64]
@@ -5018,11 +5008,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
- cpu: [arm64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
cpu: [arm64]
@@ -5033,11 +5018,6 @@ packages:
cpu: [x64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
- cpu: [x64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
cpu: [x64]
@@ -5049,12 +5029,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5067,12 +5041,6 @@ packages:
cpu: [arm]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5091,12 +5059,6 @@ packages:
cpu: [s390x]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [s390x]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5109,12 +5071,6 @@ packages:
cpu: [x64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5127,12 +5083,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5145,12 +5095,6 @@ packages:
cpu: [x64]
os: [linux]
- '@img/[email protected]':
- resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
'@img/[email protected]':
resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5162,11 +5106,6 @@ packages:
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [wasm32]
- '@img/[email protected]':
- resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [wasm32]
-
'@img/[email protected]':
resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5184,12 +5123,6 @@ packages:
cpu: [ia32]
os: [win32]
- '@img/[email protected]':
- resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [ia32]
- os: [win32]
-
'@img/[email protected]':
resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -5202,12 +5135,6 @@ packages:
cpu: [x64]
os: [win32]
- '@img/[email protected]':
- resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [win32]
-
'@img/[email protected]':
resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -16552,10 +16479,6 @@ packages:
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- [email protected]:
- resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-
[email protected]:
resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -20235,7 +20158,7 @@ snapshots:
'@clerk/shared': 2.20.10([email protected]([email protected]))([email protected])
'@clerk/types': 4.41.1
crypto-js: 4.2.0
- next: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ next: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react: 19.1.0
react-dom: 19.1.0([email protected])
server-only: 0.0.1
@@ -21979,11 +21902,6 @@ snapshots:
'@img/sharp-libvips-darwin-arm64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.2.0
@@ -21994,11 +21912,6 @@ snapshots:
'@img/sharp-libvips-darwin-x64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.2.0
@@ -22007,78 +21920,51 @@ snapshots:
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
@@ -22087,11 +21973,6 @@ snapshots:
'@img/sharp-libvips-linux-arm64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.2.0
@@ -22102,11 +21983,6 @@ snapshots:
'@img/sharp-libvips-linux-arm': 1.0.5
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.2.0
@@ -22122,11 +21998,6 @@ snapshots:
'@img/sharp-libvips-linux-s390x': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.2.0
@@ -22137,11 +22008,6 @@ snapshots:
'@img/sharp-libvips-linux-x64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.2.0
@@ -22152,11 +22018,6 @@ snapshots:
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.2.0
@@ -22167,11 +22028,6 @@ snapshots:
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
optional: true
- '@img/[email protected]':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.1.0
- optional: true
-
'@img/[email protected]':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.2.0
@@ -22182,11 +22038,6 @@ snapshots:
'@emnapi/runtime': 1.4.5
optional: true
- '@img/[email protected]':
- dependencies:
- '@emnapi/runtime': 1.4.5
- optional: true
-
'@img/[email protected]':
dependencies:
'@emnapi/runtime': 1.4.5
@@ -22198,18 +22049,12 @@ snapshots:
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
'@img/[email protected]':
optional: true
- '@img/[email protected]':
- optional: true
-
'@img/[email protected]':
optional: true
@@ -22518,7 +22363,7 @@ snapshots:
'@mapbox/[email protected]([email protected])':
dependencies:
consola: 3.4.2
- detect-libc: 2.0.3
+ detect-libc: 2.0.4
https-proxy-agent: 7.0.6
node-fetch: 2.7.0([email protected])
nopt: 8.0.0
@@ -29407,8 +29252,7 @@ snapshots:
[email protected]: {}
- [email protected]:
- optional: true
+ [email protected]: {}
[email protected]: {}
@@ -30080,7 +29924,7 @@ snapshots:
eslint: 9.25.1([email protected])
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected])))([email protected]([email protected]))
- eslint-plugin-import: 2.31.0(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected])))([email protected]([email protected])))([email protected]([email protected]))
+ eslint-plugin-import: 2.31.0(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected]([email protected]))
eslint-plugin-jsx-a11y: 6.10.2([email protected]([email protected]))
eslint-plugin-react: 7.37.0([email protected]([email protected]))
eslint-plugin-react-hooks: 5.1.0([email protected]([email protected]))
@@ -30104,7 +29948,7 @@ snapshots:
enhanced-resolve: 5.18.0
eslint: 9.25.1([email protected])
eslint-module-utils: 2.12.0(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected])))([email protected]([email protected])))([email protected]([email protected]))
- eslint-plugin-import: 2.31.0(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected])))([email protected]([email protected])))([email protected]([email protected]))
+ eslint-plugin-import: 2.31.0(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected]([email protected]))
fast-glob: 3.3.3
get-tsconfig: 4.10.1
is-core-module: 2.16.1
@@ -30146,7 +29990,7 @@ snapshots:
- supports-color
- typescript
- [email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected])))([email protected]([email protected])))([email protected]([email protected])):
+ [email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected])([email protected]([email protected])):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -34361,7 +34205,7 @@ snapshots:
[email protected]([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]))([email protected]):
dependencies:
'@auth/core': 0.37.2
- next: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ next: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react: 19.1.0
[email protected]([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected])):
@@ -34370,7 +34214,7 @@ snapshots:
'@next/env': 13.5.6
fast-glob: 3.3.3
minimist: 1.2.8
- next: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ next: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
[email protected]([email protected]([email protected]))([email protected]):
dependencies:
@@ -34379,11 +34223,11 @@ snapshots:
[email protected]([email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]):
dependencies:
- next: 15.3.1(@playwright/[email protected])([email protected]([email protected]))([email protected])
+ next: 15.3.1(@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected])
react: 19.1.0
react-dom: 19.1.0([email protected])
- [email protected](@playwright/[email protected])([email protected]([email protected]))([email protected]):
+ [email protected](@babel/[email protected])(@playwright/[email protected])([email protected]([email protected]))([email protected]):
dependencies:
'@next/env': 15.3.1
'@swc/counter': 0.1.3
@@ -34393,7 +34237,7 @@ snapshots:
postcss: 8.4.31
react: 19.1.0
react-dom: 19.1.0([email protected])
- styled-jsx: 5.1.6([email protected])
+ styled-jsx: 5.1.6(@babel/[email protected])([email protected])
optionalDependencies:
'@next/swc-darwin-arm64': 15.3.1
'@next/swc-darwin-x64': 15.3.1
@@ -34404,7 +34248,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 15.3.1
'@next/swc-win32-x64-msvc': 15.3.1
'@playwright/test': 1.52.0
- sharp: 0.34.1
+ sharp: 0.34.3
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
@@ -34417,7 +34261,7 @@ snapshots:
postcss: 8.4.31
react: 19.1.0
react-dom: 19.1.0([email protected])
- styled-jsx: 5.1.6([email protected])
+ styled-jsx: 5.1.6(@babel/[email protected])([email protected])
optionalDependencies:
'@next/swc-darwin-arm64': 15.4.2-canary.51
'@next/swc-darwin-x64': 15.4.2-canary.51
@@ -37542,34 +37386,6 @@ snapshots:
'@img/sharp-win32-ia32': 0.33.5
'@img/sharp-win32-x64': 0.33.5
- [email protected]:
- dependencies:
- color: 4.2.3
- detect-libc: 2.0.3
- semver: 7.7.2
- optionalDependencies:
- '@img/sharp-darwin-arm64': 0.34.1
- '@img/sharp-darwin-x64': 0.34.1
- '@img/sharp-libvips-darwin-arm64': 1.1.0
- '@img/sharp-libvips-darwin-x64': 1.1.0
- '@img/sharp-libvips-linux-arm': 1.1.0
- '@img/sharp-libvips-linux-arm64': 1.1.0
- '@img/sharp-libvips-linux-ppc64': 1.1.0
- '@img/sharp-libvips-linux-s390x': 1.1.0
- '@img/sharp-libvips-linux-x64': 1.1.0
- '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
- '@img/sharp-libvips-linuxmusl-x64': 1.1.0
- '@img/sharp-linux-arm': 0.34.1
- '@img/sharp-linux-arm64': 0.34.1
- '@img/sharp-linux-s390x': 0.34.1
- '@img/sharp-linux-x64': 0.34.1
- '@img/sharp-linuxmusl-arm64': 0.34.1
- '@img/sharp-linuxmusl-x64': 0.34.1
- '@img/sharp-wasm32': 0.34.1
- '@img/sharp-win32-ia32': 0.34.1
- '@img/sharp-win32-x64': 0.34.1
- optional: true
-
[email protected]:
dependencies:
color: 4.2.3
@@ -38015,10 +37831,12 @@ snapshots:
dependencies:
inline-style-parser: 0.2.4
- [email protected]([email protected]):
+ [email protected](@babel/[email protected])([email protected]):
dependencies:
client-only: 0.0.1
react: 19.1.0
+ optionalDependencies:
+ '@babel/core': 7.27.4
[email protected]([email protected]):
dependencies:
AnalysisIn the When the binary data is later reconstructed in For file upload functionality to work correctly, the request body needs to be preserved as binary data throughout the serialization process. The code should use This issue will manifest as corrupted uploaded files or complete upload failures for any non-text file types (images, videos, documents, etc.), which are the primary use case for UploadThing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Request body is converted to text using View Details📝 Patch Detailsdiff --git a/packages/uploadthing/src/convex-helpers.ts b/packages/uploadthing/src/convex-helpers.ts
index caccb1c5..1892097f 100644
--- a/packages/uploadthing/src/convex-helpers.ts
+++ b/packages/uploadthing/src/convex-helpers.ts
@@ -33,11 +33,12 @@ export const createRouteHandler = ({
req.headers.forEach((value, key) => {
headers[key] = value;
});
+ const bodyBuffer = await req.arrayBuffer();
const request = {
url: req.url,
method: req.method,
headers,
- body: await req.text(),
+ body: bodyBuffer.byteLength > 0 ? btoa(String.fromCharCode(...new Uint8Array(bodyBuffer))) : undefined,
};
const response = await ctx.runAction(internalAction, { request });
diff --git a/packages/uploadthing/src/convex.ts b/packages/uploadthing/src/convex.ts
index 75f60db5..96bc0f98 100644
--- a/packages/uploadthing/src/convex.ts
+++ b/packages/uploadthing/src/convex.ts
@@ -55,7 +55,7 @@ export const createInternalAction = <TRouter extends FileRouter>(
const request = new Request(args.request.url, {
method: args.request.method,
headers: new Headers(args.request.headers),
- body: args.request.body ? new Blob([args.request.body]) : null,
+ body: args.request.body ? new Blob([Uint8Array.from(atob(args.request.body), c => c.charCodeAt(0))]) : null,
});
const response = await handler(ctx, request);
AnalysisThe code uses When The correct approach would be to use This bug will cause all file uploads through the Convex adapter to fail with corrupted or invalid file data. |
||
| }; | ||
| const response = await ctx.runAction(internalAction, { request }); | ||
|
|
||
| return new Response(response.body, { | ||
| status: response.status, | ||
| statusText: response.statusText, | ||
| headers: addCorsHeaders(response.headers), | ||
| }); | ||
| }); | ||
|
|
||
| http.route({ | ||
| method: "OPTIONS", | ||
| path: "/api/uploadthing", | ||
| handler: httpActionGeneric(async () => | ||
| Promise.resolve( | ||
| new Response(null, { status: 204, headers: addCorsHeaders() }), | ||
| ), | ||
| ), | ||
| }); | ||
|
|
||
| http.route({ method: "GET", path: "/api/uploadthing", handler }); | ||
|
|
||
| http.route({ method: "POST", path: "/api/uploadthing", handler }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import { internalActionGeneric } from "convex/server"; | ||
| import type { GenericActionCtx, GenericDataModel } from "convex/server"; | ||
| import { v } from "convex/values"; | ||
| import * as Effect from "effect/Effect"; | ||
|
|
||
| import type { Json } from "@uploadthing/shared"; | ||
|
|
||
| import { makeAdapterHandler } from "./_internal/handler"; | ||
| import { createBuilder } from "./_internal/upload-builder"; | ||
| import type { CreateBuilderOptions } from "./_internal/upload-builder"; | ||
| import type { FileRouter, RouteHandlerOptions } from "./types"; | ||
|
|
||
| export { | ||
| UTFiles, | ||
| /** | ||
| * This is an experimental feature. | ||
| * You need to be feature flagged on our backend to use this | ||
| */ | ||
| UTRegion as experimental_UTRegion, | ||
| } from "./_internal/types"; | ||
| export type { FileRouter }; | ||
|
|
||
| type AdapterArgs = { | ||
| ctx: GenericActionCtx<GenericDataModel>; | ||
| req: Request; | ||
| }; | ||
|
|
||
| export const createUploadthing = <TErrorShape extends Json>( | ||
| opts?: CreateBuilderOptions<TErrorShape>, | ||
| ) => createBuilder<AdapterArgs, TErrorShape>(opts); | ||
|
|
||
| export const createInternalAction = <TRouter extends FileRouter>( | ||
| opts: RouteHandlerOptions<TRouter>, | ||
| ) => { | ||
| const handler = makeAdapterHandler< | ||
| [GenericActionCtx<GenericDataModel>, Request], | ||
| AdapterArgs | ||
| >( | ||
| (ctx, req) => Effect.succeed({ ctx, req }), | ||
| (_, req) => Effect.succeed(req), | ||
| opts, | ||
| "convex", | ||
| ); | ||
|
|
||
| return internalActionGeneric({ | ||
| args: { | ||
| request: v.object({ | ||
| url: v.string(), | ||
| method: v.string(), | ||
| headers: v.record(v.string(), v.string()), | ||
| body: v.optional(v.string()), | ||
| }), | ||
| }, | ||
| handler: async (ctx: GenericActionCtx<GenericDataModel>, args) => { | ||
| const request = new Request(args.request.url, { | ||
| method: args.request.method, | ||
| headers: new Headers(args.request.headers), | ||
| body: args.request.body ? new Blob([args.request.body]) : null, | ||
| }); | ||
|
|
||
| const response = await handler(ctx, request); | ||
|
|
||
| const headers: Record<string, string> = {}; | ||
| response.headers.forEach((value, key) => { | ||
| headers[key] = value; | ||
| }); | ||
|
|
||
| return { | ||
| status: response.status, | ||
| statusText: response.statusText, | ||
| headers, | ||
| body: await response.text(), | ||
| }; | ||
| }, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
CORS: avoid "*" in Allow-Headers; add Vary and echo requested headers.
Using "*" in Access-Control-Allow-Headers is not consistently honored. Echo Access-Control-Request-Headers and set Vary for cache correctness.
📝 Committable suggestion
🤖 Prompt for AI Agents