@mentra/bluetooth-sdk 3.1.0-dev.10 → 3.1.0-dev.101
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 +16 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedChangelogCatalog.kt +7 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +15 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ReleaseChangelog.kt +61 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +74 -25
- package/android/src/test/java/com/mentra/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +58 -0
- package/build/BluetoothSdk.types.d.ts +26 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/changelogs.d.ts +7 -0
- package/build/changelogs.d.ts.map +1 -0
- package/build/changelogs.js +44 -0
- package/build/changelogs.js.map +1 -0
- package/build/generated/changelogCatalog.d.ts +6 -0
- package/build/generated/changelogCatalog.d.ts.map +1 -0
- package/build/generated/changelogCatalog.js +8 -0
- package/build/generated/changelogCatalog.js.map +1 -0
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +14 -0
- package/build/index.js.map +1 -1
- package/build/ota-transport/index.d.ts +67 -0
- package/build/ota-transport/index.d.ts.map +1 -0
- package/build/ota-transport/index.js +58 -0
- package/build/ota-transport/index.js.map +1 -0
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/GeneratedChangelogCatalog.swift +6 -0
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/MentraBluetoothSDK.swift +17 -0
- package/ios/Source/ReleaseChangelog.swift +65 -0
- package/ios/Source/sgcs/MentraLive.swift +56 -14
- package/ios/Tests/MentraLivePairingAdvertisementTests.swift +56 -0
- package/ios/Tests/ReleaseChangelogTests.swift +13 -0
- package/package.json +6 -1
- package/scripts/public-ota-api.test.mjs +37 -0
- package/src/BluetoothSdk.types.ts +28 -0
- package/src/changelogs.ts +44 -0
- package/src/generated/changelogCatalog.ts +9 -0
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/index.ts +24 -0
- package/src/ota-transport/index.ts +116 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@testable import MentraBluetoothSDK
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
final class ReleaseChangelogTests: XCTestCase {
|
|
5
|
+
func testIncludesTargetNotesForTransitionWithinOneReleaseTrain() throws {
|
|
6
|
+
let changelogs = try ReleaseChangelogCatalog.select(
|
|
7
|
+
fromVersion: "3.1.0-dev.2",
|
|
8
|
+
toVersion: "3.1.0-beta.8"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
XCTAssertEqual(changelogs.map(\.version), ["3.1.0"])
|
|
12
|
+
}
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "3.1.0-dev.
|
|
3
|
+
"version": "3.1.0-dev.101",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
"types": "./build/photo-receiver/index.d.ts",
|
|
33
33
|
"default": "./build/photo-receiver/index.js"
|
|
34
34
|
},
|
|
35
|
+
"./ota-transport": {
|
|
36
|
+
"react-native": "./src/ota-transport/index.ts",
|
|
37
|
+
"types": "./build/ota-transport/index.d.ts",
|
|
38
|
+
"default": "./build/ota-transport/index.js"
|
|
39
|
+
},
|
|
35
40
|
"./debug": {
|
|
36
41
|
"react-native": "./src/debug.ts",
|
|
37
42
|
"types": "./build/debug.d.ts",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import {readFileSync} from "node:fs"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import test from "node:test"
|
|
5
|
+
import {fileURLToPath} from "node:url"
|
|
6
|
+
|
|
7
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
8
|
+
|
|
9
|
+
test("publishes the supported OTA transport entrypoint", () => {
|
|
10
|
+
const manifest = JSON.parse(readFileSync(path.join(packageRoot, "package.json"), "utf8"))
|
|
11
|
+
assert.deepEqual(manifest.exports["./ota-transport"], {
|
|
12
|
+
"react-native": "./src/ota-transport/index.ts",
|
|
13
|
+
"types": "./build/ota-transport/index.d.ts",
|
|
14
|
+
"default": "./build/ota-transport/index.js",
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const source = readFileSync(path.join(packageRoot, "src/ota-transport/index.ts"), "utf8")
|
|
18
|
+
assert.match(source, /export const otaLocalNetwork/)
|
|
19
|
+
assert.match(source, /export const otaServer/)
|
|
20
|
+
assert.doesNotMatch(source, /export \{default as Mentra(LocalNetwork|OtaServer)/)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test("keeps restart signals and correlated OTA status on the public root", () => {
|
|
24
|
+
const source = readFileSync(path.join(packageRoot, "src/index.ts"), "utf8")
|
|
25
|
+
for (const required of [
|
|
26
|
+
'"glasses_session_changed"',
|
|
27
|
+
'"mtk_update_complete"',
|
|
28
|
+
"queryOtaStatus",
|
|
29
|
+
"subscribeGlassesStatus",
|
|
30
|
+
"subscribeBluetoothStatus",
|
|
31
|
+
"setSystemTime",
|
|
32
|
+
"ping",
|
|
33
|
+
]) {
|
|
34
|
+
assert.ok(source.includes(required), `missing public OTA primitive: ${required}`)
|
|
35
|
+
}
|
|
36
|
+
assert.match(source, /Unsupported BluetoothSdk event/)
|
|
37
|
+
})
|
|
@@ -1043,6 +1043,10 @@ export type BluetoothSdkEventMap = {
|
|
|
1043
1043
|
mic_lc3: MicLc3Event
|
|
1044
1044
|
mic_health: MicHealthEvent
|
|
1045
1045
|
stream_status: StreamStatusEvent
|
|
1046
|
+
/** Mentra Live MTK updater completed and the glasses are about to restart. */
|
|
1047
|
+
mtk_update_complete: MtkUpdateCompleteEvent
|
|
1048
|
+
/** The ASG process restarted while the BES kept the BLE connection alive. */
|
|
1049
|
+
glasses_session_changed: GlassesSessionChangedEvent
|
|
1046
1050
|
ota_start_ack: OtaStartAckEvent
|
|
1047
1051
|
ota_status: OtaStatusEvent
|
|
1048
1052
|
ar99_ota_status: Ar99OtaStatusEvent
|
|
@@ -1068,6 +1072,15 @@ export interface BluetoothSdkPublicModule {
|
|
|
1068
1072
|
listener: BluetoothSdkEventListener<EventName>,
|
|
1069
1073
|
): BluetoothSdkSubscription
|
|
1070
1074
|
|
|
1075
|
+
/** Read an immutable snapshot of the current glasses state. */
|
|
1076
|
+
getGlassesStatus(): Promise<PublicGlassesStatus>
|
|
1077
|
+
/** Read an immutable snapshot of the phone Bluetooth adapter state. */
|
|
1078
|
+
getBluetoothStatus(): Promise<PublicBluetoothStatus>
|
|
1079
|
+
/** Observe immutable glasses-state patches. Returns an unsubscribe function. */
|
|
1080
|
+
subscribeGlassesStatus(listener: (changed: Partial<PublicGlassesStatus>) => void): () => void
|
|
1081
|
+
/** Observe immutable Bluetooth-state patches. Returns an unsubscribe function. */
|
|
1082
|
+
subscribeBluetoothStatus(listener: (changed: Partial<PublicBluetoothStatus>) => void): () => void
|
|
1083
|
+
|
|
1071
1084
|
getDefaultDevice(): Promise<Device | null>
|
|
1072
1085
|
setDefaultDevice(device: Device | null): Promise<void>
|
|
1073
1086
|
clearDefaultDevice(): Promise<void>
|
|
@@ -1089,11 +1102,15 @@ export interface BluetoothSdkPublicModule {
|
|
|
1089
1102
|
setHeadUpAngle(angleDegrees: number): Promise<void>
|
|
1090
1103
|
setImuEnabled(enabled: boolean): Promise<void>
|
|
1091
1104
|
setScreenDisabled(disabled: boolean): Promise<void>
|
|
1105
|
+
/** Keep legacy Mentra Live OTA sessions awake. Modern sessions normally do not require this. */
|
|
1106
|
+
ping(): Promise<void>
|
|
1092
1107
|
|
|
1093
1108
|
requestWifiScan(): Promise<WifiSearchResult[]>
|
|
1094
1109
|
sendWifiCredentials(ssid: string, password: string): Promise<WifiStatusChangeEvent>
|
|
1095
1110
|
forgetWifiNetwork(ssid: string): Promise<WifiStatusChangeEvent>
|
|
1096
1111
|
setHotspotState(enabled: boolean): Promise<HotspotStatusChangeEvent>
|
|
1112
|
+
/** Set the glasses clock from the phone after an OTA clock-skew failure. */
|
|
1113
|
+
setSystemTime(timestampMs: number): Promise<void>
|
|
1097
1114
|
/** Enable or disable Wi-Fi ADB on Mentra Live (no-op on other devices). */
|
|
1098
1115
|
setWifiAdbState(enabled: boolean): Promise<void>
|
|
1099
1116
|
|
|
@@ -1182,8 +1199,12 @@ export interface BluetoothSdkPublicModule {
|
|
|
1182
1199
|
getOtaVersionUrl(): string
|
|
1183
1200
|
/** Fetch the configured OTA manifest and return whether any ASG/BES/MTK update is available. */
|
|
1184
1201
|
checkForOtaUpdate(): Promise<boolean>
|
|
1202
|
+
/** Return bundled release changelogs crossed between two coordinated product versions, newest first. */
|
|
1203
|
+
getReleaseChangelogs(fromVersion?: string | null, toVersion?: string | null): ReleaseChangelog[]
|
|
1185
1204
|
/** Start OTA from the configured or explicitly supplied manifest URL. */
|
|
1186
1205
|
startOtaUpdate(otaVersionUrl?: string | null): Promise<OtaStartAckEvent>
|
|
1206
|
+
/** Query the active OTA session and return the correlated status response. */
|
|
1207
|
+
queryOtaStatus(): Promise<OtaQueryResult>
|
|
1187
1208
|
startAr99OtaFromFile(path: string): Promise<boolean>
|
|
1188
1209
|
cancelAr99Ota(): Promise<void>
|
|
1189
1210
|
sendAr99FactoryReset(): Promise<void>
|
|
@@ -1262,6 +1283,13 @@ export interface OtaUpdateInfo {
|
|
|
1262
1283
|
isDowngrade?: boolean
|
|
1263
1284
|
}
|
|
1264
1285
|
|
|
1286
|
+
export interface ReleaseChangelog {
|
|
1287
|
+
/** Base production version, for example `3.1.0`. */
|
|
1288
|
+
version: string
|
|
1289
|
+
/** Markdown body authored in `/changelogs/<version>.md`. */
|
|
1290
|
+
markdown: string
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1265
1293
|
export interface OtaProgress {
|
|
1266
1294
|
stage: OtaStage
|
|
1267
1295
|
status: OtaProgressStatus
|
|
@@ -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
|
+
)
|
|
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
|
|
|
12
12
|
export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "3.1.0",
|
|
15
|
-
"releaseIdentity": "3.1.0-dev.
|
|
16
|
-
"releaseSetId": "mentra-3.1.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-v3.1.0
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.1.0-dev.101",
|
|
16
|
+
"releaseSetId": "mentra-3.1.0-dev.101",
|
|
17
|
+
"sourceCommit": "7cbd0579aa228fcfd4d36adda6de1150c3a43647",
|
|
18
|
+
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.1.0/mentra-live-ota-3.1.0-dev.101.json",
|
|
19
|
+
"otaManifestSha256": "37c1d4399b7d7a9bf973138bca4035e930df80cf67da828a3e54049ed0034802"
|
|
20
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",
|
|
@@ -46,6 +49,8 @@ const PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([
|
|
|
46
49
|
"mic_lc3",
|
|
47
50
|
"mic_health",
|
|
48
51
|
"stream_status",
|
|
52
|
+
"mtk_update_complete",
|
|
53
|
+
"glasses_session_changed",
|
|
49
54
|
"ota_start_ack",
|
|
50
55
|
"ota_status",
|
|
51
56
|
"ar99_ota_status",
|
|
@@ -64,6 +69,10 @@ const startOtaUpdate: BluetoothSdkPublicModule["startOtaUpdate"] = (otaVersionUr
|
|
|
64
69
|
return PrivateBluetoothSdkModule.startOtaUpdate(otaVersionUrl)
|
|
65
70
|
}
|
|
66
71
|
|
|
72
|
+
const queryOtaStatus: BluetoothSdkPublicModule["queryOtaStatus"] = () => {
|
|
73
|
+
return PrivateBluetoothSdkModule.sendOtaQueryStatus()
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
const bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): BluetoothSdkPublicModule[K] => {
|
|
68
77
|
const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>)[name]
|
|
69
78
|
if (typeof method === "function") {
|
|
@@ -77,6 +86,12 @@ const bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): Bl
|
|
|
77
86
|
|
|
78
87
|
export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
79
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),
|
|
80
95
|
getDefaultDevice: bindPublicMethod("getDefaultDevice"),
|
|
81
96
|
setDefaultDevice: bindPublicMethod("setDefaultDevice"),
|
|
82
97
|
clearDefaultDevice: bindPublicMethod("clearDefaultDevice"),
|
|
@@ -95,10 +110,12 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
95
110
|
setHeadUpAngle: bindPublicMethod("setHeadUpAngle"),
|
|
96
111
|
setImuEnabled: bindPublicMethod("setImuEnabled"),
|
|
97
112
|
setScreenDisabled: bindPublicMethod("setScreenDisabled"),
|
|
113
|
+
ping: bindPublicMethod("ping"),
|
|
98
114
|
requestWifiScan: bindPublicMethod("requestWifiScan"),
|
|
99
115
|
sendWifiCredentials: bindPublicMethod("sendWifiCredentials"),
|
|
100
116
|
forgetWifiNetwork: bindPublicMethod("forgetWifiNetwork"),
|
|
101
117
|
setHotspotState: bindPublicMethod("setHotspotState"),
|
|
118
|
+
setSystemTime: bindPublicMethod("setSystemTime"),
|
|
102
119
|
setWifiAdbState: bindPublicMethod("setWifiAdbState"),
|
|
103
120
|
setGalleryModeEnabled: bindPublicMethod("setGalleryModeEnabled"),
|
|
104
121
|
setVoiceActivityDetectionEnabled: bindPublicMethod("setVoiceActivityDetectionEnabled"),
|
|
@@ -143,7 +160,9 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
143
160
|
setOtaVersionUrl: bindPublicMethod("setOtaVersionUrl"),
|
|
144
161
|
getOtaVersionUrl: bindPublicMethod("getOtaVersionUrl"),
|
|
145
162
|
checkForOtaUpdate: bindPublicMethod("checkForOtaUpdate"),
|
|
163
|
+
getReleaseChangelogs,
|
|
146
164
|
startOtaUpdate,
|
|
165
|
+
queryOtaStatus,
|
|
147
166
|
startAr99OtaFromFile: bindPublicMethod("startAr99OtaFromFile"),
|
|
148
167
|
cancelAr99Ota: bindPublicMethod("cancelAr99Ota"),
|
|
149
168
|
sendAr99FactoryReset: bindPublicMethod("sendAr99FactoryReset"),
|
|
@@ -212,6 +231,7 @@ export type {
|
|
|
212
231
|
HotspotErrorEvent,
|
|
213
232
|
HotspotStatus,
|
|
214
233
|
HotspotStatusChangeEvent,
|
|
234
|
+
GlassesSessionChangedEvent,
|
|
215
235
|
KeepAliveAckEvent,
|
|
216
236
|
LocalTranscriptionEvent,
|
|
217
237
|
LogEvent,
|
|
@@ -228,6 +248,8 @@ export type {
|
|
|
228
248
|
OtaStatusEvent,
|
|
229
249
|
OtaQueryResult,
|
|
230
250
|
OtaUpdateInfo,
|
|
251
|
+
ReleaseChangelog,
|
|
252
|
+
MtkUpdateCompleteEvent,
|
|
231
253
|
PairFailureEvent,
|
|
232
254
|
PairingInfoEvent,
|
|
233
255
|
EnteringPairingModeEvent,
|
|
@@ -238,6 +260,8 @@ export type {
|
|
|
238
260
|
PhotoFpsRange,
|
|
239
261
|
PhotoMeteredPreview,
|
|
240
262
|
PhotoMode,
|
|
263
|
+
PublicBluetoothStatus,
|
|
264
|
+
PublicGlassesStatus,
|
|
241
265
|
PhotoTransferMethod,
|
|
242
266
|
PhotoResponseEvent,
|
|
243
267
|
PhotoRequestedCaptureConfig,
|
|
@@ -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
|
+
})
|