@xenon-device-management/xenon 2.13.2 → 2.15.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 (350) hide show
  1. package/README.md +17 -8
  2. package/lib/package.json +5 -5
  3. package/lib/public/assets/{AnnotationOverlay-BXruClDk.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
  4. package/lib/public/assets/{ApiKeyGate-qTS4LPLC.js → ApiKeyGate-C9OoAgg_.js} +1 -1
  5. package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
  6. package/lib/public/assets/{EmptyState-Cr17PdDv.js → EmptyState-DqWU2-vM.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-Bvn08svv.js → FieldGroup-CveQ3xrA.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-DDSO8aDf.js → FilterMenu-BfKDSfHz.js} +1 -1
  9. package/lib/public/assets/{Menu-B-Qn2X3T.js → Menu-CtdCybzA.js} +1 -1
  10. package/lib/public/assets/{Modal-Cg9V5JYU.js → Modal-Bsvj1tm2.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-BTUs9VTW.js → RecordingPage-CRofOiyx.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-DYcfxITK.js → RecordingsPage-jNQHb2IR.js} +2 -2
  13. package/lib/public/assets/{SegmentedControl-Zy7suhT5.js → SegmentedControl-C8HtTha-.js} +1 -1
  14. package/lib/public/assets/{SettingCard-CWYmycoe.js → SettingCard-D8K1LZNo.js} +1 -1
  15. package/lib/public/assets/{Table-io9fwa98.js → Table-zNTX92Pn.js} +1 -1
  16. package/lib/public/assets/{activity-Bdf_uIWl.js → activity-CJ8LwZq9.js} +1 -1
  17. package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
  18. package/lib/public/assets/{api-keys-CPqtVpm3.js → api-keys-ECpo-zTo.js} +1 -1
  19. package/lib/public/assets/{apps-BgZan0H9.js → apps-BjGymyf3.js} +2 -2
  20. package/lib/public/assets/{arrow-left-B27ckB31.js → arrow-left-BWfCbeHP.js} +1 -1
  21. package/lib/public/assets/{arrow-right-DOF8ITCz.js → arrow-right-DC7UGf_n.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-eFG5KTFS.js → arrow-up-right-BOjwybDk.js} +1 -1
  23. package/lib/public/assets/{auth-shell-DlC3_27j.js → auth-shell-CxMTo9aH.js} +2 -2
  24. package/lib/public/assets/{builds-page-BuXpPfKo.js → builds-page-DOCm4HkA.js} +1 -1
  25. package/lib/public/assets/{button-fIW8owMI.js → button-Cg08-EMT.js} +1 -1
  26. package/lib/public/assets/{calendar-WNjmrF-a.js → calendar-CA1ikLJs.js} +1 -1
  27. package/lib/public/assets/{check-BdTh1Sq7.js → check-BMTaH72W.js} +1 -1
  28. package/lib/public/assets/{chevron-right-B4BKlsqk.js → chevron-right-B2QOv9Nx.js} +1 -1
  29. package/lib/public/assets/{circle-check-zJU80_EF.js → circle-check-CYXBoUqT.js} +1 -1
  30. package/lib/public/assets/{circle-x-5Uwquo0h.js → circle-x-DTwnSAnl.js} +1 -1
  31. package/lib/public/assets/{clock-BtUprDsZ.js → clock-C8_HViQP.js} +1 -1
  32. package/lib/public/assets/{copy-DGSbZI3u.js → copy-Be7LNMXV.js} +1 -1
  33. package/lib/public/assets/derive-UnLRp4r3.js +1 -0
  34. package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
  35. package/lib/public/assets/{download-WG6l7BgD.js → download-B56lwxWP.js} +1 -1
  36. package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
  37. package/lib/public/assets/h264Stream-C-OtmIuk.js +26 -0
  38. package/lib/public/assets/index-B9KQ6LsY.js +15 -0
  39. package/lib/public/assets/{index-DI1fGIyj.js → index-BOxe43p1.js} +5 -5
  40. package/lib/public/assets/{index-HDQVe1gi.js → index-CfxsUslp.js} +1 -1
  41. package/lib/public/assets/{input-BjDRKCea.js → input-CZHFjbSg.js} +1 -1
  42. package/lib/public/assets/{line-chart-C0zdgd0v.js → line-chart-Gl_Dz3X_.js} +1 -1
  43. package/lib/public/assets/{list-checks-BdW5CjM8.js → list-checks-CCgjeyGY.js} +1 -1
  44. package/lib/public/assets/{lock-Dy3L4I8E.js → lock-CkOwgDcx.js} +1 -1
  45. package/lib/public/assets/{login-BHbY9CLG.js → login-D5cc4w7M.js} +1 -1
  46. package/lib/public/assets/maintenance-settings-t7qr3fvX.js +6 -0
  47. package/lib/public/assets/{monitor-8xjkeHHi.js → monitor-DEJixKQO.js} +1 -1
  48. package/lib/public/assets/{mouse-pointer-2-CXdKMXQ8.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
  49. package/lib/public/assets/{network-Cj8JOKON.js → network-Dii9qdvk.js} +1 -1
  50. package/lib/public/assets/{overview-CTg7F0im.js → overview-rolAACrO.js} +1 -1
  51. package/lib/public/assets/{page-header--aTyJXq6.js → page-header-COQZxJfR.js} +1 -1
  52. package/lib/public/assets/{play-B-FodgHV.js → play-DrN1Se_R.js} +1 -1
  53. package/lib/public/assets/{plus-CsIk10Cq.js → plus-5aq-9uRx.js} +1 -1
  54. package/lib/public/assets/{profile-page-DkFKkMfl.js → profile-page-6i5kY6kF.js} +1 -1
  55. package/lib/public/assets/{reset-password-I2-zqLlI.js → reset-password-sp2IBrc7.js} +1 -1
  56. package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
  57. package/lib/public/assets/{select-DvCSv25z.js → select-Bpyn7rWO.js} +1 -1
  58. package/lib/public/assets/{selector-detail-redirect-BLVfMJs_.js → selector-detail-redirect-BH74vmKv.js} +1 -1
  59. package/lib/public/assets/{selector-health-page-oqadRokn.js → selector-health-page-Cw_g218H.js} +2 -2
  60. package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
  61. package/lib/public/assets/settings-C3uyGhyc.js +6 -0
  62. package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
  63. package/lib/public/assets/{stat-tile-DV9Ix-4O.js → stat-tile-xVqAKIlI.js} +1 -1
  64. package/lib/public/assets/{tablet-6b_SEN2X.js → tablet-BxUScAeO.js} +1 -1
  65. package/lib/public/assets/{teams-BjZyfuHh.js → teams-B5ljGkY2.js} +1 -1
  66. package/lib/public/assets/{trash-2-CTZpPSdd.js → trash-2-B701i8sy.js} +1 -1
  67. package/lib/public/assets/{upload-P3XzwQUb.js → upload-C2gr44RS.js} +1 -1
  68. package/lib/public/assets/{use-builds-data-1cOCMf-z.js → use-builds-data-NeQOFEoy.js} +1 -1
  69. package/lib/public/assets/{use-password-reset-mode-DgF9w088.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
  70. package/lib/public/assets/{users-DMF9Mk5H.js → users-D_vv_yz4.js} +1 -1
  71. package/lib/public/assets/{users-CiNTKUiz.js → users-MY6eNe6s.js} +1 -1
  72. package/lib/public/assets/{video-off-CHp1KU_T.js → video-off-OK1lNZQn.js} +1 -1
  73. package/lib/public/assets/webhook-settings-BU-C9lBf.js +1 -0
  74. package/lib/public/assets/{zap-DRz0tDq5.js → zap-DO9ry1iz.js} +1 -1
  75. package/lib/public/index.html +1 -1
  76. package/lib/schema.json +23 -25
  77. package/lib/src/XenonCapabilityManager.js +22 -5
  78. package/lib/src/app/dashboardPluginLink.js +117 -0
  79. package/lib/src/app/index.js +13 -34
  80. package/lib/src/app/openapi/control.yaml +73 -20
  81. package/lib/src/app/openapi/grid.yaml +31 -7
  82. package/lib/src/app/openapi/identity.yaml +103 -31
  83. package/lib/src/app/openapi/platform.yaml +165 -39
  84. package/lib/src/app/openapi/sessions.yaml +10 -3
  85. package/lib/src/app/routers/apikeys.js +14 -2
  86. package/lib/src/app/routers/auth.js +29 -5
  87. package/lib/src/app/routers/control.js +20 -2
  88. package/lib/src/app/routers/dashboard.js +69 -26
  89. package/lib/src/app/routers/grid.js +37 -13
  90. package/lib/src/app/routers/profile.js +21 -0
  91. package/lib/src/app/routers/streamType.js +7 -2
  92. package/lib/src/app/routers/users.js +10 -5
  93. package/lib/src/app/routers/webhook.js +8 -4
  94. package/lib/src/app/swagger.js +2 -0
  95. package/lib/src/app/ws/h264StreamWs.js +10 -1
  96. package/lib/src/config.js +51 -5
  97. package/lib/src/dashboard/commands.js +185 -141
  98. package/lib/src/dashboard/event-manager.js +88 -67
  99. package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
  100. package/lib/src/dashboard/sessionCommandSummary.js +39 -0
  101. package/lib/src/data-service/appleFamily.js +43 -0
  102. package/lib/src/data-service/db.js +11 -0
  103. package/lib/src/data-service/device-service.js +6 -1
  104. package/lib/src/data-service/device-store.js +76 -3
  105. package/lib/src/data-service/deviceClaims.js +37 -0
  106. package/lib/src/data-service/deviceFieldOwners.js +25 -11
  107. package/lib/src/data-service/deviceSettings.js +79 -0
  108. package/lib/src/data-service/prisma-store.js +169 -15
  109. package/lib/src/data-service/web-config-service.js +50 -92
  110. package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
  111. package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
  112. package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
  113. package/lib/src/device-managers/ios/WDAClient.js +44 -43
  114. package/lib/src/device-managers/shellCommands.js +96 -0
  115. package/lib/src/device-utils.js +114 -40
  116. package/lib/src/gateway/defaultGateway.js +1 -1
  117. package/lib/src/gateway/forwardToNode.js +2 -0
  118. package/lib/src/gateway/healReport.js +87 -0
  119. package/lib/src/gateway/sessionGateway.js +12 -2
  120. package/lib/src/generated/client/edge.js +18 -3
  121. package/lib/src/generated/client/index-browser.js +15 -0
  122. package/lib/src/generated/client/index.d.ts +2086 -379
  123. package/lib/src/generated/client/index.js +18 -3
  124. package/lib/src/generated/client/package.json +1 -1
  125. package/lib/src/generated/client/schema.prisma +38 -7
  126. package/lib/src/generated/client/wasm.js +15 -0
  127. package/lib/src/interceptors/CommandInterceptor.js +271 -188
  128. package/lib/src/interceptors/xenonScripts.js +55 -0
  129. package/lib/src/interfaces/IPluginArgs.js +1 -2
  130. package/lib/src/middleware/authMiddleware.js +15 -3
  131. package/lib/src/middleware/commandCaller.js +3 -3
  132. package/lib/src/middleware/verifyCredential.js +58 -1
  133. package/lib/src/plugin.js +23 -4
  134. package/lib/src/prisma.js +1 -1
  135. package/lib/src/scripts/database-check.js +124 -0
  136. package/lib/src/services/AICommandService.js +9 -2
  137. package/lib/src/services/AIService.js +281 -32
  138. package/lib/src/services/CleanupService.js +6 -1
  139. package/lib/src/services/EmailService.js +29 -0
  140. package/lib/src/services/InterceptorService.js +70 -13
  141. package/lib/src/services/NetworkConditioningService.js +85 -88
  142. package/lib/src/services/NotificationService.js +36 -29
  143. package/lib/src/services/OrphanSweeper.js +7 -0
  144. package/lib/src/services/PortAllocator.js +5 -0
  145. package/lib/src/services/SelectorVerificationJob.js +15 -4
  146. package/lib/src/services/ServerManager.js +105 -9
  147. package/lib/src/services/SessionLifecycleService.js +133 -75
  148. package/lib/src/services/ShutdownCoordinator.js +33 -0
  149. package/lib/src/services/SocketServer.js +19 -3
  150. package/lib/src/services/TeamService.js +20 -3
  151. package/lib/src/services/bug-report/video-slice.js +4 -1
  152. package/lib/src/services/device-access/leaseOverride.js +7 -5
  153. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
  154. package/lib/src/services/healing/HealEtalonService.js +3 -2
  155. package/lib/src/services/healing/HealingOrchestrator.js +85 -71
  156. package/lib/src/services/healing/OcrHealingProvider.js +41 -64
  157. package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
  158. package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
  159. package/lib/src/services/healing/fingerprintIdentity.js +126 -0
  160. package/lib/src/services/healing/resilioPath.js +274 -0
  161. package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
  162. package/lib/src/services/interceptor/interceptorOptions.js +44 -0
  163. package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
  164. package/lib/src/services/logcat/deviceLogBook.js +163 -0
  165. package/lib/src/services/network/AndroidRadios.js +71 -0
  166. package/lib/src/services/network/PhoneNetworkLedger.js +184 -0
  167. package/lib/src/services/network/PhoneNetworkRestore.js +330 -0
  168. package/lib/src/services/network/adbForPhone.js +60 -0
  169. package/lib/src/services/network/phoneNetworkLock.js +20 -0
  170. package/lib/src/services/network/xenonProxy.js +107 -0
  171. package/lib/src/services/ocr/ocrData.js +118 -0
  172. package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
  173. package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
  174. package/lib/src/services/omni-vision/OmniVisionService.js +132 -95
  175. package/lib/src/services/omni-vision/VisionAssertionService.js +28 -25
  176. package/lib/src/services/omni-vision/ocrTextMatch.js +105 -0
  177. package/lib/src/services/omni-vision/screenScale.js +68 -0
  178. package/lib/src/services/passwordResetLink.js +50 -9
  179. package/lib/src/services/passwordResetMode.js +3 -1
  180. package/lib/src/services/publicUrl.js +45 -0
  181. package/lib/src/services/recording/concurrency-gate.js +12 -3
  182. package/lib/src/services/session/sessionIdentity.js +5 -3
  183. package/lib/src/services/session/shutdownReason.js +26 -0
  184. package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
  185. package/lib/src/services/settings/aiEngineSettings.js +219 -0
  186. package/lib/src/services/settings/labSettings.js +149 -0
  187. package/lib/src/services/token/mintedLifetime.js +51 -0
  188. package/lib/src/services/webhookEvents.js +173 -0
  189. package/lib/src/sessions/SessionManager.js +8 -2
  190. package/lib/src/sessions/sessionMemory.js +25 -0
  191. package/lib/test/helpers/fake-adb.js +58 -0
  192. package/lib/test/helpers/fake-ai-provider.js +188 -0
  193. package/lib/test/helpers/fake-device-table.js +63 -24
  194. package/lib/test/helpers/loki-stores.js +33 -0
  195. package/lib/test/helpers/page-sources.js +164 -0
  196. package/lib/test/helpers/scratch-database.js +58 -13
  197. package/lib/test/integration/audit-ingest.spec.js +10 -10
  198. package/lib/test/integration/auth-flow.spec.js +9 -14
  199. package/lib/test/integration/auth-rate-limit.spec.js +6 -3
  200. package/lib/test/integration/bug-report-route.spec.js +22 -2
  201. package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
  202. package/lib/test/integration/forgot-password.spec.js +17 -18
  203. package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
  204. package/lib/test/integration/migration.spec.js +6 -1
  205. package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
  206. package/lib/test/integration/ports-router.spec.js +4 -4
  207. package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
  208. package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
  209. package/lib/test/integration/profile-tokens.spec.js +10 -16
  210. package/lib/test/integration/recordings-router.spec.js +16 -16
  211. package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
  212. package/lib/test/integration/role-matrix.spec.js +4 -9
  213. package/lib/test/integration/sdk-leases-router.spec.js +9 -9
  214. package/lib/test/integration/sdk-version.spec.js +2 -2
  215. package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
  216. package/lib/test/integration/team-membership-migration.spec.js +73 -12
  217. package/lib/test/integration/team-visibility-apps.spec.js +15 -22
  218. package/lib/test/integration/team-visibility-control.spec.js +96 -69
  219. package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
  220. package/lib/test/integration/team-visibility-grid.spec.js +16 -15
  221. package/lib/test/integration/team-visibility-leases.spec.js +8 -11
  222. package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
  223. package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
  224. package/lib/test/integration/users-flow.spec.js +7 -12
  225. package/lib/test/integration/users-lockout.spec.js +5 -3
  226. package/lib/test/unit/EmailService.test.js +66 -0
  227. package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
  228. package/lib/test/unit/TeamService.test.js +3 -0
  229. package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
  230. package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
  231. package/lib/test/unit/ai-engine-settings.spec.js +338 -0
  232. package/lib/test/unit/ai-provider-switch.spec.js +130 -0
  233. package/lib/test/unit/ai-rate-limit.spec.js +126 -0
  234. package/lib/test/unit/android-h264-viewers.spec.js +272 -0
  235. package/lib/test/unit/android-preview-hold.spec.js +3 -2
  236. package/lib/test/unit/apikeys-router.spec.js +84 -0
  237. package/lib/test/unit/apple-family.spec.js +36 -0
  238. package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
  239. package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
  240. package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
  241. package/lib/test/unit/cleanup-settings-db.spec.js +103 -0
  242. package/lib/test/unit/cleanup-settings.spec.js +244 -0
  243. package/lib/test/unit/dashboard-api-paths.spec.js +101 -0
  244. package/lib/test/unit/dashboard-commands.spec.js +249 -0
  245. package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
  246. package/lib/test/unit/dashboard-events-team-scope.spec.js +9 -6
  247. package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
  248. package/lib/test/unit/database-check.spec.js +108 -0
  249. package/lib/test/unit/default-plugin-args.spec.js +33 -0
  250. package/lib/test/unit/device-log-book.spec.js +180 -0
  251. package/lib/test/unit/device-offline-webhook.spec.js +81 -0
  252. package/lib/test/unit/device-setting-columns.spec.js +66 -0
  253. package/lib/test/unit/device-settings-loki.spec.js +87 -0
  254. package/lib/test/unit/device-settings-survive.spec.js +555 -0
  255. package/lib/test/unit/device-sync-lost-update.spec.js +5 -0
  256. package/lib/test/unit/emulator-boot.spec.js +91 -0
  257. package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
  258. package/lib/test/unit/event-log-session-data.spec.js +244 -0
  259. package/lib/test/unit/failure-analysis.spec.js +182 -0
  260. package/lib/test/unit/failure-categories.spec.js +128 -0
  261. package/lib/test/unit/fingerprint-identity.spec.js +433 -0
  262. package/lib/test/unit/h264-multiplexer.spec.js +46 -0
  263. package/lib/test/unit/heal-report.spec.js +71 -0
  264. package/lib/test/unit/healing-instrumentation.spec.js +6 -1
  265. package/lib/test/unit/healing-tier-gate.spec.js +73 -29
  266. package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
  267. package/lib/test/unit/hub-node-gateway-appium-server.spec.js +219 -0
  268. package/lib/test/unit/hub-node-same-host.spec.js +5 -0
  269. package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
  270. package/lib/test/unit/iphone-ipad-only.spec.js +132 -0
  271. package/lib/test/unit/json-logging-option.spec.js +74 -0
  272. package/lib/test/unit/lab-settings.spec.js +218 -0
  273. package/lib/test/unit/lease/lease-override.spec.js +23 -6
  274. package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
  275. package/lib/test/unit/max-sessions.spec.js +240 -0
  276. package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
  277. package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
  278. package/lib/test/unit/ocr-offline.spec.js +213 -0
  279. package/lib/test/unit/ocr-text-match.spec.js +44 -0
  280. package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
  281. package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
  282. package/lib/test/unit/omni-vision-ios-points.spec.js +159 -0
  283. package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
  284. package/lib/test/unit/omni-vision.spec.js +6 -8
  285. package/lib/test/unit/package-engines.spec.js +27 -0
  286. package/lib/test/unit/partial-config-file.spec.js +14 -0
  287. package/lib/test/unit/passwordResetMode.test.js +10 -2
  288. package/lib/test/unit/phone-network/boot-clean-up.spec.js +64 -0
  289. package/lib/test/unit/phone-network/interceptor-options.spec.js +77 -0
  290. package/lib/test/unit/phone-network/interceptor-proxy-restore.spec.js +145 -0
  291. package/lib/test/unit/phone-network/network-conditioning.spec.js +145 -0
  292. package/lib/test/unit/phone-network/phone-network-restore.spec.js +246 -0
  293. package/lib/test/unit/phone-network/session-end-paths.spec.js +182 -0
  294. package/lib/test/unit/phone-network/session-start.spec.js +110 -0
  295. package/lib/test/unit/phone-network/xenon-proxy.spec.js +69 -0
  296. package/lib/test/unit/plugin.spec.js +3 -3
  297. package/lib/test/unit/profile-router.test.js +122 -1
  298. package/lib/test/unit/queue-requester.spec.js +1 -1
  299. package/lib/test/unit/recording-options.spec.js +181 -0
  300. package/lib/test/unit/reset-link-address.spec.js +266 -0
  301. package/lib/test/unit/reset-link.test.js +10 -4
  302. package/lib/test/unit/resilio-path-healing.spec.js +270 -0
  303. package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
  304. package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
  305. package/lib/test/unit/selector-verification-job.spec.js +13 -13
  306. package/lib/test/unit/self-healing-boot.spec.js +80 -0
  307. package/lib/test/unit/self-healing-setting.spec.js +273 -0
  308. package/lib/test/unit/session-app-resolution.spec.js +5 -1
  309. package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
  310. package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
  311. package/lib/test/unit/session-credential-strip.spec.js +1 -1
  312. package/lib/test/unit/session-device-logs.spec.js +347 -0
  313. package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
  314. package/lib/test/unit/session-failed-webhook.spec.js +170 -0
  315. package/lib/test/unit/session-log-indexes.spec.js +64 -3
  316. package/lib/test/unit/shell-commands.spec.js +133 -0
  317. package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
  318. package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
  319. package/lib/test/unit/stream-start-pipelines.spec.js +264 -0
  320. package/lib/test/unit/stream-status-type.spec.js +4 -0
  321. package/lib/test/unit/token-mint-limits.spec.js +165 -0
  322. package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
  323. package/lib/test/unit/verify-credential.spec.js +33 -0
  324. package/lib/test/unit/vision-assertion.spec.js +119 -0
  325. package/lib/test/unit/wda-client-shell.spec.js +133 -0
  326. package/lib/test/unit/web-config-service.spec.js +98 -0
  327. package/lib/test/unit/webhook-delivery.spec.js +24 -0
  328. package/lib/test/unit/webhook-payloads.spec.js +273 -0
  329. package/lib/test/unit/xenon-execute-scripts.spec.js +138 -0
  330. package/lib/tsconfig.tsbuildinfo +1 -1
  331. package/lib/web/src/components/webhook-settings/webhookEventVariables.json +30 -0
  332. package/package.json +5 -5
  333. package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
  334. package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
  335. package/prisma/schema.prisma +38 -7
  336. package/schema.json +23 -25
  337. package/scripts/generate-types-from-schema.js +1 -2
  338. package/scripts/lib/always-present-plugin-args.js +4 -1
  339. package/lib/public/assets/BugReportButton-BoGhlI7F.js +0 -15
  340. package/lib/public/assets/DeviceMosaicView-8J0oYqMM.js +0 -2
  341. package/lib/public/assets/ai-settings-Bce5SJob.js +0 -21
  342. package/lib/public/assets/device-explorer-C-KnhMHI.js +0 -279
  343. package/lib/public/assets/forgot-password-DnudqFFo.js +0 -1
  344. package/lib/public/assets/maintenance-settings-zDVlOMVK.js +0 -6
  345. package/lib/public/assets/recording-group-store-WVM3hoXn.js +0 -26
  346. package/lib/public/assets/runbook-page-DJTVCJX7.js +0 -124
  347. package/lib/public/assets/session-detail-page-CGn55Pvl.js +0 -4
  348. package/lib/public/assets/settings-MsVU2ukE.js +0 -6
  349. package/lib/public/assets/webhook-settings-DiS8geIm.js +0 -1
  350. /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
@@ -45,56 +45,123 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.dashboardCommands = exports.DashboardCommands = void 0;
48
+ exports.dashboardCommands = exports.DashboardCommands = exports.SESSION_DETAILS_COMMANDS = void 0;
49
+ exports.sessionDetailsCommandOf = sessionDetailsCommandOf;
49
50
  const session_service_1 = require("./services/session-service");
50
51
  const prisma_1 = require("../prisma");
51
52
  const logger_1 = __importDefault(require("../logger"));
52
- const lodash_1 = __importDefault(require("lodash"));
53
53
  const SessionManager_1 = require("../sessions/SessionManager");
54
54
  const asset_manager_1 = require("./asset-manager");
55
+ const xenonScripts_1 = require("../interceptors/xenonScripts");
56
+ /**
57
+ * The execute commands that write to a session's record (its Session row):
58
+ * `driver.execute('xenon: setSessionName', 'Checkout')` and the like.
59
+ *
60
+ * Each answers `{ recorded: true }` when it wrote, or `{ recorded: false,
61
+ * message }` saying why nothing was written: no record of the session on this
62
+ * server (it runs without `enableDashboard`, or it is a node, which keeps
63
+ * none for the hub's sessions), an argument it can't use, or a failed write.
64
+ * None of them fails the test's command. They are bookkeeping, and a test
65
+ * shouldn't die because the server it ran on records no sessions. Through 2.13.2
66
+ * setSessionName, setSessionStatus and debug failed the command there
67
+ * (Prisma's P2025, a foreign-key error), and addTag and captureEvidence
68
+ * answered `null` as if they had worked.
69
+ */
70
+ exports.SESSION_DETAILS_COMMANDS = [
71
+ 'setSessionName',
72
+ 'setSessionStatus',
73
+ 'debug',
74
+ 'addTag',
75
+ 'captureEvidence',
76
+ ];
77
+ const RECORDED = { recorded: true };
78
+ const notRecorded = (message) => ({ recorded: false, message });
79
+ /** The session-details command a script names (`xenon: addTag`), or null for any other script. */
80
+ function sessionDetailsCommandOf(script) {
81
+ const name = (0, xenonScripts_1.xenonScriptName)(script);
82
+ return name !== null && exports.SESSION_DETAILS_COMMANDS.includes(name)
83
+ ? name
84
+ : null;
85
+ }
86
+ /** The script's arguments as a list, as both the W3C body and Appium's executeScript give them. */
87
+ function argumentList(args) {
88
+ if (Array.isArray(args))
89
+ return args;
90
+ return args === undefined || args === null ? [] : [args];
91
+ }
92
+ function isObject(value) {
93
+ return typeof value === 'object' && value !== null;
94
+ }
95
+ /** A string argument, or the named field of an object argument. */
96
+ function stringArg(value, field) {
97
+ if (typeof value === 'string')
98
+ return value;
99
+ if (isObject(value) && typeof value[field] === 'string')
100
+ return value[field];
101
+ return undefined;
102
+ }
55
103
  class DashboardCommands {
56
- isDashboardCommand(commandName) {
57
- return commandName.startsWith('xenon') || commandName.startsWith('xe');
58
- }
104
+ /**
105
+ * Answers a session-details command on an Express-style response, as
106
+ * `{ value: <answer> }`, and returns the answer. The hub's gateway passes
107
+ * the client's response; CommandInterceptor passes one that keeps it.
108
+ */
59
109
  process(sessionId, request, response) {
60
110
  return __awaiter(this, void 0, void 0, function* () {
61
- const { script } = request.body;
62
- logger_1.default.info(`[DashboardCommands] Processing command: ${script}`);
63
- if (!script) {
64
- return this.sendSuccessResponse(response);
65
- }
66
- const commandName = script.split(':')[1];
67
- logger_1.default.info(`[DashboardCommands] Parsed command name: ${commandName}`);
68
- if (commandName && commandName.trim()) {
69
- const trimmedCommand = commandName.trim();
70
- logger_1.default.info(`[DashboardCommands] Trimmed command: ${trimmedCommand}`);
71
- switch (trimmedCommand) {
72
- case 'setSessionName':
73
- logger_1.default.info('[DashboardCommands] Executing setSessionName');
74
- return yield this.setSessionName(sessionId, request, response);
75
- case 'setSessionStatus':
76
- logger_1.default.info('[DashboardCommands] Executing setSessionStatus');
77
- return yield this.setSessionStatus(sessionId, request, response);
78
- case 'debug':
79
- logger_1.default.info('[DashboardCommands] Executing debug command');
80
- return yield this.debug(sessionId, request, response);
81
- case 'captureEvidence':
82
- logger_1.default.info('[DashboardCommands] Executing captureEvidence');
83
- return yield this.captureEvidence(sessionId, request, response);
84
- case 'addTag':
85
- logger_1.default.info('[DashboardCommands] Executing addTag');
86
- return yield this.addTag(sessionId, request, response);
87
- default:
88
- logger_1.default.warn(`[DashboardCommands] Unknown command: ${trimmedCommand}`);
89
- return this.sendSuccessResponse(response);
111
+ var _a;
112
+ const { script, args } = (_a = request.body) !== null && _a !== void 0 ? _a : {};
113
+ const command = sessionDetailsCommandOf(script);
114
+ const answer = command
115
+ ? yield this.run(sessionId, command, args)
116
+ : notRecorded(`"${script}" is not a command that records session details.`);
117
+ response.status(200).json({ value: answer });
118
+ return answer;
119
+ });
120
+ }
121
+ /** Runs one command. Never throws: a failure is `{ recorded: false, message }`. */
122
+ run(sessionId, command, args) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ var _a;
125
+ logger_1.default.info(`[DashboardCommands] ${command} for session ${sessionId}`);
126
+ const list = argumentList(args);
127
+ let answer;
128
+ try {
129
+ const row = yield prisma_1.prisma.session.findUnique({
130
+ where: { id: sessionId },
131
+ select: { id: true, tags: true },
132
+ });
133
+ if (!row) {
134
+ answer = notRecorded(`This server keeps no record of session ${sessionId}, so nothing was saved. ` +
135
+ 'Sessions are recorded by a server started with enableDashboard, never by a node.');
136
+ }
137
+ else {
138
+ switch (command) {
139
+ case 'setSessionName':
140
+ answer = yield this.setSessionName(sessionId, list);
141
+ break;
142
+ case 'setSessionStatus':
143
+ answer = yield this.setSessionStatus(sessionId, list);
144
+ break;
145
+ case 'debug':
146
+ answer = yield this.debug(sessionId, list);
147
+ break;
148
+ case 'captureEvidence':
149
+ answer = yield this.captureEvidence(sessionId, list);
150
+ break;
151
+ case 'addTag':
152
+ answer = yield this.addTag(sessionId, list, row.tags);
153
+ break;
154
+ }
90
155
  }
91
156
  }
92
- return this.sendSuccessResponse(response);
157
+ catch (err) {
158
+ answer = notRecorded(`Xenon could not save it: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
159
+ }
160
+ if (!answer.recorded)
161
+ logger_1.default.warn(`[DashboardCommands] ${command}: ${answer.message}`);
162
+ return answer;
93
163
  });
94
164
  }
95
- sendSuccessResponse(response) {
96
- return response.status(200).json({ value: null });
97
- }
98
165
  /* Commands */
99
166
  /**
100
167
  * Set the name of current test(session)
@@ -103,63 +170,50 @@ class DashboardCommands {
103
170
  * or
104
171
  * driver.executeScript("xenon: setSessionName", {"name": "MyTestName"})
105
172
  */
106
- setSessionName(sessionId, request, response) {
173
+ setSessionName(sessionId, args) {
107
174
  return __awaiter(this, void 0, void 0, function* () {
108
- const { args } = request.body;
109
- yield (0, session_service_1.updateSessionDetails)(sessionId, {
110
- name: typeof args[0] === 'object' && args[0].name ? args[0].name : args[0],
111
- });
112
- return this.sendSuccessResponse(response);
175
+ const name = stringArg(args[0], 'name');
176
+ if (!name || !name.trim()) {
177
+ return notRecorded('setSessionName needs a name, as a string or { name }.');
178
+ }
179
+ yield (0, session_service_1.updateSessionDetails)(sessionId, { name });
180
+ return RECORDED;
113
181
  });
114
182
  }
115
183
  /**
116
184
  * Update the status of the session
117
185
  *
118
186
  * driver.executeScript("xenon: setSessionStatus", {"status": "passed/failed", "reason": "optional reason"})
187
+ * or, positionally, ("xe:setSessionStatus", "failed", "reason")
119
188
  */
120
- setSessionStatus(sessionId, request, response) {
189
+ setSessionStatus(sessionId, args) {
121
190
  return __awaiter(this, void 0, void 0, function* () {
122
- const { args } = request.body;
123
- let statusArg = {};
124
- if (lodash_1.default.isArray(args)) {
125
- if (typeof args[0] === 'object') {
126
- statusArg = args[0];
127
- }
128
- else {
129
- // Handle positional: executeScript("xe:setSessionStatus", "failed", "reason")
130
- statusArg = {
131
- status: args[0],
132
- reason: args[1],
133
- };
134
- }
135
- }
136
- else if (typeof args === 'object') {
137
- statusArg = args;
138
- }
139
- // Normalize input
140
- const inputStatus = (statusArg.status || '').toLowerCase();
191
+ const statusArg = isObject(args[0]) ? args[0] : { status: args[0], reason: args[1] };
192
+ const given = statusArg.status;
193
+ const inputStatus = typeof given === 'string' ? given.toLowerCase() : '';
141
194
  const validStatuses = ['success', 'failed', 'passed'];
142
195
  if (!validStatuses.includes(inputStatus)) {
143
- logger_1.default.warn(`[DashboardCommands] Invalid status: ${statusArg.status}. Valid: ${validStatuses.join(', ')}`);
144
- return this.sendSuccessResponse(response);
196
+ return notRecorded('setSessionStatus takes "passed" or "failed" ("success" also means passed); ' +
197
+ `it was given ${JSON.stringify(given !== null && given !== void 0 ? given : null)}.`);
145
198
  }
146
199
  // Normalize 'passed' to 'success' for consistency with SessionStatus enum
147
200
  const normalizedStatus = inputStatus === 'passed' ? 'success' : inputStatus;
201
+ const reason = typeof statusArg.reason === 'string' ? statusArg.reason : undefined;
148
202
  const updated = yield (0, session_service_1.updateSessionDetails)(sessionId, {
149
203
  status: normalizedStatus,
150
- failure_reason: statusArg.reason || undefined,
204
+ failure_reason: reason || undefined,
151
205
  });
152
206
  // --- REAL-TIME UI UPDATE ---
153
- // Principal Speed: Emit a socket event so the dashboard row updates immediately.
207
+ // Emit a socket event so the dashboard row updates immediately.
154
208
  const { SocketServer } = yield Promise.resolve().then(() => __importStar(require('../services/SocketServer')));
155
209
  const { Container } = yield Promise.resolve().then(() => __importStar(require('typedi')));
156
210
  const { SocketEvents } = yield Promise.resolve().then(() => __importStar(require('../enums/SocketEvents')));
157
211
  void Container.get(SocketServer).emitToDashboardForDevices(SocketEvents.SESSION_STOPPED, {
158
212
  id: sessionId,
159
213
  status: normalizedStatus,
160
- failure_reason: args.reason || undefined,
214
+ failure_reason: reason || undefined,
161
215
  }, { udid: updated === null || updated === void 0 ? void 0 : updated.device_udid });
162
- return this.sendSuccessResponse(response);
216
+ return RECORDED;
163
217
  });
164
218
  }
165
219
  /**
@@ -169,12 +223,18 @@ class DashboardCommands {
169
223
  * or
170
224
  * driver.executeScript("xenon: debug", "Debug message")
171
225
  */
172
- debug(sessionId, request, response) {
226
+ debug(sessionId, args) {
173
227
  return __awaiter(this, void 0, void 0, function* () {
174
- const { args } = request.body;
175
- const logData = lodash_1.default.isArray(args) ? args[0] : args;
176
- // Support both string and object format
177
- const message = typeof logData === 'string' ? logData : logData.message || JSON.stringify(logData);
228
+ const logData = args[0];
229
+ let message;
230
+ if (typeof logData === 'string')
231
+ message = logData;
232
+ else if (isObject(logData)) {
233
+ message = typeof logData.message === 'string' ? logData.message : JSON.stringify(logData);
234
+ }
235
+ if (!message) {
236
+ return notRecorded('debug needs a message, as a string or { message }.');
237
+ }
178
238
  yield prisma_1.prisma.log.create({
179
239
  data: {
180
240
  session_id: sessionId,
@@ -182,7 +242,7 @@ class DashboardCommands {
182
242
  message: message,
183
243
  },
184
244
  });
185
- return this.sendSuccessResponse(response);
245
+ return RECORDED;
186
246
  });
187
247
  }
188
248
  /**
@@ -192,44 +252,43 @@ class DashboardCommands {
192
252
  * or
193
253
  * driver.executeScript("xenon: captureEvidence", "Checkpoint reached")
194
254
  */
195
- captureEvidence(sessionId, request, response) {
255
+ captureEvidence(sessionId, args) {
196
256
  return __awaiter(this, void 0, void 0, function* () {
197
- const { args } = request.body;
198
- const evidenceData = lodash_1.default.isArray(args) ? args[0] : args;
199
- const reason = typeof evidenceData === 'string' ? evidenceData : evidenceData.reason || 'Manual capture';
200
- const label = typeof evidenceData === 'object' ? evidenceData.label : undefined;
257
+ var _a;
258
+ const evidenceData = args[0];
259
+ const reason = stringArg(evidenceData, 'reason') || 'Manual capture';
260
+ const label = isObject(evidenceData) ? evidenceData.label : undefined;
261
+ const session = SessionManager_1.SESSION_MANAGER.getSession(sessionId);
262
+ if (!session) {
263
+ return notRecorded(`Session ${sessionId} isn't running here, so no screenshot was taken.`);
264
+ }
265
+ let screenshotBase64;
201
266
  try {
202
- const session = SessionManager_1.SESSION_MANAGER.getSession(sessionId);
203
- if (!session) {
204
- logger_1.default.warn(`[DashboardCommands] captureEvidence: Session ${sessionId} not found`);
205
- return this.sendSuccessResponse(response);
206
- }
207
- const screenshotBase64 = yield session.getScreenShot();
208
- if (screenshotBase64) {
209
- const screenshotPath = (0, asset_manager_1.saveScreenShot)(sessionId, screenshotBase64);
210
- // Log the evidence capture
211
- yield prisma_1.prisma.sessionLog.create({
212
- data: {
213
- session_id: sessionId,
214
- command_name: 'captureEvidence',
215
- body: JSON.stringify({ reason, label }),
216
- response: JSON.stringify({ captured: true }),
217
- is_success: true,
218
- is_error: false,
219
- method: 'POST',
220
- title: 'Evidence Captured',
221
- subtitle: reason,
222
- screenshot: screenshotPath,
223
- url: '/execute/sync',
224
- },
225
- });
226
- logger_1.default.info(`[DashboardCommands] Evidence captured for ${sessionId}: ${reason}`);
227
- }
267
+ screenshotBase64 = yield session.getScreenShot();
228
268
  }
229
269
  catch (err) {
230
- logger_1.default.error(`[DashboardCommands] captureEvidence failed: ${err.message}`);
270
+ return notRecorded(`No screenshot could be taken: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
231
271
  }
232
- return this.sendSuccessResponse(response);
272
+ if (!screenshotBase64)
273
+ return notRecorded('No screenshot could be taken.');
274
+ const screenshotPath = (0, asset_manager_1.saveScreenShot)(sessionId, screenshotBase64);
275
+ yield prisma_1.prisma.sessionLog.create({
276
+ data: {
277
+ session_id: sessionId,
278
+ command_name: 'captureEvidence',
279
+ body: JSON.stringify({ reason, label }),
280
+ response: JSON.stringify({ captured: true }),
281
+ is_success: true,
282
+ is_error: false,
283
+ method: 'POST',
284
+ title: 'Evidence Captured',
285
+ subtitle: reason,
286
+ screenshot: screenshotPath,
287
+ url: '/execute/sync',
288
+ },
289
+ });
290
+ logger_1.default.info(`[DashboardCommands] Evidence captured for ${sessionId}: ${reason}`);
291
+ return RECORDED;
233
292
  });
234
293
  }
235
294
  /**
@@ -239,44 +298,29 @@ class DashboardCommands {
239
298
  * or
240
299
  * driver.executeScript("xenon: addTag", "smoke-test")
241
300
  */
242
- addTag(sessionId, request, response) {
301
+ addTag(sessionId, args, tags) {
243
302
  return __awaiter(this, void 0, void 0, function* () {
244
- const { args } = request.body;
245
- const tagData = lodash_1.default.isArray(args) ? args[0] : args;
246
- const newTag = typeof tagData === 'string' ? tagData : tagData.tag;
247
- if (!newTag) {
248
- logger_1.default.warn('[DashboardCommands] addTag: No tag provided');
249
- return this.sendSuccessResponse(response);
303
+ const newTag = stringArg(args[0], 'tag');
304
+ if (!newTag || !newTag.trim()) {
305
+ return notRecorded('addTag needs a tag, as a string or { tag }.');
250
306
  }
251
- try {
252
- // Get current session to append tag
253
- const session = yield prisma_1.prisma.session.findUnique({
254
- where: { id: sessionId },
255
- select: { tags: true },
256
- });
257
- // Parse existing tags or initialize empty array
258
- let existingTags = [];
259
- if (session === null || session === void 0 ? void 0 : session.tags) {
260
- try {
261
- existingTags = JSON.parse(session.tags);
262
- }
263
- catch (_a) {
264
- existingTags = [];
265
- }
307
+ let existingTags = [];
308
+ if (tags) {
309
+ try {
310
+ const parsed = JSON.parse(tags);
311
+ if (Array.isArray(parsed))
312
+ existingTags = parsed;
266
313
  }
267
- // Add new tag if not already present
268
- if (!existingTags.includes(newTag)) {
269
- existingTags.push(newTag);
270
- yield (0, session_service_1.updateSessionDetails)(sessionId, {
271
- tags: JSON.stringify(existingTags),
272
- });
273
- logger_1.default.info(`[DashboardCommands] Tag added to ${sessionId}: ${newTag}`);
314
+ catch (_a) {
315
+ existingTags = [];
274
316
  }
275
317
  }
276
- catch (err) {
277
- logger_1.default.error(`[DashboardCommands] addTag failed: ${err.message}`);
318
+ if (!existingTags.includes(newTag)) {
319
+ existingTags.push(newTag);
320
+ yield (0, session_service_1.updateSessionDetails)(sessionId, { tags: JSON.stringify(existingTags) });
321
+ logger_1.default.info(`[DashboardCommands] Tag added to ${sessionId}: ${newTag}`);
278
322
  }
279
- return this.sendSuccessResponse(response);
323
+ return RECORDED;
280
324
  });
281
325
  }
282
326
  }