@mentra/bluetooth-sdk 0.1.21-beta.3 → 3.1.0-beta.100

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 (144) hide show
  1. package/README.md +67 -25
  2. package/android/build.gradle +7 -4
  3. package/android/lc3Lib/build.gradle +18 -4
  4. package/android/silero/build.gradle +9 -1
  5. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +16 -0
  6. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +35 -4
  7. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +216 -23
  8. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +2 -0
  9. package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedChangelogCatalog.kt +7 -0
  10. package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
  11. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +127 -8
  12. package/android/src/main/java/com/mentra/bluetoothsdk/MentraLocalNetworkModule.kt +93 -12
  13. package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +5 -7
  14. package/android/src/main/java/com/mentra/bluetoothsdk/ReleaseChangelog.kt +61 -0
  15. package/android/src/main/java/com/mentra/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
  16. package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +15 -0
  17. package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +24 -0
  18. package/android/src/main/java/com/mentra/bluetoothsdk/net/LocalIpv4.kt +57 -0
  19. package/android/src/main/java/com/mentra/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
  20. package/android/src/main/java/com/mentra/bluetoothsdk/otaserver/MentraOtaServerModule.kt +120 -0
  21. package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/MentraPhotoReceiverModule.kt +2 -49
  22. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +61 -30
  23. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
  24. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
  25. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +1393 -284
  26. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
  27. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +8 -0
  28. package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +17 -0
  29. package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +12 -0
  30. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleJsonCompact.java +74 -79
  31. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +3 -3
  32. package/android/src/test/java/com/mentra/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
  33. package/android/src/test/java/com/mentra/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
  34. package/android/src/test/java/com/mentra/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
  35. package/android/src/test/java/com/mentra/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
  36. package/android/src/test/java/com/mentra/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
  37. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
  38. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
  39. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
  40. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
  41. package/android/src/test/java/com/mentra/bluetoothsdk/utils/BleJsonCompactTest.java +148 -7
  42. package/build/BluetoothSdk.types.d.ts +84 -2
  43. package/build/BluetoothSdk.types.d.ts.map +1 -1
  44. package/build/BluetoothSdk.types.js.map +1 -1
  45. package/build/_internal.d.ts +2 -0
  46. package/build/_internal.d.ts.map +1 -1
  47. package/build/_internal.js +2 -0
  48. package/build/_internal.js.map +1 -1
  49. package/build/_private/BluetoothSdkModule.d.ts +4 -1
  50. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  51. package/build/_private/BluetoothSdkModule.js +1 -1
  52. package/build/_private/BluetoothSdkModule.js.map +1 -1
  53. package/build/_private/MentraLocalNetworkModule.d.ts +1 -0
  54. package/build/_private/MentraLocalNetworkModule.d.ts.map +1 -1
  55. package/build/_private/MentraLocalNetworkModule.js.map +1 -1
  56. package/build/_private/sdkOtaManifest.d.ts +3 -12
  57. package/build/_private/sdkOtaManifest.d.ts.map +1 -1
  58. package/build/_private/sdkOtaManifest.js +5 -17
  59. package/build/_private/sdkOtaManifest.js.map +1 -1
  60. package/build/changelogs.d.ts +7 -0
  61. package/build/changelogs.d.ts.map +1 -0
  62. package/build/changelogs.js +44 -0
  63. package/build/changelogs.js.map +1 -0
  64. package/build/generated/changelogCatalog.d.ts +6 -0
  65. package/build/generated/changelogCatalog.d.ts.map +1 -0
  66. package/build/generated/changelogCatalog.js +8 -0
  67. package/build/generated/changelogCatalog.js.map +1 -0
  68. package/build/generated/releaseMetadata.d.ts +12 -0
  69. package/build/generated/releaseMetadata.d.ts.map +1 -0
  70. package/build/generated/releaseMetadata.js +10 -0
  71. package/build/generated/releaseMetadata.js.map +1 -0
  72. package/build/index.d.ts +1 -1
  73. package/build/index.d.ts.map +1 -1
  74. package/build/index.js +24 -2
  75. package/build/index.js.map +1 -1
  76. package/build/ota-server/MentraOtaServer.types.d.ts +14 -0
  77. package/build/ota-server/MentraOtaServer.types.d.ts.map +1 -0
  78. package/build/ota-server/MentraOtaServer.types.js +2 -0
  79. package/build/ota-server/MentraOtaServer.types.js.map +1 -0
  80. package/build/ota-server/MentraOtaServerModule.d.ts +21 -0
  81. package/build/ota-server/MentraOtaServerModule.d.ts.map +1 -0
  82. package/build/ota-server/MentraOtaServerModule.js +3 -0
  83. package/build/ota-server/MentraOtaServerModule.js.map +1 -0
  84. package/build/ota-server/MentraOtaServerModule.web.d.ts +10 -0
  85. package/build/ota-server/MentraOtaServerModule.web.d.ts.map +1 -0
  86. package/build/ota-server/MentraOtaServerModule.web.js +12 -0
  87. package/build/ota-server/MentraOtaServerModule.web.js.map +1 -0
  88. package/build/ota-server/index.d.ts +3 -0
  89. package/build/ota-server/index.d.ts.map +1 -0
  90. package/build/ota-server/index.js +3 -0
  91. package/build/ota-server/index.js.map +1 -0
  92. package/build/ota-transport/index.d.ts +67 -0
  93. package/build/ota-transport/index.d.ts.map +1 -0
  94. package/build/ota-transport/index.js +58 -0
  95. package/build/ota-transport/index.js.map +1 -0
  96. package/expo-module.config.json +3 -2
  97. package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
  98. package/ios/BluetoothSdkModule.swift +16 -2
  99. package/ios/LocalIPv4.swift +150 -0
  100. package/ios/LocalOtaServer.swift +309 -0
  101. package/ios/MentraBluetoothSDK.podspec +5 -1
  102. package/ios/MentraOtaServerModule.swift +147 -0
  103. package/ios/MentraPhotoReceiverModule.swift +1 -81
  104. package/ios/Source/BluetoothSdkDefaults.swift +4 -1
  105. package/ios/Source/Bridge.swift +43 -4
  106. package/ios/Source/DeviceManager.swift +154 -19
  107. package/ios/Source/DeviceStore.swift +2 -0
  108. package/ios/Source/GeneratedChangelogCatalog.swift +6 -0
  109. package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
  110. package/ios/Source/MentraBluetoothSDK.swift +91 -6
  111. package/ios/Source/OtaManifest.swift +5 -7
  112. package/ios/Source/ReleaseChangelog.swift +65 -0
  113. package/ios/Source/audio/AudioModels.swift +17 -0
  114. package/ios/Source/camera/CameraModels.swift +1 -0
  115. package/ios/Source/events/BluetoothEvents.swift +27 -0
  116. package/ios/Source/sgcs/MentraLive.swift +512 -78
  117. package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
  118. package/ios/Source/sgcs/SGCManager.swift +11 -0
  119. package/ios/Source/status/DeviceStatus.swift +23 -0
  120. package/ios/Source/types/DeviceModels.swift +23 -2
  121. package/ios/Source/utils/BleJsonCompact.swift +73 -71
  122. package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
  123. package/ios/Tests/ReleaseChangelogTests.swift +13 -0
  124. package/package.json +10 -1
  125. package/plugin/build/withIos.d.ts +3 -1
  126. package/plugin/build/withIos.js +22 -10
  127. package/scripts/public-ota-api.test.mjs +37 -0
  128. package/scripts/verify-release-package.mjs +34 -0
  129. package/scripts/write-release-metadata.mjs +154 -0
  130. package/scripts/write-release-metadata.test.mjs +29 -0
  131. package/src/BluetoothSdk.types.ts +97 -3
  132. package/src/_internal.ts +2 -0
  133. package/src/_private/BluetoothSdkModule.ts +5 -5
  134. package/src/_private/MentraLocalNetworkModule.ts +1 -1
  135. package/src/_private/sdkOtaManifest.ts +5 -17
  136. package/src/changelogs.ts +44 -0
  137. package/src/generated/changelogCatalog.ts +9 -0
  138. package/src/generated/releaseMetadata.ts +20 -0
  139. package/src/index.ts +43 -2
  140. package/src/ota-server/MentraOtaServer.types.ts +10 -0
  141. package/src/ota-server/MentraOtaServerModule.ts +23 -0
  142. package/src/ota-server/MentraOtaServerModule.web.ts +17 -0
  143. package/src/ota-server/index.ts +2 -0
  144. package/src/ota-transport/index.ts +116 -0
@@ -0,0 +1,44 @@
1
+ import type {ReleaseChangelog} from "./BluetoothSdk.types"
2
+ import {GENERATED_RELEASE_CHANGELOGS} from "./generated/changelogCatalog"
3
+ import {BLUETOOTH_SDK_RELEASE_METADATA} from "./generated/releaseMetadata"
4
+
5
+ const BASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:[-+].*)?$/
6
+
7
+ function baseVersion(version: string, label: string): string {
8
+ const match = BASE_VERSION_PATTERN.exec(version.trim())
9
+ if (!match) throw new Error(`${label} must be a semantic version such as 3.1.0, 3.1.0-dev.4, or 3.1.0-beta.2`)
10
+ return `${match[1]}.${match[2]}.${match[3]}`
11
+ }
12
+
13
+ function compareVersions(left: string, right: string): number {
14
+ const a = left.split(".").map(Number)
15
+ const b = right.split(".").map(Number)
16
+ for (let index = 0; index < 3; index += 1) {
17
+ if (a[index] !== b[index]) return a[index] - b[index]
18
+ }
19
+ return 0
20
+ }
21
+
22
+ /**
23
+ * Return authored release notes crossed between two product versions, newest first.
24
+ * The target release is always included, including transitions within one base train.
25
+ */
26
+ export function getReleaseChangelogs(fromVersion?: string | null, toVersion?: string | null): ReleaseChangelog[] {
27
+ const fallbackTarget = BLUETOOTH_SDK_RELEASE_METADATA.familyBaseVersion ?? GENERATED_RELEASE_CHANGELOGS[0]?.version
28
+ if (!fallbackTarget && !toVersion) return []
29
+ const target = baseVersion(toVersion ?? fallbackTarget, "toVersion")
30
+ if (!GENERATED_RELEASE_CHANGELOGS.some(({version}) => version === target)) {
31
+ throw new Error(`No changelog is bundled for target version ${target}`)
32
+ }
33
+ if (!fromVersion) {
34
+ return GENERATED_RELEASE_CHANGELOGS.filter(({version}) => version === target).map((entry) => ({...entry}))
35
+ }
36
+
37
+ const source = baseVersion(fromVersion, "fromVersion")
38
+ const direction = compareVersions(target, source)
39
+ return GENERATED_RELEASE_CHANGELOGS.filter(({version}) => {
40
+ if (direction === 0) return version === target
41
+ if (direction > 0) return compareVersions(version, source) > 0 && compareVersions(version, target) <= 0
42
+ return compareVersions(version, source) < 0 && compareVersions(version, target) >= 0
43
+ }).map((entry) => ({...entry}))
44
+ }
@@ -0,0 +1,9 @@
1
+ /** Generated from /changelogs. Do not edit directly. */
2
+ export const GENERATED_RELEASE_CHANGELOGS = Object.freeze(
3
+ [
4
+ {
5
+ "version": "3.1.0",
6
+ "markdown": "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- MentraOS, Mentra Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."
7
+ }
8
+ ] as const,
9
+ )
@@ -0,0 +1,20 @@
1
+ /** Generated by release CI. Do not edit in a release checkout. */
2
+ export interface BluetoothSdkReleaseMetadata {
3
+ schemaVersion: 1
4
+ familyBaseVersion: string | null
5
+ releaseIdentity: string | null
6
+ releaseSetId: string | null
7
+ sourceCommit: string | null
8
+ otaManifestUrl: string | null
9
+ otaManifestSha256: string | null
10
+ }
11
+
12
+ export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
13
+ "schemaVersion": 1,
14
+ "familyBaseVersion": "3.1.0",
15
+ "releaseIdentity": "3.1.0-beta.100",
16
+ "releaseSetId": "mentra-3.1.0-beta.100",
17
+ "sourceCommit": "c7c90f50ce7fd83dadc9a005e152db1d88083e4f",
18
+ "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.1.0/mentra-live-ota-3.1.0-beta.100.json",
19
+ "otaManifestSha256": "7fdf5b1f75d5d07007e45c929495cd4b6800c810c94e3c60c62bda99d1c61552"
20
+ })
package/src/index.ts CHANGED
@@ -3,8 +3,11 @@ import type {
3
3
  BluetoothSdkEventListener,
4
4
  BluetoothSdkEventName,
5
5
  BluetoothSdkPublicModule,
6
+ PublicBluetoothStatus,
7
+ PublicGlassesStatus,
6
8
  VideoRecordingDefaults,
7
9
  } from "./BluetoothSdk.types"
10
+ import {getReleaseChangelogs} from "./changelogs"
8
11
 
9
12
  const PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([
10
13
  "log",
@@ -36,12 +39,18 @@ const PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([
36
39
  "rgb_led_control_response",
37
40
  "settings_ack",
38
41
  "pair_failure",
42
+ "pairing_info",
43
+ "entering_pairing_mode",
44
+ "owner_replaced",
39
45
  "audio_pairing_needed",
40
46
  "audio_connected",
41
47
  "audio_disconnected",
42
48
  "mic_pcm",
43
49
  "mic_lc3",
50
+ "mic_health",
44
51
  "stream_status",
52
+ "mtk_update_complete",
53
+ "glasses_session_changed",
45
54
  "ota_start_ack",
46
55
  "ota_status",
47
56
  "ar99_ota_status",
@@ -56,8 +65,12 @@ const addListener: BluetoothSdkPublicModule["addListener"] = (eventName, listene
56
65
  return PrivateBluetoothSdkModule.addListener(eventName, listener as BluetoothSdkEventListener<BluetoothSdkEventName>)
57
66
  }
58
67
 
59
- const startOtaUpdate: BluetoothSdkPublicModule["startOtaUpdate"] = () => {
60
- return PrivateBluetoothSdkModule.startOtaUpdate()
68
+ const startOtaUpdate: BluetoothSdkPublicModule["startOtaUpdate"] = (otaVersionUrl) => {
69
+ return PrivateBluetoothSdkModule.startOtaUpdate(otaVersionUrl)
70
+ }
71
+
72
+ const queryOtaStatus: BluetoothSdkPublicModule["queryOtaStatus"] = () => {
73
+ return PrivateBluetoothSdkModule.sendOtaQueryStatus()
61
74
  }
62
75
 
63
76
  const bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): BluetoothSdkPublicModule[K] => {
@@ -73,6 +86,12 @@ const bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): Bl
73
86
 
74
87
  export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
75
88
  addListener,
89
+ getGlassesStatus: bindPublicMethod("getGlassesStatus"),
90
+ getBluetoothStatus: bindPublicMethod("getBluetoothStatus"),
91
+ subscribeGlassesStatus: (listener: (changed: Partial<PublicGlassesStatus>) => void) =>
92
+ PrivateBluetoothSdkModule.onGlassesStatus(listener),
93
+ subscribeBluetoothStatus: (listener: (changed: Partial<PublicBluetoothStatus>) => void) =>
94
+ PrivateBluetoothSdkModule.onBluetoothStatus(listener),
76
95
  getDefaultDevice: bindPublicMethod("getDefaultDevice"),
77
96
  setDefaultDevice: bindPublicMethod("setDefaultDevice"),
78
97
  clearDefaultDevice: bindPublicMethod("clearDefaultDevice"),
@@ -91,10 +110,13 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
91
110
  setHeadUpAngle: bindPublicMethod("setHeadUpAngle"),
92
111
  setImuEnabled: bindPublicMethod("setImuEnabled"),
93
112
  setScreenDisabled: bindPublicMethod("setScreenDisabled"),
113
+ ping: bindPublicMethod("ping"),
94
114
  requestWifiScan: bindPublicMethod("requestWifiScan"),
95
115
  sendWifiCredentials: bindPublicMethod("sendWifiCredentials"),
96
116
  forgetWifiNetwork: bindPublicMethod("forgetWifiNetwork"),
97
117
  setHotspotState: bindPublicMethod("setHotspotState"),
118
+ setSystemTime: bindPublicMethod("setSystemTime"),
119
+ setWifiAdbState: bindPublicMethod("setWifiAdbState"),
98
120
  setGalleryModeEnabled: bindPublicMethod("setGalleryModeEnabled"),
99
121
  setVoiceActivityDetectionEnabled: bindPublicMethod("setVoiceActivityDetectionEnabled"),
100
122
  setLoudnessGateEnabled: bindPublicMethod("setLoudnessGateEnabled"),
@@ -125,6 +147,7 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
125
147
  stopCameraWarmUp: bindPublicMethod("stopCameraWarmUp"),
126
148
  startVideoRecording: bindPublicMethod("startVideoRecording"),
127
149
  stopVideoRecording: bindPublicMethod("stopVideoRecording"),
150
+ queryVideoRecordingStatus: bindPublicMethod("queryVideoRecordingStatus"),
128
151
  startStream: bindPublicMethod("startStream"),
129
152
  stopStream: bindPublicMethod("stopStream"),
130
153
  setMicState: bindPublicMethod("setMicState"),
@@ -134,8 +157,12 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
134
157
  setGlassesMediaVolume: bindPublicMethod("setGlassesMediaVolume"),
135
158
  rgbLedControl: bindPublicMethod("rgbLedControl"),
136
159
  requestVersionInfo: bindPublicMethod("requestVersionInfo"),
160
+ setOtaVersionUrl: bindPublicMethod("setOtaVersionUrl"),
161
+ getOtaVersionUrl: bindPublicMethod("getOtaVersionUrl"),
137
162
  checkForOtaUpdate: bindPublicMethod("checkForOtaUpdate"),
163
+ getReleaseChangelogs,
138
164
  startOtaUpdate,
165
+ queryOtaStatus,
139
166
  startAr99OtaFromFile: bindPublicMethod("startAr99OtaFromFile"),
140
167
  cancelAr99Ota: bindPublicMethod("cancelAr99Ota"),
141
168
  sendAr99FactoryReset: bindPublicMethod("sendAr99FactoryReset"),
@@ -204,23 +231,37 @@ export type {
204
231
  HotspotErrorEvent,
205
232
  HotspotStatus,
206
233
  HotspotStatusChangeEvent,
234
+ GlassesSessionChangedEvent,
235
+ KeepAliveAckEvent,
207
236
  LocalTranscriptionEvent,
208
237
  LogEvent,
209
238
  MicLc3Event,
239
+ MicHealthEvent,
210
240
  MicMode,
211
241
  MicPcmEvent,
212
242
  MicPreference,
213
243
  OtaStartAckEvent,
244
+ OtaProgress,
245
+ OtaProgressStatus,
246
+ OtaStage,
214
247
  OtaStatus,
215
248
  OtaStatusEvent,
216
249
  OtaQueryResult,
250
+ OtaUpdateInfo,
251
+ ReleaseChangelog,
252
+ MtkUpdateCompleteEvent,
217
253
  PairFailureEvent,
254
+ PairingInfoEvent,
255
+ EnteringPairingModeEvent,
256
+ OwnerReplacedEvent,
218
257
  PhotoCaptureMetadata,
219
258
  PhotoResolvedConfig,
220
259
  PhotoCompression,
221
260
  PhotoFpsRange,
222
261
  PhotoMeteredPreview,
223
262
  PhotoMode,
263
+ PublicBluetoothStatus,
264
+ PublicGlassesStatus,
224
265
  PhotoTransferMethod,
225
266
  PhotoResponseEvent,
226
267
  PhotoRequestedCaptureConfig,
@@ -0,0 +1,10 @@
1
+ export type OtaServerResult = {
2
+ baseUrl: string
3
+ host: string
4
+ manifestUrl: string
5
+ port: number
6
+ }
7
+
8
+ export type MentraOtaServerModuleEvents = {
9
+ artifactDownloadProgress: (event: {destination: string; bytesWritten: number; contentLength: number}) => void
10
+ }
@@ -0,0 +1,23 @@
1
+ import {NativeModule, requireNativeModule} from "expo"
2
+
3
+ import type {MentraOtaServerModuleEvents, OtaServerResult} from "./MentraOtaServer.types"
4
+
5
+ declare class MentraOtaServerModule extends NativeModule<MentraOtaServerModuleEvents> {
6
+ /**
7
+ * Serve `manifestJson` at /version.json and `artifactPaths` (sha256 -> local file path)
8
+ * at /artifacts/<sha256>. Pass `host` when the caller knows the authoritative local
9
+ * address (e.g. from the scoped hotspot network); omit to fall back to interface
10
+ * scanning. Returns the URLs to hand to the glasses via ota_start.
11
+ */
12
+ startOtaServer(
13
+ manifestJson: string,
14
+ artifactPaths: Record<string, string>,
15
+ host?: string | null,
16
+ ): Promise<OtaServerResult>
17
+ stopOtaServer(): Promise<void>
18
+ /** Wait for iPhone Wi-Fi (`en0`) to acquire an address on the glasses gateway subnet. */
19
+ waitForWifiAddress(gateway: string, timeoutMs: number): Promise<string>
20
+ downloadArtifact(source: string, destination: string): Promise<{statusCode: number; bytesWritten: number}>
21
+ }
22
+
23
+ export default requireNativeModule<MentraOtaServerModule>("MentraOtaServer")
@@ -0,0 +1,17 @@
1
+ import {NativeModule, registerWebModule} from "expo"
2
+
3
+ import type {MentraOtaServerModuleEvents, OtaServerResult} from "./MentraOtaServer.types"
4
+
5
+ class MentraOtaServerModule extends NativeModule<MentraOtaServerModuleEvents> {
6
+ async startOtaServer(): Promise<OtaServerResult> {
7
+ throw new Error("The OTA server is only available in native apps.")
8
+ }
9
+
10
+ async stopOtaServer(): Promise<void> {}
11
+
12
+ async waitForWifiAddress(): Promise<string> {
13
+ throw new Error("The OTA server is only available in native apps.")
14
+ }
15
+ }
16
+
17
+ export default registerWebModule(MentraOtaServerModule, "MentraOtaServer")
@@ -0,0 +1,2 @@
1
+ export {default} from "./MentraOtaServerModule"
2
+ export * from "./MentraOtaServer.types"
@@ -0,0 +1,116 @@
1
+ // This public adapter is the package-owned boundary over its native implementation.
2
+ // eslint-disable-next-line no-restricted-imports
3
+ import MentraLocalNetwork from "../_private/MentraLocalNetworkModule"
4
+ // eslint-disable-next-line no-restricted-imports
5
+ import MentraOtaServer from "../ota-server"
6
+
7
+ export type OtaTransportSubscription = {remove(): void}
8
+
9
+ export type OtaLocalNetworkConnection = {
10
+ connected: boolean
11
+ ssid: string
12
+ localAddress?: string
13
+ }
14
+
15
+ export type OtaLocalNetworkLostEvent = {ssid: string}
16
+
17
+ export type OtaLocalNetworkResponse = {
18
+ status: number
19
+ headers: Record<string, string>
20
+ bodyBase64: string
21
+ }
22
+
23
+ export type OtaLocalNetworkDownloadResult = {
24
+ statusCode: number
25
+ bytesWritten: number
26
+ headers: Record<string, string>
27
+ }
28
+
29
+ export type OtaLocalNetworkDownloadProgress = {
30
+ requestId: string
31
+ bytesWritten: number
32
+ contentLength: number
33
+ statusCode?: number
34
+ headers?: Record<string, string>
35
+ }
36
+
37
+ export type OtaArtifactDownloadProgress = {
38
+ destination: string
39
+ bytesWritten: number
40
+ contentLength: number
41
+ }
42
+
43
+ export type OtaServerResult = {
44
+ baseUrl: string
45
+ host: string
46
+ manifestUrl: string
47
+ port: number
48
+ }
49
+
50
+ /**
51
+ * Scoped networking for traffic that must stay on a Mentra Live hotspot while
52
+ * the phone's default route remains on cellular or another Wi-Fi network.
53
+ *
54
+ * The module is optional because iOS uses its system Wi-Fi join flow instead.
55
+ */
56
+ export const otaLocalNetwork = Object.freeze({
57
+ isAvailable: (): boolean => MentraLocalNetwork != null,
58
+ connect: async (ssid: string, password: string): Promise<OtaLocalNetworkConnection> => {
59
+ if (!MentraLocalNetwork) throw new Error("Scoped local networking is not available in this native build")
60
+ return MentraLocalNetwork.connect(ssid, password)
61
+ },
62
+ request: async (
63
+ requestId: string,
64
+ url: string,
65
+ method: string,
66
+ headers: Record<string, string>,
67
+ body: string | null,
68
+ timeoutMs: number,
69
+ ): Promise<OtaLocalNetworkResponse> => {
70
+ if (!MentraLocalNetwork) throw new Error("Scoped local networking is not available in this native build")
71
+ return MentraLocalNetwork.request(requestId, url, method, headers, body, timeoutMs)
72
+ },
73
+ download: async (
74
+ requestId: string,
75
+ url: string,
76
+ destination: string,
77
+ headers: Record<string, string>,
78
+ connectionTimeoutMs: number,
79
+ readTimeoutMs: number,
80
+ ): Promise<OtaLocalNetworkDownloadResult> => {
81
+ if (!MentraLocalNetwork) throw new Error("Scoped local networking is not available in this native build")
82
+ return MentraLocalNetwork.download(requestId, url, destination, headers, connectionTimeoutMs, readTimeoutMs)
83
+ },
84
+ cancel: async (requestId: string): Promise<void> => {
85
+ if (!MentraLocalNetwork) return
86
+ await MentraLocalNetwork.cancel(requestId)
87
+ },
88
+ disconnect: async (): Promise<void> => {
89
+ if (!MentraLocalNetwork) return
90
+ await MentraLocalNetwork.disconnect()
91
+ },
92
+ onDownloadProgress: (listener: (event: OtaLocalNetworkDownloadProgress) => void): OtaTransportSubscription => {
93
+ if (!MentraLocalNetwork) return {remove() {}}
94
+ return MentraLocalNetwork.addListener("downloadProgress", listener)
95
+ },
96
+ onNetworkLost: (listener: (event: OtaLocalNetworkLostEvent) => void): OtaTransportSubscription => {
97
+ if (!MentraLocalNetwork) return {remove() {}}
98
+ return MentraLocalNetwork.addListener("networkLost", listener)
99
+ },
100
+ })
101
+
102
+ /** Native HTTP server and artifact downloader used by the Engine OTA coordinator. */
103
+ export const otaServer = Object.freeze({
104
+ start: (
105
+ manifestJson: string,
106
+ artifactPaths: Record<string, string>,
107
+ host?: string | null,
108
+ ): Promise<OtaServerResult> => MentraOtaServer.startOtaServer(manifestJson, artifactPaths, host),
109
+ stop: (): Promise<void> => MentraOtaServer.stopOtaServer(),
110
+ waitForWifiAddress: (gateway: string, timeoutMs: number): Promise<string> =>
111
+ MentraOtaServer.waitForWifiAddress(gateway, timeoutMs),
112
+ downloadArtifact: (source: string, destination: string): Promise<{statusCode: number; bytesWritten: number}> =>
113
+ MentraOtaServer.downloadArtifact(source, destination),
114
+ onArtifactDownloadProgress: (listener: (event: OtaArtifactDownloadProgress) => void): OtaTransportSubscription =>
115
+ MentraOtaServer.addListener("artifactDownloadProgress", listener),
116
+ })