@mentra/crust 3.2.1-beta.550 → 3.2.1-beta.570

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.
@@ -8,6 +8,12 @@ import expo.modules.kotlin.modules.Module
8
8
  import expo.modules.kotlin.modules.ModuleDefinition
9
9
  import expo.modules.kotlin.functions.Queues
10
10
  import java.net.URL
11
+ import java.util.concurrent.Executors
12
+ import kotlinx.coroutines.CoroutineName
13
+ import kotlinx.coroutines.CoroutineScope
14
+ import kotlinx.coroutines.SupervisorJob
15
+ import kotlinx.coroutines.asCoroutineDispatcher
16
+ import kotlinx.coroutines.cancel
11
17
 
12
18
  import com.mentra.crust.navigation.NavigationManager
13
19
  import com.mentra.crust.heading.HeadingManager
@@ -77,6 +83,22 @@ class CrustModule : Module() {
77
83
  // __dispatch from a per-miniapp QuickJS context (SUBSCRIBE, mic, location,
78
84
  // display, send, etc.) would be silently dropped on Android.
79
85
  @Volatile private var runtimeInstalled: Boolean = false
86
+
87
+ // MentraJS calls get their own serial queue. Expo runs every module's default-queue
88
+ // AsyncFunction on one shared thread, so a blocking call in another module held every
89
+ // host→miniapp message behind it: the ACS scoped Wi-Fi join waits on the glasses hotspot for
90
+ // tens of seconds, the miniapp never saw the host's PING, and the host respawned Mentra Call
91
+ // mid-join. Serial, so spawn, dispatch and kill still run in the order JS issued them.
92
+ private val mentraJsExecutor =
93
+ Executors.newSingleThreadExecutor { r ->
94
+ Thread(r, "MentraJS-bridge").apply { isDaemon = true }
95
+ }
96
+ private val mentraJsQueue =
97
+ CoroutineScope(
98
+ mentraJsExecutor.asCoroutineDispatcher() +
99
+ SupervisorJob() +
100
+ CoroutineName("MentraJS-bridge"),
101
+ )
80
102
  private var notificationEventReceiver: BroadcastReceiver? = null
81
103
  private var notificationBridgeContext: android.content.Context? = null
82
104
 
@@ -150,6 +172,8 @@ class CrustModule : Module() {
150
172
  notificationEventReceiver = null
151
173
  notificationBridgeContext = null
152
174
  eventEmitter = null
175
+ mentraJsQueue.cancel()
176
+ mentraJsExecutor.shutdown()
153
177
  }
154
178
 
155
179
  Function("hello") {
@@ -255,7 +279,7 @@ class CrustModule : Module() {
255
279
  polyfillBundleOverride = polyfillBundle.takeIf { it.isNotEmpty() },
256
280
  miniappJs = miniappJs,
257
281
  )
258
- }
282
+ }.runOnQueue(mentraJsQueue)
259
283
 
260
284
  AsyncFunction("mentraJsEvaluate") { packageName: String, source: String ->
261
285
  val ctx =
@@ -263,7 +287,7 @@ class CrustModule : Module() {
263
287
  ?: appContext.currentActivity
264
288
  ?: throw IllegalStateException("MentraJS: no context")
265
289
  JSCRuntime.shared(ctx).evaluate(packageName, source)
266
- }
290
+ }.runOnQueue(mentraJsQueue)
267
291
 
268
292
  AsyncFunction("mentraJsKill") { packageName: String ->
269
293
  val ctx =
@@ -271,7 +295,7 @@ class CrustModule : Module() {
271
295
  ?: appContext.currentActivity
272
296
  ?: throw IllegalStateException("MentraJS: no context")
273
297
  JSCRuntime.shared(ctx).kill(packageName)
274
- }
298
+ }.runOnQueue(mentraJsQueue)
275
299
 
276
300
  AsyncFunction("mentraJsDispatchToJs") { packageName: String, envelope: Map<String, Any?> ->
277
301
  val ctx =
@@ -280,7 +304,7 @@ class CrustModule : Module() {
280
304
  ?: throw IllegalStateException("MentraJS: no context")
281
305
  val json = org.json.JSONObject(envelope as Map<*, *>).toString()
282
306
  JSCRuntime.shared(ctx).dispatchToJs(packageName, json)
283
- }
307
+ }.runOnQueue(mentraJsQueue)
284
308
 
285
309
  AsyncFunction("mentraJsSetManifest") { packageName: String, permissions: List<String> ->
286
310
  val ctx =
@@ -291,7 +315,7 @@ class CrustModule : Module() {
291
315
  packageName,
292
316
  InstalledMiniappManifest(permissions.toSet()),
293
317
  )
294
- }
318
+ }.runOnQueue(mentraJsQueue)
295
319
 
296
320
  Function("mentraJsAlivePackages") {
297
321
  val ctx =
@@ -309,7 +333,7 @@ class CrustModule : Module() {
309
333
  ?: appContext.currentActivity
310
334
  ?: return@AsyncFunction false
311
335
  JSCRuntime.shared(ctx).debugForceGC(packageName)
312
- }
336
+ }.runOnQueue(mentraJsQueue)
313
337
 
314
338
  Function("mentraJsLoadPolyfillBundle") {
315
339
  val ctx =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/crust",
3
- "version": "3.2.1-beta.550",
3
+ "version": "3.2.1-beta.570",
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.2.1-beta.550"
38
+ "@mentra/jspolyfill": "3.2.1-beta.570"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@expo/config-plugins": ">=8.0.0",