@@ -1166,21 +1166,75 @@ export class Connection {
11661166 // Workaround for ArangoDB 3.12.0-rc1 and earlier:
11671167 // Omitting the final CRLF results in "bad request body" fatal error
11681168 body = new Blob ( [ blob , "\r\n" ] , { type : blob . type } ) ;
1169- } else if ( body ) {
1170- let contentType ;
1171- if ( isBinary ) {
1172- contentType = "application/octet-stream" ;
1173- } else if ( typeof body === "object" ) {
1174- body = JSON . stringify ( body ) ;
1175- contentType = "application/json" ;
1176- } else {
1177- body = String ( body ) ;
1178- contentType = "text/plain" ;
1169+ // Set content-length for Blob (needed for Next.js dynamic routes)
1170+ if ( ! headers . has ( "content-length" ) ) {
1171+ headers . set ( "content-length" , String ( body . size ) ) ;
11791172 }
1180- if ( ! headers . has ( "content-type" ) ) {
1181- headers . set ( "content-type" , contentType ) ;
1173+ } else if ( body !== null && body !== undefined ) {
1174+ // Handle empty string explicitly
1175+ if ( body === "" ) {
1176+ if ( ! headers . has ( "content-length" ) ) {
1177+ headers . set ( "content-length" , "0" ) ;
1178+ }
1179+ if ( ! headers . has ( "content-type" ) ) {
1180+ headers . set ( "content-type" , "text/plain" ) ;
1181+ }
1182+ } else {
1183+ let contentType ;
1184+ if ( isBinary ) {
1185+ contentType = "application/octet-stream" ;
1186+ } else if ( typeof body === "object" ) {
1187+ body = JSON . stringify ( body ) ;
1188+ contentType = "application/json" ;
1189+ } else {
1190+ body = String ( body ) ;
1191+ contentType = "text/plain" ;
1192+ }
1193+ if ( ! headers . has ( "content-type" ) ) {
1194+ headers . set ( "content-type" , contentType ) ;
1195+ }
1196+ // Explicitly set content-length for fixed-size bodies
1197+ // This is needed for Next.js dynamic routes (e.g., when using cookies())
1198+ // and ensures compatibility with environments that don't set it automatically
1199+ if ( ! headers . has ( "content-length" ) ) {
1200+ if ( typeof body === "string" ) {
1201+ // Calculate byte length for UTF-8 encoded strings
1202+ // Buffer is available in Node.js (required: >=20) and browser polyfills
1203+ if (
1204+ typeof globalThis . Buffer !== "undefined" &&
1205+ globalThis . Buffer . byteLength
1206+ ) {
1207+ const contentLength = globalThis . Buffer . byteLength ( body , "utf8" ) ;
1208+ headers . set ( "content-length" , String ( contentLength ) ) ;
1209+ } else {
1210+ // Fallback: use TextEncoder for browser environments
1211+ const encoder = new TextEncoder ( ) ;
1212+ const contentLength = encoder . encode ( body ) . length ;
1213+ headers . set ( "content-length" , String ( contentLength ) ) ;
1214+ }
1215+ } else if ( body instanceof Blob ) {
1216+ headers . set ( "content-length" , String ( body . size ) ) ;
1217+ } else if (
1218+ typeof globalThis . Buffer !== "undefined" &&
1219+ globalThis . Buffer . isBuffer &&
1220+ globalThis . Buffer . isBuffer ( body )
1221+ ) {
1222+ headers . set ( "content-length" , String ( body . length ) ) ;
1223+ }
1224+ // Note: ArangoDB does not support Transfer-Encoding: chunked.
1225+ // All public APIs only accept fixed-size bodies (string, Buffer, Blob, FormData, or objects that get JSON.stringify'd),
1226+ // so streams should never reach this point. If an unknown body type is passed, it will be converted to string above.
1227+ }
11821228 }
11831229 }
1230+ // Handle null/undefined body for POST/PUT/PATCH methods that might need content-length: 0
1231+ // This ensures compatibility with NextJS 15 and other environments that expect explicit content-length
1232+ else if (
1233+ ( method === "POST" || method === "PUT" || method === "PATCH" ) &&
1234+ ! headers . has ( "content-length" )
1235+ ) {
1236+ headers . set ( "content-length" , "0" ) ;
1237+ }
11841238
11851239 if ( this . _transactionId ) {
11861240 headers . set ( "x-arango-trx-id" , this . _transactionId ) ;
0 commit comments