@mentra/crust 3.4.0-dev.1009 → 3.4.0-dev.1017
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.
|
@@ -54,6 +54,10 @@ class FetchBridgeTest {
|
|
|
54
54
|
private val utf8Bytes = byteArrayOf(0xEF.toByte(), 0xBB.toByte(), 0xBF.toByte()) +
|
|
55
55
|
"{\"a\":\"é😀\"}".toByteArray(Charsets.UTF_8) + byteArrayOf(0x00, 0x7F)
|
|
56
56
|
|
|
57
|
+
/** Two MB of valid UTF-8 text: arrayBuffer() re-encodes it inside the 32 MB miniapp heap. */
|
|
58
|
+
private val largeUtf8Text: ByteArray =
|
|
59
|
+
"héllo 😀 中文 chunk of reply text ".repeat(52_000).toByteArray(Charsets.UTF_8)
|
|
60
|
+
|
|
57
61
|
// crust's build.gradle ships this file as the runtime's startup.js asset.
|
|
58
62
|
private val polyfill: String by lazy { File("../../jspolyfill/assets/startup.js").readText() }
|
|
59
63
|
|
|
@@ -63,6 +67,7 @@ class FetchBridgeTest {
|
|
|
63
67
|
override fun dispatch(request: RecordedRequest): MockResponse = when (request.path) {
|
|
64
68
|
"/reply.pcm" -> response("application/octet-stream").setBody(Buffer().write(pcm))
|
|
65
69
|
"/utf8.bin" -> response("application/octet-stream").setBody(Buffer().write(utf8Bytes))
|
|
70
|
+
"/large.txt" -> response("text/plain").setBody(Buffer().write(largeUtf8Text))
|
|
66
71
|
"/data.json" -> response("application/json").setBody("{\"message\":\"héllo 😀 中文\"}")
|
|
67
72
|
"/upload" -> response("text/plain").setBody("ok")
|
|
68
73
|
else -> MockResponse().setResponseCode(404)
|
|
@@ -108,6 +113,21 @@ class FetchBridgeTest {
|
|
|
108
113
|
assertArrayEquals(utf8Bytes, bytes(result["bytes"]))
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
@Test fun `arrayBuffer re-encodes a large UTF-8 body within the miniapp heap`() {
|
|
117
|
+
val result = runMiniapp(
|
|
118
|
+
"""
|
|
119
|
+
const bytes = new Uint8Array(await (await fetch(BASE + "/large.txt")).arrayBuffer())
|
|
120
|
+
let sum = 0
|
|
121
|
+
for (let i = 0; i < bytes.length; i++) sum = (sum * 31 + bytes[i]) >>> 0
|
|
122
|
+
return {length: bytes.length, sum}
|
|
123
|
+
""",
|
|
124
|
+
)
|
|
125
|
+
var sum = 0L
|
|
126
|
+
for (byte in largeUtf8Text) sum = (sum * 31 + (byte.toInt() and 0xFF)) and 0xFFFFFFFFL
|
|
127
|
+
assertEquals(largeUtf8Text.size, (result["length"] as Number).toInt())
|
|
128
|
+
assertEquals(sum, (result["sum"] as Number).toLong())
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
@Test fun `responses are sent as text only when that text re-encodes to the same bytes`() {
|
|
112
132
|
val text = JSCPolyfillBridge.fetchResult(responseWith(utf8Bytes))
|
|
113
133
|
assertEquals(String(utf8Bytes, Charsets.UTF_8), text.getString("body"))
|
package/ios/Resources/startup.js
CHANGED
|
@@ -571,38 +571,48 @@
|
|
|
571
571
|
return parts.join("");
|
|
572
572
|
}
|
|
573
573
|
if (typeof g.TextEncoder !== "function") {
|
|
574
|
+
const codePointAt = (str, i) => {
|
|
575
|
+
const code = str.charCodeAt(i);
|
|
576
|
+
if (code >= 55296 && code <= 56319 && i + 1 < str.length) {
|
|
577
|
+
const next = str.charCodeAt(i + 1);
|
|
578
|
+
if (next >= 56320 && next <= 57343) return (code - 55296 << 10) + (next - 56320) + 65536;
|
|
579
|
+
}
|
|
580
|
+
return code;
|
|
581
|
+
};
|
|
574
582
|
class TextEncoderPolyfill {
|
|
575
583
|
constructor() {
|
|
576
584
|
this.encoding = "utf-8";
|
|
577
585
|
}
|
|
578
586
|
encode(input) {
|
|
579
587
|
const str = input ?? "";
|
|
580
|
-
|
|
588
|
+
let length = 0;
|
|
581
589
|
for (let i = 0; i < str.length; i++) {
|
|
582
|
-
|
|
583
|
-
if (code
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
+
const code = codePointAt(str, i);
|
|
591
|
+
if (code > 65535) i++;
|
|
592
|
+
length += code < 128 ? 1 : code < 2048 ? 2 : code < 65536 ? 3 : 4;
|
|
593
|
+
}
|
|
594
|
+
const out = new Uint8Array(length);
|
|
595
|
+
let at = 0;
|
|
596
|
+
for (let i = 0; i < str.length; i++) {
|
|
597
|
+
const code = codePointAt(str, i);
|
|
598
|
+
if (code > 65535) i++;
|
|
590
599
|
if (code < 128) {
|
|
591
|
-
out
|
|
600
|
+
out[at++] = code;
|
|
592
601
|
} else if (code < 2048) {
|
|
593
|
-
out
|
|
602
|
+
out[at++] = 192 | code >> 6;
|
|
603
|
+
out[at++] = 128 | code & 63;
|
|
594
604
|
} else if (code < 65536) {
|
|
595
|
-
out
|
|
605
|
+
out[at++] = 224 | code >> 12;
|
|
606
|
+
out[at++] = 128 | code >> 6 & 63;
|
|
607
|
+
out[at++] = 128 | code & 63;
|
|
596
608
|
} else {
|
|
597
|
-
out
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
128 | code & 63
|
|
602
|
-
);
|
|
609
|
+
out[at++] = 240 | code >> 18;
|
|
610
|
+
out[at++] = 128 | code >> 12 & 63;
|
|
611
|
+
out[at++] = 128 | code >> 6 & 63;
|
|
612
|
+
out[at++] = 128 | code & 63;
|
|
603
613
|
}
|
|
604
614
|
}
|
|
605
|
-
return
|
|
615
|
+
return out;
|
|
606
616
|
}
|
|
607
617
|
}
|
|
608
618
|
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/crust",
|
|
3
|
-
"version": "3.4.0-dev.
|
|
3
|
+
"version": "3.4.0-dev.1017",
|
|
4
4
|
"description": "Mentra Native Module",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"license": "Apache-2.0",
|
|
36
36
|
"homepage": "https://github.com/Mentra-Community/MentraOS/tree/dev/mobile/modules/crust#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@mentra/jspolyfill": "3.4.0-dev.
|
|
38
|
+
"@mentra/jspolyfill": "3.4.0-dev.1017"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@expo/config-plugins": ">=8.0.0",
|