@mentra/crust 0.1.0-beta.0

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.
Files changed (66) hide show
  1. package/README.md +41 -0
  2. package/android/build.gradle +146 -0
  3. package/android/src/internal/AndroidManifest.xml +9 -0
  4. package/android/src/internal/java/com/mentra/crust/receivers/CaptionsTesterIncidentReceiver.kt +46 -0
  5. package/android/src/main/AndroidManifest.xml +19 -0
  6. package/android/src/main/java/com/mentra/crust/CrustModule.kt +1042 -0
  7. package/android/src/main/java/com/mentra/crust/CrustView.kt +30 -0
  8. package/android/src/main/java/com/mentra/crust/heading/HeadingManager.kt +150 -0
  9. package/android/src/main/java/com/mentra/crust/jsc/JSCDispatcher.kt +189 -0
  10. package/android/src/main/java/com/mentra/crust/jsc/JSCPolyfillBridge.kt +287 -0
  11. package/android/src/main/java/com/mentra/crust/jsc/JSCRuntime.kt +593 -0
  12. package/android/src/main/java/com/mentra/crust/navigation/NavigationManager.kt +1445 -0
  13. package/android/src/main/java/com/mentra/crust/services/NotificationListener.kt +319 -0
  14. package/android/src/main/java/com/mentra/crust/utils/ImageProcessor.java +452 -0
  15. package/android/src/main/java/com/mentra/crust/utils/VideoStabilizer.kt +556 -0
  16. package/android/src/main/res/values/strings.xml +3 -0
  17. package/app.plugin.js +3 -0
  18. package/build/Crust.types.d.ts +148 -0
  19. package/build/Crust.types.d.ts.map +1 -0
  20. package/build/Crust.types.js +2 -0
  21. package/build/Crust.types.js.map +1 -0
  22. package/build/CrustModule.d.ts +182 -0
  23. package/build/CrustModule.d.ts.map +1 -0
  24. package/build/CrustModule.js +4 -0
  25. package/build/CrustModule.js.map +1 -0
  26. package/build/CrustModule.web.d.ts +34 -0
  27. package/build/CrustModule.web.d.ts.map +1 -0
  28. package/build/CrustModule.web.js +63 -0
  29. package/build/CrustModule.web.js.map +1 -0
  30. package/build/CrustView.d.ts +4 -0
  31. package/build/CrustView.d.ts.map +1 -0
  32. package/build/CrustView.js +7 -0
  33. package/build/CrustView.js.map +1 -0
  34. package/build/CrustView.web.d.ts +4 -0
  35. package/build/CrustView.web.d.ts.map +1 -0
  36. package/build/CrustView.web.js +7 -0
  37. package/build/CrustView.web.js.map +1 -0
  38. package/build/index.d.ts +4 -0
  39. package/build/index.d.ts.map +1 -0
  40. package/build/index.js +6 -0
  41. package/build/index.js.map +1 -0
  42. package/expo-module.config.json +9 -0
  43. package/ios/Crust.podspec +65 -0
  44. package/ios/CrustModule.swift +781 -0
  45. package/ios/CrustView.swift +38 -0
  46. package/ios/Resources/startup.js +814 -0
  47. package/ios/Source/JSCDispatcher.swift +226 -0
  48. package/ios/Source/JSCPolyfillBridge.swift +378 -0
  49. package/ios/Source/JSCRuntime.swift +673 -0
  50. package/ios/Source/utils/ImageProcessor.swift +392 -0
  51. package/ios/Source/utils/SystemGestures.swift +53 -0
  52. package/ios/Source/utils/VideoStabilizer.swift +374 -0
  53. package/ios/heading/HeadingManager.swift +74 -0
  54. package/ios/navigation/NavPayloads.swift +62 -0
  55. package/ios/navigation/NavigationManager.swift +720 -0
  56. package/package.json +69 -0
  57. package/plugin/build/index.d.ts +19 -0
  58. package/plugin/build/index.js +23 -0
  59. package/plugin/build/withAndroid.d.ts +2 -0
  60. package/plugin/build/withAndroid.js +78 -0
  61. package/src/Crust.types.ts +157 -0
  62. package/src/CrustModule.ts +191 -0
  63. package/src/CrustModule.web.ts +66 -0
  64. package/src/CrustView.tsx +10 -0
  65. package/src/CrustView.web.tsx +11 -0
  66. package/src/index.ts +5 -0
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # @mentra/crust
2
+
3
+ The MentraOS native runtime layer: an [Expo module](https://docs.expo.dev/modules/overview/)
4
+ providing the native capabilities the Mentra Engine's miniapp runtime sits on —
5
+ per-miniapp JS contexts (QuickJS on Android, JavaScriptCore on iOS), the
6
+ native side of the MentraJS bridge, navigation, and device utilities.
7
+
8
+ You don't call crust directly from app code: it's a **peer dependency of
9
+ [`@mentra/engine`](https://www.npmjs.com/package/@mentra/engine)**. A host app
10
+ embedding the engine installs crust alongside it and Expo autolinking picks it
11
+ up.
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ npm install @mentra/crust@dev
17
+ ```
18
+
19
+ > Currently published on the `dev` dist-tag (prerelease channel).
20
+
21
+ ## Config plugin
22
+
23
+ The package ships an Expo config plugin (`app.plugin.js`) that carries its
24
+ Android build contract — Mapbox's maven repository, protobuf exclusions, and
25
+ core-library desugaring. Add it to the host app's Expo config:
26
+
27
+ ```json
28
+ {"expo": {"plugins": ["@mentra/crust"]}}
29
+ ```
30
+
31
+ Building with the navigation feature requires a `MAPBOX_DOWNLOADS_TOKEN` in
32
+ the Android build environment (Mapbox's SDK repository is authenticated).
33
+
34
+ At build time the Android side also reads the MentraJS polyfill bundle from
35
+ its [`@mentra/jspolyfill`](https://www.npmjs.com/package/@mentra/jspolyfill)
36
+ sibling, which is declared as a dependency.
37
+
38
+ ## Part of MentraOS
39
+
40
+ Source lives in the [MentraOS monorepo](https://github.com/Mentra-Community/MentraOS)
41
+ under `mobile/modules/crust`. Issues and contributions welcome there.
@@ -0,0 +1,146 @@
1
+ apply plugin: 'com.android.library'
2
+
3
+ group = 'com.mentra.crust'
4
+ version = '0.1.0'
5
+
6
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
+ apply from: expoModulesCorePlugin
8
+ applyKotlinExpoModulesCorePlugin()
9
+ useCoreDependencies()
10
+ useExpoPublishing()
11
+
12
+ // MentraJS Android runtime: QuickJS via dokar3/quickjs-kt.
13
+ //
14
+ // Zipline's `bind(name, service)` registers services in an internal Kotlin
15
+ // map keyed by name for the Kotlin/JS-compiled `Zipline.take()` API; it does
16
+ // not install JS globals on globalThis. Our polyfill is hand-written JS that
17
+ // reads `globalThis.__mentraNativeBridge`, so the Zipline path silently
18
+ // dropped every JS→host dispatch on Android.
19
+ //
20
+ // dokar3/quickjs-kt exposes `QuickJs.function(name) { args -> ... }` which
21
+ // installs the lambda directly as a property of globalThis via QuickJS's
22
+ // `JS_SetPropertyStr(JS_NewCFunction(...))`. This matches iOS Apple JSC's
23
+ // `ctx.setObject(closure, forKeyedSubscript: ...)` pattern point-for-point.
24
+
25
+ // If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
26
+ // The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
27
+ // Most of the time, you may like to manage the Android SDK versions yourself.
28
+ def useManagedAndroidSdkVersions = false
29
+ if (useManagedAndroidSdkVersions) {
30
+ useDefaultAndroidSdkVersions()
31
+ } else {
32
+ buildscript {
33
+ // Simple helper that allows the root project to override versions declared by this library.
34
+ ext.safeExtGet = { prop, fallback ->
35
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
36
+ }
37
+ }
38
+ project.android {
39
+ compileSdkVersion safeExtGet("compileSdkVersion", 36)
40
+ defaultConfig {
41
+ minSdkVersion safeExtGet("minSdkVersion", 24)
42
+ targetSdkVersion safeExtGet("targetSdkVersion", 36)
43
+ }
44
+ }
45
+ }
46
+
47
+ android {
48
+ namespace "com.mentra.crust"
49
+ defaultConfig {
50
+ versionCode 1
51
+ versionName "0.1.0"
52
+ multiDexEnabled true
53
+ }
54
+ // Pull the MentraJS polyfill bundle from the sibling @mentra/jspolyfill
55
+ // module's `assets/` directory — single committed source of truth. The
56
+ // file is read at runtime via `appContext.assets.open("startup.js")`.
57
+ // Cross-module sourceSet entry beats checking the same artifact into git
58
+ // multiple times.
59
+ sourceSets {
60
+ main {
61
+ assets.srcDirs += '../../jspolyfill/assets'
62
+ }
63
+ }
64
+ compileOptions {
65
+ coreLibraryDesugaringEnabled true
66
+ }
67
+ buildTypes {
68
+ internal {
69
+ initWith release
70
+ matchingFallbacks = ['release']
71
+ }
72
+ }
73
+ buildTypes {
74
+ internal {
75
+ initWith release
76
+ matchingFallbacks = ['release']
77
+ }
78
+ }
79
+ lintOptions {
80
+ abortOnError false
81
+ }
82
+ }
83
+
84
+ dependencies {
85
+ // Mapbox Navigation SDK v3 (replaces Google Navigation SDK).
86
+ // Drives headless turn-by-turn nav in NavigationManager.kt: route
87
+ // progress, off-route + automatic rerouting, enhanced (map-matched)
88
+ // location, and the MapboxReplayer simulation harness for dev trips.
89
+ // Resolved from the authenticated Mapbox Downloads Maven repo, which is
90
+ // injected into the root project's allprojects.repositories at prebuild by
91
+ // mobile/plugins/android.ts (withProjectBuildGradleModifications), using the
92
+ // MAPBOX_DOWNLOADS_TOKEN (Downloads:Read sk.… token) from the env/gradle.properties.
93
+ //
94
+ // We depend on the headless modules directly, NOT the umbrella
95
+ // `navigationcore:android` artifact — that one also drags in `ui-maps`,
96
+ // `voice`, and `copilot`, which a custom glasses HUD doesn't use (dead
97
+ // APK weight). `:navigation` is the core engine; `:tripdata` carries the
98
+ // banner/maneuver formatting used to label turns.
99
+ // Version pinned to 3.25.0 — re-check https://docs.mapbox.com/android/navigation/releases/
100
+ def isChinaBuild = System.getenv("EXPO_PUBLIC_DEPLOYMENT_REGION") == "china"
101
+ if (isChinaBuild) {
102
+ compileOnly 'com.mapbox.navigationcore:navigation:3.25.0'
103
+ compileOnly 'com.mapbox.navigationcore:tripdata:3.25.0'
104
+ } else {
105
+ implementation 'com.mapbox.navigationcore:navigation:3.25.0'
106
+ implementation 'com.mapbox.navigationcore:tripdata:3.25.0'
107
+ }
108
+
109
+ // Required for Java 8+ APIs on minSdk < 26 (was needed by Google Nav SDK;
110
+ // Mapbox Nav SDK likewise targets desugared core libs).
111
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
112
+ }
113
+
114
+ dependencies {
115
+ implementation 'com.google.android.gms:play-services-location:21.0.1'
116
+ implementation 'com.google.android.gms:play-services-base:18.2.0'
117
+ }
118
+
119
+ dependencies {
120
+ // MentraJS — QuickJS for per-miniapp JS contexts. dokar3/quickjs-kt is a
121
+ // KMP wrapper around Bellard QuickJS that exposes `function(name) { ... }`
122
+ // for installing Kotlin lambdas as JS globals via `JS_SetPropertyStr`.
123
+ // Mirrors iOS Apple JSC's `setObject(_, forKeyedSubscript:)` pattern.
124
+ //
125
+ // Version pin: this Expo SDK 55 build uses Kotlin 2.1.20, which can read
126
+ // metadata up to 2.2.0. dokar3 1.0.1+ ships classes with metadata 2.3.0
127
+ // (compiled with Kotlin 2.3.x) and is unreadable here. 1.0.0-alpha13 is
128
+ // the last release compiled with Kotlin 2.0 (metadata 2.0.0) — its API
129
+ // (`QuickJs.create`, `evaluate`, `function` extension) matches 1.0.5 1:1.
130
+ // Bump only when the host Kotlin compiler clears 2.3.0 metadata.
131
+ implementation 'io.github.dokar3:quickjs-kt-android:1.0.0-alpha13'
132
+
133
+ // OkHttp for fetch / WebSocket — already used elsewhere in MentraOS;
134
+ // pinned here so the gradle plugin doesn't downgrade us.
135
+ implementation 'com.squareup.okhttp3:okhttp:4.12.0'
136
+
137
+ // Tink for X25519 (Android stdlib X25519 is API 33+ only; minSdk is 24).
138
+ // ~1.2 MB AAR. Crypto.subtle's SHA / AES-GCM / HMAC stay on javax.crypto
139
+ // which ships on the platform.
140
+ implementation 'com.google.crypto.tink:tink-android:1.14.1'
141
+
142
+ // Kotlin coroutines: dokar3's `evaluate()` is suspend; we bridge it via
143
+ // `runBlocking(dispatcher)` from the per-miniapp single-thread executor.
144
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1'
145
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
146
+ }
@@ -0,0 +1,9 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <receiver android:name="com.mentra.crust.receivers.CaptionsTesterIncidentReceiver" android:exported="true">
4
+ <intent-filter>
5
+ <action android:name="com.mentra.CAPTIONS_TESTER_INCIDENT"/>
6
+ </intent-filter>
7
+ </receiver>
8
+ </application>
9
+ </manifest>
@@ -0,0 +1,46 @@
1
+ package com.mentra.crust.receivers
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.util.Log
7
+ import com.mentra.crust.CrustModule
8
+
9
+ /**
10
+ * Receives broadcasts from the external captions tester and forwards them into React Native so
11
+ * the app can file a normal incident through the existing mobile incident pipeline.
12
+ */
13
+ class CaptionsTesterIncidentReceiver : BroadcastReceiver() {
14
+ @Suppress("DEPRECATION")
15
+ override fun onReceive(context: Context?, intent: Intent?) {
16
+ if (intent == null) {
17
+ Log.w("CaptionsTesterIncident", "Received null intent")
18
+ return
19
+ }
20
+
21
+ val body =
22
+ hashMapOf<String, Any>(
23
+ "action" to (intent.action ?: "unknown"),
24
+ "timestamp" to System.currentTimeMillis(),
25
+ )
26
+
27
+ intent.getStringExtra("failure_code")?.let { body["failure_code"] = it }
28
+ intent.getStringExtra("failure_message")?.let { body["failure_message"] = it }
29
+ intent.getStringExtra("test_run_id")?.let { body["test_run_id"] = it }
30
+ intent.getStringExtra("scenario_name")?.let { body["scenario_name"] = it }
31
+ intent.getStringExtra("source")?.let { body["source"] = it }
32
+
33
+ intent.extras?.keySet()?.forEach { key ->
34
+ if (body.containsKey(key)) {
35
+ return@forEach
36
+ }
37
+ val value = intent.extras?.get(key) ?: return@forEach
38
+ when (value) {
39
+ is String, is Int, is Long, is Boolean, is Double, is Float -> body[key] = value
40
+ else -> body[key] = value.toString()
41
+ }
42
+ }
43
+
44
+ CrustModule.emitCaptionsTesterIncident(body)
45
+ }
46
+ }
@@ -0,0 +1,19 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <service
4
+ android:name="com.mentra.crust.services.NotificationListenerServiceImpl"
5
+ android:label="@string/mentra_crust_notification_listener_label"
6
+ android:exported="false"
7
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
8
+ <intent-filter>
9
+ <action android:name="android.service.notification.NotificationListenerService" />
10
+ </intent-filter>
11
+ <meta-data android:name="android.service.notification.default_filter_types" android:value="conversations|alerting" />
12
+ <meta-data android:name="android.service.notification.disabled_filter_types" android:value="ongoing|silent" />
13
+ </service>
14
+
15
+ <!-- The Mapbox Navigation SDK delivers turn-by-turn steps inline via
16
+ RouteProgress (no Messenger-IPC service), so the Google-era
17
+ NavInfoReceiverService is gone. Nothing to register here for nav. -->
18
+ </application>
19
+ </manifest>