@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.
- package/README.md +17 -8
- package/lib/package.json +5 -5
- package/lib/public/assets/{AnnotationOverlay-BXruClDk.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-qTS4LPLC.js → ApiKeyGate-C9OoAgg_.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
- package/lib/public/assets/{EmptyState-Cr17PdDv.js → EmptyState-DqWU2-vM.js} +1 -1
- package/lib/public/assets/{FieldGroup-Bvn08svv.js → FieldGroup-CveQ3xrA.js} +1 -1
- package/lib/public/assets/{FilterMenu-DDSO8aDf.js → FilterMenu-BfKDSfHz.js} +1 -1
- package/lib/public/assets/{Menu-B-Qn2X3T.js → Menu-CtdCybzA.js} +1 -1
- package/lib/public/assets/{Modal-Cg9V5JYU.js → Modal-Bsvj1tm2.js} +1 -1
- package/lib/public/assets/{RecordingPage-BTUs9VTW.js → RecordingPage-CRofOiyx.js} +1 -1
- package/lib/public/assets/{RecordingsPage-DYcfxITK.js → RecordingsPage-jNQHb2IR.js} +2 -2
- package/lib/public/assets/{SegmentedControl-Zy7suhT5.js → SegmentedControl-C8HtTha-.js} +1 -1
- package/lib/public/assets/{SettingCard-CWYmycoe.js → SettingCard-D8K1LZNo.js} +1 -1
- package/lib/public/assets/{Table-io9fwa98.js → Table-zNTX92Pn.js} +1 -1
- package/lib/public/assets/{activity-Bdf_uIWl.js → activity-CJ8LwZq9.js} +1 -1
- package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
- package/lib/public/assets/{api-keys-CPqtVpm3.js → api-keys-ECpo-zTo.js} +1 -1
- package/lib/public/assets/{apps-BgZan0H9.js → apps-BjGymyf3.js} +2 -2
- package/lib/public/assets/{arrow-left-B27ckB31.js → arrow-left-BWfCbeHP.js} +1 -1
- package/lib/public/assets/{arrow-right-DOF8ITCz.js → arrow-right-DC7UGf_n.js} +1 -1
- package/lib/public/assets/{arrow-up-right-eFG5KTFS.js → arrow-up-right-BOjwybDk.js} +1 -1
- package/lib/public/assets/{auth-shell-DlC3_27j.js → auth-shell-CxMTo9aH.js} +2 -2
- package/lib/public/assets/{builds-page-BuXpPfKo.js → builds-page-DOCm4HkA.js} +1 -1
- package/lib/public/assets/{button-fIW8owMI.js → button-Cg08-EMT.js} +1 -1
- package/lib/public/assets/{calendar-WNjmrF-a.js → calendar-CA1ikLJs.js} +1 -1
- package/lib/public/assets/{check-BdTh1Sq7.js → check-BMTaH72W.js} +1 -1
- package/lib/public/assets/{chevron-right-B4BKlsqk.js → chevron-right-B2QOv9Nx.js} +1 -1
- package/lib/public/assets/{circle-check-zJU80_EF.js → circle-check-CYXBoUqT.js} +1 -1
- package/lib/public/assets/{circle-x-5Uwquo0h.js → circle-x-DTwnSAnl.js} +1 -1
- package/lib/public/assets/{clock-BtUprDsZ.js → clock-C8_HViQP.js} +1 -1
- package/lib/public/assets/{copy-DGSbZI3u.js → copy-Be7LNMXV.js} +1 -1
- package/lib/public/assets/derive-UnLRp4r3.js +1 -0
- package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
- package/lib/public/assets/{download-WG6l7BgD.js → download-B56lwxWP.js} +1 -1
- package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
- package/lib/public/assets/h264Stream-C-OtmIuk.js +26 -0
- package/lib/public/assets/index-B9KQ6LsY.js +15 -0
- package/lib/public/assets/{index-DI1fGIyj.js → index-BOxe43p1.js} +5 -5
- package/lib/public/assets/{index-HDQVe1gi.js → index-CfxsUslp.js} +1 -1
- package/lib/public/assets/{input-BjDRKCea.js → input-CZHFjbSg.js} +1 -1
- package/lib/public/assets/{line-chart-C0zdgd0v.js → line-chart-Gl_Dz3X_.js} +1 -1
- package/lib/public/assets/{list-checks-BdW5CjM8.js → list-checks-CCgjeyGY.js} +1 -1
- package/lib/public/assets/{lock-Dy3L4I8E.js → lock-CkOwgDcx.js} +1 -1
- package/lib/public/assets/{login-BHbY9CLG.js → login-D5cc4w7M.js} +1 -1
- package/lib/public/assets/maintenance-settings-t7qr3fvX.js +6 -0
- package/lib/public/assets/{monitor-8xjkeHHi.js → monitor-DEJixKQO.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-CXdKMXQ8.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
- package/lib/public/assets/{network-Cj8JOKON.js → network-Dii9qdvk.js} +1 -1
- package/lib/public/assets/{overview-CTg7F0im.js → overview-rolAACrO.js} +1 -1
- package/lib/public/assets/{page-header--aTyJXq6.js → page-header-COQZxJfR.js} +1 -1
- package/lib/public/assets/{play-B-FodgHV.js → play-DrN1Se_R.js} +1 -1
- package/lib/public/assets/{plus-CsIk10Cq.js → plus-5aq-9uRx.js} +1 -1
- package/lib/public/assets/{profile-page-DkFKkMfl.js → profile-page-6i5kY6kF.js} +1 -1
- package/lib/public/assets/{reset-password-I2-zqLlI.js → reset-password-sp2IBrc7.js} +1 -1
- package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
- package/lib/public/assets/{select-DvCSv25z.js → select-Bpyn7rWO.js} +1 -1
- package/lib/public/assets/{selector-detail-redirect-BLVfMJs_.js → selector-detail-redirect-BH74vmKv.js} +1 -1
- package/lib/public/assets/{selector-health-page-oqadRokn.js → selector-health-page-Cw_g218H.js} +2 -2
- package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
- package/lib/public/assets/settings-C3uyGhyc.js +6 -0
- package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
- package/lib/public/assets/{stat-tile-DV9Ix-4O.js → stat-tile-xVqAKIlI.js} +1 -1
- package/lib/public/assets/{tablet-6b_SEN2X.js → tablet-BxUScAeO.js} +1 -1
- package/lib/public/assets/{teams-BjZyfuHh.js → teams-B5ljGkY2.js} +1 -1
- package/lib/public/assets/{trash-2-CTZpPSdd.js → trash-2-B701i8sy.js} +1 -1
- package/lib/public/assets/{upload-P3XzwQUb.js → upload-C2gr44RS.js} +1 -1
- package/lib/public/assets/{use-builds-data-1cOCMf-z.js → use-builds-data-NeQOFEoy.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-DgF9w088.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
- package/lib/public/assets/{users-DMF9Mk5H.js → users-D_vv_yz4.js} +1 -1
- package/lib/public/assets/{users-CiNTKUiz.js → users-MY6eNe6s.js} +1 -1
- package/lib/public/assets/{video-off-CHp1KU_T.js → video-off-OK1lNZQn.js} +1 -1
- package/lib/public/assets/webhook-settings-BU-C9lBf.js +1 -0
- package/lib/public/assets/{zap-DRz0tDq5.js → zap-DO9ry1iz.js} +1 -1
- package/lib/public/index.html +1 -1
- package/lib/schema.json +23 -25
- package/lib/src/XenonCapabilityManager.js +22 -5
- package/lib/src/app/dashboardPluginLink.js +117 -0
- package/lib/src/app/index.js +13 -34
- package/lib/src/app/openapi/control.yaml +73 -20
- package/lib/src/app/openapi/grid.yaml +31 -7
- package/lib/src/app/openapi/identity.yaml +103 -31
- package/lib/src/app/openapi/platform.yaml +165 -39
- package/lib/src/app/openapi/sessions.yaml +10 -3
- package/lib/src/app/routers/apikeys.js +14 -2
- package/lib/src/app/routers/auth.js +29 -5
- package/lib/src/app/routers/control.js +20 -2
- package/lib/src/app/routers/dashboard.js +69 -26
- package/lib/src/app/routers/grid.js +37 -13
- package/lib/src/app/routers/profile.js +21 -0
- package/lib/src/app/routers/streamType.js +7 -2
- package/lib/src/app/routers/users.js +10 -5
- package/lib/src/app/routers/webhook.js +8 -4
- package/lib/src/app/swagger.js +2 -0
- package/lib/src/app/ws/h264StreamWs.js +10 -1
- package/lib/src/config.js +51 -5
- package/lib/src/dashboard/commands.js +185 -141
- package/lib/src/dashboard/event-manager.js +88 -67
- package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
- package/lib/src/dashboard/sessionCommandSummary.js +39 -0
- package/lib/src/data-service/appleFamily.js +43 -0
- package/lib/src/data-service/db.js +11 -0
- package/lib/src/data-service/device-service.js +6 -1
- package/lib/src/data-service/device-store.js +76 -3
- package/lib/src/data-service/deviceClaims.js +37 -0
- package/lib/src/data-service/deviceFieldOwners.js +25 -11
- package/lib/src/data-service/deviceSettings.js +79 -0
- package/lib/src/data-service/prisma-store.js +169 -15
- package/lib/src/data-service/web-config-service.js +50 -92
- package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
- package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
- package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
- package/lib/src/device-managers/ios/WDAClient.js +44 -43
- package/lib/src/device-managers/shellCommands.js +96 -0
- package/lib/src/device-utils.js +114 -40
- package/lib/src/gateway/defaultGateway.js +1 -1
- package/lib/src/gateway/forwardToNode.js +2 -0
- package/lib/src/gateway/healReport.js +87 -0
- package/lib/src/gateway/sessionGateway.js +12 -2
- package/lib/src/generated/client/edge.js +18 -3
- package/lib/src/generated/client/index-browser.js +15 -0
- package/lib/src/generated/client/index.d.ts +2086 -379
- package/lib/src/generated/client/index.js +18 -3
- package/lib/src/generated/client/package.json +1 -1
- package/lib/src/generated/client/schema.prisma +38 -7
- package/lib/src/generated/client/wasm.js +15 -0
- package/lib/src/interceptors/CommandInterceptor.js +271 -188
- package/lib/src/interceptors/xenonScripts.js +55 -0
- package/lib/src/interfaces/IPluginArgs.js +1 -2
- package/lib/src/middleware/authMiddleware.js +15 -3
- package/lib/src/middleware/commandCaller.js +3 -3
- package/lib/src/middleware/verifyCredential.js +58 -1
- package/lib/src/plugin.js +23 -4
- package/lib/src/prisma.js +1 -1
- package/lib/src/scripts/database-check.js +124 -0
- package/lib/src/services/AICommandService.js +9 -2
- package/lib/src/services/AIService.js +281 -32
- package/lib/src/services/CleanupService.js +6 -1
- package/lib/src/services/EmailService.js +29 -0
- package/lib/src/services/InterceptorService.js +70 -13
- package/lib/src/services/NetworkConditioningService.js +85 -88
- package/lib/src/services/NotificationService.js +36 -29
- package/lib/src/services/OrphanSweeper.js +7 -0
- package/lib/src/services/PortAllocator.js +5 -0
- package/lib/src/services/SelectorVerificationJob.js +15 -4
- package/lib/src/services/ServerManager.js +105 -9
- package/lib/src/services/SessionLifecycleService.js +133 -75
- package/lib/src/services/ShutdownCoordinator.js +33 -0
- package/lib/src/services/SocketServer.js +19 -3
- package/lib/src/services/TeamService.js +20 -3
- package/lib/src/services/bug-report/video-slice.js +4 -1
- package/lib/src/services/device-access/leaseOverride.js +7 -5
- package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
- package/lib/src/services/healing/HealEtalonService.js +3 -2
- package/lib/src/services/healing/HealingOrchestrator.js +85 -71
- package/lib/src/services/healing/OcrHealingProvider.js +41 -64
- package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
- package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
- package/lib/src/services/healing/fingerprintIdentity.js +126 -0
- package/lib/src/services/healing/resilioPath.js +274 -0
- package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
- package/lib/src/services/interceptor/interceptorOptions.js +44 -0
- package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
- package/lib/src/services/logcat/deviceLogBook.js +163 -0
- package/lib/src/services/network/AndroidRadios.js +71 -0
- package/lib/src/services/network/PhoneNetworkLedger.js +184 -0
- package/lib/src/services/network/PhoneNetworkRestore.js +330 -0
- package/lib/src/services/network/adbForPhone.js +60 -0
- package/lib/src/services/network/phoneNetworkLock.js +20 -0
- package/lib/src/services/network/xenonProxy.js +107 -0
- package/lib/src/services/ocr/ocrData.js +118 -0
- package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
- package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
- package/lib/src/services/omni-vision/OmniVisionService.js +132 -95
- package/lib/src/services/omni-vision/VisionAssertionService.js +28 -25
- package/lib/src/services/omni-vision/ocrTextMatch.js +105 -0
- package/lib/src/services/omni-vision/screenScale.js +68 -0
- package/lib/src/services/passwordResetLink.js +50 -9
- package/lib/src/services/passwordResetMode.js +3 -1
- package/lib/src/services/publicUrl.js +45 -0
- package/lib/src/services/recording/concurrency-gate.js +12 -3
- package/lib/src/services/session/sessionIdentity.js +5 -3
- package/lib/src/services/session/shutdownReason.js +26 -0
- package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
- package/lib/src/services/settings/aiEngineSettings.js +219 -0
- package/lib/src/services/settings/labSettings.js +149 -0
- package/lib/src/services/token/mintedLifetime.js +51 -0
- package/lib/src/services/webhookEvents.js +173 -0
- package/lib/src/sessions/SessionManager.js +8 -2
- package/lib/src/sessions/sessionMemory.js +25 -0
- package/lib/test/helpers/fake-adb.js +58 -0
- package/lib/test/helpers/fake-ai-provider.js +188 -0
- package/lib/test/helpers/fake-device-table.js +63 -24
- package/lib/test/helpers/loki-stores.js +33 -0
- package/lib/test/helpers/page-sources.js +164 -0
- package/lib/test/helpers/scratch-database.js +58 -13
- package/lib/test/integration/audit-ingest.spec.js +10 -10
- package/lib/test/integration/auth-flow.spec.js +9 -14
- package/lib/test/integration/auth-rate-limit.spec.js +6 -3
- package/lib/test/integration/bug-report-route.spec.js +22 -2
- package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
- package/lib/test/integration/forgot-password.spec.js +17 -18
- package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
- package/lib/test/integration/migration.spec.js +6 -1
- package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
- package/lib/test/integration/ports-router.spec.js +4 -4
- package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
- package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
- package/lib/test/integration/profile-tokens.spec.js +10 -16
- package/lib/test/integration/recordings-router.spec.js +16 -16
- package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
- package/lib/test/integration/role-matrix.spec.js +4 -9
- package/lib/test/integration/sdk-leases-router.spec.js +9 -9
- package/lib/test/integration/sdk-version.spec.js +2 -2
- package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
- package/lib/test/integration/team-membership-migration.spec.js +73 -12
- package/lib/test/integration/team-visibility-apps.spec.js +15 -22
- package/lib/test/integration/team-visibility-control.spec.js +96 -69
- package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
- package/lib/test/integration/team-visibility-grid.spec.js +16 -15
- package/lib/test/integration/team-visibility-leases.spec.js +8 -11
- package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
- package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
- package/lib/test/integration/users-flow.spec.js +7 -12
- package/lib/test/integration/users-lockout.spec.js +5 -3
- package/lib/test/unit/EmailService.test.js +66 -0
- package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
- package/lib/test/unit/TeamService.test.js +3 -0
- package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
- package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
- package/lib/test/unit/ai-engine-settings.spec.js +338 -0
- package/lib/test/unit/ai-provider-switch.spec.js +130 -0
- package/lib/test/unit/ai-rate-limit.spec.js +126 -0
- package/lib/test/unit/android-h264-viewers.spec.js +272 -0
- package/lib/test/unit/android-preview-hold.spec.js +3 -2
- package/lib/test/unit/apikeys-router.spec.js +84 -0
- package/lib/test/unit/apple-family.spec.js +36 -0
- package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
- package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
- package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
- package/lib/test/unit/cleanup-settings-db.spec.js +103 -0
- package/lib/test/unit/cleanup-settings.spec.js +244 -0
- package/lib/test/unit/dashboard-api-paths.spec.js +101 -0
- package/lib/test/unit/dashboard-commands.spec.js +249 -0
- package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
- package/lib/test/unit/dashboard-events-team-scope.spec.js +9 -6
- package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
- package/lib/test/unit/database-check.spec.js +108 -0
- package/lib/test/unit/default-plugin-args.spec.js +33 -0
- package/lib/test/unit/device-log-book.spec.js +180 -0
- package/lib/test/unit/device-offline-webhook.spec.js +81 -0
- package/lib/test/unit/device-setting-columns.spec.js +66 -0
- package/lib/test/unit/device-settings-loki.spec.js +87 -0
- package/lib/test/unit/device-settings-survive.spec.js +555 -0
- package/lib/test/unit/device-sync-lost-update.spec.js +5 -0
- package/lib/test/unit/emulator-boot.spec.js +91 -0
- package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
- package/lib/test/unit/event-log-session-data.spec.js +244 -0
- package/lib/test/unit/failure-analysis.spec.js +182 -0
- package/lib/test/unit/failure-categories.spec.js +128 -0
- package/lib/test/unit/fingerprint-identity.spec.js +433 -0
- package/lib/test/unit/h264-multiplexer.spec.js +46 -0
- package/lib/test/unit/heal-report.spec.js +71 -0
- package/lib/test/unit/healing-instrumentation.spec.js +6 -1
- package/lib/test/unit/healing-tier-gate.spec.js +73 -29
- package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +219 -0
- package/lib/test/unit/hub-node-same-host.spec.js +5 -0
- package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
- package/lib/test/unit/iphone-ipad-only.spec.js +132 -0
- package/lib/test/unit/json-logging-option.spec.js +74 -0
- package/lib/test/unit/lab-settings.spec.js +218 -0
- package/lib/test/unit/lease/lease-override.spec.js +23 -6
- package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
- package/lib/test/unit/max-sessions.spec.js +240 -0
- package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
- package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
- package/lib/test/unit/ocr-offline.spec.js +213 -0
- package/lib/test/unit/ocr-text-match.spec.js +44 -0
- package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
- package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
- package/lib/test/unit/omni-vision-ios-points.spec.js +159 -0
- package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
- package/lib/test/unit/omni-vision.spec.js +6 -8
- package/lib/test/unit/package-engines.spec.js +27 -0
- package/lib/test/unit/partial-config-file.spec.js +14 -0
- package/lib/test/unit/passwordResetMode.test.js +10 -2
- package/lib/test/unit/phone-network/boot-clean-up.spec.js +64 -0
- package/lib/test/unit/phone-network/interceptor-options.spec.js +77 -0
- package/lib/test/unit/phone-network/interceptor-proxy-restore.spec.js +145 -0
- package/lib/test/unit/phone-network/network-conditioning.spec.js +145 -0
- package/lib/test/unit/phone-network/phone-network-restore.spec.js +246 -0
- package/lib/test/unit/phone-network/session-end-paths.spec.js +182 -0
- package/lib/test/unit/phone-network/session-start.spec.js +110 -0
- package/lib/test/unit/phone-network/xenon-proxy.spec.js +69 -0
- package/lib/test/unit/plugin.spec.js +3 -3
- package/lib/test/unit/profile-router.test.js +122 -1
- package/lib/test/unit/queue-requester.spec.js +1 -1
- package/lib/test/unit/recording-options.spec.js +181 -0
- package/lib/test/unit/reset-link-address.spec.js +266 -0
- package/lib/test/unit/reset-link.test.js +10 -4
- package/lib/test/unit/resilio-path-healing.spec.js +270 -0
- package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
- package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
- package/lib/test/unit/selector-verification-job.spec.js +13 -13
- package/lib/test/unit/self-healing-boot.spec.js +80 -0
- package/lib/test/unit/self-healing-setting.spec.js +273 -0
- package/lib/test/unit/session-app-resolution.spec.js +5 -1
- package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
- package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
- package/lib/test/unit/session-credential-strip.spec.js +1 -1
- package/lib/test/unit/session-device-logs.spec.js +347 -0
- package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
- package/lib/test/unit/session-failed-webhook.spec.js +170 -0
- package/lib/test/unit/session-log-indexes.spec.js +64 -3
- package/lib/test/unit/shell-commands.spec.js +133 -0
- package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
- package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
- package/lib/test/unit/stream-start-pipelines.spec.js +264 -0
- package/lib/test/unit/stream-status-type.spec.js +4 -0
- package/lib/test/unit/token-mint-limits.spec.js +165 -0
- package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
- package/lib/test/unit/verify-credential.spec.js +33 -0
- package/lib/test/unit/vision-assertion.spec.js +119 -0
- package/lib/test/unit/wda-client-shell.spec.js +133 -0
- package/lib/test/unit/web-config-service.spec.js +98 -0
- package/lib/test/unit/webhook-delivery.spec.js +24 -0
- package/lib/test/unit/webhook-payloads.spec.js +273 -0
- package/lib/test/unit/xenon-execute-scripts.spec.js +138 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/web/src/components/webhook-settings/webhookEventVariables.json +30 -0
- package/package.json +5 -5
- package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
- package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
- package/prisma/schema.prisma +38 -7
- package/schema.json +23 -25
- package/scripts/generate-types-from-schema.js +1 -2
- package/scripts/lib/always-present-plugin-args.js +4 -1
- package/lib/public/assets/BugReportButton-BoGhlI7F.js +0 -15
- package/lib/public/assets/DeviceMosaicView-8J0oYqMM.js +0 -2
- package/lib/public/assets/ai-settings-Bce5SJob.js +0 -21
- package/lib/public/assets/device-explorer-C-KnhMHI.js +0 -279
- package/lib/public/assets/forgot-password-DnudqFFo.js +0 -1
- package/lib/public/assets/maintenance-settings-zDVlOMVK.js +0 -6
- package/lib/public/assets/recording-group-store-WVM3hoXn.js +0 -26
- package/lib/public/assets/runbook-page-DJTVCJX7.js +0 -124
- package/lib/public/assets/session-detail-page-CGn55Pvl.js +0 -4
- package/lib/public/assets/settings-MsVU2ukE.js +0 -6
- package/lib/public/assets/webhook-settings-DiS8geIm.js +0 -1
- /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
|
@@ -1483,13 +1483,20 @@ paths:
|
|
|
1483
1483
|
refused, and so is a command that fails, **with `200`** and an `error` field instead of
|
|
1484
1484
|
`output` (the dashboard's terminal prints either).
|
|
1485
1485
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1486
|
+
A command must be one of the commands below, word for word, on one line. Where it takes
|
|
1487
|
+
arguments, they are plain words: letters, digits and `._/:=@%+,-`. Anything a shell would
|
|
1488
|
+
interpret (`;`, `|`, `&`, `$`, backticks, quotes, `<`, `>`) is refused.
|
|
1489
1489
|
|
|
1490
|
-
- **
|
|
1491
|
-
`
|
|
1492
|
-
|
|
1490
|
+
- **Android** (`adb shell`): `ls`, `ps`, `top`, `getprop`, `pm list packages`, `ip addr`,
|
|
1491
|
+
`date` and `netstat`, with arguments; `dumpsys battery`, `dumpsys wifi`, `dumpsys power`,
|
|
1492
|
+
`whoami`, `cat /proc/meminfo`, `cat /proc/cpuinfo` and `uptime`, without.
|
|
1493
|
+
|
|
1494
|
+
- **iOS simulator:** `listapps`, and `get_app_container` and `getenv` with arguments
|
|
1495
|
+
(through `simctl`); `ls`, `ps`, `whoami`, `date`, `uptime` and `id` without arguments
|
|
1496
|
+
(spawned in the simulator).
|
|
1497
|
+
|
|
1498
|
+
- **Real iPhone** (go-ios, through the phone's tunnel): `apps` with arguments and `info`
|
|
1499
|
+
without. Xenon names the phone; a command may not pass `--udid`.
|
|
1493
1500
|
|
|
1494
1501
|
Needs the `MEMBER` role and the `devices` scope. Refused with `409` while another user holds
|
|
1495
1502
|
the device (their live preview or recording) or runs an Appium session on it; admins are
|
|
@@ -1639,14 +1646,14 @@ paths:
|
|
|
1639
1646
|
operationId: scanDeviceScreen
|
|
1640
1647
|
summary: Analyse the screen with OCR and AI
|
|
1641
1648
|
description: >-
|
|
1642
|
-
Screenshots the device, runs OCR over it (every word with its confidence and box
|
|
1643
|
-
|
|
1644
|
-
needed. Slow: allow tens of seconds.
|
|
1649
|
+
Screenshots the device, runs OCR over it (every word with its confidence and box, in the
|
|
1650
|
+
screenshot's pixels) and sends the screenshot to the configured AI provider for a short
|
|
1651
|
+
description of the screen. No Appium session is needed. Slow: allow tens of seconds.
|
|
1645
1652
|
|
|
1646
1653
|
|
|
1647
1654
|
If the analysis itself fails (an empty screenshot, OCR failing), the answer is `500` with
|
|
1648
|
-
`{ status: 'error', message }`. If only the AI step fails,
|
|
1649
|
-
`ai_insights` is `null
|
|
1655
|
+
`{ status: 'error', message }`. If only the AI step fails, or no AI provider is
|
|
1656
|
+
configured, the answer is `200`, `ai_insights` is `null` and `ai_insights_error` says why.
|
|
1650
1657
|
|
|
1651
1658
|
|
|
1652
1659
|
Open to watchers. Needs the `MEMBER` role; any scope will do.
|
|
@@ -1683,10 +1690,27 @@ paths:
|
|
|
1683
1690
|
y0: 210
|
|
1684
1691
|
x1: 188
|
|
1685
1692
|
y1: 236
|
|
1686
|
-
ai_insights:
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1693
|
+
ai_insights: >-
|
|
1694
|
+
A sign-in screen with empty email and password fields and a disabled Sign
|
|
1695
|
+
in button. No error or dialog is shown.
|
|
1696
|
+
noProvider:
|
|
1697
|
+
summary: No AI provider configured
|
|
1698
|
+
value:
|
|
1699
|
+
status: success
|
|
1700
|
+
value:
|
|
1701
|
+
timestamp: '2026-10-04T14:05:22.118Z'
|
|
1702
|
+
ocr:
|
|
1703
|
+
text: Sign in
|
|
1704
|
+
words:
|
|
1705
|
+
- text: Sign
|
|
1706
|
+
confidence: 96.2
|
|
1707
|
+
bbox:
|
|
1708
|
+
x0: 142
|
|
1709
|
+
y0: 210
|
|
1710
|
+
x1: 188
|
|
1711
|
+
y1: 236
|
|
1712
|
+
ai_insights: null
|
|
1713
|
+
ai_insights_error: No AI provider is configured
|
|
1690
1714
|
'400':
|
|
1691
1715
|
description: This server has no device manager for the platform, or the udid is malformed.
|
|
1692
1716
|
content:
|
|
@@ -1745,8 +1769,9 @@ paths:
|
|
|
1745
1769
|
Runs one of Xenon's AI locator strategies against a fresh screenshot, as a test would with
|
|
1746
1770
|
`findElement`, without an Appium session.
|
|
1747
1771
|
|
|
1748
|
-
- `-custom:ai-text`: OCR; every
|
|
1749
|
-
|
|
1772
|
+
- `-custom:ai-text`: OCR; every place `selector` appears (case-insensitive), within a word
|
|
1773
|
+
or across neighbouring words on one line, so `Sign in` matches; each match read with
|
|
1774
|
+
confidence above 60%.
|
|
1750
1775
|
|
|
1751
1776
|
- `-custom:ai-icon`: the configured AI provider looks for what `selector` describes; at most
|
|
1752
1777
|
one match, a 40×40 box around the point it names.
|
|
@@ -1939,6 +1964,30 @@ paths:
|
|
|
1939
1964
|
On a hub, for a node's phone, the request is forwarded to the node, which holds the phone by
|
|
1940
1965
|
its own rules; on success the hub also marks the phone busy and held by you at once. A cloud
|
|
1941
1966
|
provider's phone answers `501`.
|
|
1967
|
+
|
|
1968
|
+
One capture per Android device where it can be. A page that shows MJPEG (a browser that
|
|
1969
|
+
cannot decode H.264, which on plain http it cannot, or a page whose H.264 player failed)
|
|
1970
|
+
sends `player: mjpeg`: the server then starts the MJPEG capture, and ends an H.264 capture
|
|
1971
|
+
running for the device once nobody plays it: first, if nobody does, else when its last
|
|
1972
|
+
viewer leaves. Another page may still be playing it, and keeps it until then. A node on
|
|
1973
|
+
2.13 or older ignores `player`.
|
|
1974
|
+
requestBody:
|
|
1975
|
+
required: false
|
|
1976
|
+
content:
|
|
1977
|
+
application/json:
|
|
1978
|
+
schema:
|
|
1979
|
+
type: object
|
|
1980
|
+
properties:
|
|
1981
|
+
player:
|
|
1982
|
+
type: string
|
|
1983
|
+
enum:
|
|
1984
|
+
- mjpeg
|
|
1985
|
+
description: >-
|
|
1986
|
+
Set to `mjpeg` when the page shows MJPEG. Left out, or any other value, the
|
|
1987
|
+
server chooses: H.264 for an Android device when the setting is on and the
|
|
1988
|
+
device is not being recorded, MJPEG otherwise.
|
|
1989
|
+
example:
|
|
1990
|
+
player: mjpeg
|
|
1942
1991
|
responses:
|
|
1943
1992
|
'200':
|
|
1944
1993
|
description: The preview is running. `type` says which transport to use.
|
|
@@ -2968,10 +3017,14 @@ components:
|
|
|
2968
3017
|
y1:
|
|
2969
3018
|
type: number
|
|
2970
3019
|
ai_insights:
|
|
2971
|
-
type:
|
|
3020
|
+
type: string
|
|
2972
3021
|
nullable: true
|
|
2973
|
-
|
|
2974
|
-
|
|
3022
|
+
description: >-
|
|
3023
|
+
The AI provider's description of the screen, in plain text; null when there is no
|
|
3024
|
+
AI provider or its call failed.
|
|
3025
|
+
ai_insights_error:
|
|
3026
|
+
type: string
|
|
3027
|
+
description: Why `ai_insights` is null. Present only then.
|
|
2975
3028
|
ControlTestLocatorRequest:
|
|
2976
3029
|
type: object
|
|
2977
3030
|
required:
|
|
@@ -16,7 +16,11 @@ paths:
|
|
|
16
16
|
`session_id` is that value, as an object, or an empty `200` body
|
|
17
17
|
when there is none. When the Appium dashboard plugin is installed,
|
|
18
18
|
each row in the list also gets `dashboard_link` and
|
|
19
|
-
`total_session_count`.
|
|
19
|
+
`total_session_count`. Xenon reaches the plugin on this server's own
|
|
20
|
+
address and port, and the link is `<XENON_PUBLIC_URL>/dashboard?…`,
|
|
21
|
+
or `/dashboard?…` on the server the caller has open when
|
|
22
|
+
`XENON_PUBLIC_URL` isn't set. Through 2.14 both were built from the
|
|
23
|
+
`Host` header of the first request after startup, signed in or not.
|
|
20
24
|
|
|
21
25
|
`GET /api/device` is the same endpoint.
|
|
22
26
|
tags:
|
|
@@ -141,7 +145,8 @@ paths:
|
|
|
141
145
|
description: |
|
|
142
146
|
Sets `userBlocked` on a device, so no new session or lease is
|
|
143
147
|
allocated to it. A session already running on it is not affected,
|
|
144
|
-
and neither is `busy`.
|
|
148
|
+
and neither is `busy`. The device stays blocked when it disconnects
|
|
149
|
+
and comes back, through restarts too.
|
|
145
150
|
|
|
146
151
|
Send both `udid` and `host`, exactly as `GET /api/devices` shows
|
|
147
152
|
them: the device is the row of that udid on that host. Without
|
|
@@ -247,7 +252,9 @@ paths:
|
|
|
247
252
|
Replaces the device's tag list with `tags` (it doesn't append). Tags
|
|
248
253
|
are free-form labels, such as `flaky` or `lab-row-3`, that a lease
|
|
249
254
|
can filter on. The row is chosen by exact `udid` and `host`; a pair
|
|
250
|
-
that names no device
|
|
255
|
+
that names no device is `404` (through 2.13 it changed nothing and
|
|
256
|
+
answered `200`). The device keeps its tags when it disconnects and
|
|
257
|
+
comes back, through restarts too.
|
|
251
258
|
|
|
252
259
|
Needs role `ADMIN` and the `devices` scope.
|
|
253
260
|
tags:
|
|
@@ -298,6 +305,14 @@ paths:
|
|
|
298
305
|
$ref: '#/components/responses/Unauthorized'
|
|
299
306
|
'403':
|
|
300
307
|
$ref: '#/components/responses/Forbidden'
|
|
308
|
+
'404':
|
|
309
|
+
description: No device of that udid on that host.
|
|
310
|
+
content:
|
|
311
|
+
application/json:
|
|
312
|
+
schema:
|
|
313
|
+
$ref: '#/components/schemas/Error'
|
|
314
|
+
example:
|
|
315
|
+
error: Device not found
|
|
301
316
|
'429':
|
|
302
317
|
$ref: '#/components/responses/RateLimited'
|
|
303
318
|
/api/device/{udid}/team:
|
|
@@ -307,10 +322,14 @@ paths:
|
|
|
307
322
|
description: |
|
|
308
323
|
Gives the device to a team, or with `teamId: null` returns it to the
|
|
309
324
|
shared pool, which every member sees. A missing `teamId` counts as
|
|
310
|
-
null. Every
|
|
325
|
+
null. Every device with this udid changes (on a hub, each node that
|
|
311
326
|
reports it), and allocation and live dashboard events follow the new
|
|
312
327
|
team at once.
|
|
313
328
|
|
|
329
|
+
A device keeps its team when it disconnects and comes back, through
|
|
330
|
+
restarts too, and this also moves one of this udid that isn't
|
|
331
|
+
connected now: a team that one belongs to can't be deleted.
|
|
332
|
+
|
|
314
333
|
Needs role `ADMIN` and the `admin` scope.
|
|
315
334
|
tags:
|
|
316
335
|
- Devices
|
|
@@ -336,7 +355,7 @@ paths:
|
|
|
336
355
|
example: clx9k2v0a0000qz8r4h7m3n2p
|
|
337
356
|
responses:
|
|
338
357
|
'200':
|
|
339
|
-
description: The device's team changed. `updated` is how many
|
|
358
|
+
description: The device's team changed. `updated` is how many devices changed, connected or not.
|
|
340
359
|
content:
|
|
341
360
|
application/json:
|
|
342
361
|
schema:
|
|
@@ -432,7 +451,10 @@ paths:
|
|
|
432
451
|
(`reservedByUserId`), who alone, or an admin, may release or extend
|
|
433
452
|
it. A device already reserved by someone else, or running an Appium
|
|
434
453
|
session, is refused with `409`. The same user under the same
|
|
435
|
-
`reservedBy` may reserve it again, which restarts the clock.
|
|
454
|
+
`reservedBy` may reserve it again, which restarts the clock. The
|
|
455
|
+
reservation lasts until it ends even if the device disconnects or
|
|
456
|
+
the server restarts meanwhile; one that ended while the device was
|
|
457
|
+
away is not brought back.
|
|
436
458
|
|
|
437
459
|
The device is the row of `udid` on `host`, so send both exactly as
|
|
438
460
|
`GET /api/devices` shows them. No such row, or a device outside the
|
|
@@ -2047,7 +2069,9 @@ components:
|
|
|
2047
2069
|
description: On a hub, the preview hold the node last reported (`manual_<userId>_<udid>`).
|
|
2048
2070
|
dashboard_link:
|
|
2049
2071
|
type: string
|
|
2050
|
-
description:
|
|
2072
|
+
description: >-
|
|
2073
|
+
Only with the Appium dashboard plugin installed: the plugin's page for this device,
|
|
2074
|
+
under `XENON_PUBLIC_URL`, or a path on this server when it isn't set.
|
|
2051
2075
|
total_session_count:
|
|
2052
2076
|
type: integer
|
|
2053
2077
|
description: Only with the Appium dashboard plugin installed.
|
|
@@ -10,9 +10,10 @@ paths:
|
|
|
10
10
|
Public. Tells the sign-in page how a user who forgot their password can get back in, before
|
|
11
11
|
anyone is signed in.
|
|
12
12
|
|
|
13
|
-
`passwordReset` is `email` when the server has SMTP configured
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
`passwordReset` is `email` when the server has SMTP configured and `XENON_PUBLIC_URL` set to
|
|
14
|
+
its address (the forgot-password form really emails a link, which points there),
|
|
15
|
+
otherwise `admin` (the user must ask an administrator, who issues a link with
|
|
16
|
+
`POST /api/users/{id}/reset-link`). Nothing else about the mail setup is revealed.
|
|
16
17
|
tags:
|
|
17
18
|
- Authentication
|
|
18
19
|
security: []
|
|
@@ -34,8 +35,8 @@ paths:
|
|
|
34
35
|
Public. Checks the email (case-insensitive) and password of an `ACTIVE` user and, on success,
|
|
35
36
|
sets the `xenon_dashboard_session` cookie (HttpOnly, `SameSite=Strict`, `Secure` when the
|
|
36
37
|
request came over HTTPS or with `X-Forwarded-Proto: https`). The cookie lives for the
|
|
37
|
-
server's user-session lifetime (24 hours by default, `XENON_USER_SESSION_TTL_MS
|
|
38
|
-
renewed on every authenticated request. Updates the user's last sign-in time.
|
|
38
|
+
server's user-session lifetime (24 hours by default, `XENON_USER_SESSION_TTL_MS`, which may be
|
|
39
|
+
longer or shorter) and is renewed for that long on every authenticated request. Updates the user's last sign-in time.
|
|
39
40
|
|
|
40
41
|
A wrong password, an unknown email and an inactive user all answer the same `401`.
|
|
41
42
|
|
|
@@ -116,8 +117,11 @@ paths:
|
|
|
116
117
|
addresses have accounts. Then, in the background, if the email belongs to an `ACTIVE` user and
|
|
117
118
|
the server can deliver mail (SMTP configured, or the opt-in log fallback
|
|
118
119
|
`XENON_PASSWORD_RESET_LOG_FALLBACK=true`), it creates a single-use reset token (valid 1 hour by
|
|
119
|
-
default) and sends a link to
|
|
120
|
-
|
|
120
|
+
default, `XENON_RESET_TOKEN_TTL_MS`) and sends a link to
|
|
121
|
+
`<server address>/xenon/reset-password#<token>`. The server address is `XENON_PUBLIC_URL`
|
|
122
|
+
(such as `https://xenon.example.com`; a trailing `/xenon/` is dropped), never the request's
|
|
123
|
+
`Host`, which whoever asks chooses. Without a way to deliver mail, or without a usable
|
|
124
|
+
`XENON_PUBLIC_URL`, no token is created; `GET /api/auth/options` says `admin` then.
|
|
121
125
|
|
|
122
126
|
**Rate limit.** 3 requests per 15 minutes per client IP by default, then `429` with
|
|
123
127
|
`Retry-After`.
|
|
@@ -387,16 +391,28 @@ paths:
|
|
|
387
391
|
(`XENON_MCP_TOKEN_TTL_SEC`). It carries granular `scopes` (by default `appium:use` and
|
|
388
392
|
`xenon:devices:read`, as far as the caller's scopes allow) and, as a REST bearer token, only
|
|
389
393
|
the flat scopes those need (`appium:use` gives `sessions`, `xenon:devices:lock` gives
|
|
390
|
-
`devices`).
|
|
391
|
-
to put in an Appium session's
|
|
394
|
+
`devices`). When the grant includes `appium:use` the answer also has a `sessionToken`
|
|
395
|
+
(audience `xenon-session`, same lifetime) to put in an Appium session's
|
|
396
|
+
`xe:options.sessionToken`. It carries the `sessions` scope, and `admin` only when the
|
|
397
|
+
credential minting it has `admin` and the grant is the default one (no `scopes` asked for) or
|
|
398
|
+
a full-admin one. With `admin` a session may use a lease someone else made, and only while
|
|
399
|
+
its user is still an `ADMIN` (a `SUPER_ADMIN`'s session may, `admin` or not). A credential
|
|
400
|
+
without `sessions` or `admin`, a read-only one for instance, gets no `sessionToken`.
|
|
401
|
+
|
|
402
|
+
**Never longer than the credential.** A token minted with a Bearer token, or with an API key
|
|
403
|
+
that expires, ends no later than that credential: `expiresIn` is cut to what is left of it. A
|
|
404
|
+
credential with no time left answers `400`. A dashboard sign-in renews itself, so its tokens get
|
|
405
|
+
the full lifetime.
|
|
406
|
+
|
|
407
|
+
**Scopes follow the role.** A token's scopes are fixed when it is minted, but its `admin` scope
|
|
408
|
+
stops counting once its user is a `MEMBER`: the API and per-command auth read the token's scopes
|
|
409
|
+
without it.
|
|
392
410
|
|
|
393
411
|
Granular scopes a credential may grant: `read` gives `xenon:devices:read` and
|
|
394
412
|
`xenon:analytics:read`; `sessions` gives `appium:use` and `xenon:recordings`; `devices` gives
|
|
395
413
|
`xenon:devices:read`, `xenon:devices:lock` and `xenon:recordings`; `admin` gives all of them.
|
|
396
414
|
|
|
397
|
-
Cookie callers need a same-host `Origin` or `Referer`.
|
|
398
|
-
caller using only `Authorization: Bearer`: the same-origin check exempts only requests with an
|
|
399
|
-
`x-xenon-access-key` header.
|
|
415
|
+
Cookie callers need a same-host `Origin` or `Referer`.
|
|
400
416
|
tags:
|
|
401
417
|
- Authentication
|
|
402
418
|
requestBody:
|
|
@@ -441,7 +457,9 @@ paths:
|
|
|
441
457
|
- xenon:devices:read
|
|
442
458
|
sessionToken: eyJhbGciOiJSUzI1NiIsImtpZCI6IjNmMmE5YzRlN2QxYiJ9.eyJzdWIiOiI3YzFlMmQ0YSIsImF1ZCI6Inhlbm9uLXNlc3Npb24ifQ.c2lnbmF0dXJl
|
|
443
459
|
'400':
|
|
444
|
-
description:
|
|
460
|
+
description: |
|
|
461
|
+
An unsupported audience, `scopes` that isn't an array, an unknown granular scope, or a
|
|
462
|
+
credential with no time left to give the token.
|
|
445
463
|
content:
|
|
446
464
|
application/json:
|
|
447
465
|
schema:
|
|
@@ -451,6 +469,10 @@ paths:
|
|
|
451
469
|
value:
|
|
452
470
|
error: bad_request
|
|
453
471
|
details: 'unsupported audience: xenon-node'
|
|
472
|
+
expired:
|
|
473
|
+
value:
|
|
474
|
+
error: bad_request
|
|
475
|
+
details: the credential used to mint this token has expired
|
|
454
476
|
unknownScope:
|
|
455
477
|
value:
|
|
456
478
|
error: unknown_scope
|
|
@@ -584,8 +606,12 @@ paths:
|
|
|
584
606
|
description: |
|
|
585
607
|
Gives the caller a new access key. The old one stops working at once, for every one of their
|
|
586
608
|
API tokens: scripts and CI using the key pair must be updated. The tokens themselves are kept.
|
|
587
|
-
|
|
588
|
-
|
|
609
|
+
|
|
610
|
+
Since that cuts off every key pair the user has, whatever its scopes, it takes a dashboard
|
|
611
|
+
sign-in (the cookie) or a credential with the `admin` scope. Any other API token or Bearer
|
|
612
|
+
token, a `read`-only one for instance, gets `403`. Through 2.14 any credential could. With
|
|
613
|
+
authentication disabled it rotates the first `SUPER_ADMIN`'s key. Cookie callers need a
|
|
614
|
+
same-host `Origin` or `Referer`.
|
|
589
615
|
tags:
|
|
590
616
|
- Profile
|
|
591
617
|
responses:
|
|
@@ -600,7 +626,13 @@ paths:
|
|
|
600
626
|
'401':
|
|
601
627
|
$ref: '#/components/responses/Unauthorized'
|
|
602
628
|
'403':
|
|
603
|
-
|
|
629
|
+
description: A credential other than a dashboard sign-in, without the `admin` scope.
|
|
630
|
+
content:
|
|
631
|
+
application/json:
|
|
632
|
+
schema:
|
|
633
|
+
$ref: '#/components/schemas/Error'
|
|
634
|
+
example:
|
|
635
|
+
error: rotating the access key needs a dashboard sign-in or a credential with the admin scope
|
|
604
636
|
'404':
|
|
605
637
|
$ref: '#/components/responses/IdentityUserNotFound'
|
|
606
638
|
'429':
|
|
@@ -653,6 +685,11 @@ paths:
|
|
|
653
685
|
role was checked, so an admin's `read`-only key could mint a wider token. The token has the
|
|
654
686
|
default rate limit (300 a minute) and no team binding.
|
|
655
687
|
|
|
688
|
+
Made with a credential that expires (a Bearer token, or an API key with an `expiresAt`), the
|
|
689
|
+
token expires no later than it: without `expiresAt` it gets that credential's, and a later
|
|
690
|
+
`expiresAt` answers `400`. Through 2.14 a 1-hour Bearer token could make a token that never
|
|
691
|
+
expired. From the dashboard, `expiresAt` may be left out for a token that never expires.
|
|
692
|
+
|
|
656
693
|
Any signed-in user may call it. Cookie callers need a same-host `Origin` or `Referer`.
|
|
657
694
|
tags:
|
|
658
695
|
- Profile
|
|
@@ -681,8 +718,8 @@ paths:
|
|
|
681
718
|
expiresAt: '2027-01-01T00:00:00.000Z'
|
|
682
719
|
'400':
|
|
683
720
|
description: >-
|
|
684
|
-
`name` is missing, `expiresAt` is invalid
|
|
685
|
-
beyond your role or the credential you are using.
|
|
721
|
+
`name` is missing, `expiresAt` is invalid, past or later than the credential you are
|
|
722
|
+
using, a scope is unknown, or a scope is beyond your role or the credential you are using.
|
|
686
723
|
content:
|
|
687
724
|
application/json:
|
|
688
725
|
schema:
|
|
@@ -694,6 +731,11 @@ paths:
|
|
|
694
731
|
expiry:
|
|
695
732
|
value:
|
|
696
733
|
error: expiresAt must be in the future
|
|
734
|
+
outlives:
|
|
735
|
+
value:
|
|
736
|
+
error: >-
|
|
737
|
+
expiresAt can be no later than the credential you are using, which expires at
|
|
738
|
+
2026-10-04T13:00:00.000Z
|
|
697
739
|
unknown:
|
|
698
740
|
value:
|
|
699
741
|
error: scopes must be some of read, sessions, devices, admin
|
|
@@ -872,7 +914,9 @@ paths:
|
|
|
872
914
|
- You can't change your own role.
|
|
873
915
|
- The last active `SUPER_ADMIN` can't be demoted or deactivated.
|
|
874
916
|
- Setting `status` to `INACTIVE` signs the user out of every dashboard session. Their API
|
|
875
|
-
tokens and
|
|
917
|
+
tokens, bearer tokens and session tokens stop working too, since an inactive user's
|
|
918
|
+
credentials are refused: on this API at once, for a new Appium session at once, and for the
|
|
919
|
+
commands of a session already running within 30 seconds with `XENON_REQUIRE_COMMAND_AUTH`.
|
|
876
920
|
|
|
877
921
|
Cookie callers need a same-host `Origin` or `Referer`.
|
|
878
922
|
tags:
|
|
@@ -973,9 +1017,11 @@ paths:
|
|
|
973
1017
|
Needs role `ADMIN` or above. An `ADMIN` may issue links only for `MEMBER` accounts. Creates a
|
|
974
1018
|
single-use reset link for an `ACTIVE` user, valid 1 hour by default.
|
|
975
1019
|
|
|
976
|
-
With SMTP configured the link is emailed to the user and the answer is
|
|
977
|
-
|
|
978
|
-
|
|
1020
|
+
With SMTP and `XENON_PUBLIC_URL` configured the link is emailed to the user and the answer is
|
|
1021
|
+
`emailed: true`; the emailed link points at `XENON_PUBLIC_URL`, never at the request's `Host`.
|
|
1022
|
+
Without either the link is returned once, in this answer only (`Cache-Control: no-store`), for
|
|
1023
|
+
the admin to pass on; it is never written to the server log. A returned link points at
|
|
1024
|
+
`XENON_PUBLIC_URL` when it is set, else at the address the admin reached the server on. Your own password goes through
|
|
979
1025
|
`POST /api/auth/change-password` instead. Cookie callers need a same-host `Origin` or
|
|
980
1026
|
`Referer`.
|
|
981
1027
|
tags:
|
|
@@ -1322,10 +1368,20 @@ paths:
|
|
|
1322
1368
|
summary: Create an API key
|
|
1323
1369
|
description: |
|
|
1324
1370
|
Creates an API token owned by the caller and returns its value **once** as `key`; it is used as
|
|
1325
|
-
`x-xenon-token` with the caller's access key. Unlike `POST /api/profile/tokens`, it can
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1371
|
+
`x-xenon-token` with the caller's access key. Unlike `POST /api/profile/tokens`, it can name a
|
|
1372
|
+
team, set its rate limit and grant any scope, `admin` included. `scopes` must be some of `read`,
|
|
1373
|
+
`sessions`, `devices` and `admin`; any other string answers `400` (through 2.14 it was stored,
|
|
1374
|
+
and gave the key nothing). Needs role `ADMIN` or above and the `admin` scope. Cookie callers
|
|
1375
|
+
need a same-host `Origin` or `Referer`.
|
|
1376
|
+
|
|
1377
|
+
**The team doesn't narrow the key.** The key belongs to the caller, an administrator, and an
|
|
1378
|
+
administrator's credentials reach every team's devices, so the key does too whichever team it
|
|
1379
|
+
names. The team is recorded on the leases the key takes, and limits the key only if its owner
|
|
1380
|
+
is later made a `MEMBER`. A test session keeps to one team with `xe:options.team`.
|
|
1381
|
+
|
|
1382
|
+
Made with a credential that expires (a Bearer token, or an API key with an `expiresAt`), the
|
|
1383
|
+
key expires no later than it: without `expiresAt` it gets that credential's, and a later
|
|
1384
|
+
`expiresAt` answers `400`.
|
|
1329
1385
|
tags:
|
|
1330
1386
|
- API Keys
|
|
1331
1387
|
requestBody:
|
|
@@ -1365,7 +1421,9 @@ paths:
|
|
|
1365
1421
|
key: 5d2e8f1a9c4b7e3d6a0f2c8b1e5d9a4c7f3b6e0d2a8c5f1e9b4d7a3c6f0e2b8d
|
|
1366
1422
|
expiresAt: '2027-04-01T00:00:00.000Z'
|
|
1367
1423
|
'400':
|
|
1368
|
-
description:
|
|
1424
|
+
description: >-
|
|
1425
|
+
`name` or `scopes` is missing, a scope is unknown, or `expiresAt` is invalid, past or later
|
|
1426
|
+
than the credential making the request.
|
|
1369
1427
|
content:
|
|
1370
1428
|
application/json:
|
|
1371
1429
|
schema:
|
|
@@ -1374,6 +1432,9 @@ paths:
|
|
|
1374
1432
|
missing:
|
|
1375
1433
|
value:
|
|
1376
1434
|
error: name and scopes required
|
|
1435
|
+
unknown:
|
|
1436
|
+
value:
|
|
1437
|
+
error: scopes must be some of read, sessions, devices, admin
|
|
1377
1438
|
expiry:
|
|
1378
1439
|
value:
|
|
1379
1440
|
error: expiresAt must be an ISO-8601 datetime
|
|
@@ -1835,7 +1896,9 @@ components:
|
|
|
1835
1896
|
type: string
|
|
1836
1897
|
sessionToken:
|
|
1837
1898
|
type: string
|
|
1838
|
-
description:
|
|
1899
|
+
description: >-
|
|
1900
|
+
`xenon-mcp` only, and only when the grant includes `appium:use`: a session token for
|
|
1901
|
+
`xe:options.sessionToken`, with the same lifetime.
|
|
1839
1902
|
IdentityAccessKey:
|
|
1840
1903
|
type: object
|
|
1841
1904
|
properties:
|
|
@@ -1881,7 +1944,10 @@ components:
|
|
|
1881
1944
|
type: string
|
|
1882
1945
|
format: date-time
|
|
1883
1946
|
nullable: true
|
|
1884
|
-
description:
|
|
1947
|
+
description: >-
|
|
1948
|
+
When the token stops working; must be in the future, and no later than the credential
|
|
1949
|
+
making the request when that one expires. Null or absent for never, or, with a credential
|
|
1950
|
+
that expires, for when that credential does.
|
|
1885
1951
|
IdentityCreatedToken:
|
|
1886
1952
|
type: object
|
|
1887
1953
|
properties:
|
|
@@ -2099,12 +2165,18 @@ components:
|
|
|
2099
2165
|
teamId:
|
|
2100
2166
|
type: string
|
|
2101
2167
|
nullable: true
|
|
2102
|
-
description:
|
|
2168
|
+
description: >-
|
|
2169
|
+
A team to note on the key. The key belongs to the caller, an administrator, so like them it
|
|
2170
|
+
reaches every team's devices whichever team this names: the team is recorded on the leases
|
|
2171
|
+
the key takes, and limits the key only if its owner is later made a `MEMBER`.
|
|
2103
2172
|
expiresAt:
|
|
2104
2173
|
type: string
|
|
2105
2174
|
format: date-time
|
|
2106
2175
|
nullable: true
|
|
2107
|
-
description:
|
|
2176
|
+
description: >-
|
|
2177
|
+
When the key stops working; must be in the future, and no later than the credential
|
|
2178
|
+
making the request when that one expires. Null or absent for never, or, with a credential
|
|
2179
|
+
that expires, for when that credential does.
|
|
2108
2180
|
IdentityProject:
|
|
2109
2181
|
type: object
|
|
2110
2182
|
properties:
|