Skip to content

Commit 1dd6ace

Browse files
authored
fix(fetch-http-handler): add polyfill to collect Blob in react-native (#1483)
1 parent b2d54aa commit 1dd6ace

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

.changeset/metal-emus-chew.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/fetch-http-handler": patch
3+
---
4+
5+
Add polyfill to collect Blob in react-native environments

packages/fetch-http-handler/src/stream-collector.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
import { StreamCollector } from "@smithy/types";
2+
import { fromBase64 } from "@smithy/util-base64";
23

34
export const streamCollector: StreamCollector = async (stream: Blob | ReadableStream): Promise<Uint8Array> => {
45
if ((typeof Blob === "function" && stream instanceof Blob) || stream.constructor?.name === "Blob") {
5-
return new Uint8Array(await (stream as Blob).arrayBuffer());
6+
if (Blob.prototype.arrayBuffer !== undefined) {
7+
return new Uint8Array(await (stream as Blob).arrayBuffer());
8+
}
9+
return collectBlob(stream as Blob);
610
}
711

812
return collectStream(stream as ReadableStream);
913
};
1014

15+
async function collectBlob(blob: Blob): Promise<Uint8Array> {
16+
const base64 = await readToBase64(blob);
17+
const arrayBuffer = fromBase64(base64);
18+
return new Uint8Array(arrayBuffer);
19+
}
20+
1121
async function collectStream(stream: ReadableStream): Promise<Uint8Array> {
1222
const chunks = [];
1323
const reader = stream.getReader();
@@ -32,3 +42,26 @@ async function collectStream(stream: ReadableStream): Promise<Uint8Array> {
3242

3343
return collected;
3444
}
45+
46+
function readToBase64(blob: Blob): Promise<string> {
47+
return new Promise((resolve, reject) => {
48+
const reader = new FileReader();
49+
reader.onloadend = () => {
50+
// reference: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
51+
// response from readAsDataURL is always prepended with "data:*/*;base64,"
52+
if (reader.readyState !== 2) {
53+
return reject(new Error("Reader aborted too early"));
54+
}
55+
const result = (reader.result ?? "") as string;
56+
// Response can include only 'data:' for empty blob, return empty string in this case.
57+
// Otherwise, return the string after ','
58+
const commaIndex = result.indexOf(",");
59+
const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
60+
resolve(result.substring(dataOffset));
61+
};
62+
reader.onabort = () => reject(new Error("Read aborted"));
63+
reader.onerror = () => reject(reader.error);
64+
// reader.readAsArrayBuffer is not always available
65+
reader.readAsDataURL(blob);
66+
});
67+
}

0 commit comments

Comments
 (0)