@mentra/crust 3.3.0-dev.839 → 3.3.0-dev.840

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/README.md CHANGED
@@ -58,3 +58,11 @@ shutdown cancels only that module's outstanding host requests.
58
58
 
59
59
  Engine callers use the ordinary cloud-client API with a signal. They do not call
60
60
  native start/cancel methods or maintain their own request registry.
61
+
62
+ Android native HTTP failures carry fixed `E_NATIVE_HTTP_*` codes for DNS,
63
+ connection, timeout, TLS, socket, interrupted I/O, generic I/O, or other failures.
64
+ The cloud client records only those allowlisted codes in its existing network
65
+ warning; report submission still rejects with `NETWORK_ERROR`. Exception text,
66
+ URLs, credentials and stacks are not copied into that warning. These categories
67
+ describe a failed request; they do not establish the phone's network routing or
68
+ why its Internet connection was unavailable.
@@ -23,6 +23,7 @@ import com.mentra.crust.jsc.JSCRuntime
23
23
  import com.mentra.crust.jsc.InstalledMiniappManifest
24
24
  import com.mentra.crust.jsc.JSCPolyfillBridge
25
25
  import com.mentra.crust.http.NativeHttpRequests
26
+ import com.mentra.crust.http.nativeHttpFailureCode
26
27
 
27
28
  class CrustModule : Module() {
28
29
  companion object {
@@ -210,7 +211,7 @@ class CrustModule : Module() {
210
211
  )
211
212
  )
212
213
  },
213
- onError = { error -> promise.reject("E_NATIVE_HTTP", error.message ?: "Native HTTP request failed", error) },
214
+ onError = { error -> promise.reject(nativeHttpFailureCode(error), error.message ?: "Native HTTP request failed", error) },
214
215
  )
215
216
  }
216
217
 
@@ -0,0 +1,31 @@
1
+ package com.mentra.crust.http
2
+
3
+ import java.io.IOException
4
+ import java.io.InterruptedIOException
5
+ import java.net.ConnectException
6
+ import java.net.NoRouteToHostException
7
+ import java.net.SocketException
8
+ import java.net.SocketTimeoutException
9
+ import java.net.UnknownHostException
10
+ import javax.net.ssl.SSLException
11
+
12
+ /** Fixed diagnostic codes only: exception messages can contain private URLs and addresses. */
13
+ internal fun nativeHttpFailureCode(error: Throwable): String {
14
+ var current: Throwable? = error
15
+ var fallback = "E_NATIVE_HTTP_OTHER"
16
+ // Native wrappers can retain the useful cause. Bound traversal even for a cyclic cause chain.
17
+ repeat(8) {
18
+ val cause = current ?: return fallback
19
+ when (cause) {
20
+ is UnknownHostException -> return "E_NATIVE_HTTP_DNS"
21
+ is SocketTimeoutException -> return "E_NATIVE_HTTP_TIMEOUT"
22
+ is SSLException -> return "E_NATIVE_HTTP_TLS"
23
+ is ConnectException, is NoRouteToHostException -> return "E_NATIVE_HTTP_CONNECT"
24
+ is SocketException -> return "E_NATIVE_HTTP_SOCKET"
25
+ is InterruptedIOException -> return "E_NATIVE_HTTP_INTERRUPTED"
26
+ is IOException -> fallback = "E_NATIVE_HTTP_IO"
27
+ }
28
+ current = cause.cause
29
+ }
30
+ return fallback
31
+ }
@@ -0,0 +1,44 @@
1
+ package com.mentra.crust.http
2
+
3
+ import java.io.IOException
4
+ import java.io.InterruptedIOException
5
+ import java.net.ConnectException
6
+ import java.net.NoRouteToHostException
7
+ import java.net.SocketException
8
+ import java.net.SocketTimeoutException
9
+ import java.net.UnknownHostException
10
+ import javax.net.ssl.SSLHandshakeException
11
+ import org.junit.Assert.assertEquals
12
+ import org.junit.Test
13
+
14
+ class NativeHttpFailureTest {
15
+ @Test fun `preserves failure category without exception text`() {
16
+ val privateMessage = "https://private.example?token=secret SSID private-address"
17
+ val cases = listOf(
18
+ UnknownHostException(privateMessage) to "E_NATIVE_HTTP_DNS",
19
+ ConnectException(privateMessage) to "E_NATIVE_HTTP_CONNECT",
20
+ NoRouteToHostException(privateMessage) to "E_NATIVE_HTTP_CONNECT",
21
+ SocketTimeoutException(privateMessage) to "E_NATIVE_HTTP_TIMEOUT",
22
+ SSLHandshakeException(privateMessage) to "E_NATIVE_HTTP_TLS",
23
+ SocketException(privateMessage) to "E_NATIVE_HTTP_SOCKET",
24
+ InterruptedIOException(privateMessage) to "E_NATIVE_HTTP_INTERRUPTED",
25
+ IOException(privateMessage) to "E_NATIVE_HTTP_IO",
26
+ IllegalStateException(privateMessage) to "E_NATIVE_HTTP_OTHER",
27
+ )
28
+ cases.forEach { (error, expected) -> assertEquals(expected, nativeHttpFailureCode(error)) }
29
+ }
30
+
31
+ @Test fun `retains a specific cause inside a generic native wrapper`() {
32
+ val wrapped = IOException("private wrapper", UnknownHostException("private hostname"))
33
+ assertEquals("E_NATIVE_HTTP_DNS", nativeHttpFailureCode(wrapped))
34
+ assertEquals("E_NATIVE_HTTP_IO", nativeHttpFailureCode(IllegalStateException(IOException("private"))))
35
+ }
36
+
37
+ @Test fun `never parses a category from private error text and bounds cyclic causes`() {
38
+ assertEquals("E_NATIVE_HTTP_OTHER", nativeHttpFailureCode(Exception("E_NATIVE_HTTP_DNS")))
39
+ val first = Exception("private one")
40
+ val second = Exception("private two", first)
41
+ first.initCause(second)
42
+ assertEquals("E_NATIVE_HTTP_OTHER", nativeHttpFailureCode(first))
43
+ }
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/crust",
3
- "version": "3.3.0-dev.839",
3
+ "version": "3.3.0-dev.840",
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.3.0-dev.839"
38
+ "@mentra/jspolyfill": "3.3.0-dev.840"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@expo/config-plugins": ">=8.0.0",