@xenon-device-management/xenon 2.15.0 → 2.16.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 (183) hide show
  1. package/README.md +38 -26
  2. package/lib/package.json +2 -1
  3. package/lib/public/assets/{AnnotationOverlay-Btq3dZRI.js → AnnotationOverlay-2W4JvEyZ.js} +1 -1
  4. package/lib/public/assets/{ApiKeyGate-C9OoAgg_.js → ApiKeyGate-GmckX_7r.js} +1 -1
  5. package/lib/public/assets/{DeviceMosaicView-DBC_xczB.js → DeviceMosaicView-DqODzkyo.js} +1 -1
  6. package/lib/public/assets/{EmptyState-DqWU2-vM.js → EmptyState-7hETKEWb.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-CveQ3xrA.js → FieldGroup-GOgssFEP.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-BfKDSfHz.js → FilterMenu-Yvf6RGMd.js} +1 -1
  9. package/lib/public/assets/{Menu-CtdCybzA.js → Menu-KrPnfdsf.js} +1 -1
  10. package/lib/public/assets/{Modal-Bsvj1tm2.js → Modal-C6WjZFeI.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-CRofOiyx.js → RecordingPage-CSRIhZEh.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-jNQHb2IR.js → RecordingsPage-CB8ST3nE.js} +1 -1
  13. package/lib/public/assets/{SegmentedControl-C8HtTha-.js → SegmentedControl-C9o90KId.js} +1 -1
  14. package/lib/public/assets/{SettingCard-D8K1LZNo.js → SettingCard-CPm3w9l2.js} +1 -1
  15. package/lib/public/assets/{Table-zNTX92Pn.js → Table-DwIgERRt.js} +1 -1
  16. package/lib/public/assets/{activity-CJ8LwZq9.js → activity-DrLbHifn.js} +1 -1
  17. package/lib/public/assets/{ai-settings-CgxQZqrc.js → ai-settings-DU_Ls06P.js} +1 -1
  18. package/lib/public/assets/{api-keys-ECpo-zTo.js → api-keys-CWYdEzJ_.js} +1 -1
  19. package/lib/public/assets/{apps-BjGymyf3.js → apps-BqNVdln7.js} +1 -1
  20. package/lib/public/assets/{arrow-left-BWfCbeHP.js → arrow-left-BtB0_Jg_.js} +1 -1
  21. package/lib/public/assets/{arrow-right-DC7UGf_n.js → arrow-right-C8NhdtyN.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-BOjwybDk.js → arrow-up-right-gMg0ffvv.js} +1 -1
  23. package/lib/public/assets/{auth-shell-CxMTo9aH.js → auth-shell-CiYZ3N4M.js} +2 -2
  24. package/lib/public/assets/{builds-page-DOCm4HkA.js → builds-page-EaaqDmLN.js} +1 -1
  25. package/lib/public/assets/{button-Cg08-EMT.js → button-DDau4Axv.js} +1 -1
  26. package/lib/public/assets/{calendar-CA1ikLJs.js → calendar-DQ83B1ed.js} +1 -1
  27. package/lib/public/assets/{check-BMTaH72W.js → check-K1ovTQam.js} +1 -1
  28. package/lib/public/assets/{chevron-right-B2QOv9Nx.js → chevron-right-Biq00pMt.js} +1 -1
  29. package/lib/public/assets/{circle-check-CYXBoUqT.js → circle-check-CBv88cH7.js} +1 -1
  30. package/lib/public/assets/{circle-x-DTwnSAnl.js → circle-x-Bmltailn.js} +1 -1
  31. package/lib/public/assets/{clock-C8_HViQP.js → clock-BPrld-3h.js} +1 -1
  32. package/lib/public/assets/{copy-Be7LNMXV.js → copy-t0QB14JI.js} +1 -1
  33. package/lib/public/assets/{device-explorer-BOqtfGXz.js → device-explorer-BgGZ8AvV.js} +1 -1
  34. package/lib/public/assets/{download-B56lwxWP.js → download-BroHxNOh.js} +1 -1
  35. package/lib/public/assets/{forgot-password-CCU6bzLn.js → forgot-password-Bjmf49i6.js} +1 -1
  36. package/lib/public/assets/{h264Stream-C-OtmIuk.js → h264Stream-DeD__6wa.js} +1 -1
  37. package/lib/public/assets/{index-CfxsUslp.js → index-72oF89LJ.js} +1 -1
  38. package/lib/public/assets/{index-B9KQ6LsY.js → index-B0JeuZbg.js} +1 -1
  39. package/lib/public/assets/index-B0gQkEg0.js +219 -0
  40. package/lib/public/assets/{input-CZHFjbSg.js → input-DIc4MSC7.js} +1 -1
  41. package/lib/public/assets/{line-chart-Gl_Dz3X_.js → line-chart-BcWm2vW8.js} +1 -1
  42. package/lib/public/assets/{list-checks-CCgjeyGY.js → list-checks-B06IJJad.js} +1 -1
  43. package/lib/public/assets/{lock-CkOwgDcx.js → lock-pVLvnN30.js} +1 -1
  44. package/lib/public/assets/{login-D5cc4w7M.js → login-CN77vy--.js} +1 -1
  45. package/lib/public/assets/{maintenance-settings-t7qr3fvX.js → maintenance-settings-CSdzQSkY.js} +1 -1
  46. package/lib/public/assets/{monitor-DEJixKQO.js → monitor-BtrN5IkI.js} +1 -1
  47. package/lib/public/assets/{mouse-pointer-2-CtOrk4M8.js → mouse-pointer-2-CNsQfo6w.js} +1 -1
  48. package/lib/public/assets/{network-Dii9qdvk.js → network-BSfA8ZxG.js} +1 -1
  49. package/lib/public/assets/{overview-rolAACrO.js → overview-BfTebCK5.js} +1 -1
  50. package/lib/public/assets/{page-header-COQZxJfR.js → page-header-D8KUX6Qg.js} +1 -1
  51. package/lib/public/assets/{play-DrN1Se_R.js → play-Cvc8xzic.js} +1 -1
  52. package/lib/public/assets/{plus-5aq-9uRx.js → plus-C9Zj84UF.js} +1 -1
  53. package/lib/public/assets/{profile-page-6i5kY6kF.js → profile-page-Bi27STgs.js} +1 -1
  54. package/lib/public/assets/{reset-password-sp2IBrc7.js → reset-password-CPsOuwSu.js} +1 -1
  55. package/lib/public/assets/{runbook-page-DJDjeopU.js → runbook-page-DEQ-DBOX.js} +153 -102
  56. package/lib/public/assets/{select-Bpyn7rWO.js → select-BWpnhWXj.js} +1 -1
  57. package/lib/public/assets/{selector-detail-redirect-BH74vmKv.js → selector-detail-redirect-BefSCSpe.js} +1 -1
  58. package/lib/public/assets/{selector-health-page-Cw_g218H.js → selector-health-page-MSk96Zz7.js} +1 -1
  59. package/lib/public/assets/session-detail-page-DPyBNef_.js +4 -0
  60. package/lib/public/assets/{settings-C3uyGhyc.js → settings-V6x-cXwy.js} +1 -1
  61. package/lib/public/assets/{stat-tile-xVqAKIlI.js → stat-tile-Duex-GZD.js} +1 -1
  62. package/lib/public/assets/{tablet-BxUScAeO.js → tablet-BBcoqBmL.js} +1 -1
  63. package/lib/public/assets/{teams-B5ljGkY2.js → teams-ts8p5rEh.js} +1 -1
  64. package/lib/public/assets/{trash-2-B701i8sy.js → trash-2-CZ2ew6AZ.js} +1 -1
  65. package/lib/public/assets/{upload-C2gr44RS.js → upload-Dv99y_le.js} +1 -1
  66. package/lib/public/assets/{use-builds-data-NeQOFEoy.js → use-builds-data-DrYC8JCF.js} +1 -1
  67. package/lib/public/assets/{use-password-reset-mode-DEzJq5ef.js → use-password-reset-mode-C7QkBNkP.js} +1 -1
  68. package/lib/public/assets/{users-D_vv_yz4.js → users-D7tKMESH.js} +1 -1
  69. package/lib/public/assets/{users-MY6eNe6s.js → users-gJ5Y01yo.js} +1 -1
  70. package/lib/public/assets/{video-off-OK1lNZQn.js → video-off-CqZVuZGs.js} +1 -1
  71. package/lib/public/assets/{webhook-settings-BU-C9lBf.js → webhook-settings-DI5DSW99.js} +1 -1
  72. package/lib/public/assets/{zap-DO9ry1iz.js → zap-ClcHFxfo.js} +1 -1
  73. package/lib/public/index.html +1 -1
  74. package/lib/schema.json +11 -7
  75. package/lib/src/InternalHttpClient.js +27 -5
  76. package/lib/src/XenonCapabilityManager.js +10 -3
  77. package/lib/src/app/openapi/sessions.yaml +7 -5
  78. package/lib/src/app/routers/auth.js +2 -1
  79. package/lib/src/app/routers/users.js +2 -1
  80. package/lib/src/app/ws/nodeSocketRelay.js +77 -11
  81. package/lib/src/dashboard/commandLogFields.js +42 -0
  82. package/lib/src/dashboard/event-manager.js +26 -154
  83. package/lib/src/dashboard/services/failure-analysis-service.js +8 -86
  84. package/lib/src/dashboard/services/failureCategories.js +264 -0
  85. package/lib/src/device-managers/AndroidDeviceManager.js +61 -23
  86. package/lib/src/device-managers/IOSDeviceManager.js +10 -0
  87. package/lib/src/device-utils.js +14 -6
  88. package/lib/src/gateway/forwardToNode.js +4 -11
  89. package/lib/src/gateway/hubSessionToken.js +27 -4
  90. package/lib/src/gateway/nodeWebDriverUrl.js +3 -5
  91. package/lib/src/helpers/outboundProxy.js +219 -0
  92. package/lib/src/index.js +21 -0
  93. package/lib/src/interceptors/CommandInterceptor.js +13 -15
  94. package/lib/src/interceptors/xenonScripts.js +28 -7
  95. package/lib/src/logger.js +3 -1
  96. package/lib/src/plugin.js +8 -3
  97. package/lib/src/scripts/database-check.js +3 -3
  98. package/lib/src/scripts/initialize-database.js +35 -33
  99. package/lib/src/scripts/run-migrations.js +1079 -27
  100. package/lib/src/services/ApiKeyService.js +16 -5
  101. package/lib/src/services/InterceptorService.js +6 -2
  102. package/lib/src/services/OrphanSweeper.js +6 -0
  103. package/lib/src/services/SelectorStateService.js +11 -7
  104. package/lib/src/services/SelectorVerificationJob.js +6 -2
  105. package/lib/src/services/SessionLifecycleService.js +32 -18
  106. package/lib/src/services/SocketClient.js +11 -0
  107. package/lib/src/services/SocketServer.js +361 -42
  108. package/lib/src/services/TeamService.js +5 -1
  109. package/lib/src/services/TracingService.js +171 -60
  110. package/lib/src/services/UserService.js +14 -3
  111. package/lib/src/services/UserSessionService.js +16 -4
  112. package/lib/src/services/healing/HealingOrchestrator.js +3 -1
  113. package/lib/src/services/identity/identityChanges.js +41 -0
  114. package/lib/src/services/logcat/SessionDeviceLogs.js +97 -10
  115. package/lib/src/services/logcat/deviceLogBook.js +5 -4
  116. package/lib/src/services/logcat/iosDriverLog.js +178 -0
  117. package/lib/src/services/selector-health/SelectorVisibilityResolver.js +121 -0
  118. package/lib/src/services/token/JwtKeyService.js +8 -2
  119. package/lib/src/services/token/mcpTokenTtl.js +27 -0
  120. package/lib/src/sessions/LocalSession.js +29 -1
  121. package/lib/src/sessions/RemoteSession.js +12 -2
  122. package/lib/src/sessions/SessionManager.js +5 -8
  123. package/lib/test/helpers/driver-log.js +38 -0
  124. package/lib/test/helpers/fake-http-proxy.js +106 -0
  125. package/lib/test/helpers/otlp-probe.js +107 -0
  126. package/lib/test/integration/androidDevices.spec.js +1 -1
  127. package/lib/test/integration/ios/01iOSSimulator.spec.js +1 -1
  128. package/lib/test/integration/ios/02iOSDevices.spec.js +1 -1
  129. package/lib/test/integration/selector-state-flow.spec.js +5 -5
  130. package/lib/test/unit/XenonCapabilityManager.spec.js +23 -0
  131. package/lib/test/unit/android-adb-retry.spec.js +112 -0
  132. package/lib/test/unit/command-log-network-capture.spec.js +191 -0
  133. package/lib/test/unit/dashboard-events-device-logs.spec.js +59 -11
  134. package/lib/test/unit/dashboard-events-team-scope.spec.js +6 -3
  135. package/lib/test/unit/database-check.spec.js +1 -0
  136. package/lib/test/unit/device-utils.spec.js +13 -4
  137. package/lib/test/unit/event-log-session-data.spec.js +11 -4
  138. package/lib/test/unit/failure-analysis.spec.js +22 -8
  139. package/lib/test/unit/failure-categories.spec.js +24 -22
  140. package/lib/test/unit/failure-categorization.spec.js +393 -0
  141. package/lib/test/unit/healing-tier-gate.spec.js +3 -2
  142. package/lib/test/unit/hub-node-gateway-appium-server.spec.js +72 -1
  143. package/lib/test/unit/ios-driver-log.spec.js +168 -0
  144. package/lib/test/unit/ios-simulator-session-readiness.spec.js +187 -0
  145. package/lib/test/unit/ios-simulator-session-teardown.spec.js +158 -0
  146. package/lib/test/unit/logcat-ws.spec.js +78 -37
  147. package/lib/test/unit/logger-json-levels.spec.js +44 -0
  148. package/lib/test/unit/mcp-token-ttl.spec.js +38 -0
  149. package/lib/test/unit/observability-example-loki.spec.js +25 -0
  150. package/lib/test/unit/openapi-for-site.spec.js +80 -0
  151. package/lib/test/unit/outbound-proxy.spec.js +320 -0
  152. package/lib/test/unit/port-exhaustion.spec.js +2 -1
  153. package/lib/test/unit/proxy-option.spec.js +358 -0
  154. package/lib/test/unit/run-migrations-database.spec.js +807 -0
  155. package/lib/test/unit/run-migrations-fail-fast.test.js +41 -27
  156. package/lib/test/unit/run-migrations.test.js +864 -0
  157. package/lib/test/unit/selector-health-actions.spec.js +3 -1
  158. package/lib/test/unit/selector-state-service.spec.js +72 -23
  159. package/lib/test/unit/selector-verification-clean-build.spec.js +1 -1
  160. package/lib/test/unit/selector-verification-job.spec.js +15 -6
  161. package/lib/test/unit/selector-verification-missed-regression.spec.js +2 -2
  162. package/lib/test/unit/selector-visibility-resolver.spec.js +209 -0
  163. package/lib/test/unit/session-device-logs-ios.spec.js +180 -0
  164. package/lib/test/unit/session-device-logs.spec.js +11 -2
  165. package/lib/test/unit/session-end-failure-analysis.spec.js +5 -5
  166. package/lib/test/unit/session-log-indexes.spec.js +1 -1
  167. package/lib/test/unit/socket-team-scope.integration.spec.js +749 -0
  168. package/lib/test/unit/socketServer.scopedEmit.spec.js +237 -5
  169. package/lib/test/unit/tracing-export-routing.spec.js +137 -0
  170. package/lib/test/unit/tracing-session-spans.spec.js +337 -0
  171. package/lib/test/unit/unexpected-shutdown-reason.spec.js +2 -2
  172. package/lib/tsconfig.tsbuildinfo +1 -1
  173. package/package.json +2 -1
  174. package/schema.json +11 -7
  175. package/scripts/dev/readme-screenshots.js +276 -23
  176. package/scripts/dev/screenshot-fixtures/logcat.js +157 -0
  177. package/scripts/dev/screenshot-fixtures/phone-screen.html +469 -0
  178. package/scripts/dev/screenshot-fixtures/session.js +242 -0
  179. package/scripts/export-openapi.js +32 -0
  180. package/scripts/lib/openapi-for-site.js +79 -0
  181. package/lib/public/assets/index-BOxe43p1.js +0 -219
  182. package/lib/public/assets/session-detail-page-AZJE6XXE.js +0 -4
  183. package/lib/src/scripts/prepare-prisma.js +0 -89
@@ -8,8 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const chai_1 = require("chai");
16
+ const os_1 = __importDefault(require("os"));
17
+ const path_1 = __importDefault(require("path"));
13
18
  const run_migrations_1 = require("../../src/scripts/run-migrations");
14
19
  const config_1 = require("../../src/config");
15
20
  /**
@@ -22,51 +27,60 @@ const config_1 = require("../../src/config");
22
27
  * runMigrations must fail fast, and say what actually happened.
23
28
  */
24
29
  describe('runMigrations failure handling', () => {
30
+ // runMigrations reads the database before it chooses a command. A file that
31
+ // isn't there has no history and is never opened, so nothing here reaches
32
+ // the server's own database.
33
+ const scratchFile = path_1.default.join(os_1.default.tmpdir(), `xenon-fail-fast-${process.pid}-absent.db`);
25
34
  let originalAutoMigrate;
26
- let originalProvider;
35
+ let originalUrl;
27
36
  beforeEach(() => {
28
37
  originalAutoMigrate = config_1.config.autoMigrate;
29
- originalProvider = config_1.config.databaseProvider;
38
+ originalUrl = config_1.config.databaseUrl;
30
39
  config_1.config.autoMigrate = true;
31
- config_1.config.databaseProvider = 'sqlite';
40
+ config_1.config.databaseUrl = `file:${scratchFile}`;
32
41
  });
33
42
  afterEach(() => {
34
43
  config_1.config.autoMigrate = originalAutoMigrate;
35
- config_1.config.databaseProvider = originalProvider;
44
+ config_1.config.databaseUrl = originalUrl;
36
45
  });
46
+ function failureOf(stderr) {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const failingRunner = () => {
49
+ throw Object.assign(new Error('Command failed'), { stderr: Buffer.from(stderr) });
50
+ };
51
+ try {
52
+ yield (0, run_migrations_1.runMigrations)(failingRunner);
53
+ }
54
+ catch (e) {
55
+ return e;
56
+ }
57
+ throw new Error('runMigrations must not swallow the failure');
58
+ });
59
+ }
37
60
  it('throws instead of swallowing when the schema sync fails', () => __awaiter(void 0, void 0, void 0, function* () {
38
- const prismaErr = new Error('Command failed');
39
- prismaErr.stderr = Buffer.from('We found changes that cannot be executed:\n' +
61
+ const thrown = yield failureOf('We found changes that cannot be executed:\n' +
40
62
  ' - Added the required column `userId` to the `ApiKey` table without a default value.');
41
- const failingRunner = () => {
42
- throw prismaErr;
43
- };
44
- let thrown;
45
- try {
46
- yield (0, run_migrations_1.runMigrations)(failingRunner);
47
- }
48
- catch (e) {
49
- thrown = e;
50
- }
51
- (0, chai_1.expect)(thrown, 'runMigrations must not swallow the failure').to.be.an('Error');
63
+ (0, chai_1.expect)(thrown).to.be.an('Error');
52
64
  // The message has to carry the real cause, not just "sync failed".
53
65
  (0, chai_1.expect)(thrown.message).to.match(/userId/);
54
66
  (0, chai_1.expect)(thrown.message).to.match(/ApiKey/);
67
+ (0, chai_1.expect)(thrown.message).to.match(/adds a required column to a table that already has rows/);
55
68
  }));
56
69
  it('names the database so the operator knows what to back up', () => __awaiter(void 0, void 0, void 0, function* () {
57
- const failingRunner = () => {
58
- throw Object.assign(new Error('Command failed'), { stderr: Buffer.from('boom') });
59
- };
60
- let thrown;
61
- try {
62
- yield (0, run_migrations_1.runMigrations)(failingRunner);
63
- }
64
- catch (e) {
65
- thrown = e;
66
- }
70
+ const thrown = yield failureOf('boom');
67
71
  (0, chai_1.expect)(thrown).to.be.an('Error');
72
+ (0, chai_1.expect)(thrown.message).to.include(scratchFile);
68
73
  (0, chai_1.expect)(thrown.message).to.match(/XENON_AUTO_MIGRATE/);
69
74
  }));
75
+ // Through 2.15.0 every failure was put down to a required column, P3005
76
+ // ("The database schema is not empty") included.
77
+ it("doesn't blame a required column when that isn't the cause", () => __awaiter(void 0, void 0, void 0, function* () {
78
+ const thrown = yield failureOf('Error: P3005\n\nThe database schema is not empty. Read more about how to baseline an ' +
79
+ 'existing production database: https://pris.ly/d/migrate-baseline');
80
+ (0, chai_1.expect)(thrown.message).to.not.match(/required column/i);
81
+ (0, chai_1.expect)(thrown.message).to.match(/P3005/);
82
+ (0, chai_1.expect)(thrown.message).to.match(/could not bring the database at .* up to date/);
83
+ }));
70
84
  it('resolves normally when the schema sync succeeds', () => __awaiter(void 0, void 0, void 0, function* () {
71
85
  let called = false;
72
86
  yield (0, run_migrations_1.runMigrations)(() => {