@mentra/engine 3.2.0-dev.158 → 3.2.0-dev.161

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.
@@ -32,6 +32,16 @@ export interface MtkPatch {
32
32
  sha256?: string
33
33
  }
34
34
 
35
+ export interface MtkFullOta {
36
+ start_firmware?: never
37
+ end_firmware: string
38
+ url: string
39
+ sha256: string
40
+ size: number
41
+ }
42
+
43
+ export type MtkUpdate = MtkPatch | MtkFullOta
44
+
35
45
  export interface BesFirmware {
36
46
  version: string
37
47
  url: string
@@ -44,6 +54,7 @@ export interface VersionJson {
44
54
  [packageName: string]: VersionInfo
45
55
  }
46
56
  mtk_patches?: MtkPatch[]
57
+ mtk_full_ota?: MtkFullOta
47
58
  bes_firmware?: BesFirmware
48
59
  versionCode?: number
49
60
  versionName?: string
@@ -58,7 +69,8 @@ export interface OtaCheckResult {
58
69
  updateAvailable: boolean
59
70
  latestVersionInfo: VersionInfo | null
60
71
  updates: string[]
61
- mtkPatch: MtkPatch | null
72
+ /** Selected MTK artifact: exact-base incremental, otherwise a newer full OTA. */
73
+ mtkPatch: MtkUpdate | null
62
74
  besVersion: string | null
63
75
  /** True when the pending APK step installs an OLDER build than the glasses currently run. */
64
76
  isApkDowngrade: boolean
@@ -254,17 +266,45 @@ export function findMatchingMtkPatch(
254
266
 
255
267
  return (
256
268
  patches.find((patch) => {
257
- if (patch.start_firmware === currentVersion) {
258
- return true
259
- }
260
- const serverDate = patch.start_firmware.includes("_")
261
- ? patch.start_firmware.split("_").pop()
262
- : patch.start_firmware
263
- return serverDate === currentVersion
269
+ return normalizeMtkVersion(patch.start_firmware) === normalizeMtkVersion(currentVersion)
264
270
  }) || null
265
271
  )
266
272
  }
267
273
 
274
+ function normalizeMtkVersion(version: string): string {
275
+ return version.trim().split("_").pop() ?? ""
276
+ }
277
+
278
+ /** Full OTAs are not rollback packages. Unknown versions must not grant eligibility. */
279
+ export function selectMtkUpdate(
280
+ manifest: VersionJson | undefined,
281
+ currentVersion: string | undefined,
282
+ ): MtkUpdate | null {
283
+ const patch = findMatchingMtkPatch(manifest?.mtk_patches, currentVersion)
284
+ if (patch) return patch
285
+ const full = manifest?.mtk_full_ota
286
+ if (!full || !currentVersion || typeof full.end_firmware !== "string") return null
287
+ const current = normalizeMtkVersion(currentVersion)
288
+ const target = normalizeMtkVersion(full.end_firmware)
289
+ const versionPattern = /^\d{8}(?:\.\d{1,9})?$/
290
+ if (!versionPattern.test(current) || !versionPattern.test(target)) return null
291
+ const [currentDate, currentRevision = 0] = current.split(".").map(Number)
292
+ const [targetDate, targetRevision = 0] = target.split(".").map(Number)
293
+ if (targetDate < currentDate || (targetDate === currentDate && targetRevision <= currentRevision)) return null
294
+ if (
295
+ full.start_firmware !== undefined ||
296
+ typeof full.url !== "string" ||
297
+ !/^https?:\/\/[^/\s]+\//.test(full.url) ||
298
+ typeof full.sha256 !== "string" ||
299
+ !/^[a-fA-F0-9]{64}$/.test(full.sha256) ||
300
+ !Number.isSafeInteger(full.size) ||
301
+ full.size <= 0 ||
302
+ full.size > 1024 * 1024 * 1024
303
+ )
304
+ return null
305
+ return full
306
+ }
307
+
268
308
  export function checkBesUpdate(besFirmware: BesFirmware | undefined, currentVersion: string | undefined): boolean {
269
309
  if (!besFirmware) {
270
310
  return false
@@ -360,7 +400,7 @@ export async function checkForOtaUpdate(
360
400
  `OTA: APK update available: ${apkUpdateAvailable} (current: ${currentBuildNumber}, direction: ${apkDirection ?? "none"})`,
361
401
  )
362
402
 
363
- const mtkPatch = findMatchingMtkPatch(versionJson?.mtk_patches, currentMtkVersion)
403
+ const mtkPatch = selectMtkUpdate(versionJson, currentMtkVersion)
364
404
  const mtkUpdateAvailable = mtkPatch !== null
365
405
  if (!currentMtkVersion && versionJson?.mtk_patches?.length) {
366
406
  console.log(`OTA: MTK current version unknown - skipping MTK patch check`)
@@ -8,6 +8,7 @@ export type NormalizedOtaStatusEvent = {
8
8
  step_type: string
9
9
  phase: "download" | "install"
10
10
  step_percent: number
11
+ bytes_downloaded?: number
11
12
  overall_percent: number
12
13
  status: string
13
14
  error_message?: string
@@ -21,6 +22,7 @@ export function normalizeOtaStatusEvent(event: Record<string, unknown>): Normali
21
22
  const e = event as Record<string, any>
22
23
  const phase: "download" | "install" = e?.phase === "install" ? "install" : "download"
23
24
  const err = e?.error_message ?? e?.errorMessage
25
+ const bytes = e?.bytes_downloaded ?? e?.bytesDownloaded
24
26
  return {
25
27
  session_id: String(e?.session_id ?? e?.sessionId ?? ""),
26
28
  total_steps: Number(e?.total_steps ?? e?.totalSteps ?? 0),
@@ -28,6 +30,7 @@ export function normalizeOtaStatusEvent(event: Record<string, unknown>): Normali
28
30
  step_type: String(e?.step_type ?? e?.stepType ?? "apk"),
29
31
  phase,
30
32
  step_percent: Number(e?.step_percent ?? e?.stepPercent ?? 0),
33
+ bytes_downloaded: Number.isSafeInteger(bytes) && bytes >= 0 ? bytes : undefined,
31
34
  overall_percent: Number(e?.overall_percent ?? e?.overallPercent ?? 0),
32
35
  status: String(e?.status ?? "idle"),
33
36
  error_message: err == null || err === "" ? undefined : String(err),
@@ -42,6 +45,7 @@ export function otaStatusFromNormalized(n: NormalizedOtaStatusEvent): OtaStatus
42
45
  stepType: n.step_type as OtaStatus["stepType"],
43
46
  phase: n.phase,
44
47
  stepPercent: n.step_percent,
48
+ bytesDownloaded: n.bytes_downloaded,
45
49
  overallPercent: n.overall_percent,
46
50
  status: n.status as OtaStatus["status"],
47
51
  error: n.error_message,
@@ -63,7 +67,7 @@ export function legacyOtaProgressFromOtaStatusEvent(
63
67
  stage: n.phase === "install" ? "install" : "download",
64
68
  status: st,
65
69
  progress: Math.round(raw),
66
- bytesDownloaded: 0,
70
+ bytesDownloaded: n.bytes_downloaded ?? 0,
67
71
  totalBytes: 0,
68
72
  currentUpdate: n.step_type || "apk",
69
73
  errorMessage: n.error_message,