Skip to content

Commit 9556d72

Browse files
MaxwellCalkinclaude
andcommitted
fix: add stream duplex handling to uploadToSignedUrl
The raw-body path in uploadToSignedUrl was missing the stream detection and duplex: 'half' propagation that uploadOrUpdate already has. Without this, passing a ReadableStream or Node.js stream to uploadToSignedUrl fails on Node 20+ fetch which requires duplex: 'half' for stream bodies. Mirrors the exact pattern from uploadOrUpdate (lines 121-142) into uploadToSignedUrl for consistency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 71d1ab9 commit 9556d72

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

packages/core/storage-js/src/packages/StorageFileApi.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,26 @@ export default class StorageFileApi extends BaseApiClient<StorageError> {
287287
if (metadata) {
288288
headers['x-metadata'] = this.toBase64(this.encodeMetadata(metadata))
289289
}
290+
291+
// Node.js streams require duplex option for fetch in Node 20+
292+
// Check for both web ReadableStream and Node.js streams
293+
const isStream =
294+
(typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) ||
295+
(body && typeof body === 'object' && 'pipe' in body && typeof body.pipe === 'function')
296+
297+
if (isStream && !options.duplex) {
298+
options.duplex = 'half'
299+
}
290300
}
291301

292302
if (fileOptions?.headers) {
293303
headers = { ...headers, ...fileOptions.headers }
294304
}
295305

296-
const data = await put(this.fetch, url.toString(), body as object, { headers })
306+
const data = await put(this.fetch, url.toString(), body as object, {
307+
headers,
308+
...(options?.duplex ? { duplex: options.duplex } : {}),
309+
})
297310

298311
return { path: cleanPath, fullPath: data.Key }
299312
})

0 commit comments

Comments
 (0)