@sogni-ai/expo-client 1.0.0-alpha.13 → 1.0.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/lib/mediaInput.d.ts +15 -5
- package/dist/cjs/lib/mediaInput.d.ts.map +1 -1
- package/dist/cjs/lib/mediaInput.js +23 -8
- package/dist/cjs/lib/mediaInput.js.map +1 -1
- package/dist/esm/lib/mediaInput.js +23 -8
- package/dist/esm/lib/mediaInput.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/mediaInput.ts +25 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.0.0-alpha.14](https://github.com/Sogni-AI/expo-client/compare/v1.0.0-alpha.13...v1.0.0-alpha.14) (2026-05-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **media:** read upload bytes via arrayBuffer, not Blob ([90f99c5](https://github.com/Sogni-AI/expo-client/commit/90f99c532f888b0ec50a2bb9cca9a2fc84418cae))
|
|
7
|
+
|
|
1
8
|
# [1.0.0-alpha.13](https://github.com/Sogni-AI/expo-client/compare/v1.0.0-alpha.12...v1.0.0-alpha.13) (2026-05-12)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -22,12 +22,22 @@ export interface MediaInputBody {
|
|
|
22
22
|
/**
|
|
23
23
|
* Convert a MediaInput into a fetch body for upload to a presigned PUT URL.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* Reads the URI via `fetch(uri).arrayBuffer()` and hands back a `Uint8Array`.
|
|
26
|
+
* We deliberately avoid `res.blob()` here for two reasons:
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* 1. React Native's `Blob` is a minimal polyfill without `.text()` or
|
|
29
|
+
* `.arrayBuffer()` (see `Libraries/Blob/Blob.js`), so working with the
|
|
30
|
+
* raw bytes is more portable than rolling with a Blob whose surface
|
|
31
|
+
* depends on platform version.
|
|
32
|
+
* 2. On iOS PhotoKit (`ph://`) URIs, `res.blob()` has been observed to
|
|
33
|
+
* silently return a 0-byte blob — we'd PUT an empty body and the server
|
|
34
|
+
* would store a corrupted image. Reading as an ArrayBuffer makes the
|
|
35
|
+
* byte count visible and lets us throw on empty input.
|
|
36
|
+
*
|
|
37
|
+
* For very large files (videos, raw audio), this buffers the whole payload
|
|
38
|
+
* in JS memory. Acceptable for typical image / short audio reference
|
|
39
|
+
* uploads. If you have raw bytes already (e.g. from `expo-file-system`),
|
|
40
|
+
* pass `Uint8Array` directly to skip the fetch.
|
|
31
41
|
*/
|
|
32
42
|
export declare function toFetchBody(input: MediaInput, contentTypeOverride?: string): Promise<MediaInputBody>;
|
|
33
43
|
//# sourceMappingURL=mediaInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaInput.d.ts","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,IAAI,aAAa,CAEzE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED
|
|
1
|
+
{"version":3,"file":"mediaInput.d.ts","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,IAAI,aAAa,CAEzE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,UAAU,EACjB,mBAAmB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,cAAc,CAAC,CAoBzB"}
|
|
@@ -8,12 +8,22 @@ function isMediaInputUri(input) {
|
|
|
8
8
|
/**
|
|
9
9
|
* Convert a MediaInput into a fetch body for upload to a presigned PUT URL.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Reads the URI via `fetch(uri).arrayBuffer()` and hands back a `Uint8Array`.
|
|
12
|
+
* We deliberately avoid `res.blob()` here for two reasons:
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* 1. React Native's `Blob` is a minimal polyfill without `.text()` or
|
|
15
|
+
* `.arrayBuffer()` (see `Libraries/Blob/Blob.js`), so working with the
|
|
16
|
+
* raw bytes is more portable than rolling with a Blob whose surface
|
|
17
|
+
* depends on platform version.
|
|
18
|
+
* 2. On iOS PhotoKit (`ph://`) URIs, `res.blob()` has been observed to
|
|
19
|
+
* silently return a 0-byte blob — we'd PUT an empty body and the server
|
|
20
|
+
* would store a corrupted image. Reading as an ArrayBuffer makes the
|
|
21
|
+
* byte count visible and lets us throw on empty input.
|
|
22
|
+
*
|
|
23
|
+
* For very large files (videos, raw audio), this buffers the whole payload
|
|
24
|
+
* in JS memory. Acceptable for typical image / short audio reference
|
|
25
|
+
* uploads. If you have raw bytes already (e.g. from `expo-file-system`),
|
|
26
|
+
* pass `Uint8Array` directly to skip the fetch.
|
|
17
27
|
*/
|
|
18
28
|
async function toFetchBody(input, contentTypeOverride) {
|
|
19
29
|
if (input instanceof Uint8Array) {
|
|
@@ -23,10 +33,15 @@ async function toFetchBody(input, contentTypeOverride) {
|
|
|
23
33
|
if (!res.ok) {
|
|
24
34
|
throw new Error(`Failed to read media at ${input.uri}: HTTP ${res.status}`);
|
|
25
35
|
}
|
|
26
|
-
const
|
|
36
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
37
|
+
if (arrayBuffer.byteLength === 0) {
|
|
38
|
+
throw new Error(`Read 0 bytes from ${input.uri}. On iOS, ph:// PhotoKit URIs sometimes return empty bodies — copy the asset to a file:// path first (e.g. via expo-image-picker with allowsEditing or expo-image-manipulator).`);
|
|
39
|
+
}
|
|
40
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
41
|
+
const responseContentType = res.headers.get('content-type') ?? undefined;
|
|
27
42
|
return {
|
|
28
|
-
body:
|
|
29
|
-
contentType: contentTypeOverride ?? input.type ??
|
|
43
|
+
body: bytes,
|
|
44
|
+
contentType: contentTypeOverride ?? input.type ?? responseContentType
|
|
30
45
|
};
|
|
31
46
|
}
|
|
32
47
|
//# sourceMappingURL=mediaInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaInput.js","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":";;AAkBA,0CAEC;
|
|
1
|
+
{"version":3,"file":"mediaInput.js","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":";;AAkBA,0CAEC;AA2BD,kCAuBC;AApDD,SAAgB,eAAe,CAAC,KAAiB;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC;AACrD,CAAC;AAOD;;;;;;;;;;;;;;;;;;;GAmBG;AACI,KAAK,UAAU,WAAW,CAC/B,KAAiB,EACjB,mBAA4B;IAE5B,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,KAA4B,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;IAClF,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,CAAC,GAAG,UAAU,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,WAAW,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,GAAG,iLAAiL,CAChN,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC;IACzE,OAAO;QACL,IAAI,EAAE,KAA4B;QAClC,WAAW,EAAE,mBAAmB,IAAI,KAAK,CAAC,IAAI,IAAI,mBAAmB;KACtE,CAAC;AACJ,CAAC"}
|
|
@@ -4,12 +4,22 @@ export function isMediaInputUri(input) {
|
|
|
4
4
|
/**
|
|
5
5
|
* Convert a MediaInput into a fetch body for upload to a presigned PUT URL.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Reads the URI via `fetch(uri).arrayBuffer()` and hands back a `Uint8Array`.
|
|
8
|
+
* We deliberately avoid `res.blob()` here for two reasons:
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* 1. React Native's `Blob` is a minimal polyfill without `.text()` or
|
|
11
|
+
* `.arrayBuffer()` (see `Libraries/Blob/Blob.js`), so working with the
|
|
12
|
+
* raw bytes is more portable than rolling with a Blob whose surface
|
|
13
|
+
* depends on platform version.
|
|
14
|
+
* 2. On iOS PhotoKit (`ph://`) URIs, `res.blob()` has been observed to
|
|
15
|
+
* silently return a 0-byte blob — we'd PUT an empty body and the server
|
|
16
|
+
* would store a corrupted image. Reading as an ArrayBuffer makes the
|
|
17
|
+
* byte count visible and lets us throw on empty input.
|
|
18
|
+
*
|
|
19
|
+
* For very large files (videos, raw audio), this buffers the whole payload
|
|
20
|
+
* in JS memory. Acceptable for typical image / short audio reference
|
|
21
|
+
* uploads. If you have raw bytes already (e.g. from `expo-file-system`),
|
|
22
|
+
* pass `Uint8Array` directly to skip the fetch.
|
|
13
23
|
*/
|
|
14
24
|
export async function toFetchBody(input, contentTypeOverride) {
|
|
15
25
|
if (input instanceof Uint8Array) {
|
|
@@ -19,10 +29,15 @@ export async function toFetchBody(input, contentTypeOverride) {
|
|
|
19
29
|
if (!res.ok) {
|
|
20
30
|
throw new Error(`Failed to read media at ${input.uri}: HTTP ${res.status}`);
|
|
21
31
|
}
|
|
22
|
-
const
|
|
32
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
33
|
+
if (arrayBuffer.byteLength === 0) {
|
|
34
|
+
throw new Error(`Read 0 bytes from ${input.uri}. On iOS, ph:// PhotoKit URIs sometimes return empty bodies — copy the asset to a file:// path first (e.g. via expo-image-picker with allowsEditing or expo-image-manipulator).`);
|
|
35
|
+
}
|
|
36
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
37
|
+
const responseContentType = res.headers.get('content-type') ?? undefined;
|
|
23
38
|
return {
|
|
24
|
-
body:
|
|
25
|
-
contentType: contentTypeOverride ?? input.type ??
|
|
39
|
+
body: bytes,
|
|
40
|
+
contentType: contentTypeOverride ?? input.type ?? responseContentType
|
|
26
41
|
};
|
|
27
42
|
}
|
|
28
43
|
//# sourceMappingURL=mediaInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaInput.js","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC;AACrD,CAAC;AAOD
|
|
1
|
+
{"version":3,"file":"mediaInput.js","sourceRoot":"","sources":["../../../src/lib/mediaInput.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC;AACrD,CAAC;AAOD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAiB,EACjB,mBAA4B;IAE5B,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,KAA4B,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;IAClF,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,CAAC,GAAG,UAAU,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,WAAW,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,GAAG,iLAAiL,CAChN,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC;IACzE,OAAO;QACL,IAAI,EAAE,KAA4B;QAClC,WAAW,EAAE,mBAAmB,IAAI,KAAK,CAAC,IAAI,IAAI,mBAAmB;KACtE,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/lib/mediaInput.ts
CHANGED
|
@@ -28,12 +28,22 @@ export interface MediaInputBody {
|
|
|
28
28
|
/**
|
|
29
29
|
* Convert a MediaInput into a fetch body for upload to a presigned PUT URL.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* Reads the URI via `fetch(uri).arrayBuffer()` and hands back a `Uint8Array`.
|
|
32
|
+
* We deliberately avoid `res.blob()` here for two reasons:
|
|
33
33
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* 1. React Native's `Blob` is a minimal polyfill without `.text()` or
|
|
35
|
+
* `.arrayBuffer()` (see `Libraries/Blob/Blob.js`), so working with the
|
|
36
|
+
* raw bytes is more portable than rolling with a Blob whose surface
|
|
37
|
+
* depends on platform version.
|
|
38
|
+
* 2. On iOS PhotoKit (`ph://`) URIs, `res.blob()` has been observed to
|
|
39
|
+
* silently return a 0-byte blob — we'd PUT an empty body and the server
|
|
40
|
+
* would store a corrupted image. Reading as an ArrayBuffer makes the
|
|
41
|
+
* byte count visible and lets us throw on empty input.
|
|
42
|
+
*
|
|
43
|
+
* For very large files (videos, raw audio), this buffers the whole payload
|
|
44
|
+
* in JS memory. Acceptable for typical image / short audio reference
|
|
45
|
+
* uploads. If you have raw bytes already (e.g. from `expo-file-system`),
|
|
46
|
+
* pass `Uint8Array` directly to skip the fetch.
|
|
37
47
|
*/
|
|
38
48
|
export async function toFetchBody(
|
|
39
49
|
input: MediaInput,
|
|
@@ -46,9 +56,16 @@ export async function toFetchBody(
|
|
|
46
56
|
if (!res.ok) {
|
|
47
57
|
throw new Error(`Failed to read media at ${input.uri}: HTTP ${res.status}`);
|
|
48
58
|
}
|
|
49
|
-
const
|
|
59
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
60
|
+
if (arrayBuffer.byteLength === 0) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Read 0 bytes from ${input.uri}. On iOS, ph:// PhotoKit URIs sometimes return empty bodies — copy the asset to a file:// path first (e.g. via expo-image-picker with allowsEditing or expo-image-manipulator).`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
66
|
+
const responseContentType = res.headers.get('content-type') ?? undefined;
|
|
50
67
|
return {
|
|
51
|
-
body:
|
|
52
|
-
contentType: contentTypeOverride ?? input.type ??
|
|
68
|
+
body: bytes as unknown as BodyInit,
|
|
69
|
+
contentType: contentTypeOverride ?? input.type ?? responseContentType
|
|
53
70
|
};
|
|
54
71
|
}
|