@mentra/engine 0.1.0-dev.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 (787) hide show
  1. package/README.md +79 -0
  2. package/build/devtools.d.ts +11 -0
  3. package/build/devtools.d.ts.map +1 -0
  4. package/build/devtools.js +13 -0
  5. package/build/devtools.js.map +1 -0
  6. package/build/engine.d.ts +261 -0
  7. package/build/engine.d.ts.map +1 -0
  8. package/build/engine.js +170 -0
  9. package/build/engine.js.map +1 -0
  10. package/build/facades/dev.d.ts +57 -0
  11. package/build/facades/dev.d.ts.map +1 -0
  12. package/build/facades/dev.js +187 -0
  13. package/build/facades/dev.js.map +1 -0
  14. package/build/facades/display.d.ts +21 -0
  15. package/build/facades/display.d.ts.map +1 -0
  16. package/build/facades/display.js +17 -0
  17. package/build/facades/display.js.map +1 -0
  18. package/build/facades/displayMirror.d.ts +15 -0
  19. package/build/facades/displayMirror.d.ts.map +1 -0
  20. package/build/facades/displayMirror.js +29 -0
  21. package/build/facades/displayMirror.js.map +1 -0
  22. package/build/facades/gallery.d.ts +62 -0
  23. package/build/facades/gallery.d.ts.map +1 -0
  24. package/build/facades/gallery.js +61 -0
  25. package/build/facades/gallery.js.map +1 -0
  26. package/build/facades/glasses.d.ts +141 -0
  27. package/build/facades/glasses.d.ts.map +1 -0
  28. package/build/facades/glasses.js +199 -0
  29. package/build/facades/glasses.js.map +1 -0
  30. package/build/facades/glassesSettings.d.ts +13 -0
  31. package/build/facades/glassesSettings.d.ts.map +1 -0
  32. package/build/facades/glassesSettings.js +54 -0
  33. package/build/facades/glassesSettings.js.map +1 -0
  34. package/build/facades/glassesWifi.d.ts +25 -0
  35. package/build/facades/glassesWifi.d.ts.map +1 -0
  36. package/build/facades/glassesWifi.js +57 -0
  37. package/build/facades/glassesWifi.js.map +1 -0
  38. package/build/facades/miniapps.d.ts +43 -0
  39. package/build/facades/miniapps.d.ts.map +1 -0
  40. package/build/facades/miniapps.js +49 -0
  41. package/build/facades/miniapps.js.map +1 -0
  42. package/build/facades/notifications.d.ts +13 -0
  43. package/build/facades/notifications.d.ts.map +1 -0
  44. package/build/facades/notifications.js +12 -0
  45. package/build/facades/notifications.js.map +1 -0
  46. package/build/facades/ota.d.ts +103 -0
  47. package/build/facades/ota.d.ts.map +1 -0
  48. package/build/facades/ota.js +156 -0
  49. package/build/facades/ota.js.map +1 -0
  50. package/build/facades/pairing.d.ts +114 -0
  51. package/build/facades/pairing.d.ts.map +1 -0
  52. package/build/facades/pairing.js +275 -0
  53. package/build/facades/pairing.js.map +1 -0
  54. package/build/facades/permissions.d.ts +23 -0
  55. package/build/facades/permissions.d.ts.map +1 -0
  56. package/build/facades/permissions.js +145 -0
  57. package/build/facades/permissions.js.map +1 -0
  58. package/build/facades/phoneNotifications.d.ts +21 -0
  59. package/build/facades/phoneNotifications.d.ts.map +1 -0
  60. package/build/facades/phoneNotifications.js +51 -0
  61. package/build/facades/phoneNotifications.js.map +1 -0
  62. package/build/facades/reports.d.ts +36 -0
  63. package/build/facades/reports.d.ts.map +1 -0
  64. package/build/facades/reports.js +134 -0
  65. package/build/facades/reports.js.map +1 -0
  66. package/build/facades/session.d.ts +21 -0
  67. package/build/facades/session.d.ts.map +1 -0
  68. package/build/facades/session.js +52 -0
  69. package/build/facades/session.js.map +1 -0
  70. package/build/facades/settings.d.ts +37 -0
  71. package/build/facades/settings.d.ts.map +1 -0
  72. package/build/facades/settings.js +55 -0
  73. package/build/facades/settings.js.map +1 -0
  74. package/build/facades/speech.d.ts +30 -0
  75. package/build/facades/speech.d.ts.map +1 -0
  76. package/build/facades/speech.js +37 -0
  77. package/build/facades/speech.js.map +1 -0
  78. package/build/index.d.ts +43 -0
  79. package/build/index.d.ts.map +1 -0
  80. package/build/index.js +45 -0
  81. package/build/index.js.map +1 -0
  82. package/build/internal.d.ts +66 -0
  83. package/build/internal.d.ts.map +1 -0
  84. package/build/internal.js +89 -0
  85. package/build/internal.js.map +1 -0
  86. package/build/runtime/bootstrap.d.ts +83 -0
  87. package/build/runtime/bootstrap.d.ts.map +1 -0
  88. package/build/runtime/bootstrap.js +56 -0
  89. package/build/runtime/bootstrap.js.map +1 -0
  90. package/build/runtime/config.d.ts +146 -0
  91. package/build/runtime/config.d.ts.map +1 -0
  92. package/build/runtime/config.js +18 -0
  93. package/build/runtime/config.js.map +1 -0
  94. package/build/runtime/streamConfig.d.ts +4 -0
  95. package/build/runtime/streamConfig.d.ts.map +1 -0
  96. package/build/runtime/streamConfig.js +38 -0
  97. package/build/runtime/streamConfig.js.map +1 -0
  98. package/build/services/AppRegistry.d.ts +303 -0
  99. package/build/services/AppRegistry.d.ts.map +1 -0
  100. package/build/services/AppRegistry.js +1029 -0
  101. package/build/services/AppRegistry.js.map +1 -0
  102. package/build/services/AudioCloudUplink.d.ts +3 -0
  103. package/build/services/AudioCloudUplink.d.ts.map +1 -0
  104. package/build/services/AudioCloudUplink.js +33 -0
  105. package/build/services/AudioCloudUplink.js.map +1 -0
  106. package/build/services/AudioPlaybackService.d.ts +144 -0
  107. package/build/services/AudioPlaybackService.d.ts.map +1 -0
  108. package/build/services/AudioPlaybackService.js +533 -0
  109. package/build/services/AudioPlaybackService.js.map +1 -0
  110. package/build/services/AutomaticReportResult.d.ts +20 -0
  111. package/build/services/AutomaticReportResult.d.ts.map +1 -0
  112. package/build/services/AutomaticReportResult.js +29 -0
  113. package/build/services/AutomaticReportResult.js.map +1 -0
  114. package/build/services/BlobStore.d.ts +91 -0
  115. package/build/services/BlobStore.d.ts.map +1 -0
  116. package/build/services/BlobStore.js +668 -0
  117. package/build/services/BlobStore.js.map +1 -0
  118. package/build/services/CaptionsTesterReportService.d.ts +4 -0
  119. package/build/services/CaptionsTesterReportService.d.ts.map +1 -0
  120. package/build/services/CaptionsTesterReportService.js +80 -0
  121. package/build/services/CaptionsTesterReportService.js.map +1 -0
  122. package/build/services/CloudAudioSubscriptionSync.d.ts +24 -0
  123. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -0
  124. package/build/services/CloudAudioSubscriptionSync.js +39 -0
  125. package/build/services/CloudAudioSubscriptionSync.js.map +1 -0
  126. package/build/services/CloudClientService.d.ts +143 -0
  127. package/build/services/CloudClientService.d.ts.map +1 -0
  128. package/build/services/CloudClientService.js +627 -0
  129. package/build/services/CloudClientService.js.map +1 -0
  130. package/build/services/CloudTranscriptE2EMetrics.d.ts +4 -0
  131. package/build/services/CloudTranscriptE2EMetrics.d.ts.map +1 -0
  132. package/build/services/CloudTranscriptE2EMetrics.js +24 -0
  133. package/build/services/CloudTranscriptE2EMetrics.js.map +1 -0
  134. package/build/services/ConnectionCoordinator.d.ts +51 -0
  135. package/build/services/ConnectionCoordinator.d.ts.map +1 -0
  136. package/build/services/ConnectionCoordinator.js +34 -0
  137. package/build/services/ConnectionCoordinator.js.map +1 -0
  138. package/build/services/DevServerBridge.d.ts +63 -0
  139. package/build/services/DevServerBridge.d.ts.map +1 -0
  140. package/build/services/DevServerBridge.js +294 -0
  141. package/build/services/DevServerBridge.js.map +1 -0
  142. package/build/services/DeviceEventRouter.d.ts +3 -0
  143. package/build/services/DeviceEventRouter.d.ts.map +1 -0
  144. package/build/services/DeviceEventRouter.js +190 -0
  145. package/build/services/DeviceEventRouter.js.map +1 -0
  146. package/build/services/DeviceStoreHydration.d.ts +38 -0
  147. package/build/services/DeviceStoreHydration.d.ts.map +1 -0
  148. package/build/services/DeviceStoreHydration.js +124 -0
  149. package/build/services/DeviceStoreHydration.js.map +1 -0
  150. package/build/services/DisplayProcessor.d.ts +223 -0
  151. package/build/services/DisplayProcessor.d.ts.map +1 -0
  152. package/build/services/DisplayProcessor.js +552 -0
  153. package/build/services/DisplayProcessor.js.map +1 -0
  154. package/build/services/GlassesReadiness.d.ts +41 -0
  155. package/build/services/GlassesReadiness.d.ts.map +1 -0
  156. package/build/services/GlassesReadiness.js +82 -0
  157. package/build/services/GlassesReadiness.js.map +1 -0
  158. package/build/services/GlassesSettingsSync.d.ts +33 -0
  159. package/build/services/GlassesSettingsSync.d.ts.map +1 -0
  160. package/build/services/GlassesSettingsSync.js +121 -0
  161. package/build/services/GlassesSettingsSync.js.map +1 -0
  162. package/build/services/GlassesStatusProjection.d.ts +3 -0
  163. package/build/services/GlassesStatusProjection.d.ts.map +1 -0
  164. package/build/services/GlassesStatusProjection.js +65 -0
  165. package/build/services/GlassesStatusProjection.js.map +1 -0
  166. package/build/services/HeadingService.d.ts +27 -0
  167. package/build/services/HeadingService.d.ts.map +1 -0
  168. package/build/services/HeadingService.js +96 -0
  169. package/build/services/HeadingService.js.map +1 -0
  170. package/build/services/LocalDisplayManager.d.ts +139 -0
  171. package/build/services/LocalDisplayManager.d.ts.map +1 -0
  172. package/build/services/LocalDisplayManager.js +579 -0
  173. package/build/services/LocalDisplayManager.js.map +1 -0
  174. package/build/services/LocalMiniappRuntime.d.ts +433 -0
  175. package/build/services/LocalMiniappRuntime.d.ts.map +1 -0
  176. package/build/services/LocalMiniappRuntime.js +3561 -0
  177. package/build/services/LocalMiniappRuntime.js.map +1 -0
  178. package/build/services/LocalSttFallbackCoordinator.d.ts +54 -0
  179. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -0
  180. package/build/services/LocalSttFallbackCoordinator.js +131 -0
  181. package/build/services/LocalSttFallbackCoordinator.js.map +1 -0
  182. package/build/services/MentraJSCrashController.d.ts +97 -0
  183. package/build/services/MentraJSCrashController.d.ts.map +1 -0
  184. package/build/services/MentraJSCrashController.js +138 -0
  185. package/build/services/MentraJSCrashController.js.map +1 -0
  186. package/build/services/MentraJSCrashloopReportService.d.ts +9 -0
  187. package/build/services/MentraJSCrashloopReportService.d.ts.map +1 -0
  188. package/build/services/MentraJSCrashloopReportService.js +54 -0
  189. package/build/services/MentraJSCrashloopReportService.js.map +1 -0
  190. package/build/services/MentraJSLogPipeline.d.ts +87 -0
  191. package/build/services/MentraJSLogPipeline.d.ts.map +1 -0
  192. package/build/services/MentraJSLogPipeline.js +137 -0
  193. package/build/services/MentraJSLogPipeline.js.map +1 -0
  194. package/build/services/MentraJSRouter.d.ts +203 -0
  195. package/build/services/MentraJSRouter.d.ts.map +1 -0
  196. package/build/services/MentraJSRouter.js +480 -0
  197. package/build/services/MentraJSRouter.js.map +1 -0
  198. package/build/services/MentraUIRouter.d.ts +137 -0
  199. package/build/services/MentraUIRouter.d.ts.map +1 -0
  200. package/build/services/MentraUIRouter.js +210 -0
  201. package/build/services/MentraUIRouter.js.map +1 -0
  202. package/build/services/MicStateCoordinator.d.ts +37 -0
  203. package/build/services/MicStateCoordinator.d.ts.map +1 -0
  204. package/build/services/MicStateCoordinator.js +81 -0
  205. package/build/services/MicStateCoordinator.js.map +1 -0
  206. package/build/services/MiniappEngine.d.ts +31 -0
  207. package/build/services/MiniappEngine.d.ts.map +1 -0
  208. package/build/services/MiniappEngine.js +119 -0
  209. package/build/services/MiniappEngine.js.map +1 -0
  210. package/build/services/MiniappLauncher.d.ts +129 -0
  211. package/build/services/MiniappLauncher.d.ts.map +1 -0
  212. package/build/services/MiniappLauncher.js +291 -0
  213. package/build/services/MiniappLauncher.js.map +1 -0
  214. package/build/services/MiniappRunningRegistry.d.ts +24 -0
  215. package/build/services/MiniappRunningRegistry.d.ts.map +1 -0
  216. package/build/services/MiniappRunningRegistry.js +52 -0
  217. package/build/services/MiniappRunningRegistry.js.map +1 -0
  218. package/build/services/NavigationHandlers.d.ts +90 -0
  219. package/build/services/NavigationHandlers.d.ts.map +1 -0
  220. package/build/services/NavigationHandlers.js +379 -0
  221. package/build/services/NavigationHandlers.js.map +1 -0
  222. package/build/services/NavigationService.d.ts +254 -0
  223. package/build/services/NavigationService.d.ts.map +1 -0
  224. package/build/services/NavigationService.js +553 -0
  225. package/build/services/NavigationService.js.map +1 -0
  226. package/build/services/NotificationsEmitter.d.ts +28 -0
  227. package/build/services/NotificationsEmitter.d.ts.map +1 -0
  228. package/build/services/NotificationsEmitter.js +22 -0
  229. package/build/services/NotificationsEmitter.js.map +1 -0
  230. package/build/services/OfflineSpeechModelService.d.ts +33 -0
  231. package/build/services/OfflineSpeechModelService.d.ts.map +1 -0
  232. package/build/services/OfflineSpeechModelService.js +136 -0
  233. package/build/services/OfflineSpeechModelService.js.map +1 -0
  234. package/build/services/OtaInstallCoordinator.d.ts +195 -0
  235. package/build/services/OtaInstallCoordinator.d.ts.map +1 -0
  236. package/build/services/OtaInstallCoordinator.js +1047 -0
  237. package/build/services/OtaInstallCoordinator.js.map +1 -0
  238. package/build/services/OtaService.d.ts +3 -0
  239. package/build/services/OtaService.d.ts.map +1 -0
  240. package/build/services/OtaService.js +65 -0
  241. package/build/services/OtaService.js.map +1 -0
  242. package/build/services/OtaUpdateCheckService.d.ts +65 -0
  243. package/build/services/OtaUpdateCheckService.d.ts.map +1 -0
  244. package/build/services/OtaUpdateCheckService.js +260 -0
  245. package/build/services/OtaUpdateCheckService.js.map +1 -0
  246. package/build/services/PairingIdentity.d.ts +80 -0
  247. package/build/services/PairingIdentity.d.ts.map +1 -0
  248. package/build/services/PairingIdentity.js +145 -0
  249. package/build/services/PairingIdentity.js.map +1 -0
  250. package/build/services/PhoneLocationService.d.ts +36 -0
  251. package/build/services/PhoneLocationService.d.ts.map +1 -0
  252. package/build/services/PhoneLocationService.js +115 -0
  253. package/build/services/PhoneLocationService.js.map +1 -0
  254. package/build/services/PhoneNotificationsSync.d.ts +3 -0
  255. package/build/services/PhoneNotificationsSync.d.ts.map +1 -0
  256. package/build/services/PhoneNotificationsSync.js +35 -0
  257. package/build/services/PhoneNotificationsSync.js.map +1 -0
  258. package/build/services/PhonePhotoCoordinator.d.ts +86 -0
  259. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -0
  260. package/build/services/PhonePhotoCoordinator.js +274 -0
  261. package/build/services/PhonePhotoCoordinator.js.map +1 -0
  262. package/build/services/PhoneStreamCoordinator.d.ts +168 -0
  263. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -0
  264. package/build/services/PhoneStreamCoordinator.js +632 -0
  265. package/build/services/PhoneStreamCoordinator.js.map +1 -0
  266. package/build/services/PhoneVideoCoordinator.d.ts +50 -0
  267. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -0
  268. package/build/services/PhoneVideoCoordinator.js +147 -0
  269. package/build/services/PhoneVideoCoordinator.js.map +1 -0
  270. package/build/services/STTModelManager.d.ts +65 -0
  271. package/build/services/STTModelManager.d.ts.map +1 -0
  272. package/build/services/STTModelManager.js +292 -0
  273. package/build/services/STTModelManager.js.map +1 -0
  274. package/build/services/SceneRenderer.d.ts +90 -0
  275. package/build/services/SceneRenderer.d.ts.map +1 -0
  276. package/build/services/SceneRenderer.js +248 -0
  277. package/build/services/SceneRenderer.js.map +1 -0
  278. package/build/services/StreamLifecycleController.d.ts +67 -0
  279. package/build/services/StreamLifecycleController.d.ts.map +1 -0
  280. package/build/services/StreamLifecycleController.js +152 -0
  281. package/build/services/StreamLifecycleController.js.map +1 -0
  282. package/build/services/TTSModelManager.d.ts +90 -0
  283. package/build/services/TTSModelManager.d.ts.map +1 -0
  284. package/build/services/TTSModelManager.js +366 -0
  285. package/build/services/TTSModelManager.js.map +1 -0
  286. package/build/services/WebviewBridge.d.ts +22 -0
  287. package/build/services/WebviewBridge.d.ts.map +1 -0
  288. package/build/services/WebviewBridge.js +47 -0
  289. package/build/services/WebviewBridge.js.map +1 -0
  290. package/build/services/asg/GalleryMediaIntegrityReportService.d.ts +17 -0
  291. package/build/services/asg/GalleryMediaIntegrityReportService.d.ts.map +1 -0
  292. package/build/services/asg/GalleryMediaIntegrityReportService.js +43 -0
  293. package/build/services/asg/GalleryMediaIntegrityReportService.js.map +1 -0
  294. package/build/services/asg/asgCameraApi.d.ts +165 -0
  295. package/build/services/asg/asgCameraApi.d.ts.map +1 -0
  296. package/build/services/asg/asgCameraApi.js +997 -0
  297. package/build/services/asg/asgCameraApi.js.map +1 -0
  298. package/build/services/asg/galleryMediaValidation.d.ts +29 -0
  299. package/build/services/asg/galleryMediaValidation.d.ts.map +1 -0
  300. package/build/services/asg/galleryMediaValidation.js +149 -0
  301. package/build/services/asg/galleryMediaValidation.js.map +1 -0
  302. package/build/services/asg/galleryNotices.d.ts +33 -0
  303. package/build/services/asg/galleryNotices.d.ts.map +1 -0
  304. package/build/services/asg/galleryNotices.js +29 -0
  305. package/build/services/asg/galleryNotices.js.map +1 -0
  306. package/build/services/asg/gallerySettingsService.d.ts +19 -0
  307. package/build/services/asg/gallerySettingsService.d.ts.map +1 -0
  308. package/build/services/asg/gallerySettingsService.js +51 -0
  309. package/build/services/asg/gallerySettingsService.js.map +1 -0
  310. package/build/services/asg/gallerySyncNotifications.d.ts +56 -0
  311. package/build/services/asg/gallerySyncNotifications.d.ts.map +1 -0
  312. package/build/services/asg/gallerySyncNotifications.js +198 -0
  313. package/build/services/asg/gallerySyncNotifications.js.map +1 -0
  314. package/build/services/asg/gallerySyncService.d.ts +137 -0
  315. package/build/services/asg/gallerySyncService.d.ts.map +1 -0
  316. package/build/services/asg/gallerySyncService.js +1839 -0
  317. package/build/services/asg/gallerySyncService.js.map +1 -0
  318. package/build/services/asg/localStorageService.d.ts +128 -0
  319. package/build/services/asg/localStorageService.d.ts.map +1 -0
  320. package/build/services/asg/localStorageService.js +423 -0
  321. package/build/services/asg/localStorageService.js.map +1 -0
  322. package/build/services/asg/mediaProcessingQueue.d.ts +60 -0
  323. package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -0
  324. package/build/services/asg/mediaProcessingQueue.js +320 -0
  325. package/build/services/asg/mediaProcessingQueue.js.map +1 -0
  326. package/build/services/asgOtaVersionUrl.d.ts +2 -0
  327. package/build/services/asgOtaVersionUrl.d.ts.map +1 -0
  328. package/build/services/asgOtaVersionUrl.js +36 -0
  329. package/build/services/asgOtaVersionUrl.js.map +1 -0
  330. package/build/services/blobPaths.d.ts +31 -0
  331. package/build/services/blobPaths.d.ts.map +1 -0
  332. package/build/services/blobPaths.js +86 -0
  333. package/build/services/blobPaths.js.map +1 -0
  334. package/build/services/cloudStreamApi.d.ts +59 -0
  335. package/build/services/cloudStreamApi.d.ts.map +1 -0
  336. package/build/services/cloudStreamApi.js +81 -0
  337. package/build/services/cloudStreamApi.js.map +1 -0
  338. package/build/services/gallerySyncClock.d.ts +17 -0
  339. package/build/services/gallerySyncClock.d.ts.map +1 -0
  340. package/build/services/gallerySyncClock.js +21 -0
  341. package/build/services/gallerySyncClock.js.map +1 -0
  342. package/build/services/glassesClockSync.d.ts +20 -0
  343. package/build/services/glassesClockSync.d.ts.map +1 -0
  344. package/build/services/glassesClockSync.js +97 -0
  345. package/build/services/glassesClockSync.js.map +1 -0
  346. package/build/services/manifestVersionGate.d.ts +28 -0
  347. package/build/services/manifestVersionGate.d.ts.map +1 -0
  348. package/build/services/manifestVersionGate.js +41 -0
  349. package/build/services/manifestVersionGate.js.map +1 -0
  350. package/build/services/mentraUiShim.d.ts +38 -0
  351. package/build/services/mentraUiShim.d.ts.map +1 -0
  352. package/build/services/mentraUiShim.js +360 -0
  353. package/build/services/mentraUiShim.js.map +1 -0
  354. package/build/services/navigation/roadNameResolver.d.ts +67 -0
  355. package/build/services/navigation/roadNameResolver.d.ts.map +1 -0
  356. package/build/services/navigation/roadNameResolver.js +96 -0
  357. package/build/services/navigation/roadNameResolver.js.map +1 -0
  358. package/build/services/navigation/routesApiCodec.d.ts +38 -0
  359. package/build/services/navigation/routesApiCodec.d.ts.map +1 -0
  360. package/build/services/navigation/routesApiCodec.js +68 -0
  361. package/build/services/navigation/routesApiCodec.js.map +1 -0
  362. package/build/services/otaDisplayState.d.ts +42 -0
  363. package/build/services/otaDisplayState.d.ts.map +1 -0
  364. package/build/services/otaDisplayState.js +92 -0
  365. package/build/services/otaDisplayState.js.map +1 -0
  366. package/build/services/otaInstallPolicy.d.ts +81 -0
  367. package/build/services/otaInstallPolicy.d.ts.map +1 -0
  368. package/build/services/otaInstallPolicy.js +96 -0
  369. package/build/services/otaInstallPolicy.js.map +1 -0
  370. package/build/services/otaLegacyMapping.d.ts +22 -0
  371. package/build/services/otaLegacyMapping.d.ts.map +1 -0
  372. package/build/services/otaLegacyMapping.js +56 -0
  373. package/build/services/otaLegacyMapping.js.map +1 -0
  374. package/build/services/slimStreamStatus.d.ts +7 -0
  375. package/build/services/slimStreamStatus.d.ts.map +1 -0
  376. package/build/services/slimStreamStatus.js +26 -0
  377. package/build/services/slimStreamStatus.js.map +1 -0
  378. package/build/stores/apps.d.ts +104 -0
  379. package/build/stores/apps.d.ts.map +1 -0
  380. package/build/stores/apps.js +492 -0
  381. package/build/stores/apps.js.map +1 -0
  382. package/build/stores/bluetoothSettingKeys.d.ts +4 -0
  383. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -0
  384. package/build/stores/bluetoothSettingKeys.js +31 -0
  385. package/build/stores/bluetoothSettingKeys.js.map +1 -0
  386. package/build/stores/cloudClientStatus.d.ts +9 -0
  387. package/build/stores/cloudClientStatus.d.ts.map +1 -0
  388. package/build/stores/cloudClientStatus.js +24 -0
  389. package/build/stores/cloudClientStatus.js.map +1 -0
  390. package/build/stores/connection.d.ts +22 -0
  391. package/build/stores/connection.d.ts.map +1 -0
  392. package/build/stores/connection.js +43 -0
  393. package/build/stores/connection.js.map +1 -0
  394. package/build/stores/core.d.ts +15 -0
  395. package/build/stores/core.d.ts.map +1 -0
  396. package/build/stores/core.js +21 -0
  397. package/build/stores/core.js.map +1 -0
  398. package/build/stores/display.d.ts +24 -0
  399. package/build/stores/display.d.ts.map +1 -0
  400. package/build/stores/display.js +96 -0
  401. package/build/stores/display.js.map +1 -0
  402. package/build/stores/gallerySync.d.ts +101 -0
  403. package/build/stores/gallerySync.d.ts.map +1 -0
  404. package/build/stores/gallerySync.js +217 -0
  405. package/build/stores/gallerySync.js.map +1 -0
  406. package/build/stores/glasses.d.ts +62 -0
  407. package/build/stores/glasses.d.ts.map +1 -0
  408. package/build/stores/glasses.js +203 -0
  409. package/build/stores/glasses.js.map +1 -0
  410. package/build/stores/settings.d.ts +37 -0
  411. package/build/stores/settings.d.ts.map +1 -0
  412. package/build/stores/settings.js +915 -0
  413. package/build/stores/settings.js.map +1 -0
  414. package/build/types/applet.d.ts +96 -0
  415. package/build/types/applet.d.ts.map +1 -0
  416. package/build/types/applet.js +5 -0
  417. package/build/types/applet.js.map +1 -0
  418. package/build/types/asg.d.ts +46 -0
  419. package/build/types/asg.d.ts.map +1 -0
  420. package/build/types/asg.js +2 -0
  421. package/build/types/asg.js.map +1 -0
  422. package/build/types/capabilities/even-realities-g1.d.ts +12 -0
  423. package/build/types/capabilities/even-realities-g1.d.ts.map +1 -0
  424. package/build/types/capabilities/even-realities-g1.js +55 -0
  425. package/build/types/capabilities/even-realities-g1.js.map +1 -0
  426. package/build/types/capabilities/even-realities-g2.d.ts +12 -0
  427. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -0
  428. package/build/types/capabilities/even-realities-g2.js +75 -0
  429. package/build/types/capabilities/even-realities-g2.js.map +1 -0
  430. package/build/types/capabilities/mentra-display.d.ts +12 -0
  431. package/build/types/capabilities/mentra-display.d.ts.map +1 -0
  432. package/build/types/capabilities/mentra-display.js +63 -0
  433. package/build/types/capabilities/mentra-display.js.map +1 -0
  434. package/build/types/capabilities/mentra-live.d.ts +12 -0
  435. package/build/types/capabilities/mentra-live.d.ts.map +1 -0
  436. package/build/types/capabilities/mentra-live.js +92 -0
  437. package/build/types/capabilities/mentra-live.js.map +1 -0
  438. package/build/types/capabilities/none.d.ts +13 -0
  439. package/build/types/capabilities/none.d.ts.map +1 -0
  440. package/build/types/capabilities/none.js +65 -0
  441. package/build/types/capabilities/none.js.map +1 -0
  442. package/build/types/capabilities/simulated-glasses.d.ts +13 -0
  443. package/build/types/capabilities/simulated-glasses.d.ts.map +1 -0
  444. package/build/types/capabilities/simulated-glasses.js +65 -0
  445. package/build/types/capabilities/simulated-glasses.js.map +1 -0
  446. package/build/types/capabilities/vuzix-z100.d.ts +12 -0
  447. package/build/types/capabilities/vuzix-z100.d.ts.map +1 -0
  448. package/build/types/capabilities/vuzix-z100.js +52 -0
  449. package/build/types/capabilities/vuzix-z100.js.map +1 -0
  450. package/build/types/enums.d.ts +40 -0
  451. package/build/types/enums.d.ts.map +1 -0
  452. package/build/types/enums.js +44 -0
  453. package/build/types/enums.js.map +1 -0
  454. package/build/types/hardware.d.ts +160 -0
  455. package/build/types/hardware.d.ts.map +1 -0
  456. package/build/types/hardware.js +36 -0
  457. package/build/types/hardware.js.map +1 -0
  458. package/build/types/index.d.ts +11 -0
  459. package/build/types/index.d.ts.map +1 -0
  460. package/build/types/index.js +10 -0
  461. package/build/types/index.js.map +1 -0
  462. package/build/utils/GlobalEventEmitter.d.ts +10 -0
  463. package/build/utils/GlobalEventEmitter.d.ts.map +1 -0
  464. package/build/utils/GlobalEventEmitter.js +13 -0
  465. package/build/utils/GlobalEventEmitter.js.map +1 -0
  466. package/build/utils/cloudClient/RnUdpAdapter.d.ts +3 -0
  467. package/build/utils/cloudClient/RnUdpAdapter.d.ts.map +1 -0
  468. package/build/utils/cloudClient/RnUdpAdapter.js +41 -0
  469. package/build/utils/cloudClient/RnUdpAdapter.js.map +1 -0
  470. package/build/utils/cloudClient/cloudSecureStore.d.ts +3 -0
  471. package/build/utils/cloudClient/cloudSecureStore.d.ts.map +1 -0
  472. package/build/utils/cloudClient/cloudSecureStore.js +26 -0
  473. package/build/utils/cloudClient/cloudSecureStore.js.map +1 -0
  474. package/build/utils/debouncedPatch.d.ts +6 -0
  475. package/build/utils/debouncedPatch.d.ts.map +1 -0
  476. package/build/utils/debouncedPatch.js +25 -0
  477. package/build/utils/debouncedPatch.js.map +1 -0
  478. package/build/utils/devLogging.d.ts +26 -0
  479. package/build/utils/devLogging.d.ts.map +1 -0
  480. package/build/utils/devLogging.js +116 -0
  481. package/build/utils/devLogging.js.map +1 -0
  482. package/build/utils/devMiniappLaunch.d.ts +44 -0
  483. package/build/utils/devMiniappLaunch.d.ts.map +1 -0
  484. package/build/utils/devMiniappLaunch.js +52 -0
  485. package/build/utils/devMiniappLaunch.js.map +1 -0
  486. package/build/utils/diagnosticContext.d.ts +3 -0
  487. package/build/utils/diagnosticContext.d.ts.map +1 -0
  488. package/build/utils/diagnosticContext.js +119 -0
  489. package/build/utils/diagnosticContext.js.map +1 -0
  490. package/build/utils/display/composer/ColumnComposer.d.ts +131 -0
  491. package/build/utils/display/composer/ColumnComposer.d.ts.map +1 -0
  492. package/build/utils/display/composer/ColumnComposer.js +204 -0
  493. package/build/utils/display/composer/ColumnComposer.js.map +1 -0
  494. package/build/utils/display/composer/index.d.ts +9 -0
  495. package/build/utils/display/composer/index.d.ts.map +1 -0
  496. package/build/utils/display/composer/index.js +9 -0
  497. package/build/utils/display/composer/index.js.map +1 -0
  498. package/build/utils/display/helpers/DisplayHelpers.d.ts +165 -0
  499. package/build/utils/display/helpers/DisplayHelpers.d.ts.map +1 -0
  500. package/build/utils/display/helpers/DisplayHelpers.js +312 -0
  501. package/build/utils/display/helpers/DisplayHelpers.js.map +1 -0
  502. package/build/utils/display/helpers/ScrollView.d.ts +183 -0
  503. package/build/utils/display/helpers/ScrollView.d.ts.map +1 -0
  504. package/build/utils/display/helpers/ScrollView.js +257 -0
  505. package/build/utils/display/helpers/ScrollView.js.map +1 -0
  506. package/build/utils/display/helpers/index.d.ts +11 -0
  507. package/build/utils/display/helpers/index.d.ts.map +1 -0
  508. package/build/utils/display/helpers/index.js +10 -0
  509. package/build/utils/display/helpers/index.js.map +1 -0
  510. package/build/utils/display/index.d.ts +174 -0
  511. package/build/utils/display/index.d.ts.map +1 -0
  512. package/build/utils/display/index.js +185 -0
  513. package/build/utils/display/index.js.map +1 -0
  514. package/build/utils/display/measurer/TextMeasurer.d.ts +160 -0
  515. package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -0
  516. package/build/utils/display/measurer/TextMeasurer.js +273 -0
  517. package/build/utils/display/measurer/TextMeasurer.js.map +1 -0
  518. package/build/utils/display/measurer/index.d.ts +10 -0
  519. package/build/utils/display/measurer/index.d.ts.map +1 -0
  520. package/build/utils/display/measurer/index.js +11 -0
  521. package/build/utils/display/measurer/index.js.map +1 -0
  522. package/build/utils/display/measurer/script-detection.d.ts +53 -0
  523. package/build/utils/display/measurer/script-detection.d.ts.map +1 -0
  524. package/build/utils/display/measurer/script-detection.js +184 -0
  525. package/build/utils/display/measurer/script-detection.js.map +1 -0
  526. package/build/utils/display/profiles/g1.d.ts +33 -0
  527. package/build/utils/display/profiles/g1.d.ts.map +1 -0
  528. package/build/utils/display/profiles/g1.js +213 -0
  529. package/build/utils/display/profiles/g1.js.map +1 -0
  530. package/build/utils/display/profiles/g2.d.ts +13 -0
  531. package/build/utils/display/profiles/g2.d.ts.map +1 -0
  532. package/build/utils/display/profiles/g2.js +34 -0
  533. package/build/utils/display/profiles/g2.js.map +1 -0
  534. package/build/utils/display/profiles/index.d.ts +12 -0
  535. package/build/utils/display/profiles/index.d.ts.map +1 -0
  536. package/build/utils/display/profiles/index.js +15 -0
  537. package/build/utils/display/profiles/index.js.map +1 -0
  538. package/build/utils/display/profiles/nex.d.ts +10 -0
  539. package/build/utils/display/profiles/nex.d.ts.map +1 -0
  540. package/build/utils/display/profiles/nex.js +150 -0
  541. package/build/utils/display/profiles/nex.js.map +1 -0
  542. package/build/utils/display/profiles/types.d.ts +103 -0
  543. package/build/utils/display/profiles/types.d.ts.map +1 -0
  544. package/build/utils/display/profiles/types.js +2 -0
  545. package/build/utils/display/profiles/types.js.map +1 -0
  546. package/build/utils/display/profiles/z100.d.ts +33 -0
  547. package/build/utils/display/profiles/z100.d.ts.map +1 -0
  548. package/build/utils/display/profiles/z100.js +182 -0
  549. package/build/utils/display/profiles/z100.js.map +1 -0
  550. package/build/utils/display/scene/degrade.d.ts +25 -0
  551. package/build/utils/display/scene/degrade.d.ts.map +1 -0
  552. package/build/utils/display/scene/degrade.js +64 -0
  553. package/build/utils/display/scene/degrade.js.map +1 -0
  554. package/build/utils/display/scene/differ.d.ts +38 -0
  555. package/build/utils/display/scene/differ.d.ts.map +1 -0
  556. package/build/utils/display/scene/differ.js +107 -0
  557. package/build/utils/display/scene/differ.js.map +1 -0
  558. package/build/utils/display/scene/index.d.ts +10 -0
  559. package/build/utils/display/scene/index.d.ts.map +1 -0
  560. package/build/utils/display/scene/index.js +6 -0
  561. package/build/utils/display/scene/index.js.map +1 -0
  562. package/build/utils/display/scene/process.d.ts +35 -0
  563. package/build/utils/display/scene/process.d.ts.map +1 -0
  564. package/build/utils/display/scene/process.js +187 -0
  565. package/build/utils/display/scene/process.js.map +1 -0
  566. package/build/utils/display/scene/store.d.ts +48 -0
  567. package/build/utils/display/scene/store.d.ts.map +1 -0
  568. package/build/utils/display/scene/store.js +0 -0
  569. package/build/utils/display/scene/store.js.map +1 -0
  570. package/build/utils/display/scene/types.d.ts +120 -0
  571. package/build/utils/display/scene/types.d.ts.map +1 -0
  572. package/build/utils/display/scene/types.js +0 -0
  573. package/build/utils/display/scene/types.js.map +1 -0
  574. package/build/utils/display/wrapper/TextWrapper.d.ts +102 -0
  575. package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -0
  576. package/build/utils/display/wrapper/TextWrapper.js +471 -0
  577. package/build/utils/display/wrapper/TextWrapper.js.map +1 -0
  578. package/build/utils/display/wrapper/index.d.ts +12 -0
  579. package/build/utils/display/wrapper/index.d.ts.map +1 -0
  580. package/build/utils/display/wrapper/index.js +12 -0
  581. package/build/utils/display/wrapper/index.js.map +1 -0
  582. package/build/utils/display/wrapper/types.d.ts +75 -0
  583. package/build/utils/display/wrapper/types.d.ts.map +1 -0
  584. package/build/utils/display/wrapper/types.js +11 -0
  585. package/build/utils/display/wrapper/types.js.map +1 -0
  586. package/build/utils/e2eMetrics.d.ts +6 -0
  587. package/build/utils/e2eMetrics.d.ts.map +1 -0
  588. package/build/utils/e2eMetrics.js +27 -0
  589. package/build/utils/e2eMetrics.js.map +1 -0
  590. package/build/utils/hardware/hardware.d.ts +42 -0
  591. package/build/utils/hardware/hardware.d.ts.map +1 -0
  592. package/build/utils/hardware/hardware.js +127 -0
  593. package/build/utils/hardware/hardware.js.map +1 -0
  594. package/build/utils/hardware/index.d.ts +2 -0
  595. package/build/utils/hardware/index.d.ts.map +1 -0
  596. package/build/utils/hardware/index.js +2 -0
  597. package/build/utils/hardware/index.js.map +1 -0
  598. package/build/utils/miniappGlobals.d.ts +60 -0
  599. package/build/utils/miniappGlobals.d.ts.map +1 -0
  600. package/build/utils/miniappGlobals.js +224 -0
  601. package/build/utils/miniappGlobals.js.map +1 -0
  602. package/build/utils/permissions/MediaLibraryPermissions.d.ts +34 -0
  603. package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -0
  604. package/build/utils/permissions/MediaLibraryPermissions.js +122 -0
  605. package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -0
  606. package/build/utils/permissions/galleryDisplayName.d.ts +8 -0
  607. package/build/utils/permissions/galleryDisplayName.d.ts.map +1 -0
  608. package/build/utils/permissions/galleryDisplayName.js +25 -0
  609. package/build/utils/permissions/galleryDisplayName.js.map +1 -0
  610. package/build/utils/storage/index.d.ts +3 -0
  611. package/build/utils/storage/index.d.ts.map +1 -0
  612. package/build/utils/storage/index.js +3 -0
  613. package/build/utils/storage/index.js.map +1 -0
  614. package/build/utils/storage/storage.d.ts +24 -0
  615. package/build/utils/storage/storage.d.ts.map +1 -0
  616. package/build/utils/storage/storage.js +85 -0
  617. package/build/utils/storage/storage.js.map +1 -0
  618. package/build/utils/storage/zip.d.ts +3 -0
  619. package/build/utils/storage/zip.d.ts.map +1 -0
  620. package/build/utils/storage/zip.js +14 -0
  621. package/build/utils/storage/zip.js.map +1 -0
  622. package/build/utils/timers/index.d.ts +3 -0
  623. package/build/utils/timers/index.d.ts.map +1 -0
  624. package/build/utils/timers/index.js +3 -0
  625. package/build/utils/timers/index.js.map +1 -0
  626. package/build/utils/timers/timers.d.ts +9 -0
  627. package/build/utils/timers/timers.d.ts.map +1 -0
  628. package/build/utils/timers/timers.js +105 -0
  629. package/build/utils/timers/timers.js.map +1 -0
  630. package/package.json +119 -0
  631. package/src/devtools.ts +13 -0
  632. package/src/engine.ts +173 -0
  633. package/src/facades/dev.ts +197 -0
  634. package/src/facades/display.ts +17 -0
  635. package/src/facades/displayMirror.ts +33 -0
  636. package/src/facades/gallery.ts +69 -0
  637. package/src/facades/glasses.ts +206 -0
  638. package/src/facades/glassesSettings.ts +56 -0
  639. package/src/facades/glassesWifi.ts +68 -0
  640. package/src/facades/miniapps.ts +55 -0
  641. package/src/facades/notifications.ts +15 -0
  642. package/src/facades/ota.ts +174 -0
  643. package/src/facades/pairing.ts +329 -0
  644. package/src/facades/permissions.ts +151 -0
  645. package/src/facades/phoneNotifications.ts +50 -0
  646. package/src/facades/reports.ts +185 -0
  647. package/src/facades/session.ts +55 -0
  648. package/src/facades/settings.ts +57 -0
  649. package/src/facades/speech.ts +38 -0
  650. package/src/index.ts +191 -0
  651. package/src/internal.ts +158 -0
  652. package/src/runtime/bootstrap.ts +118 -0
  653. package/src/runtime/config.ts +147 -0
  654. package/src/runtime/streamConfig.ts +34 -0
  655. package/src/services/AppRegistry.ts +1139 -0
  656. package/src/services/AudioCloudUplink.ts +34 -0
  657. package/src/services/AudioPlaybackService.ts +624 -0
  658. package/src/services/AutomaticReportResult.ts +48 -0
  659. package/src/services/BlobStore.ts +746 -0
  660. package/src/services/CaptionsTesterReportService.ts +107 -0
  661. package/src/services/CloudAudioSubscriptionSync.ts +41 -0
  662. package/src/services/CloudClientService.ts +668 -0
  663. package/src/services/CloudTranscriptE2EMetrics.ts +27 -0
  664. package/src/services/ConnectionCoordinator.ts +65 -0
  665. package/src/services/DevServerBridge.ts +332 -0
  666. package/src/services/DeviceEventRouter.ts +238 -0
  667. package/src/services/DeviceStoreHydration.ts +130 -0
  668. package/src/services/DisplayProcessor.ts +775 -0
  669. package/src/services/GlassesReadiness.ts +103 -0
  670. package/src/services/GlassesSettingsSync.ts +134 -0
  671. package/src/services/GlassesStatusProjection.ts +73 -0
  672. package/src/services/HeadingService.ts +98 -0
  673. package/src/services/LocalDisplayManager.ts +703 -0
  674. package/src/services/LocalMiniappRuntime.ts +4038 -0
  675. package/src/services/LocalSttFallbackCoordinator.ts +140 -0
  676. package/src/services/MentraJSCrashController.ts +189 -0
  677. package/src/services/MentraJSCrashloopReportService.ts +66 -0
  678. package/src/services/MentraJSLogPipeline.ts +166 -0
  679. package/src/services/MentraJSRouter.ts +557 -0
  680. package/src/services/MentraUIRouter.ts +244 -0
  681. package/src/services/MicStateCoordinator.ts +94 -0
  682. package/src/services/MiniappEngine.ts +143 -0
  683. package/src/services/MiniappLauncher.ts +340 -0
  684. package/src/services/MiniappRunningRegistry.ts +57 -0
  685. package/src/services/NavigationHandlers.ts +423 -0
  686. package/src/services/NavigationService.ts +731 -0
  687. package/src/services/NotificationsEmitter.ts +48 -0
  688. package/src/services/OfflineSpeechModelService.ts +168 -0
  689. package/src/services/OtaInstallCoordinator.ts +1205 -0
  690. package/src/services/OtaService.ts +83 -0
  691. package/src/services/OtaUpdateCheckService.ts +386 -0
  692. package/src/services/PairingIdentity.ts +154 -0
  693. package/src/services/PhoneLocationService.ts +122 -0
  694. package/src/services/PhoneNotificationsSync.ts +44 -0
  695. package/src/services/PhonePhotoCoordinator.ts +337 -0
  696. package/src/services/PhoneStreamCoordinator.ts +777 -0
  697. package/src/services/PhoneVideoCoordinator.ts +189 -0
  698. package/src/services/STTModelManager.ts +360 -0
  699. package/src/services/SceneRenderer.ts +292 -0
  700. package/src/services/StreamLifecycleController.ts +213 -0
  701. package/src/services/TTSModelManager.ts +466 -0
  702. package/src/services/WebviewBridge.ts +50 -0
  703. package/src/services/asg/GalleryMediaIntegrityReportService.ts +70 -0
  704. package/src/services/asg/asgCameraApi.ts +1204 -0
  705. package/src/services/asg/galleryMediaValidation.ts +183 -0
  706. package/src/services/asg/galleryNotices.ts +60 -0
  707. package/src/services/asg/gallerySettingsService.ts +65 -0
  708. package/src/services/asg/gallerySyncNotifications.ts +236 -0
  709. package/src/services/asg/gallerySyncService.ts +2167 -0
  710. package/src/services/asg/localStorageService.ts +497 -0
  711. package/src/services/asg/mediaProcessingQueue.ts +371 -0
  712. package/src/services/asgOtaVersionUrl.ts +41 -0
  713. package/src/services/blobPaths.ts +86 -0
  714. package/src/services/cloudStreamApi.ts +154 -0
  715. package/src/services/gallerySyncClock.ts +39 -0
  716. package/src/services/glassesClockSync.ts +115 -0
  717. package/src/services/manifestVersionGate.ts +43 -0
  718. package/src/services/mentraUiShim.ts +366 -0
  719. package/src/services/navigation/roadNameResolver.ts +112 -0
  720. package/src/services/navigation/routesApiCodec.ts +69 -0
  721. package/src/services/otaDisplayState.ts +115 -0
  722. package/src/services/otaInstallPolicy.ts +106 -0
  723. package/src/services/otaLegacyMapping.ts +71 -0
  724. package/src/services/slimStreamStatus.ts +28 -0
  725. package/src/stores/apps.ts +614 -0
  726. package/src/stores/bluetoothSettingKeys.ts +36 -0
  727. package/src/stores/cloudClientStatus.ts +37 -0
  728. package/src/stores/connection.ts +69 -0
  729. package/src/stores/core.ts +32 -0
  730. package/src/stores/display.ts +121 -0
  731. package/src/stores/gallerySync.ts +380 -0
  732. package/src/stores/glasses.ts +309 -0
  733. package/src/stores/settings.ts +993 -0
  734. package/src/types/applet.ts +112 -0
  735. package/src/types/asg.ts +51 -0
  736. package/src/types/capabilities/even-realities-g1.ts +67 -0
  737. package/src/types/capabilities/even-realities-g2.ts +88 -0
  738. package/src/types/capabilities/mentra-display.ts +75 -0
  739. package/src/types/capabilities/mentra-live.ts +103 -0
  740. package/src/types/capabilities/none.ts +76 -0
  741. package/src/types/capabilities/simulated-glasses.ts +76 -0
  742. package/src/types/capabilities/vuzix-z100.ts +64 -0
  743. package/src/types/enums.ts +43 -0
  744. package/src/types/hardware.ts +203 -0
  745. package/src/types/index.ts +37 -0
  746. package/src/utils/GlobalEventEmitter.ts +14 -0
  747. package/src/utils/cloudClient/RnUdpAdapter.ts +47 -0
  748. package/src/utils/cloudClient/cloudSecureStore.ts +28 -0
  749. package/src/utils/debouncedPatch.ts +28 -0
  750. package/src/utils/devLogging.ts +140 -0
  751. package/src/utils/devMiniappLaunch.ts +68 -0
  752. package/src/utils/diagnosticContext.ts +155 -0
  753. package/src/utils/display/composer/ColumnComposer.ts +285 -0
  754. package/src/utils/display/composer/index.ts +15 -0
  755. package/src/utils/display/helpers/DisplayHelpers.ts +413 -0
  756. package/src/utils/display/helpers/ScrollView.ts +337 -0
  757. package/src/utils/display/helpers/index.ts +14 -0
  758. package/src/utils/display/index.ts +273 -0
  759. package/src/utils/display/measurer/TextMeasurer.ts +346 -0
  760. package/src/utils/display/measurer/index.ts +21 -0
  761. package/src/utils/display/measurer/script-detection.ts +218 -0
  762. package/src/utils/display/profiles/g1.ts +236 -0
  763. package/src/utils/display/profiles/g2.ts +39 -0
  764. package/src/utils/display/profiles/index.ts +28 -0
  765. package/src/utils/display/profiles/nex.ts +166 -0
  766. package/src/utils/display/profiles/types.ts +132 -0
  767. package/src/utils/display/profiles/z100.ts +198 -0
  768. package/src/utils/display/scene/degrade.ts +80 -0
  769. package/src/utils/display/scene/differ.ts +128 -0
  770. package/src/utils/display/scene/index.ts +21 -0
  771. package/src/utils/display/scene/process.ts +214 -0
  772. package/src/utils/display/scene/store.ts +0 -0
  773. package/src/utils/display/scene/types.ts +0 -0
  774. package/src/utils/display/wrapper/TextWrapper.ts +546 -0
  775. package/src/utils/display/wrapper/index.ts +15 -0
  776. package/src/utils/display/wrapper/types.ts +102 -0
  777. package/src/utils/e2eMetrics.ts +30 -0
  778. package/src/utils/hardware/hardware.ts +166 -0
  779. package/src/utils/hardware/index.ts +1 -0
  780. package/src/utils/miniappGlobals.ts +260 -0
  781. package/src/utils/permissions/MediaLibraryPermissions.ts +130 -0
  782. package/src/utils/permissions/galleryDisplayName.ts +28 -0
  783. package/src/utils/storage/index.ts +2 -0
  784. package/src/utils/storage/storage.ts +101 -0
  785. package/src/utils/storage/zip.ts +13 -0
  786. package/src/utils/timers/index.ts +2 -0
  787. package/src/utils/timers/timers.ts +139 -0
@@ -0,0 +1,1204 @@
1
+ /**
2
+ * ASG Camera Server API Client
3
+ * Provides methods to interact with the AsgCameraServer Java APIs
4
+ */
5
+
6
+ import * as RNFS from "@dr.pogodin/react-native-fs"
7
+
8
+ import {PhotoInfo, CaptureGroup, GalleryResponse, ServerStatus, HealthResponse} from "../../types/asg"
9
+ import {BgTimer} from "../../utils/timers"
10
+
11
+ import {localStorageService} from "./localStorageService"
12
+ import {validateDownloadedMediaFile} from "./galleryMediaValidation"
13
+ import {reportInvalidGalleryMedia} from "./GalleryMediaIntegrityReportService"
14
+
15
+ export class AsgCameraApiClient {
16
+ private baseUrl: string
17
+ private port: number
18
+ private lastRequestTime: number = 0
19
+
20
+ constructor(serverUrl?: string, port: number = 8089) {
21
+ this.port = port
22
+ this.baseUrl = serverUrl || `http://localhost:${port}`
23
+ console.log(`[ASG Camera API] Client initialized with server: ${this.baseUrl}`)
24
+ }
25
+
26
+ private createTimeoutSignal(timeoutMs: number): AbortSignal {
27
+ const controller = new AbortController()
28
+ BgTimer.setTimeout(() => controller.abort(), timeoutMs)
29
+ return controller.signal
30
+ }
31
+
32
+ /**
33
+ * Set the server URL and port
34
+ */
35
+ setServer(serverUrl: string, port?: number) {
36
+ console.log(`[ASG Camera API] setServer called with serverUrl: ${serverUrl}, port: ${port}`)
37
+ const newPort = port || this.port
38
+ const newUrl = `http://${serverUrl.replace(/^https?:\/\//, "")}:${newPort}`
39
+
40
+ console.log(`[ASG Camera API] Constructed newUrl: ${newUrl}`)
41
+ // console.log(`[ASG Camera API] Current baseUrl: ${this.baseUrl}`)
42
+
43
+ // Only update if the URL actually changed
44
+ if (this.baseUrl !== newUrl) {
45
+ this.baseUrl = newUrl
46
+ this.port = newPort
47
+ // console.log(`[ASG Camera API] Server changed from ${oldUrl} to ${this.baseUrl}`)
48
+ } else {
49
+ // console.log(`[ASG Camera API] Server URL unchanged: ${this.baseUrl}`)
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Get the current server URL
55
+ */
56
+ getServerUrl(): string {
57
+ return this.baseUrl
58
+ }
59
+
60
+ /**
61
+ * Rate limiting helper - ensures minimum delay between requests
62
+ */
63
+ private async rateLimit(): Promise<void> {
64
+ const now = Date.now()
65
+ const timeSinceLastRequest = now - this.lastRequestTime
66
+ const minDelay = 500 // 500ms minimum delay between requests
67
+
68
+ if (timeSinceLastRequest < minDelay) {
69
+ const delay = minDelay - timeSinceLastRequest
70
+ console.log(`[ASG Camera API] Rate limiting: waiting ${delay}ms`)
71
+ await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), delay))
72
+ }
73
+
74
+ this.lastRequestTime = Date.now()
75
+ }
76
+
77
+ /**
78
+ * Make a request to the ASG Camera Server with rate limiting and retry logic
79
+ */
80
+ private async makeRequest<T>(endpoint: string, options?: RequestInit, retries: number = 5): Promise<T> {
81
+ const url = `${this.baseUrl}${endpoint}`
82
+ const method = options?.method || "GET"
83
+
84
+ console.log(`[ASG Camera API] makeRequest called with endpoint: ${endpoint}`)
85
+ console.log(`[ASG Camera API] Current baseUrl: ${this.baseUrl}`)
86
+ console.log(`[ASG Camera API] Full URL: ${url}`)
87
+ console.log(`[ASG Camera API] Method: ${method}`)
88
+ console.log(`[ASG Camera API] Retries remaining: ${retries}`)
89
+ console.log(`[ASG Camera API] Request options:`, {
90
+ method,
91
+ headers: options?.headers,
92
+ body: options?.body ? "Present" : "None",
93
+ })
94
+
95
+ const startTime = Date.now()
96
+
97
+ try {
98
+ // Apply rate limiting only for non-GET requests
99
+ if (method !== "GET") {
100
+ await this.rateLimit()
101
+ }
102
+
103
+ // Prepare headers - don't set Content-Type for GET requests
104
+ const headers: Record<string, string> = {
105
+ "Accept": "application/json",
106
+ "User-Agent": "MentraOS-Mobile/1.0",
107
+ }
108
+ if (method !== "GET") {
109
+ headers["Content-Type"] = "application/json"
110
+ }
111
+ if (options?.headers) {
112
+ Object.assign(headers, options.headers)
113
+ }
114
+
115
+ console.log(`[ASG Camera API] Making fetch request to: ${url}`)
116
+ console.log(`[ASG Camera API] Headers being sent:`, headers)
117
+
118
+ // N4: Add 30s timeout to all fetch calls in makeRequest
119
+ const response = await fetch(url, {
120
+ headers,
121
+ ...options,
122
+ signal: options?.signal || this.createTimeoutSignal(30000),
123
+ })
124
+
125
+ const duration = Date.now() - startTime
126
+ console.log(`[ASG Camera API] Response received in ${duration}ms:`, {
127
+ status: response.status,
128
+ statusText: response.statusText,
129
+ contentType: response.headers.get("content-type"),
130
+ contentLength: response.headers.get("content-length"),
131
+ url: response.url,
132
+ })
133
+
134
+ if (!response.ok) {
135
+ console.error(`[ASG Camera API] HTTP Error ${response.status}: ${response.statusText}`)
136
+
137
+ // Handle rate limiting with retry
138
+ if (response.status === 429 && retries > 0) {
139
+ // N3: Cap individual retry delay at 10s
140
+ const retryDelay = Math.min(Math.pow(2, 6 - retries) * 1000, 10000)
141
+ console.log(`[ASG Camera API] Rate limited, retrying in ${retryDelay}ms (${retries} retries left)`)
142
+ await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), retryDelay))
143
+ return this.makeRequest<T>(endpoint, options, retries - 1)
144
+ }
145
+
146
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
147
+ }
148
+
149
+ // Handle different response types
150
+ const contentType = response.headers.get("content-type")
151
+ console.log(`[ASG Camera API] Response content-type: ${contentType}`)
152
+
153
+ if (contentType?.includes("application/json")) {
154
+ const data = await response.json()
155
+ console.log(`[ASG Camera API] JSON Response received:`, data)
156
+ return data
157
+ } else if (contentType?.includes("image/") || contentType?.includes("application/octet-stream")) {
158
+ // For image responses and binary data (including AVIF), return the blob
159
+ const blob = await response.blob()
160
+ console.log(`[ASG Camera API] Binary/Image Response received:`, {
161
+ size: blob.size,
162
+ type: blob.type,
163
+ })
164
+
165
+ // Quick check if this might be an AVIF file
166
+ if (contentType?.includes("application/octet-stream") && blob.size > 12) {
167
+ const arrayBuffer = await blob.arrayBuffer()
168
+ const bytes = new Uint8Array(arrayBuffer.slice(4, 12))
169
+ const ftypSignature = String.fromCharCode(...bytes)
170
+ if (ftypSignature === "ftypavif") {
171
+ console.log(`[ASG Camera API] Detected AVIF file in response`)
172
+ }
173
+ // Return a new blob since we consumed the original
174
+ return new Blob([arrayBuffer], {type: blob.type}) as T
175
+ }
176
+
177
+ return blob as T
178
+ } else {
179
+ // For text responses
180
+ const text = await response.text()
181
+ console.log(
182
+ `[ASG Camera API] Text Response received:`,
183
+ text.substring(0, 200) + (text.length > 200 ? "..." : ""),
184
+ )
185
+ return text as T
186
+ }
187
+ } catch (error) {
188
+ const duration = Date.now() - startTime
189
+ console.error(`[ASG Camera API] Error (${endpoint}) after ${duration}ms:`, error)
190
+ console.error(`[ASG Camera API] Error details:`, {
191
+ endpoint,
192
+ url,
193
+ method,
194
+ duration,
195
+ errorMessage: error instanceof Error ? error.message : String(error),
196
+ errorStack: error instanceof Error ? error.stack : undefined,
197
+ })
198
+ throw error
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Take a picture using the ASG camera
204
+ */
205
+ async takePicture(): Promise<{message: string}> {
206
+ console.log(`[ASG Camera API] Taking picture...`)
207
+ return this.makeRequest<{message: string}>("/api/take-picture", {
208
+ method: "POST",
209
+ })
210
+ }
211
+
212
+ /**
213
+ * Get the latest photo as a blob
214
+ */
215
+ async getLatestPhoto(): Promise<Blob> {
216
+ console.log(`[ASG Camera API] Getting latest photo...`)
217
+ return this.makeRequest<Blob>("/api/latest-photo")
218
+ }
219
+
220
+ /**
221
+ * Get the latest photo as a data URL
222
+ */
223
+ async getLatestPhotoAsDataUrl(): Promise<string> {
224
+ console.log(`[ASG Camera API] Getting latest photo as data URL...`)
225
+ const blob = await this.getLatestPhoto()
226
+ return new Promise((resolve, reject) => {
227
+ const reader = new FileReader()
228
+ reader.onload = () => resolve(reader.result as string)
229
+ reader.onerror = reject
230
+ reader.readAsDataURL(blob)
231
+ })
232
+ }
233
+
234
+ /**
235
+ * Get gallery photos from the server with optional pagination
236
+ */
237
+ async getGallery(limit?: number, offset?: number): Promise<GalleryResponse> {
238
+ console.log(`[ASG Camera API] getGallery called with limit=${limit}, offset=${offset}`)
239
+ // console.log(`[ASG Camera API] Current baseUrl: ${this.baseUrl}`)
240
+
241
+ // Build URL with optional query parameters
242
+ let galleryUrl = `${this.baseUrl}/api/gallery`
243
+ const params = new URLSearchParams()
244
+ if (limit !== undefined) params.append("limit", limit.toString())
245
+ if (offset !== undefined) params.append("offset", offset.toString())
246
+ if (params.toString()) galleryUrl += `?${params.toString()}`
247
+
248
+ console.log(`[ASG Camera API] Full gallery URL: ${galleryUrl}`)
249
+
250
+ // Use browser-like headers since we know the browser works
251
+ try {
252
+ console.log(`[ASG Camera API] Making direct fetch to gallery endpoint`)
253
+ const response = await fetch(galleryUrl, {
254
+ method: "GET",
255
+ headers: {
256
+ "Accept": "application/json",
257
+ "User-Agent": "MentraOS-Mobile/1.0",
258
+ },
259
+ signal: this.createTimeoutSignal(10000), // 10 second timeout
260
+ })
261
+
262
+ console.log(`[ASG Camera API] Response status: ${response.status}`)
263
+
264
+ if (!response.ok) {
265
+ throw new Error(`Gallery endpoint returned: ${response.status}`)
266
+ }
267
+
268
+ const responseText = await response.text()
269
+ console.log(`[ASG Camera API] Raw response:`, responseText.substring(0, 1000))
270
+
271
+ let data: any
272
+ try {
273
+ data = JSON.parse(responseText)
274
+ } catch (parseError) {
275
+ console.log(`[ASG Camera API] Failed to parse JSON:`, parseError)
276
+ throw new Error("Invalid JSON response from gallery endpoint")
277
+ }
278
+
279
+ // Handle the exact response format we see from browser
280
+ if (data && data.status === "success" && data.data?.photos) {
281
+ console.log(`[ASG Camera API] Found ${data.data.photos.length} photos (total: ${data.data.total_count})`)
282
+
283
+ // Map photos to ensure proper URL construction
284
+ const photos = data.data.photos.map((photo: any) => ({
285
+ ...photo,
286
+ url: this.constructPhotoUrl(photo.url || photo.name),
287
+ download: this.constructDownloadUrl(photo.download || photo.name),
288
+ }))
289
+
290
+ return {
291
+ status: "success",
292
+ data: {
293
+ photos,
294
+ total_count: data.data.total_count,
295
+ returned_count: data.data.returned_count,
296
+ has_more: data.data.has_more,
297
+ offset: data.data.offset,
298
+ limit: data.data.limit,
299
+ },
300
+ } as GalleryResponse
301
+ } else {
302
+ console.log(`[ASG Camera API] Invalid response structure:`, data)
303
+ throw new Error("Invalid response structure from gallery endpoint")
304
+ }
305
+ } catch (error) {
306
+ console.log(`[ASG Camera API] Gallery request failed:`, error)
307
+ throw error
308
+ }
309
+ }
310
+
311
+ async deleteGalleryPhoto(photoId: string): Promise<any> {
312
+ const response = await this.makeRequest<any>(`/api/gallery/${photoId}`, {
313
+ method: "DELETE",
314
+ })
315
+ console.log("Photo deleted successfully:", photoId)
316
+ return response
317
+ }
318
+
319
+ /**
320
+ * Get the gallery photos array with proper URL construction
321
+ */
322
+ async getGalleryPhotos(
323
+ limit?: number,
324
+ offset?: number,
325
+ ): Promise<{
326
+ photos: PhotoInfo[]
327
+ hasMore: boolean
328
+ totalCount: number
329
+ }> {
330
+ console.log(`[ASG Camera API] Getting gallery photos with limit=${limit}, offset=${offset}...`)
331
+ try {
332
+ const response = await this.getGallery(limit, offset)
333
+ console.log(`[ASG Camera API] Gallery response:`, response)
334
+
335
+ if (!response.data || !response.data.photos) {
336
+ console.warn(`[ASG Camera API] Invalid gallery response structure:`, response)
337
+ return {photos: [], hasMore: false, totalCount: 0}
338
+ }
339
+
340
+ const photos = response.data.photos
341
+ console.log(`[ASG Camera API] Found ${photos.length} photos (total: ${(response.data as any).total_count})`)
342
+
343
+ // Ensure each photo has proper URLs and detect AVIF files
344
+ const processedPhotos = photos.map((photo) => {
345
+ // Check if filename suggests AVIF (no extension or .avif)
346
+ const mightBeAvif = !photo.name.includes(".") || photo.name.match(/\.(avif|avifs)$/i)
347
+
348
+ return {
349
+ ...photo,
350
+ url: this.constructPhotoUrl(photo.name),
351
+ download: this.constructDownloadUrl(photo.name),
352
+ mime_type: photo.mime_type || (mightBeAvif ? "image/avif" : undefined),
353
+ }
354
+ })
355
+
356
+ console.log(`[ASG Camera API] Processed photos:`, processedPhotos)
357
+ return {
358
+ photos: processedPhotos,
359
+ hasMore: (response.data as any).has_more || false,
360
+ totalCount: (response.data as any).total_count || photos.length,
361
+ }
362
+ } catch (error) {
363
+ console.error(`[ASG Camera API] Error getting gallery photos:`, error)
364
+ throw error
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Discover available endpoints on the server
370
+ */
371
+ async discoverEndpoints(): Promise<string[]> {
372
+ const availableEndpoints: string[] = []
373
+ const testEndpoints = [
374
+ "/",
375
+ "/api",
376
+ "/api/health",
377
+ "/api/status",
378
+ "/api/gallery",
379
+ "/gallery",
380
+ "/api/photos",
381
+ "/photos",
382
+ "/api/images",
383
+ "/images",
384
+ "/api/take-picture",
385
+ "/api/latest-photo",
386
+ ]
387
+
388
+ console.log(`[ASG Camera API] Discovering available endpoints...`)
389
+
390
+ for (const endpoint of testEndpoints) {
391
+ try {
392
+ console.log(`[ASG Camera API] Testing endpoint: ${endpoint}`)
393
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
394
+ method: "HEAD",
395
+ headers: {
396
+ "Accept": "*/*",
397
+ "User-Agent": "MentraOS-Mobile/1.0",
398
+ },
399
+ signal: this.createTimeoutSignal(5000),
400
+ })
401
+
402
+ if (response.ok) {
403
+ availableEndpoints.push(endpoint)
404
+ console.log(`[ASG Camera API] Found endpoint: ${endpoint} (${response.status})`)
405
+ } else {
406
+ console.log(`[ASG Camera API] Endpoint ${endpoint} returned: ${response.status}`)
407
+ }
408
+ } catch (error) {
409
+ console.log(`[ASG Camera API] Endpoint ${endpoint} failed:`, error)
410
+ // For /api/gallery specifically, let's try a GET request to see if it's a HEAD request issue
411
+ if (endpoint === "/api/gallery") {
412
+ try {
413
+ console.log(`[ASG Camera API] Trying GET request for /api/gallery...`)
414
+ const getResponse = await fetch(`${this.baseUrl}${endpoint}`, {
415
+ method: "GET",
416
+ headers: {
417
+ "Accept": "application/json",
418
+ "User-Agent": "MentraOS-Mobile/1.0",
419
+ },
420
+ signal: this.createTimeoutSignal(5000),
421
+ })
422
+ console.log(`[ASG Camera API] GET /api/gallery status: ${getResponse.status}`)
423
+ if (getResponse.ok) {
424
+ console.log(`[ASG Camera API] GET /api/gallery works! Adding to available endpoints`)
425
+ availableEndpoints.push(endpoint)
426
+ }
427
+ } catch (getError) {
428
+ console.log(`[ASG Camera API] GET /api/gallery also failed:`, getError)
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ console.log(`[ASG Camera API] Available endpoints:`, availableEndpoints)
435
+ return availableEndpoints
436
+ }
437
+
438
+ /**
439
+ * Construct a photo URL for a given filename
440
+ */
441
+ private constructPhotoUrl(filename: string): string {
442
+ return `${this.baseUrl}/api/photo?file=${encodeURIComponent(filename)}`
443
+ }
444
+
445
+ /**
446
+ * Construct a download URL for a given filename
447
+ */
448
+ private constructDownloadUrl(filename: string): string {
449
+ return `${this.baseUrl}/api/download?file=${encodeURIComponent(filename)}`
450
+ }
451
+
452
+ /**
453
+ * Get a specific photo by filename
454
+ */
455
+ async getPhoto(filename: string): Promise<Blob> {
456
+ console.log(`[ASG Camera API] Getting photo: ${filename}`)
457
+ return this.makeRequest<Blob>(`/api/photo?file=${encodeURIComponent(filename)}`)
458
+ }
459
+
460
+ /**
461
+ * Get a specific photo as a data URL
462
+ */
463
+ async getPhotoAsDataUrl(filename: string): Promise<string> {
464
+ console.log(`[ASG Camera API] Getting photo as data URL: ${filename}`)
465
+ const blob = await this.getPhoto(filename)
466
+ return new Promise((resolve, reject) => {
467
+ const reader = new FileReader()
468
+ reader.onload = () => resolve(reader.result as string)
469
+ reader.onerror = reject
470
+ reader.readAsDataURL(blob)
471
+ })
472
+ }
473
+
474
+ /**
475
+ * Download a photo (returns download URL)
476
+ */
477
+ async downloadPhoto(filename: string): Promise<string> {
478
+ console.log(`[ASG Camera API] Downloading photo: ${filename}`)
479
+ const downloadUrl = `${this.baseUrl}/api/download?file=${encodeURIComponent(filename)}`
480
+ console.log(`[ASG Camera API] Download URL: ${downloadUrl}`)
481
+ return downloadUrl
482
+ }
483
+
484
+ /**
485
+ * Get server status information
486
+ */
487
+ async getStatus(): Promise<ServerStatus> {
488
+ console.log(`[ASG Camera API] Getting server status...`)
489
+ return this.makeRequest<ServerStatus>("/api/status")
490
+ }
491
+
492
+ /**
493
+ * Get server health check
494
+ */
495
+ async getHealth(): Promise<HealthResponse> {
496
+ console.log(`[ASG Camera API] Getting server health...`)
497
+ return this.makeRequest<HealthResponse>("/api/health")
498
+ }
499
+
500
+ /**
501
+ * Get the index page (for testing)
502
+ */
503
+ async getIndexPage(): Promise<string> {
504
+ console.log(`[ASG Camera API] Getting index page...`)
505
+ return this.makeRequest<string>("/")
506
+ }
507
+
508
+ /**
509
+ * Check if the server is reachable (simple ping)
510
+ */
511
+ async isServerReachable(): Promise<boolean> {
512
+ try {
513
+ console.log(`[ASG Camera API] Checking server reachability...`)
514
+ // Use a simple HEAD request to check reachability
515
+ const controller = new AbortController()
516
+ const timeoutId = BgTimer.setTimeout(() => controller.abort(), 3000) // 3 second timeout
517
+
518
+ const response = await fetch(`${this.baseUrl}/api/health`, {
519
+ method: "HEAD",
520
+ signal: controller.signal,
521
+ })
522
+
523
+ BgTimer.clearTimeout(timeoutId)
524
+ console.log(`[ASG Camera API] Server is reachable`)
525
+ return response.ok
526
+ } catch (error) {
527
+ console.log(`[ASG Camera API] Server is not reachable:`, error)
528
+ return false
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Get comprehensive server information
534
+ */
535
+ async getServerInfo(): Promise<{
536
+ reachable: boolean
537
+ status?: ServerStatus
538
+ health?: HealthResponse
539
+ error?: string
540
+ }> {
541
+ try {
542
+ const [status, health] = await Promise.all([this.getStatus(), this.getHealth()])
543
+
544
+ return {
545
+ reachable: true,
546
+ status,
547
+ health,
548
+ }
549
+ } catch (error) {
550
+ return {
551
+ reachable: false,
552
+ error: error instanceof Error ? error.message : "Unknown error",
553
+ }
554
+ }
555
+ }
556
+
557
+ /**
558
+ * Sync with server to get changed files since last sync
559
+ */
560
+ async syncWithServer(
561
+ clientId: string,
562
+ lastSyncTime?: number,
563
+ includeThumbnails: boolean = false,
564
+ ): Promise<{
565
+ status: string
566
+ data: {
567
+ api_version?: number
568
+ client_id: string
569
+ captures?: CaptureGroup[]
570
+ changed_files: PhotoInfo[]
571
+ deleted_files: string[]
572
+ server_time: number
573
+ total_changed: number
574
+ total_size: number
575
+ }
576
+ }> {
577
+ const params = new URLSearchParams({
578
+ client_id: clientId,
579
+ include_thumbnails: includeThumbnails.toString(),
580
+ })
581
+
582
+ if (lastSyncTime) {
583
+ params.append("last_sync_time", lastSyncTime.toString())
584
+ }
585
+
586
+ const response = await this.makeRequest(`/api/sync?${params.toString()}`, {
587
+ method: "GET",
588
+ })
589
+
590
+ return response as {
591
+ status: string
592
+ data: {
593
+ api_version?: number
594
+ client_id: string
595
+ captures?: CaptureGroup[]
596
+ changed_files: PhotoInfo[]
597
+ deleted_files: string[]
598
+ server_time: number
599
+ total_changed: number
600
+ total_size: number
601
+ }
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Batch sync files from server with controlled concurrency.
607
+ * Used by the legacy executeDownload path for old asg_client firmware
608
+ * that doesn't send api_version=2.
609
+ */
610
+ async batchSyncFiles(
611
+ files: PhotoInfo[],
612
+ includeThumbnails: boolean = false,
613
+ onProgress?: (
614
+ current: number,
615
+ total: number,
616
+ fileName: string,
617
+ fileProgress?: number,
618
+ downloadedFile?: PhotoInfo,
619
+ ) => void,
620
+ abortSignal?: AbortSignal,
621
+ ): Promise<{
622
+ downloaded: PhotoInfo[]
623
+ failed: string[]
624
+ total_size: number
625
+ }> {
626
+ const results = {
627
+ downloaded: [] as PhotoInfo[],
628
+ failed: [] as string[],
629
+ total_size: 0,
630
+ }
631
+
632
+ // Process files in parallel batches for better performance
633
+ // Use controlled concurrency to avoid overwhelming the network
634
+ const CONCURRENCY_LIMIT = 1
635
+
636
+ // Process files in batches
637
+ for (let i = 0; i < files.length; i += CONCURRENCY_LIMIT) {
638
+ const batch = files.slice(i, i + CONCURRENCY_LIMIT)
639
+ console.log(
640
+ `[ASG Camera API] Processing batch ${Math.floor(i / CONCURRENCY_LIMIT) + 1}/${Math.ceil(files.length / CONCURRENCY_LIMIT)}: ${batch.length} files`,
641
+ )
642
+
643
+ // Process batch in parallel
644
+ const batchPromises = batch.map(async (file, batchIndex) => {
645
+ const globalIndex = i + batchIndex
646
+
647
+ // Report progress if callback provided - start of this file (0%)
648
+ if (onProgress) {
649
+ onProgress(globalIndex + 1, files.length, file.name, 0)
650
+ }
651
+
652
+ try {
653
+ console.log(`[ASG Camera API] Downloading file ${globalIndex + 1}/${files.length}: ${file.name}`)
654
+
655
+ // Download file with progress tracking
656
+ const fileData = await this.downloadFile(
657
+ file.name,
658
+ includeThumbnails,
659
+ (fileProgress) => {
660
+ if (onProgress) {
661
+ onProgress(globalIndex + 1, files.length, file.name, fileProgress)
662
+ }
663
+ },
664
+ abortSignal,
665
+ file.size, // Pass expected size for validation when Content-Length is missing
666
+ )
667
+
668
+ // Combine file info with downloaded file paths
669
+ const downloadedFile = {
670
+ ...file,
671
+ filePath: fileData.filePath,
672
+ thumbnailPath: fileData.thumbnailPath,
673
+ mime_type: fileData.mime_type || file.mime_type,
674
+ }
675
+
676
+ console.log(`[ASG Camera API] Successfully downloaded: ${file.name}`)
677
+
678
+ // Notify progress callback that this file is complete with file info
679
+ if (onProgress) {
680
+ onProgress(globalIndex + 1, files.length, file.name, 100, downloadedFile)
681
+ }
682
+
683
+ // Don't delete from glasses here — deletion is deferred until after
684
+ // processing completes (in mediaProcessingQueue) to avoid data loss on crash.
685
+
686
+ return {downloadedFile, fileSize: file.size}
687
+ } catch (error: any) {
688
+ // Re-throw cancellation so it terminates the entire batch
689
+ if (error?.message === "Sync cancelled") {
690
+ throw error
691
+ }
692
+ console.error(`[ASG Camera API] Failed to download ${file.name}:`, error)
693
+ return {error: file.name}
694
+ }
695
+ })
696
+
697
+ // Wait for batch to complete
698
+ const batchResults = await Promise.all(batchPromises)
699
+
700
+ // Process batch results
701
+ for (const result of batchResults) {
702
+ if ("downloadedFile" in result && result.downloadedFile) {
703
+ results.downloaded.push(result.downloadedFile)
704
+ results.total_size += result.fileSize || 0
705
+ } else if ("error" in result) {
706
+ results.failed.push(result.error)
707
+ }
708
+ }
709
+
710
+ // Small delay between batches to prevent overwhelming the server
711
+ if (i + CONCURRENCY_LIMIT < files.length) {
712
+ console.log(`[ASG Camera API] Waiting 300ms between batches`)
713
+ await new Promise<void>((resolve) => BgTimer.setTimeout(() => resolve(), 300))
714
+ }
715
+ }
716
+
717
+ console.log(
718
+ `[ASG Camera API] Batch sync completed: ${results.downloaded.length} downloaded, ${results.failed.length} failed`,
719
+ )
720
+ return results
721
+ }
722
+
723
+ /**
724
+ * Download all files in a capture group sequentially.
725
+ * Reports aggregate byte progress across all files in the group.
726
+ */
727
+ async downloadCapture(
728
+ capture: CaptureGroup,
729
+ onProgress?: (bytesDownloaded: number, totalBytes: number) => void,
730
+ abortSignal?: AbortSignal,
731
+ ): Promise<{captureDir: string; primaryPath: string; bracketPaths: string[]; sidecarPath?: string}> {
732
+ const captureDir = localStorageService.getPhotoFilePath(capture.capture_id)
733
+ console.log(
734
+ `[ASG Camera API] downloadCapture: ${capture.capture_id} (${capture.files.length} files) -> ${captureDir}`,
735
+ )
736
+
737
+ // Ensure capture directory exists
738
+ const dirExists = await RNFS.exists(captureDir)
739
+ if (!dirExists) {
740
+ await RNFS.mkdir(captureDir)
741
+ console.log(`[ASG Camera API] downloadCapture: created dir ${captureDir}`)
742
+ }
743
+
744
+ let primaryPath = ""
745
+ const bracketPaths: string[] = []
746
+ let sidecarPath: string | undefined
747
+
748
+ let totalBytesDownloaded = 0
749
+ const totalBytes = capture.total_size
750
+
751
+ // Sort files: brackets first, then primary, then sidecar
752
+ // This ensures brackets are available before merge runs on the primary
753
+ const sortedFiles = [...capture.files].sort((a, b) => {
754
+ const order = {bracket: 0, primary: 1, sidecar: 2}
755
+ return (order[a.role] ?? 1) - (order[b.role] ?? 1)
756
+ })
757
+
758
+ for (const file of sortedFiles) {
759
+ // Derive local filename: use leaf of path if folder-based, otherwise full name
760
+ const leafName = file.name.includes("/") ? file.name.split("/").pop()! : file.name
761
+ const localFilePath = `${captureDir}/${leafName}`
762
+
763
+ const isVideo = file.name.match(/\.(mp4|mov|avi|webm|mkv)$/i)
764
+ const downloadEndpoint = isVideo ? "download" : "photo"
765
+ const downloadUrl = `${this.baseUrl}/api/${downloadEndpoint}?file=${encodeURIComponent(file.name)}`
766
+
767
+ console.log(`[ASG Camera API] downloadCapture: downloading ${file.name} (${file.role}) -> ${localFilePath}`)
768
+
769
+ try {
770
+ // Throttle progress: only fire when bytesWritten changes meaningfully
771
+ let lastReportedBytes = -1
772
+ const {jobId, promise: dlPromise} = RNFS.downloadFile({
773
+ fromUrl: downloadUrl,
774
+ toFile: localFilePath,
775
+ headers: {
776
+ "Accept": "*/*",
777
+ "User-Agent": "MentraOS-Mobile/1.0",
778
+ },
779
+ connectionTimeout: 300000,
780
+ readTimeout: 300000,
781
+ backgroundTimeout: 600000,
782
+ progressDivider: 5,
783
+ progressInterval: 250,
784
+ progress: (res: {bytesWritten: number}) => {
785
+ const currentBytes = totalBytesDownloaded + (res.bytesWritten || 0)
786
+ if (onProgress && currentBytes !== lastReportedBytes) {
787
+ lastReportedBytes = currentBytes
788
+ onProgress(currentBytes, totalBytes)
789
+ }
790
+ },
791
+ })
792
+
793
+ // Wire up abort signal via polling (safe for all Hermes versions)
794
+ let abortPollTimer: number | undefined
795
+ if (abortSignal) {
796
+ if (abortSignal.aborted) {
797
+ RNFS.stopDownload(jobId)
798
+ throw new Error("Sync cancelled")
799
+ }
800
+ abortPollTimer = BgTimer.setInterval(() => {
801
+ if (abortSignal.aborted) {
802
+ RNFS.stopDownload(jobId)
803
+ }
804
+ }, 500)
805
+ }
806
+
807
+ let downloadResult
808
+ try {
809
+ downloadResult = await dlPromise
810
+ } finally {
811
+ if (abortPollTimer !== undefined) BgTimer.clearInterval(abortPollTimer)
812
+ }
813
+
814
+ if (downloadResult.statusCode !== 200) {
815
+ await RNFS.unlink(localFilePath).catch(() => {})
816
+ throw new Error(`HTTP ${downloadResult.statusCode}`)
817
+ }
818
+
819
+ // Check if aborted after completion
820
+ if (abortSignal?.aborted) {
821
+ await RNFS.unlink(localFilePath).catch(() => {})
822
+ throw new Error("Sync cancelled")
823
+ }
824
+
825
+ const mediaKind = file.role === "sidecar" ? "unknown" : isVideo ? "video" : "photo"
826
+ try {
827
+ await validateDownloadedMediaFile({
828
+ path: localFilePath,
829
+ name: file.name,
830
+ expectedSize: file.size,
831
+ mediaKind,
832
+ })
833
+ } catch (validationErr: any) {
834
+ const reason = validationErr?.message || validationErr?.toString?.() || JSON.stringify(validationErr)
835
+ reportInvalidGalleryMedia({
836
+ name: file.name,
837
+ path: localFilePath,
838
+ mediaKind,
839
+ stage: "download_capture_validation",
840
+ reason,
841
+ expectedSize: file.size,
842
+ captureId: capture.capture_id,
843
+ duration: capture.duration,
844
+ })
845
+ await RNFS.unlink(localFilePath).catch(() => {})
846
+ throw validationErr
847
+ }
848
+
849
+ console.log(`[ASG Camera API] downloadCapture: completed ${file.name} (${file.size} bytes)`)
850
+ } catch (dlErr: any) {
851
+ // S2: Clean up partial file on failure
852
+ await RNFS.unlink(localFilePath).catch(() => {})
853
+ const errMsg = dlErr?.message || dlErr?.toString?.() || JSON.stringify(dlErr)
854
+ console.error(`[ASG Camera API] downloadCapture: FAILED ${file.name}: ${errMsg}`)
855
+ throw new Error(`Failed to download ${file.name}: ${errMsg}`)
856
+ }
857
+
858
+ totalBytesDownloaded += file.size
859
+
860
+ if (file.role === "primary") {
861
+ primaryPath = localFilePath
862
+ } else if (file.role === "bracket") {
863
+ bracketPaths.push(localFilePath)
864
+ } else if (file.role === "sidecar") {
865
+ sidecarPath = localFilePath
866
+ }
867
+ }
868
+
869
+ // C3: If no file was marked as primary, fall back to first downloaded file
870
+ if (primaryPath === "" && sortedFiles.length > 0) {
871
+ const leafName = sortedFiles[0].name.includes("/") ? sortedFiles[0].name.split("/").pop()! : sortedFiles[0].name
872
+ primaryPath = `${captureDir}/${leafName}`
873
+ console.warn(`[ASG Camera API] downloadCapture: No primary file found, falling back to ${primaryPath}`)
874
+ }
875
+
876
+ // Report final progress
877
+ if (onProgress) {
878
+ onProgress(totalBytes, totalBytes)
879
+ }
880
+
881
+ return {captureDir, primaryPath, bracketPaths, sidecarPath}
882
+ }
883
+
884
+ /**
885
+ * Delete files from server
886
+ */
887
+ async deleteFilesFromServer(fileNames: string[]): Promise<{
888
+ deleted: string[]
889
+ failed: string[]
890
+ }> {
891
+ if (fileNames.length === 0) {
892
+ return {deleted: [], failed: []}
893
+ }
894
+
895
+ try {
896
+ const response = await this.makeRequest("/api/delete-files", {
897
+ method: "POST",
898
+ body: JSON.stringify({files: fileNames}),
899
+ })
900
+
901
+ // Parse the response format from the ASG server
902
+ const responseData = response as any
903
+ if (responseData.data && responseData.data.results) {
904
+ const deleted: string[] = []
905
+ const failed: string[] = []
906
+
907
+ for (const result of responseData.data.results) {
908
+ if (result.success) {
909
+ deleted.push(result.file)
910
+ } else {
911
+ failed.push(result.file)
912
+ }
913
+ }
914
+
915
+ console.log(`[ASG Camera API] Delete results: ${deleted.length} deleted, ${failed.length} failed`)
916
+ return {deleted, failed}
917
+ }
918
+
919
+ return response as {
920
+ deleted: string[]
921
+ failed: string[]
922
+ }
923
+ } catch (error) {
924
+ console.error("Failed to delete files from server:", error)
925
+ return {deleted: [], failed: fileNames}
926
+ }
927
+ }
928
+
929
+ /**
930
+ * Get sync status from server
931
+ */
932
+ async getSyncStatus(): Promise<{
933
+ total_files: number
934
+ total_size: number
935
+ last_modified: number
936
+ }> {
937
+ const response = await this.makeRequest("/sync/status", {
938
+ method: "GET",
939
+ })
940
+
941
+ return response as {
942
+ total_files: number
943
+ total_size: number
944
+ last_modified: number
945
+ }
946
+ }
947
+
948
+ /**
949
+ * Download a file from the server and save to filesystem
950
+ */
951
+ async downloadFile(
952
+ filename: string,
953
+ includeThumbnail: boolean = false,
954
+ onProgress?: (progress: number) => void,
955
+ abortSignal?: AbortSignal,
956
+ expectedSize?: number,
957
+ ): Promise<{
958
+ filePath: string
959
+ thumbnailPath?: string
960
+ mime_type: string
961
+ }> {
962
+ console.log(`[ASG Camera API] Downloading file: ${filename}`)
963
+
964
+ try {
965
+ // Get the local file path where we'll save this
966
+ const localFilePath = localStorageService.getPhotoFilePath(filename)
967
+ const localThumbnailPath = includeThumbnail ? localStorageService.getThumbnailFilePath(filename) : undefined
968
+
969
+ // Ensure parent directory exists (for folder-based capture paths like IMG_xxx/base.jpg)
970
+ if (filename.includes("/")) {
971
+ const parentDir = localFilePath.substring(0, localFilePath.lastIndexOf("/"))
972
+ const parentExists = await RNFS.exists(parentDir)
973
+ if (!parentExists) {
974
+ await RNFS.mkdir(parentDir)
975
+ }
976
+ }
977
+
978
+ // Determine if this is a video file based on extension
979
+ const isVideo = filename.match(/\.(mp4|mov|avi|webm|mkv)$/i)
980
+
981
+ // Use /api/download for videos (full file) and /api/photo for images
982
+ const downloadEndpoint = isVideo ? "download" : "photo"
983
+ const downloadUrl = `${this.baseUrl}/api/${downloadEndpoint}?file=${encodeURIComponent(filename)}`
984
+
985
+ // Download the file directly to filesystem
986
+ console.log(`[ASG Camera API] Downloading ${isVideo ? "video" : "photo"} from: ${downloadUrl}`)
987
+ console.log(`[ASG Camera API] Saving to: ${localFilePath}`)
988
+
989
+ // Track content length from begin callback for post-download validation
990
+ let expectedContentLength = 0
991
+ // Throttle progress: only call onProgress when percentage actually changes
992
+ let lastReportedProgress = -1
993
+
994
+ const {jobId, promise: downloadPromise} = RNFS.downloadFile({
995
+ fromUrl: downloadUrl,
996
+ toFile: localFilePath,
997
+ headers: {
998
+ "Accept": "*/*",
999
+ "User-Agent": "MentraOS-Mobile/1.0",
1000
+ },
1001
+ connectionTimeout: 300000, // 5 minutes for connection establishment
1002
+ readTimeout: 300000, // 5 minutes for data reading
1003
+ backgroundTimeout: 600000, // 10 minutes for background downloads (iOS)
1004
+ progressDivider: 5, // Fire progress every 5% to reduce event frequency
1005
+ progressInterval: 250, // Update progress every 250ms max
1006
+ begin: (res) => {
1007
+ expectedContentLength = res.contentLength || 0
1008
+ console.log(`[ASG Camera API] Download started for ${filename}, size: ${res.contentLength}`)
1009
+ },
1010
+ progress: (res) => {
1011
+ // Validate progress data to prevent negative percentages
1012
+ const contentLength = res.contentLength || 0
1013
+ const bytesWritten = res.bytesWritten || 0
1014
+
1015
+ let percentage = 0
1016
+ if (contentLength > 0 && bytesWritten >= 0) {
1017
+ percentage = Math.round((bytesWritten / contentLength) * 100)
1018
+ // Clamp percentage between 0 and 100
1019
+ percentage = Math.max(0, Math.min(100, percentage))
1020
+ }
1021
+
1022
+ // Only call onProgress when percentage actually changes (throttle)
1023
+ if (onProgress && percentage !== lastReportedProgress) {
1024
+ lastReportedProgress = percentage
1025
+ onProgress(percentage)
1026
+ }
1027
+
1028
+ // Log every 10%
1029
+ if (percentage % 10 === 0) {
1030
+ console.log(`[ASG Camera API] Download progress ${filename}: ${percentage}%`)
1031
+ }
1032
+ },
1033
+ })
1034
+
1035
+ // Wire up abort signal to stop download via polling (safe for all Hermes versions)
1036
+ let abortPollTimer: number | undefined
1037
+ if (abortSignal) {
1038
+ if (abortSignal.aborted) {
1039
+ RNFS.stopDownload(jobId)
1040
+ throw new Error("Sync cancelled")
1041
+ }
1042
+ abortPollTimer = BgTimer.setInterval(() => {
1043
+ if (abortSignal.aborted) {
1044
+ RNFS.stopDownload(jobId)
1045
+ }
1046
+ }, 500)
1047
+ }
1048
+
1049
+ let downloadResult
1050
+ try {
1051
+ downloadResult = await downloadPromise
1052
+ } finally {
1053
+ if (abortPollTimer !== undefined) BgTimer.clearInterval(abortPollTimer)
1054
+ }
1055
+
1056
+ if (downloadResult.statusCode !== 200) {
1057
+ // S2: Clean up partial file on HTTP error
1058
+ await RNFS.unlink(localFilePath).catch(() => {})
1059
+ throw new Error(`Failed to download ${filename}: HTTP ${downloadResult.statusCode}`)
1060
+ }
1061
+
1062
+ // Check if download was aborted after completion
1063
+ if (abortSignal?.aborted) {
1064
+ await RNFS.unlink(localFilePath).catch(() => {})
1065
+ throw new Error("Sync cancelled")
1066
+ }
1067
+
1068
+ // N1: Validate file size after download.
1069
+ // Use Content-Length from the HTTP response if available, otherwise fall back
1070
+ // to expectedSize from the sync response metadata. This catches truncated
1071
+ // downloads even when the server uses chunked transfer encoding (no Content-Length).
1072
+ const sizeToCheck =
1073
+ expectedContentLength > 0 ? expectedContentLength : expectedSize && expectedSize > 0 ? expectedSize : 0
1074
+
1075
+ try {
1076
+ await validateDownloadedMediaFile({
1077
+ path: localFilePath,
1078
+ name: filename,
1079
+ expectedSize: sizeToCheck,
1080
+ mediaKind: isVideo ? "video" : "photo",
1081
+ })
1082
+ } catch (validationErr: any) {
1083
+ const reason = validationErr?.message || validationErr?.toString?.() || JSON.stringify(validationErr)
1084
+ reportInvalidGalleryMedia({
1085
+ name: filename,
1086
+ path: localFilePath,
1087
+ mediaKind: isVideo ? "video" : "photo",
1088
+ stage: "download_validation",
1089
+ reason,
1090
+ expectedSize: sizeToCheck,
1091
+ })
1092
+ await RNFS.unlink(localFilePath).catch(() => {})
1093
+ throw validationErr
1094
+ }
1095
+
1096
+ console.log(`[ASG Camera API] Successfully downloaded ${filename} to filesystem`)
1097
+
1098
+ // Detect MIME type by checking file signature
1099
+ let mimeType = "application/octet-stream"
1100
+ try {
1101
+ // Read first 20 bytes to check file signature
1102
+ const firstBytes = await RNFS.read(localFilePath, 20, 0, "base64")
1103
+ const decodedBytes = atob(firstBytes)
1104
+
1105
+ // Check for AVIF signature
1106
+ if (decodedBytes.length > 11) {
1107
+ const ftypSignature = decodedBytes.substring(4, 12)
1108
+ if (ftypSignature === "ftypavif") {
1109
+ mimeType = "image/avif"
1110
+ console.log(`[ASG Camera API] Detected AVIF file: ${filename}`)
1111
+ } else if (decodedBytes.substring(0, 2) === "\xFF\xD8") {
1112
+ mimeType = "image/jpeg"
1113
+ } else if (decodedBytes.substring(0, 8) === "\x89PNG\r\n\x1a\n") {
1114
+ mimeType = "image/png"
1115
+ }
1116
+ }
1117
+
1118
+ // Also check by extension
1119
+ if (mimeType === "application/octet-stream") {
1120
+ if (filename.toLowerCase().endsWith(".jpg") || filename.toLowerCase().endsWith(".jpeg")) {
1121
+ mimeType = "image/jpeg"
1122
+ } else if (filename.toLowerCase().endsWith(".png")) {
1123
+ mimeType = "image/png"
1124
+ } else if (filename.toLowerCase().endsWith(".mp4")) {
1125
+ mimeType = "video/mp4"
1126
+ } else if (!filename.includes(".")) {
1127
+ // Files without extension are likely AVIF
1128
+ mimeType = "image/avif"
1129
+ }
1130
+ }
1131
+ } catch (e) {
1132
+ console.warn(`[ASG Camera API] Could not detect MIME type for ${filename}:`, e)
1133
+ }
1134
+
1135
+ // Download thumbnail if requested and it's a video
1136
+ let thumbnailPath: string | undefined
1137
+ if (includeThumbnail && filename.toLowerCase().match(/\.(mp4|mov|avi|mkv|webm)$/)) {
1138
+ try {
1139
+ console.log(`[ASG Camera API] Downloading thumbnail for ${filename}`)
1140
+ console.log(`[ASG Camera API] Using /api/photo endpoint for video thumbnail`)
1141
+
1142
+ // The server's /api/photo endpoint serves thumbnails for video files
1143
+ // It detects video files and automatically generates/serves thumbnails instead of the full video
1144
+ const thumbResult = await RNFS.downloadFile({
1145
+ fromUrl: `${this.baseUrl}/api/photo?file=${encodeURIComponent(filename)}`,
1146
+ toFile: localThumbnailPath as string,
1147
+ headers: {
1148
+ "Accept": "image/*",
1149
+ "User-Agent": "MentraOS-Mobile/1.0",
1150
+ },
1151
+ connectionTimeout: 60000, // 1 minute for thumbnails (smaller files)
1152
+ readTimeout: 60000, // 1 minute for thumbnails
1153
+ progressDivider: 1, // Get all progress updates for thumbnails too
1154
+ begin: (res) => {
1155
+ console.log(`[ASG Camera API] Thumbnail download started for ${filename}, size: ${res.contentLength}`)
1156
+ },
1157
+ progress: (res) => {
1158
+ const percentage = Math.round((res.bytesWritten / res.contentLength) * 100)
1159
+ if (percentage % 25 === 0) {
1160
+ console.log(`[ASG Camera API] Thumbnail download progress ${filename}: ${percentage}%`)
1161
+ }
1162
+ },
1163
+ }).promise
1164
+
1165
+ console.log(
1166
+ `[ASG Camera API] Thumbnail download result for ${filename}: status=${thumbResult.statusCode}, bytesWritten=${thumbResult.bytesWritten}`,
1167
+ )
1168
+
1169
+ if (thumbResult.statusCode === 200) {
1170
+ thumbnailPath = localThumbnailPath as string
1171
+ console.log(`[ASG Camera API] Successfully downloaded thumbnail to: ${thumbnailPath}`)
1172
+
1173
+ // Verify the file exists
1174
+ const exists = await RNFS.exists(thumbnailPath)
1175
+ console.log(`[ASG Camera API] Thumbnail file exists: ${exists}`)
1176
+ } else {
1177
+ console.warn(`[ASG Camera API] Thumbnail download failed with status: ${thumbResult.statusCode}`)
1178
+ }
1179
+ } catch (error) {
1180
+ console.warn(`[ASG Camera API] Failed to download thumbnail for ${filename}:`, error)
1181
+ }
1182
+ } else {
1183
+ console.log(
1184
+ `[ASG Camera API] Skipping thumbnail download - includeThumbnail: ${includeThumbnail}, filename: ${filename}, is video extension: ${filename.toLowerCase().match(/\.(mp4|mov|avi|mkv|webm)$/) ? "yes" : "no"}`,
1185
+ )
1186
+ }
1187
+
1188
+ return {
1189
+ filePath: localFilePath,
1190
+ thumbnailPath: thumbnailPath,
1191
+ mime_type: mimeType,
1192
+ }
1193
+ } catch (error) {
1194
+ console.error(`[ASG Camera API] Error downloading file ${filename}:`, error)
1195
+ // S2: Clean up partial file on any failure
1196
+ const localFilePath = localStorageService.getPhotoFilePath(filename)
1197
+ await RNFS.unlink(localFilePath).catch(() => {})
1198
+ throw error
1199
+ }
1200
+ }
1201
+ }
1202
+
1203
+ // Export a default instance - will be initialized with proper IP when used
1204
+ export const asgCameraApi = new AsgCameraApiClient()