@xenon-device-management/xenon 1.7.0 → 1.7.2

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 (93) hide show
  1. package/lib/package.json +1 -1
  2. package/lib/public/assets/{ApiKeyGate-BSN8crwz.js → ApiKeyGate-BousCIQZ.js} +1 -1
  3. package/lib/public/assets/{BugReportButton-DNja1wQ1.js → BugReportButton-Gw4lnGnV.js} +1 -1
  4. package/lib/public/assets/{DeviceMosaicView-DVk1IpIR.js → DeviceMosaicView-BX2hfhBf.js} +2 -2
  5. package/lib/public/assets/{EmptyState-CqQ21n-H.js → EmptyState-CPOfuV3O.js} +1 -1
  6. package/lib/public/assets/{FieldGroup-DE3u01Nu.js → FieldGroup-C5UkCHbe.js} +1 -1
  7. package/lib/public/assets/{Modal-BJcFdiBP.js → Modal-MMGhL8eW.js} +1 -1
  8. package/lib/public/assets/{SegmentedControl-CSHjmrvy.js → SegmentedControl-CZfAicws.js} +1 -1
  9. package/lib/public/assets/{SettingCard-M-lFn_Wm.js → SettingCard-Dp7XIdcl.js} +1 -1
  10. package/lib/public/assets/{Table-B3EUgBi6.js → Table-DsN_IX6J.js} +1 -1
  11. package/lib/public/assets/{activity-DK3R5GAb.js → activity-DCBAvxuo.js} +1 -1
  12. package/lib/public/assets/ai-settings-yNS_bU1m.js +21 -0
  13. package/lib/public/assets/api-keys-CQ9g1g1b.js +1 -0
  14. package/lib/public/assets/apps-Bqh1eav9.js +21 -0
  15. package/lib/public/assets/apps-CTrGClro.css +1 -0
  16. package/lib/public/assets/{arrow-left-9933DNlF.js → arrow-left-GX0vzYtn.js} +1 -1
  17. package/lib/public/assets/{arrow-up-right-B7q_1mXs.js → arrow-up-right-DePHHOby.js} +1 -1
  18. package/lib/public/assets/auth-shell-BBGlC6i3.js +1 -0
  19. package/lib/public/assets/builds-page-Czf7RsmD.js +6 -0
  20. package/lib/public/assets/{button-lkxVyarW.js → button-ybNY3GYx.js} +1 -1
  21. package/lib/public/assets/{check-BkT38An9.js → check-BZMx8AhR.js} +1 -1
  22. package/lib/public/assets/{chevron-right-WELZ1Z8v.js → chevron-right-WL_bcB02.js} +1 -1
  23. package/lib/public/assets/{circle-check--2DSsfaI.js → circle-check-CI2xUlDo.js} +1 -1
  24. package/lib/public/assets/{circle-x-x7R8vTBo.js → circle-x-De3thbcr.js} +1 -1
  25. package/lib/public/assets/{clock-DIpGd4Pn.js → clock-BFVLE7wW.js} +1 -1
  26. package/lib/public/assets/{copy-CEcFYYHm.js → copy-ve3lNhva.js} +1 -1
  27. package/lib/public/assets/device-explorer-elRO7T00.css +1 -0
  28. package/lib/public/assets/device-explorer-vzZxT4-Y.js +210 -0
  29. package/lib/public/assets/{download-CaKkGvKw.js → download-BDZj44ke.js} +1 -1
  30. package/lib/public/assets/forgot-password-BSYQX2oR.js +1 -0
  31. package/lib/public/assets/{funnel-D2rLIKlM.js → funnel-CptlpFZ9.js} +1 -1
  32. package/lib/public/assets/index-BW3kENYH.css +1 -0
  33. package/lib/public/assets/{index-BrVV0Kla.js → index-PtnKslHU.js} +12 -12
  34. package/lib/public/assets/{layers-DZwF8z_0.js → layers-DRpwoKhI.js} +1 -1
  35. package/lib/public/assets/{lock-CVUUnm1V.js → lock-CrQhC34I.js} +1 -1
  36. package/lib/public/assets/login-DaJOt8Qz.js +1 -0
  37. package/lib/public/assets/maintenance-settings-D629C2IC.js +6 -0
  38. package/lib/public/assets/{mouse-pointer-2-n4xUMxHJ.js → mouse-pointer-2-Dpcc76zN.js} +1 -1
  39. package/lib/public/assets/overview-CGEKYX62.js +11 -0
  40. package/lib/public/assets/{page-header-C0pnt4xz.js → page-header-CSvuGbSO.js} +1 -1
  41. package/lib/public/assets/{plus-BObE-_z6.js → plus-vJJF9g79.js} +1 -1
  42. package/lib/public/assets/profile-page-CF7ZQNQz.js +6 -0
  43. package/lib/public/assets/reset-password-BgpjbCac.js +1 -0
  44. package/lib/public/assets/runbook-page-Dxuzftyv.js +124 -0
  45. package/lib/public/assets/selector-detail-page-B_puCd9g.js +1 -0
  46. package/lib/public/assets/{selector-health-DraY2a4b.js → selector-health-BjMHf106.js} +1 -1
  47. package/lib/public/assets/selector-health-page-Du_bGD2p.js +16 -0
  48. package/lib/public/assets/session-detail-page-lQTe5_B1.js +13 -0
  49. package/lib/public/assets/settings-Cxx_aYWT.css +1 -0
  50. package/lib/public/assets/settings-DhxWGUzy.js +1 -0
  51. package/lib/public/assets/{shield-BBc4qisQ.js → shield-JGzamJo5.js} +1 -1
  52. package/lib/public/assets/{shield-alert-BfoPJ8q_.js → shield-alert-DzE36jcb.js} +1 -1
  53. package/lib/public/assets/status-pill-outline-50aN0wRU.js +1 -0
  54. package/lib/public/assets/{tablet-CaOqzQv_.js → tablet-DHY88mxw.js} +1 -1
  55. package/lib/public/assets/teams-EOAIPbZC.js +1 -0
  56. package/lib/public/assets/time-B8FIgwPE.js +1 -0
  57. package/lib/public/assets/{trash-2-CE5TRHb2.js → trash-2-BrTSfFh5.js} +1 -1
  58. package/lib/public/assets/{useSocket-Bkt5i-U6.js → useSocket-BRto9a5m.js} +1 -1
  59. package/lib/public/assets/users-Dd44jLAB.js +11 -0
  60. package/lib/public/assets/webhook-settings-DBYmqim_.js +1 -0
  61. package/lib/public/assets/{webhook-settings-DEZQtSgr.css → webhook-settings-tW1oXXrJ.css} +1 -1
  62. package/lib/public/assets/{zap-BzdRuL9F.js → zap-JUbOoK3o.js} +1 -1
  63. package/lib/public/index.html +2 -2
  64. package/lib/src/app/routers/auth.js +19 -2
  65. package/lib/src/scripts/run-migrations.js +14 -3
  66. package/lib/test/unit/auth-me-auth-disabled.test.js +77 -0
  67. package/lib/test/unit/run-migrations-fail-fast.test.js +87 -0
  68. package/lib/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +1 -1
  70. package/lib/public/assets/ai-settings-AKMDh8pd.js +0 -21
  71. package/lib/public/assets/api-keys-B5Q1EkGN.js +0 -1
  72. package/lib/public/assets/apps-CWWrkTZW.js +0 -21
  73. package/lib/public/assets/apps-Dt5dUIag.css +0 -1
  74. package/lib/public/assets/builds-page-DgWXOgh5.js +0 -6
  75. package/lib/public/assets/device-explorer-3H1hf8ld.css +0 -1
  76. package/lib/public/assets/device-explorer-nV6L3w7x.js +0 -210
  77. package/lib/public/assets/forgot-password-CsAF11d2.js +0 -1
  78. package/lib/public/assets/index-Dz1K6OJU.css +0 -1
  79. package/lib/public/assets/login-BavGkTli.js +0 -1
  80. package/lib/public/assets/maintenance-settings-Vr_u8hoR.js +0 -6
  81. package/lib/public/assets/overview-DVgoOoYF.js +0 -11
  82. package/lib/public/assets/profile-page-DNKD4MS2.js +0 -1
  83. package/lib/public/assets/reset-password-C2gSMy8a.js +0 -1
  84. package/lib/public/assets/runbook-page-BRxjWJVQ.js +0 -104
  85. package/lib/public/assets/selector-detail-page-DcV8jQuX.js +0 -1
  86. package/lib/public/assets/selector-health-page-tb5e3CXy.js +0 -16
  87. package/lib/public/assets/session-detail-page-CEtQr37W.js +0 -13
  88. package/lib/public/assets/settings-CpRbubta.css +0 -1
  89. package/lib/public/assets/settings-Cr-YjLbX.js +0 -1
  90. package/lib/public/assets/status-pill-outline-Cc4PF7Mg.js +0 -1
  91. package/lib/public/assets/teams-B3Tt_9i2.js +0 -1
  92. package/lib/public/assets/users-BIvjvjM6.js +0 -11
  93. package/lib/public/assets/webhook-settings-dAp8wwEB.js +0 -1
@@ -1 +1 @@
1
- .webhook-list-grid{display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-5)}.webhook-row-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:16px 20px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:12px;transition:border-color .15s}.webhook-row-card:hover{border-color:#22c55e4d}.webhook-row-card__header{display:flex;align-items:center;gap:12px}.webhook-row-card__url{flex:1;min-width:0;font-family:JetBrains Mono,monospace;font-size:12.5px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.webhook-row-card__events{display:flex;flex-wrap:wrap;gap:6px}.webhook-row-card__no-events{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim)}.event-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:999px;font-family:JetBrains Mono,monospace;font-size:10.5px;font-weight:600;letter-spacing:.04em;border:1px solid transparent;line-height:1.4;text-transform:none}.event-pill--red{background:#ef44441a;color:var(--status-error-fg);border-color:#ef44444d}.event-pill--green{background:#22c55e1a;color:var(--green);border-color:#22c55e4d}.event-pill--amber{background:#f59e0b1f;color:var(--amber);border-color:#f59e0b59}.event-pill--gray{background:#ffffff0a;color:var(--text-muted);border-color:var(--border-strong)}.add-webhook-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);overflow:hidden;margin-top:var(--space-4)}.add-webhook-card__header{display:flex;align-items:center;gap:8px;padding:14px 20px;color:var(--green);font-family:JetBrains Mono,monospace;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.12em;border-bottom:1px solid var(--border);background:#22c55e0a}.add-webhook-card__body{padding:24px;display:flex;flex-direction:column;gap:4px}.add-webhook-card__footer{display:flex;justify-content:flex-end;gap:10px;padding:16px 24px;border-top:1px solid var(--border);background:#00000026}.event-toggle-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}.event-toggle{display:inline-flex;align-items:center;gap:10px;padding:10px 14px;border-radius:var(--radius-md);background:#ffffff06;border:1px solid var(--border-strong);color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s;text-align:left}.event-toggle:hover:not(.is-selected){border-color:#fff3;color:var(--text)}.event-toggle.is-selected{color:var(--text);background:#22c55e0f;border-color:var(--green);box-shadow:inset 0 0 0 1px #22c55e59}.event-toggle__lead{flex-shrink:0}.event-toggle--red.is-selected .event-toggle__lead{color:var(--status-error-fg)}.event-toggle--green.is-selected .event-toggle__lead{color:var(--green)}.event-toggle--amber.is-selected .event-toggle__lead{color:var(--amber)}.event-toggle__check{color:var(--green);margin-left:auto}.template-section{margin-top:var(--space-3);border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;background:#00000026}.template-section__toggle{width:100%;display:flex;align-items:center;gap:10px;padding:12px 16px;background:transparent;border:0;color:var(--text);font-family:Inter,sans-serif;font-size:13px;font-weight:600;cursor:pointer;text-align:left;transition:background .15s}.template-section__toggle:hover{background:#ffffff08}.template-section__toggle .tone-amber{color:var(--amber)}.template-section__toggle .tone-dim{color:var(--text-dim)}.template-section__indicator{margin-left:auto;font-size:18px;color:var(--text-dim);line-height:1}.template-editor{padding:16px;border-top:1px solid var(--border);background:#0000001a;display:flex;flex-direction:column;gap:12px}.template-editor__hint{margin:0;color:var(--text-muted);font-size:12px;line-height:1.5}.template-editor__chips{display:flex;flex-wrap:wrap;gap:6px}.template-editor__chip{padding:4px 10px;border-radius:999px;background:#22c55e0f;border:1px solid rgba(34,197,94,.25);color:var(--green);font-family:JetBrains Mono,monospace;font-size:10.5px;cursor:pointer;transition:filter .15s,transform .15s}.template-editor__chip:hover{filter:brightness(1.15);transform:translateY(-1px)}.template-editor__textarea{width:100%;background:#0000004d;border:1px solid var(--border);border-radius:var(--radius-md);color:var(--text);padding:12px 14px;font-family:JetBrains Mono,monospace;font-size:12px;line-height:1.55;resize:vertical;min-height:80px;box-sizing:border-box;transition:border-color .15s}.template-editor__textarea:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 1px var(--green)}
1
+ .webhook-list-grid{display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-5)}.webhook-row-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:16px 20px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:12px;transition:border-color .15s}.webhook-row-card:hover{border-color:#22c55e4d}.webhook-row-card__header{display:flex;align-items:center;gap:12px}.webhook-row-card__url{flex:1;min-width:0;font-family:JetBrains Mono,monospace;font-size:12.5px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.webhook-row-card__events{display:flex;flex-wrap:wrap;gap:6px}.webhook-row-card__no-events{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim)}.event-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:999px;font-family:JetBrains Mono,monospace;font-size:10.5px;font-weight:600;letter-spacing:.04em;border:1px solid transparent;line-height:1.4;text-transform:none}.event-pill--red{background:#ef44441a;color:var(--status-error-fg);border-color:#ef44444d}.event-pill--green{background:#22c55e1a;color:var(--green);border-color:#22c55e4d}.event-pill--amber{background:#f59e0b1f;color:var(--amber);border-color:#f59e0b59}.event-pill--gray{background:#ffffff0a;color:var(--text-muted);border-color:var(--border-strong)}.add-webhook-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);overflow:hidden;margin-top:var(--space-4)}.add-webhook-card__header{display:flex;align-items:center;gap:8px;padding:14px 20px;color:var(--green);font-family:JetBrains Mono,monospace;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.12em;border-bottom:1px solid var(--border);background:#22c55e0a}.add-webhook-card__body{padding:24px;display:flex;flex-direction:column;gap:4px}.add-webhook-card__footer{display:flex;justify-content:flex-end;gap:10px;padding:16px 24px;border-top:1px solid var(--border);background:#00000026}.event-toggle-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}.event-toggle{display:inline-flex;align-items:center;gap:10px;padding:10px 14px;border-radius:var(--radius-md);background:#ffffff06;border:1px solid var(--border-strong);color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s;text-align:left}.event-toggle:hover:not(.is-selected){border-color:#fff3;color:var(--text)}.event-toggle.is-selected{color:var(--text);background:#22c55e0f;border-color:var(--green);box-shadow:inset 0 0 0 1px #22c55e59}.event-toggle__lead{flex-shrink:0;color:var(--text-dim)}.event-toggle.is-selected .event-toggle__lead{color:inherit}.event-toggle__check{color:var(--green);margin-left:auto}.event-toggle--red.is-selected{background:#ef44440f;border-color:var(--red);box-shadow:inset 0 0 0 1px #ef444459}.event-toggle--red.is-selected .event-toggle__check,.event-toggle--red.is-selected .event-toggle__lead{color:var(--red)}.event-toggle--amber.is-selected{background:#f59e0b0f;border-color:var(--amber);box-shadow:inset 0 0 0 1px #f59e0b59}.event-toggle--amber.is-selected .event-toggle__check,.event-toggle--amber.is-selected .event-toggle__lead{color:var(--amber)}.event-toggle--green.is-selected{background:#22c55e0f;border-color:var(--green);box-shadow:inset 0 0 0 1px #22c55e59}.event-toggle--green.is-selected .event-toggle__check,.event-toggle--green.is-selected .event-toggle__lead{color:var(--green)}.template-section{margin-top:var(--space-3);border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;background:#00000026}.template-section__toggle{width:100%;display:flex;align-items:center;gap:10px;padding:12px 16px;background:transparent;border:0;color:var(--text);font-family:Inter,sans-serif;font-size:13px;font-weight:600;cursor:pointer;text-align:left;transition:background .15s}.template-section__toggle:hover{background:#ffffff08}.template-section__toggle .tone-amber{color:var(--amber)}.template-section__toggle .tone-dim{color:var(--text-dim)}.template-section__indicator{margin-left:auto;font-size:18px;color:var(--text-dim);line-height:1}.template-editor{padding:16px;border-top:1px solid var(--border);background:#0000001a;display:flex;flex-direction:column;gap:12px}.template-editor__hint{margin:0;color:var(--text-muted);font-size:12px;line-height:1.5}.template-editor__chips{display:flex;flex-wrap:wrap;gap:6px}.template-editor__chip{padding:4px 10px;border-radius:999px;background:#22c55e0f;border:1px solid rgba(34,197,94,.25);color:var(--green);font-family:JetBrains Mono,monospace;font-size:10.5px;cursor:pointer;transition:filter .15s,transform .15s}.template-editor__chip:hover{filter:brightness(1.15);transform:translateY(-1px)}.template-editor__textarea{width:100%;background:#0000004d;border:1px solid var(--border);border-radius:var(--radius-md);color:var(--text);padding:12px 14px;font-family:JetBrains Mono,monospace;font-size:12px;line-height:1.55;resize:vertical;min-height:80px;box-sizing:border-box;transition:border-color .15s}.template-editor__textarea:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 1px var(--green)}
@@ -1,4 +1,4 @@
1
- import{g as a}from"./index-BrVV0Kla.js";/**
1
+ import{g as a}from"./index-PtnKslHU.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -24,8 +24,8 @@
24
24
  Learn how to configure a non-root public URL by running `npm run build`.
25
25
  -->
26
26
  <title>Xenon</title>
27
- <script type="module" crossorigin src="/xenon/assets/index-BrVV0Kla.js"></script>
28
- <link rel="stylesheet" crossorigin href="/xenon/assets/index-Dz1K6OJU.css">
27
+ <script type="module" crossorigin src="/xenon/assets/index-PtnKslHU.js"></script>
28
+ <link rel="stylesheet" crossorigin href="/xenon/assets/index-BW3kENYH.css">
29
29
  </head>
30
30
 
31
31
  <body>
@@ -165,10 +165,27 @@ function authAuthedRouter() {
165
165
  return res.status(204).end();
166
166
  }));
167
167
  r.get('/me', (req, res) => __awaiter(this, void 0, void 0, function* () {
168
- var _a;
168
+ var _a, _b, _c;
169
169
  const auth = req.auth;
170
170
  if (!auth)
171
171
  return res.status(401).json({ error: 'unauthenticated' });
172
+ // authDisabled fabricates a synthetic SUPER_ADMIN (authMiddleware.ts) whose
173
+ // userId has no User row. Resolving it would 401 and strand the dashboard on
174
+ // /login — on a server that has auth switched off. Answer from the synthetic
175
+ // identity instead of the database.
176
+ if (config_1.config.authDisabled === true) {
177
+ return res.json({
178
+ userId: auth.userId,
179
+ email: 'auth-disabled@xenon.local',
180
+ name: 'Auth Disabled',
181
+ role: (_a = auth.role) !== null && _a !== void 0 ? _a : 'SUPER_ADMIN',
182
+ accessKey: null,
183
+ scopes: auth.scopes,
184
+ teamId: (_b = auth.teamId) !== null && _b !== void 0 ? _b : null,
185
+ kind: auth.kind,
186
+ teams: [],
187
+ });
188
+ }
172
189
  const user = yield userSvc.findById(auth.userId);
173
190
  if (!user)
174
191
  return res.status(401).json({ error: 'unauthenticated' });
@@ -191,7 +208,7 @@ function authAuthedRouter() {
191
208
  role: user.role,
192
209
  accessKey: user.accessKey,
193
210
  scopes: auth.scopes,
194
- teamId: (_a = auth.teamId) !== null && _a !== void 0 ? _a : null,
211
+ teamId: (_c = auth.teamId) !== null && _c !== void 0 ? _c : null,
195
212
  kind: auth.kind,
196
213
  teams,
197
214
  });
@@ -82,7 +82,7 @@ function resolvePrismaInvocation(rootDir) {
82
82
  return { cmd: 'npx', prefix: ['prisma'] };
83
83
  }
84
84
  function runMigrations() {
85
- return __awaiter(this, void 0, void 0, function* () {
85
+ return __awaiter(this, arguments, void 0, function* (runSync = node_child_process_1.execFileSync) {
86
86
  var _a;
87
87
  if (!config_1.config.autoMigrate) {
88
88
  logger_1.default.info('[DBMigrate] Auto-migrate disabled by XENON_AUTO_MIGRATE=false. ' +
@@ -107,12 +107,23 @@ function runMigrations() {
107
107
  : [...prefix, 'migrate', 'deploy', '--schema', schemaPath];
108
108
  try {
109
109
  logger_1.default.info(`[DBMigrate] Syncing database schema (${config_1.config.databaseProvider}, ${isSqlite ? 'db push' : 'migrate deploy'})...`);
110
- (0, node_child_process_1.execFileSync)(cmd, args, { env, cwd: rootDir, stdio: 'pipe' });
110
+ runSync(cmd, args, { env, cwd: rootDir, stdio: 'pipe' });
111
111
  logger_1.default.info('[DBMigrate] Database schema in sync.');
112
112
  }
113
113
  catch (err) {
114
- const msg = ((_a = err === null || err === void 0 ? void 0 : err.stderr) === null || _a === void 0 ? void 0 : _a.toString()) || (err === null || err === void 0 ? void 0 : err.message) || String(err);
114
+ const msg = (((_a = err === null || err === void 0 ? void 0 : err.stderr) === null || _a === void 0 ? void 0 : _a.toString()) || (err === null || err === void 0 ? void 0 : err.message) || String(err)).trim();
115
115
  logger_1.default.error(`[DBMigrate] Auto-sync failed: ${msg}`);
116
+ // Boot must not continue. The schema is not what the code expects, so the
117
+ // next query fails somewhere unrelated — `prisma.user.count()` reporting a
118
+ // missing User table, say — and buries this, the actual cause. Stop here
119
+ // and hand back something the operator can act on.
120
+ throw new Error(`[DBMigrate] Cannot start: database schema sync failed for ${config_1.config.databaseProvider}.\n` +
121
+ `${msg}\n\n` +
122
+ `Database: ${config_1.config.databaseUrl}\n` +
123
+ `A required column cannot be added to a table that already has rows. ` +
124
+ `Back up the database above, then either migrate it by hand or start ` +
125
+ `from a fresh one. To boot without touching the schema (the schema must ` +
126
+ `already match), set XENON_AUTO_MIGRATE=false.`);
116
127
  }
117
128
  });
118
129
  }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ require("reflect-metadata");
16
+ const chai_1 = require("chai");
17
+ const sinon_1 = __importDefault(require("sinon"));
18
+ const express_1 = __importDefault(require("express"));
19
+ const supertest_1 = __importDefault(require("supertest"));
20
+ const typedi_1 = require("typedi");
21
+ const auth_1 = require("../../src/app/routers/auth");
22
+ const UserService_1 = require("../../src/services/UserService");
23
+ const config_1 = require("../../src/config");
24
+ /**
25
+ * When XENON_AUTH_DISABLED=true, authMiddleware fabricates a synthetic
26
+ * SUPER_ADMIN whose userId ('auth-disabled') has no row in the User table.
27
+ * GET /auth/me must not try to resolve that id against the database — if it
28
+ * does, it 401s, the dashboard's RouteGuard bounces to /login, and the
29
+ * dashboard is unreachable on a server that has auth turned off.
30
+ */
31
+ function appWithSyntheticAuth() {
32
+ const app = (0, express_1.default)();
33
+ // Stand in for authMiddleware's authDisabled branch (authMiddleware.ts:63-74).
34
+ app.use((req, _res, next) => {
35
+ req.auth = {
36
+ kind: 'api-key',
37
+ userId: 'auth-disabled',
38
+ role: 'SUPER_ADMIN',
39
+ scopes: 'admin',
40
+ rateLimit: 100000,
41
+ teamIds: undefined,
42
+ };
43
+ next();
44
+ });
45
+ app.use('/auth', (0, auth_1.authAuthedRouter)());
46
+ return app;
47
+ }
48
+ describe('GET /auth/me with authDisabled', () => {
49
+ let original;
50
+ beforeEach(() => {
51
+ original = config_1.config.authDisabled;
52
+ });
53
+ afterEach(() => {
54
+ config_1.config.authDisabled = original;
55
+ sinon_1.default.restore();
56
+ });
57
+ it('returns the synthetic admin identity without a User row', () => __awaiter(void 0, void 0, void 0, function* () {
58
+ config_1.config.authDisabled = true;
59
+ // No User row exists for the synthetic id — this is the real-world state.
60
+ const findById = sinon_1.default.stub(typedi_1.Container.get(UserService_1.UserService), 'findById').resolves(null);
61
+ const res = yield (0, supertest_1.default)(appWithSyntheticAuth()).get('/auth/me');
62
+ (0, chai_1.expect)(res.status).to.equal(200);
63
+ (0, chai_1.expect)(res.body.userId).to.equal('auth-disabled');
64
+ (0, chai_1.expect)(res.body.role).to.equal('SUPER_ADMIN');
65
+ (0, chai_1.expect)(res.body.scopes).to.equal('admin');
66
+ (0, chai_1.expect)(res.body.teams).to.deep.equal([]);
67
+ // The synthetic id must never be looked up — there is nothing to find.
68
+ (0, chai_1.expect)(findById.called, 'findById should not be called when auth is disabled').to.be.false;
69
+ }));
70
+ it('still 401s when auth is enabled and the user does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
71
+ config_1.config.authDisabled = false;
72
+ sinon_1.default.stub(typedi_1.Container.get(UserService_1.UserService), 'findById').resolves(null);
73
+ const res = yield (0, supertest_1.default)(appWithSyntheticAuth()).get('/auth/me');
74
+ (0, chai_1.expect)(res.status).to.equal(401);
75
+ (0, chai_1.expect)(res.body.error).to.equal('unauthenticated');
76
+ }));
77
+ });
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const chai_1 = require("chai");
13
+ const run_migrations_1 = require("../../src/scripts/run-migrations");
14
+ const config_1 = require("../../src/config");
15
+ /**
16
+ * A failed schema sync used to be logged and swallowed, so boot carried on into
17
+ * an unrelated crash — `prisma.user.count()` reporting "table main.User does not
18
+ * exist", which names the wrong table and hides the real cause. Upgrading a
19
+ * populated SQLite DB hits exactly this: `db push` cannot add a required column
20
+ * to a table that has rows, so the operator ends up debugging the wrong thing.
21
+ *
22
+ * runMigrations must fail fast, and say what actually happened.
23
+ */
24
+ describe('runMigrations failure handling', () => {
25
+ let originalAutoMigrate;
26
+ let originalProvider;
27
+ beforeEach(() => {
28
+ originalAutoMigrate = config_1.config.autoMigrate;
29
+ originalProvider = config_1.config.databaseProvider;
30
+ config_1.config.autoMigrate = true;
31
+ config_1.config.databaseProvider = 'sqlite';
32
+ });
33
+ afterEach(() => {
34
+ config_1.config.autoMigrate = originalAutoMigrate;
35
+ config_1.config.databaseProvider = originalProvider;
36
+ });
37
+ 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' +
40
+ ' - 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');
52
+ // The message has to carry the real cause, not just "sync failed".
53
+ (0, chai_1.expect)(thrown.message).to.match(/userId/);
54
+ (0, chai_1.expect)(thrown.message).to.match(/ApiKey/);
55
+ }));
56
+ 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
+ }
67
+ (0, chai_1.expect)(thrown).to.be.an('Error');
68
+ (0, chai_1.expect)(thrown.message).to.match(/XENON_AUTO_MIGRATE/);
69
+ }));
70
+ it('resolves normally when the schema sync succeeds', () => __awaiter(void 0, void 0, void 0, function* () {
71
+ let called = false;
72
+ yield (0, run_migrations_1.runMigrations)(() => {
73
+ called = true;
74
+ return Buffer.from('ok');
75
+ });
76
+ (0, chai_1.expect)(called).to.be.true;
77
+ }));
78
+ it('does not invoke the runner when autoMigrate is off', () => __awaiter(void 0, void 0, void 0, function* () {
79
+ config_1.config.autoMigrate = false;
80
+ let called = false;
81
+ yield (0, run_migrations_1.runMigrations)(() => {
82
+ called = true;
83
+ return Buffer.from('ok');
84
+ });
85
+ (0, chai_1.expect)(called).to.be.false;
86
+ }));
87
+ });
@@ -1 +1 @@
1
- {"root":["../src/InternalHttpClient.ts","../src/PluginContext.ts","../src/XenonCapabilityManager.ts","../src/chromeUtils.ts","../src/config.ts","../src/device-utils.ts","../src/index.ts","../src/logger.ts","../src/plugin.ts","../src/prisma.ts","../src/app/index.ts","../src/app/swagger-docs.ts","../src/app/swagger.ts","../src/app/routers/apikeys.ts","../src/app/routers/apps.ts","../src/app/routers/auth.ts","../src/app/routers/bug-report.ts","../src/app/routers/build-export.ts","../src/app/routers/config.ts","../src/app/routers/control.ts","../src/app/routers/dashboard.ts","../src/app/routers/grid.ts","../src/app/routers/interceptor.ts","../src/app/routers/ports.ts","../src/app/routers/processes.ts","../src/app/routers/profile.ts","../src/app/routers/recordings.ts","../src/app/routers/reservation.ts","../src/app/routers/sdk-leases.ts","../src/app/routers/sdk-version.ts","../src/app/routers/teams.ts","../src/app/routers/users.ts","../src/app/routers/webhook.ts","../src/commands/handle.ts","../src/commands/index.ts","../src/dashboard/asset-manager.ts","../src/dashboard/commands.ts","../src/dashboard/event-manager.ts","../src/dashboard/services/app-service.ts","../src/dashboard/services/failure-analysis-service.ts","../src/dashboard/services/session-service.ts","../src/data-service/CircuitBreaker.ts","../src/data-service/config-service.ts","../src/data-service/db.ts","../src/data-service/device-service.ts","../src/data-service/device-store.interface.ts","../src/data-service/device-store.ts","../src/data-service/pending-sessions-service.ts","../src/data-service/pluginArgs.ts","../src/data-service/prisma-service.ts","../src/data-service/prisma-store.ts","../src/data-service/queue-service.ts","../src/data-service/web-config-service.ts","../src/device-managers/AndroidDeviceManager.ts","../src/device-managers/ChromeDriverManager.ts","../src/device-managers/HealthMonitorService.ts","../src/device-managers/IOSDeviceManager.ts","../src/device-managers/NodeDevices.ts","../src/device-managers/iOSTracker.ts","../src/device-managers/index.ts","../src/device-managers/android/AndroidStreamService.ts","../src/device-managers/android/DeviceLockManager.ts","../src/device-managers/cloud/CapabilityManager.ts","../src/device-managers/cloud/Devices.ts","../src/device-managers/ios/IOSDiscoveryService.ts","../src/device-managers/ios/IOSStreamService.ts","../src/device-managers/ios/WDAClient.ts","../src/enums/Capabilities.ts","../src/enums/Cloud.ts","../src/enums/Platform.ts","../src/enums/SessionType.ts","../src/enums/SocketEvents.ts","../src/generated/client/default.d.ts","../src/generated/client/default.js","../src/generated/client/edge.d.ts","../src/generated/client/edge.js","../src/generated/client/index-browser.js","../src/generated/client/index.d.ts","../src/generated/client/index.js","../src/generated/client/wasm.d.ts","../src/generated/client/wasm.js","../src/generated/client/runtime/edge-esm.js","../src/generated/client/runtime/edge.js","../src/generated/client/runtime/index-browser.d.ts","../src/generated/client/runtime/index-browser.js","../src/generated/client/runtime/library.d.ts","../src/generated/client/runtime/library.js","../src/generated/client/runtime/react-native.js","../src/generated/client/runtime/wasm.js","../src/helpers/UniversalMjpegProxy.ts","../src/helpers/index.ts","../src/interceptors/CommandInterceptor.ts","../src/interfaces/ICloudManager.ts","../src/interfaces/IDevice.ts","../src/interfaces/IDeviceFilterOptions.ts","../src/interfaces/IDeviceManager.ts","../src/interfaces/IOptions.ts","../src/interfaces/IPluginArgs.ts","../src/interfaces/ISessionCapability.ts","../src/logging/sessionContext.ts","../src/middleware/authMiddleware.ts","../src/middleware/csrfMiddleware.ts","../src/middleware/leaseTokenMiddleware.ts","../src/middleware/loginRateLimiter.ts","../src/middleware/rateLimitMiddleware.ts","../src/middleware/roleGuard.ts","../src/middleware/scopeGuard.ts","../src/profiling/AndroidAppProfiler.ts","../src/proxy/wd-command-proxy.ts","../src/scripts/generate-database-migration.ts","../src/scripts/initialize-database.ts","../src/scripts/install-go-ios.ts","../src/scripts/prepare-prisma.ts","../src/scripts/run-migrations.ts","../src/services/AICommandService.ts","../src/services/AIService.ts","../src/services/ApiKeyService.ts","../src/services/CircuitBreaker.ts","../src/services/CleanupService.ts","../src/services/DeviceReconciler.ts","../src/services/EmailService.ts","../src/services/EventBus.ts","../src/services/InspectorService.ts","../src/services/InterceptorService.ts","../src/services/MetricsService.ts","../src/services/NetworkConditioningService.ts","../src/services/NotificationService.ts","../src/services/OrphanSweeper.ts","../src/services/PasswordResetService.ts","../src/services/PortAllocator.ts","../src/services/ProcessMetricsService.ts","../src/services/ProcessRegistry.ts","../src/services/RequestLogService.ts","../src/services/ResourceIsolationService.ts","../src/services/SecurityService.ts","../src/services/SelectorStateService.ts","../src/services/SelectorVerificationJob.ts","../src/services/ServerManager.ts","../src/services/SessionHeartbeatService.ts","../src/services/SessionLifecycleService.ts","../src/services/ShutdownCoordinator.ts","../src/services/SocketClient.ts","../src/services/SocketServer.ts","../src/services/TeamService.ts","../src/services/TracingService.ts","../src/services/UserService.ts","../src/services/UserSessionService.ts","../src/services/VideoPipelineService.ts","../src/services/autowait/AutowaitService.ts","../src/services/autowait/waitFor.ts","../src/services/bug-report/BugReportService.ts","../src/services/bug-report/archive.ts","../src/services/bug-report/har-collector.ts","../src/services/bug-report/manifest.ts","../src/services/bug-report/readme.ts","../src/services/bug-report/types.ts","../src/services/bug-report/video-slice.ts","../src/services/bug-report/window.ts","../src/services/healing/FuzzyXmlHealingProvider.ts","../src/services/healing/HealEtalonService.ts","../src/services/healing/HealedLocatorGenerator.ts","../src/services/healing/HealingMetrics.ts","../src/services/healing/HealingOrchestrator.ts","../src/services/healing/LlmHealingProvider.ts","../src/services/healing/OcrHealingProvider.ts","../src/services/healing/ResilioTreeHealingProvider.ts","../src/services/healing/VisualAiHealingProvider.ts","../src/services/healing/types.ts","../src/services/identity/bootstrap.ts","../src/services/identity/sessionCleanupCron.ts","../src/services/identity/userAuthorization.ts","../src/services/interceptor/AndroidProxyAdapter.ts","../src/services/interceptor/CertManager.ts","../src/services/interceptor/HarBuilder.ts","../src/services/interceptor/HostFilter.ts","../src/services/interceptor/MitmProxyHost.ts","../src/services/interceptor/MockEngine.ts","../src/services/interceptor/RequestBuffer.ts","../src/services/interceptor/SessionArchive.ts","../src/services/interceptor/types.ts","../src/services/lease/LeaseOrphanSweeper.ts","../src/services/lease/LeaseService.ts","../src/services/lease/buildCapabilityBag.ts","../src/services/lease/leaseToken.ts","../src/services/omni-vision/OmniVisionService.ts","../src/services/omni-vision/VisionAssertionService.ts","../src/services/ports/PortAllocatorClient.ts","../src/services/ports/PortAllocatorService.ts","../src/services/recording/RecordingOrchestrator.ts","../src/services/recording/annotation-render.ts","../src/services/recording/busy-precheck.ts","../src/services/recording/concurrency-gate.ts","../src/services/recording/manualLock.ts","../src/services/recording/proof-bundle.ts","../src/services/recording/recording-store.ts","../src/services/telemetry/attributes.ts","../src/sessions/CloudSession.ts","../src/sessions/LocalSession.ts","../src/sessions/RemoteSession.ts","../src/sessions/SessionManager.ts","../src/sessions/XenonSession.ts","../src/types/CLIArgs.ts","../src/types/CloudArgs.ts","../src/types/CloudSchema.ts","../src/types/DeviceType.ts","../src/types/DeviceUpdate.ts","../src/types/IOSDevice.ts","../src/types/Platform.ts","../src/types/SessionStatus.ts","../src/types/express.d.ts","../src/types/healing.d.ts","../src/types/identity.ts","../src/validators/CapabilityValidator.ts","../test/e2e/e2ehelper.ts","../test/e2e/plugin-harness.ts","../test/e2e/plugin.spec.ts","../test/e2e/startup-verification.spec.ts","../test/e2e/telemetry_verification.spec.ts","../test/e2e/video-recording-test.spec.js","../test/e2e/android/conf.spec.js","../test/e2e/android/conf2.spec.js","../test/e2e/android/conf3.spec.js","../test/e2e/hubnode/forward-request.spec.ts","../test/e2e/hubnode/hubnode.spec.ts","../test/e2e/ios/conf1.spec.js","../test/e2e/ios/conf2.spec.js","../test/helpers/seedUser.ts","../test/helpers/test-container.ts","../test/integration/androidDevices.spec.ts","../test/integration/auth-flow.spec.ts","../test/integration/auth-rate-limit.spec.ts","../test/integration/bug-report-route.spec.ts","../test/integration/cliArgs.js","../test/integration/cross-workflow.spec.ts","../test/integration/forgot-password-rate-limit.spec.ts","../test/integration/forgot-password.spec.ts","../test/integration/legacy-deprecation-headers.spec.ts","../test/integration/migration.spec.ts","../test/integration/node-pair-auth-rest.spec.ts","../test/integration/ports-router.spec.ts","../test/integration/profile-tokens.spec.ts","../test/integration/recordings-router.spec.ts","../test/integration/reset-revokes-sessions.spec.ts","../test/integration/role-matrix.spec.ts","../test/integration/sdk-leases-router.spec.ts","../test/integration/sdk-version.spec.ts","../test/integration/selector-state-flow.spec.ts","../test/integration/team-membership-migration.spec.ts","../test/integration/team-visibility-dashboard.spec.ts","../test/integration/team-visibility-grid.spec.ts","../test/integration/team-visibility-recordings.spec.ts","../test/integration/users-flow.spec.ts","../test/integration/users-lockout.spec.ts","../test/integration/ios/01iOSSimulator.spec.ts","../test/integration/ios/02iOSDevices.spec.ts","../test/unit/AndroidDeviceManager.spec.ts","../test/unit/ApiKeyService.test.ts","../test/unit/AutowaitService.spec.ts","../test/unit/ChromeDriverManager.spec.js","../test/unit/CleanupService.spec.ts","../test/unit/CommandInterceptor.autowait.spec.ts","../test/unit/DeviceModel.spec.ts","../test/unit/EmailService.test.ts","../test/unit/FuzzyXmlHealingProvider.test.ts","../test/unit/GetAdbOriginal.js","../test/unit/HealingCascade.test.ts","../test/unit/IOSDeviceManager.spec.js","../test/unit/OrphanSweeper.test.ts","../test/unit/PasswordResetService.test.ts","../test/unit/PortAllocator.test.ts","../test/unit/ProcessRegistry.test.ts","../test/unit/RemoteIOs.spec.js","../test/unit/ResilioTreeHealingProvider.test.ts","../test/unit/SessionHeartbeatWrite.test.ts","../test/unit/TeamService.test.ts","../test/unit/UserService.test.ts","../test/unit/UserSessionService.test.ts","../test/unit/XenonCapabilityManager.spec.ts","../test/unit/aggregate-hotspots-tuple-key.spec.ts","../test/unit/authMiddleware.test.ts","../test/unit/bootstrap-identity.test.ts","../test/unit/build-export.spec.ts","../test/unit/busy-precheck.spec.ts","../test/unit/commands.spec.js","../test/unit/concurrency-gate.spec.ts","../test/unit/config.spec.js","../test/unit/device-service.spec.ts","../test/unit/device-utils.spec.ts","../test/unit/event-manager-regression-hook.spec.ts","../test/unit/extract-access-key-token-pair.test.ts","../test/unit/findAndLockDevice-leasemerge.spec.ts","../test/unit/healing-instrumentation.spec.ts","../test/unit/healing-state-endpoints.spec.ts","../test/unit/helpers.spec.ts","../test/unit/loginRateLimiter.test.ts","../test/unit/omni-vision.spec.ts","../test/unit/plugin.spec.ts","../test/unit/prisma.spec.ts","../test/unit/profile-router.test.ts","../test/unit/proof-bundle.spec.ts","../test/unit/rateLimitMiddleware.test.ts","../test/unit/recording-instrumentation.spec.ts","../test/unit/recording-orchestrator.spec.ts","../test/unit/recording-store.spec.ts","../test/unit/roleGuard.test.ts","../test/unit/run-migrations.test.ts","../test/unit/selector-state-service.spec.ts","../test/unit/selector-verification-job.spec.ts","../test/unit/team-filter.test.ts","../test/unit/tracing-service-init.spec.ts","../test/unit/userAuthorization.test.ts","../test/unit/users-router.test.ts","../test/unit/video-pipeline-outputpath.spec.ts","../test/unit/bug-report/archive.spec.ts","../test/unit/bug-report/har-collector.spec.ts","../test/unit/bug-report/manifest.spec.ts","../test/unit/bug-report/readme.spec.ts","../test/unit/bug-report/route.spec.ts","../test/unit/bug-report/service.spec.ts","../test/unit/bug-report/video-slice.spec.ts","../test/unit/bug-report/window.spec.ts","../test/unit/fixtures/device.config.js","../test/unit/fixtures/devices.js","../test/unit/interceptor/AndroidProxyAdapter.spec.ts","../test/unit/interceptor/CertManager.spec.ts","../test/unit/interceptor/HarBuilder.spec.ts","../test/unit/interceptor/HostFilter.spec.ts","../test/unit/interceptor/MitmProxyHost.spec.ts","../test/unit/interceptor/MockEngine.spec.ts","../test/unit/interceptor/RequestBuffer.spec.ts","../test/unit/interceptor/SessionArchive.spec.ts","../test/unit/lease/LeaseOrphanSweeper.spec.ts","../test/unit/lease/LeaseService.spec.ts","../test/unit/lease/buildCapabilityBag.spec.ts","../test/unit/lease/leaseToken.spec.ts","../test/unit/ports/PortAllocatorService.spec.ts"],"version":"5.9.3"}
1
+ {"root":["../src/InternalHttpClient.ts","../src/PluginContext.ts","../src/XenonCapabilityManager.ts","../src/chromeUtils.ts","../src/config.ts","../src/device-utils.ts","../src/index.ts","../src/logger.ts","../src/plugin.ts","../src/prisma.ts","../src/app/index.ts","../src/app/swagger-docs.ts","../src/app/swagger.ts","../src/app/routers/apikeys.ts","../src/app/routers/apps.ts","../src/app/routers/auth.ts","../src/app/routers/bug-report.ts","../src/app/routers/build-export.ts","../src/app/routers/config.ts","../src/app/routers/control.ts","../src/app/routers/dashboard.ts","../src/app/routers/grid.ts","../src/app/routers/interceptor.ts","../src/app/routers/ports.ts","../src/app/routers/processes.ts","../src/app/routers/profile.ts","../src/app/routers/recordings.ts","../src/app/routers/reservation.ts","../src/app/routers/sdk-leases.ts","../src/app/routers/sdk-version.ts","../src/app/routers/teams.ts","../src/app/routers/users.ts","../src/app/routers/webhook.ts","../src/commands/handle.ts","../src/commands/index.ts","../src/dashboard/asset-manager.ts","../src/dashboard/commands.ts","../src/dashboard/event-manager.ts","../src/dashboard/services/app-service.ts","../src/dashboard/services/failure-analysis-service.ts","../src/dashboard/services/session-service.ts","../src/data-service/CircuitBreaker.ts","../src/data-service/config-service.ts","../src/data-service/db.ts","../src/data-service/device-service.ts","../src/data-service/device-store.interface.ts","../src/data-service/device-store.ts","../src/data-service/pending-sessions-service.ts","../src/data-service/pluginArgs.ts","../src/data-service/prisma-service.ts","../src/data-service/prisma-store.ts","../src/data-service/queue-service.ts","../src/data-service/web-config-service.ts","../src/device-managers/AndroidDeviceManager.ts","../src/device-managers/ChromeDriverManager.ts","../src/device-managers/HealthMonitorService.ts","../src/device-managers/IOSDeviceManager.ts","../src/device-managers/NodeDevices.ts","../src/device-managers/iOSTracker.ts","../src/device-managers/index.ts","../src/device-managers/android/AndroidStreamService.ts","../src/device-managers/android/DeviceLockManager.ts","../src/device-managers/cloud/CapabilityManager.ts","../src/device-managers/cloud/Devices.ts","../src/device-managers/ios/IOSDiscoveryService.ts","../src/device-managers/ios/IOSStreamService.ts","../src/device-managers/ios/WDAClient.ts","../src/enums/Capabilities.ts","../src/enums/Cloud.ts","../src/enums/Platform.ts","../src/enums/SessionType.ts","../src/enums/SocketEvents.ts","../src/generated/client/default.d.ts","../src/generated/client/default.js","../src/generated/client/edge.d.ts","../src/generated/client/edge.js","../src/generated/client/index-browser.js","../src/generated/client/index.d.ts","../src/generated/client/index.js","../src/generated/client/wasm.d.ts","../src/generated/client/wasm.js","../src/generated/client/runtime/edge-esm.js","../src/generated/client/runtime/edge.js","../src/generated/client/runtime/index-browser.d.ts","../src/generated/client/runtime/index-browser.js","../src/generated/client/runtime/library.d.ts","../src/generated/client/runtime/library.js","../src/generated/client/runtime/react-native.js","../src/generated/client/runtime/wasm.js","../src/helpers/UniversalMjpegProxy.ts","../src/helpers/index.ts","../src/interceptors/CommandInterceptor.ts","../src/interfaces/ICloudManager.ts","../src/interfaces/IDevice.ts","../src/interfaces/IDeviceFilterOptions.ts","../src/interfaces/IDeviceManager.ts","../src/interfaces/IOptions.ts","../src/interfaces/IPluginArgs.ts","../src/interfaces/ISessionCapability.ts","../src/logging/sessionContext.ts","../src/middleware/authMiddleware.ts","../src/middleware/csrfMiddleware.ts","../src/middleware/leaseTokenMiddleware.ts","../src/middleware/loginRateLimiter.ts","../src/middleware/rateLimitMiddleware.ts","../src/middleware/roleGuard.ts","../src/middleware/scopeGuard.ts","../src/profiling/AndroidAppProfiler.ts","../src/proxy/wd-command-proxy.ts","../src/scripts/generate-database-migration.ts","../src/scripts/initialize-database.ts","../src/scripts/install-go-ios.ts","../src/scripts/prepare-prisma.ts","../src/scripts/run-migrations.ts","../src/services/AICommandService.ts","../src/services/AIService.ts","../src/services/ApiKeyService.ts","../src/services/CircuitBreaker.ts","../src/services/CleanupService.ts","../src/services/DeviceReconciler.ts","../src/services/EmailService.ts","../src/services/EventBus.ts","../src/services/InspectorService.ts","../src/services/InterceptorService.ts","../src/services/MetricsService.ts","../src/services/NetworkConditioningService.ts","../src/services/NotificationService.ts","../src/services/OrphanSweeper.ts","../src/services/PasswordResetService.ts","../src/services/PortAllocator.ts","../src/services/ProcessMetricsService.ts","../src/services/ProcessRegistry.ts","../src/services/RequestLogService.ts","../src/services/ResourceIsolationService.ts","../src/services/SecurityService.ts","../src/services/SelectorStateService.ts","../src/services/SelectorVerificationJob.ts","../src/services/ServerManager.ts","../src/services/SessionHeartbeatService.ts","../src/services/SessionLifecycleService.ts","../src/services/ShutdownCoordinator.ts","../src/services/SocketClient.ts","../src/services/SocketServer.ts","../src/services/TeamService.ts","../src/services/TracingService.ts","../src/services/UserService.ts","../src/services/UserSessionService.ts","../src/services/VideoPipelineService.ts","../src/services/autowait/AutowaitService.ts","../src/services/autowait/waitFor.ts","../src/services/bug-report/BugReportService.ts","../src/services/bug-report/archive.ts","../src/services/bug-report/har-collector.ts","../src/services/bug-report/manifest.ts","../src/services/bug-report/readme.ts","../src/services/bug-report/types.ts","../src/services/bug-report/video-slice.ts","../src/services/bug-report/window.ts","../src/services/healing/FuzzyXmlHealingProvider.ts","../src/services/healing/HealEtalonService.ts","../src/services/healing/HealedLocatorGenerator.ts","../src/services/healing/HealingMetrics.ts","../src/services/healing/HealingOrchestrator.ts","../src/services/healing/LlmHealingProvider.ts","../src/services/healing/OcrHealingProvider.ts","../src/services/healing/ResilioTreeHealingProvider.ts","../src/services/healing/VisualAiHealingProvider.ts","../src/services/healing/types.ts","../src/services/identity/bootstrap.ts","../src/services/identity/sessionCleanupCron.ts","../src/services/identity/userAuthorization.ts","../src/services/interceptor/AndroidProxyAdapter.ts","../src/services/interceptor/CertManager.ts","../src/services/interceptor/HarBuilder.ts","../src/services/interceptor/HostFilter.ts","../src/services/interceptor/MitmProxyHost.ts","../src/services/interceptor/MockEngine.ts","../src/services/interceptor/RequestBuffer.ts","../src/services/interceptor/SessionArchive.ts","../src/services/interceptor/types.ts","../src/services/lease/LeaseOrphanSweeper.ts","../src/services/lease/LeaseService.ts","../src/services/lease/buildCapabilityBag.ts","../src/services/lease/leaseToken.ts","../src/services/omni-vision/OmniVisionService.ts","../src/services/omni-vision/VisionAssertionService.ts","../src/services/ports/PortAllocatorClient.ts","../src/services/ports/PortAllocatorService.ts","../src/services/recording/RecordingOrchestrator.ts","../src/services/recording/annotation-render.ts","../src/services/recording/busy-precheck.ts","../src/services/recording/concurrency-gate.ts","../src/services/recording/manualLock.ts","../src/services/recording/proof-bundle.ts","../src/services/recording/recording-store.ts","../src/services/telemetry/attributes.ts","../src/sessions/CloudSession.ts","../src/sessions/LocalSession.ts","../src/sessions/RemoteSession.ts","../src/sessions/SessionManager.ts","../src/sessions/XenonSession.ts","../src/types/CLIArgs.ts","../src/types/CloudArgs.ts","../src/types/CloudSchema.ts","../src/types/DeviceType.ts","../src/types/DeviceUpdate.ts","../src/types/IOSDevice.ts","../src/types/Platform.ts","../src/types/SessionStatus.ts","../src/types/express.d.ts","../src/types/healing.d.ts","../src/types/identity.ts","../src/validators/CapabilityValidator.ts","../test/e2e/e2ehelper.ts","../test/e2e/plugin-harness.ts","../test/e2e/plugin.spec.ts","../test/e2e/startup-verification.spec.ts","../test/e2e/telemetry_verification.spec.ts","../test/e2e/video-recording-test.spec.js","../test/e2e/android/conf.spec.js","../test/e2e/android/conf2.spec.js","../test/e2e/android/conf3.spec.js","../test/e2e/hubnode/forward-request.spec.ts","../test/e2e/hubnode/hubnode.spec.ts","../test/e2e/ios/conf1.spec.js","../test/e2e/ios/conf2.spec.js","../test/helpers/seedUser.ts","../test/helpers/test-container.ts","../test/integration/androidDevices.spec.ts","../test/integration/auth-flow.spec.ts","../test/integration/auth-rate-limit.spec.ts","../test/integration/bug-report-route.spec.ts","../test/integration/cliArgs.js","../test/integration/cross-workflow.spec.ts","../test/integration/forgot-password-rate-limit.spec.ts","../test/integration/forgot-password.spec.ts","../test/integration/legacy-deprecation-headers.spec.ts","../test/integration/migration.spec.ts","../test/integration/node-pair-auth-rest.spec.ts","../test/integration/ports-router.spec.ts","../test/integration/profile-tokens.spec.ts","../test/integration/recordings-router.spec.ts","../test/integration/reset-revokes-sessions.spec.ts","../test/integration/role-matrix.spec.ts","../test/integration/sdk-leases-router.spec.ts","../test/integration/sdk-version.spec.ts","../test/integration/selector-state-flow.spec.ts","../test/integration/team-membership-migration.spec.ts","../test/integration/team-visibility-dashboard.spec.ts","../test/integration/team-visibility-grid.spec.ts","../test/integration/team-visibility-recordings.spec.ts","../test/integration/users-flow.spec.ts","../test/integration/users-lockout.spec.ts","../test/integration/ios/01iOSSimulator.spec.ts","../test/integration/ios/02iOSDevices.spec.ts","../test/unit/AndroidDeviceManager.spec.ts","../test/unit/ApiKeyService.test.ts","../test/unit/AutowaitService.spec.ts","../test/unit/ChromeDriverManager.spec.js","../test/unit/CleanupService.spec.ts","../test/unit/CommandInterceptor.autowait.spec.ts","../test/unit/DeviceModel.spec.ts","../test/unit/EmailService.test.ts","../test/unit/FuzzyXmlHealingProvider.test.ts","../test/unit/GetAdbOriginal.js","../test/unit/HealingCascade.test.ts","../test/unit/IOSDeviceManager.spec.js","../test/unit/OrphanSweeper.test.ts","../test/unit/PasswordResetService.test.ts","../test/unit/PortAllocator.test.ts","../test/unit/ProcessRegistry.test.ts","../test/unit/RemoteIOs.spec.js","../test/unit/ResilioTreeHealingProvider.test.ts","../test/unit/SessionHeartbeatWrite.test.ts","../test/unit/TeamService.test.ts","../test/unit/UserService.test.ts","../test/unit/UserSessionService.test.ts","../test/unit/XenonCapabilityManager.spec.ts","../test/unit/aggregate-hotspots-tuple-key.spec.ts","../test/unit/auth-me-auth-disabled.test.ts","../test/unit/authMiddleware.test.ts","../test/unit/bootstrap-identity.test.ts","../test/unit/build-export.spec.ts","../test/unit/busy-precheck.spec.ts","../test/unit/commands.spec.js","../test/unit/concurrency-gate.spec.ts","../test/unit/config.spec.js","../test/unit/device-service.spec.ts","../test/unit/device-utils.spec.ts","../test/unit/event-manager-regression-hook.spec.ts","../test/unit/extract-access-key-token-pair.test.ts","../test/unit/findAndLockDevice-leasemerge.spec.ts","../test/unit/healing-instrumentation.spec.ts","../test/unit/healing-state-endpoints.spec.ts","../test/unit/helpers.spec.ts","../test/unit/loginRateLimiter.test.ts","../test/unit/omni-vision.spec.ts","../test/unit/plugin.spec.ts","../test/unit/prisma.spec.ts","../test/unit/profile-router.test.ts","../test/unit/proof-bundle.spec.ts","../test/unit/rateLimitMiddleware.test.ts","../test/unit/recording-instrumentation.spec.ts","../test/unit/recording-orchestrator.spec.ts","../test/unit/recording-store.spec.ts","../test/unit/roleGuard.test.ts","../test/unit/run-migrations-fail-fast.test.ts","../test/unit/run-migrations.test.ts","../test/unit/selector-state-service.spec.ts","../test/unit/selector-verification-job.spec.ts","../test/unit/team-filter.test.ts","../test/unit/tracing-service-init.spec.ts","../test/unit/userAuthorization.test.ts","../test/unit/users-router.test.ts","../test/unit/video-pipeline-outputpath.spec.ts","../test/unit/bug-report/archive.spec.ts","../test/unit/bug-report/har-collector.spec.ts","../test/unit/bug-report/manifest.spec.ts","../test/unit/bug-report/readme.spec.ts","../test/unit/bug-report/route.spec.ts","../test/unit/bug-report/service.spec.ts","../test/unit/bug-report/video-slice.spec.ts","../test/unit/bug-report/window.spec.ts","../test/unit/fixtures/device.config.js","../test/unit/fixtures/devices.js","../test/unit/interceptor/AndroidProxyAdapter.spec.ts","../test/unit/interceptor/CertManager.spec.ts","../test/unit/interceptor/HarBuilder.spec.ts","../test/unit/interceptor/HostFilter.spec.ts","../test/unit/interceptor/MitmProxyHost.spec.ts","../test/unit/interceptor/MockEngine.spec.ts","../test/unit/interceptor/RequestBuffer.spec.ts","../test/unit/interceptor/SessionArchive.spec.ts","../test/unit/lease/LeaseOrphanSweeper.spec.ts","../test/unit/lease/LeaseService.spec.ts","../test/unit/lease/buildCapabilityBag.spec.ts","../test/unit/lease/leaseToken.spec.ts","../test/unit/ports/PortAllocatorService.spec.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenon-device-management/xenon",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
5
5
  "main": "./lib/src/index.js",
6
6
  "exports": {
@@ -1,21 +0,0 @@
1
- import{g as p,m as A,r as l,X as m,j as e,s as N,v as k,y as E}from"./index-BrVV0Kla.js";/* empty css */import{S as T,A as z}from"./SettingCard-M-lFn_Wm.js";import{P as F}from"./page-header-C0pnt4xz.js";import{L as S}from"./lock-CVUUnm1V.js";import{C as I}from"./circle-check--2DSsfaI.js";import{A as U}from"./activity-DK3R5GAb.js";/**
2
- * @license lucide-react v0.555.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const B=[["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M17 20v2",key:"1rnc9c"}],["path",{d:"M17 2v2",key:"11trls"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M2 17h2",key:"7oei6x"}],["path",{d:"M2 7h2",key:"asdhe0"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"M20 17h2",key:"1fpfkl"}],["path",{d:"M20 7h2",key:"1o8tra"}],["path",{d:"M7 20v2",key:"4gnj0m"}],["path",{d:"M7 2v2",key:"1i4yhu"}],["rect",{x:"4",y:"4",width:"16",height:"16",rx:"2",key:"1vbyd7"}],["rect",{x:"8",y:"8",width:"8",height:"8",rx:"1",key:"z9xiuo"}]],$=p("cpu",B);/**
7
- * @license lucide-react v0.555.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const q=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],D=p("globe",q);/**
12
- * @license lucide-react v0.555.0 - ISC
13
- *
14
- * This source code is licensed under the ISC license.
15
- * See the LICENSE file in the root directory of this source tree.
16
- */const G=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],L=p("server",G);/**
17
- * @license lucide-react v0.555.0 - ISC
18
- *
19
- * This source code is licensed under the ISC license.
20
- * See the LICENSE file in the root directory of this source tree.
21
- */const O=[["path",{d:"M10 8h4",key:"1sr2af"}],["path",{d:"M12 21v-9",key:"17s77i"}],["path",{d:"M12 8V3",key:"13r4qs"}],["path",{d:"M17 16h4",key:"h1uq16"}],["path",{d:"M19 12V3",key:"o1uvq1"}],["path",{d:"M19 21v-5",key:"qua636"}],["path",{d:"M3 14h4",key:"bcjad9"}],["path",{d:"M5 10V3",key:"cb8scm"}],["path",{d:"M5 21v-7",key:"1w1uti"}]],R=p("sliders-vertical",O),b={aiProvider:"gemini",aiModel:"",aiBaseUrl:"",geminiModel:"",openaiModel:"",anthropicModel:"",ollamaModel:"",geminiSet:!1,openaiSet:!1,anthropicSet:!1,aiTemperature:1,aiMaxTokens:4096,aiTopP:1},V=(s,a)=>s.aiProvider===a.aiProvider&&s.aiTemperature===a.aiTemperature&&s.aiMaxTokens===a.aiMaxTokens&&s.aiTopP===a.aiTopP,c=s=>{switch(s){case"gemini":return"gemini-3-flash-preview";case"openai":return"gpt-4o";case"anthropic":return"claude-sonnet-4-6";case"ollama":return"llama3";default:return"—"}},X=s=>{switch(s){case"ollama":return"http://localhost:11434";default:return"Provider default"}},ee=()=>{const{toast:s}=A(),[a,t]=l.useState(b),[h,u]=l.useState(b),[P,g]=l.useState(!0),[x,v]=l.useState(!1),[f,j]=l.useState(!1);l.useEffect(()=>{_()},[]);const _=async()=>{g(!0);try{const i=await m.getGlobalConfig(),n={aiProvider:i.aiProvider||"gemini",aiModel:i.aiModel||"",aiBaseUrl:i.aiBaseUrl||"",geminiModel:i.geminiModel||"",openaiModel:i.openaiModel||"",anthropicModel:i.anthropicModel||"",ollamaModel:i.ollamaModel||"",geminiSet:!!i.geminiSet,openaiSet:!!i.openaiSet,anthropicSet:!!i.anthropicSet,aiTemperature:typeof i.aiTemperature=="number"?i.aiTemperature:1,aiMaxTokens:typeof i.aiMaxTokens=="number"?i.aiMaxTokens:4096,aiTopP:typeof i.aiTopP=="number"?i.aiTopP:1};t(n),u(n)}catch(i){console.error("Failed to load AISettings",i),s("Failed to access AI configuration.","error")}finally{g(!1)}},C=async()=>{v(!0);try{await m.updateGlobalConfig({aiProvider:a.aiProvider,aiTemperature:a.aiTemperature,aiMaxTokens:a.aiMaxTokens,aiTopP:a.aiTopP}),u(a),s("AI engine configuration saved.","success")}catch(i){console.error("Failed to save AISettings",i),s("Failed to persist updates.","error")}finally{v(!1)}},w=async()=>{j(!0);const i=Date.now();try{const n=await m.testAIConfig({aiProvider:a.aiProvider}),r=Date.now()-i;n.success?s(`${n.message} (${r}ms)`,"success"):s(n.message,"error")}catch(n){s(`Connection failed: ${(n==null?void 0:n.message)||"unknown error"}`,"error")}finally{j(!1)}},d=[{id:"gemini",name:"Google Gemini",description:"Gemini 1.5 Pro — Multimodal reasoning",icon:e.jsx("span",{className:"ai-provider-glyph",children:"G"}),isConfigured:!!a.geminiSet},{id:"openai",name:"OpenAI",description:"GPT-4o — OpenAI v1 compatible",icon:e.jsx($,{size:18}),isConfigured:!!a.openaiSet},{id:"anthropic",name:"Anthropic",description:"Claude Sonnet 4.6 — Advanced analysis",icon:e.jsx(N,{size:18}),isConfigured:!!a.anthropicSet},{id:"ollama",name:"Ollama",description:"Local / Self-hosted — No API key required",icon:e.jsx(L,{size:18}),isConfigured:!!a.ollamaModel||!!a.aiModel||!!a.aiBaseUrl}],o=d.find(i=>i.id===a.aiProvider),y=d.filter(i=>i.isConfigured).length,M=!V(a,h);return P?e.jsxs("div",{className:"settings-loading",children:[e.jsx(k,{className:"animate-spin",size:32}),e.jsx("span",{children:"Synchronizing Global State..."})]}):e.jsxs("div",{className:"settings-container",children:[e.jsx(F,{icon:E,title:"AI Engine Configuration",subtitle:e.jsxs(e.Fragment,{children:["All credentials and endpoints are managed via environment variables.",e.jsxs("span",{className:"page-header-subnote",children:[e.jsx(S,{size:12}),"Select the active provider from configured options below."]})]})}),e.jsx("div",{className:"settings-content",children:e.jsxs("div",{className:"settings-grid settings-grid--two-equal",children:[e.jsx(T,{icon:e.jsx(N,{size:16}),title:"Provider Registry",titleExtra:e.jsxs("span",{className:`provider-count-pill ${y>0?"is-ok":"is-empty"}`,children:[y," / ",d.length," CONFIGURED"]}),description:"Providers are activated via environment variables. Select a configured engine to activate.",children:e.jsx("div",{className:"provider-list",children:d.map(i=>{const n=a.aiProvider===i.id,r=i.isConfigured;return e.jsxs("button",{type:"button",className:`provider-row ${n?"is-active":""} ${r?"":"is-disabled"}`,onClick:()=>r&&t({...a,aiProvider:i.id}),disabled:!r,title:r?`Activate ${i.name}`:`Set XENON_${i.id.toUpperCase()}_API_KEY to enable`,children:[e.jsx("div",{className:"provider-row__icon",children:i.icon}),e.jsxs("div",{className:"provider-row__body",children:[e.jsx("div",{className:"provider-row__name",children:i.name}),e.jsx("div",{className:"provider-row__desc",children:i.description}),e.jsx("div",{className:"provider-row__status",children:n?e.jsxs("span",{className:"provider-status provider-status--active",children:[e.jsx(I,{size:11}),"ACTIVE"]}):e.jsxs("span",{className:"provider-status provider-status--off",children:[e.jsx(S,{size:10}),"NOT SET"]})})]})]},i.id)})})}),e.jsxs(T,{icon:e.jsx(D,{size:16}),title:"Runtime Configuration",description:"Environmental overrides for AI model endpoints and identifiers.",children:[e.jsxs("div",{className:"ai-config-display",children:[e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Active Provider"}),e.jsxs("span",{className:"ai-config-value",children:[o==null?void 0:o.icon,(o==null?void 0:o.name)||"—"]})]}),e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Model"}),e.jsxs("span",{className:"ai-config-value mono",children:[e.jsxs("span",{children:[a.aiProvider==="gemini"&&(a.geminiModel||a.aiModel||c("gemini")),a.aiProvider==="openai"&&(a.openaiModel||a.aiModel||c("openai")),a.aiProvider==="anthropic"&&(a.anthropicModel||a.aiModel||c("anthropic")),a.aiProvider==="ollama"&&(a.ollamaModel||a.aiModel||c("ollama"))]}),e.jsx("span",{className:"ai-config-default",children:"DEFAULT"})]})]}),e.jsxs("div",{className:"ai-config-row",children:[e.jsx("span",{className:"ai-config-label",children:"Base URL"}),e.jsxs("span",{className:"ai-config-value mono",children:[e.jsx("span",{children:a.aiBaseUrl||X(a.aiProvider)}),!a.aiBaseUrl&&e.jsx("span",{className:"ai-config-default",children:"DEFAULT"})]})]})]}),e.jsxs("div",{className:"model-params",children:[e.jsxs("div",{className:"model-params__header",children:[e.jsx(R,{size:14}),e.jsx("span",{children:"Model Parameters"})]}),e.jsxs("div",{className:"model-param",children:[e.jsxs("div",{className:"model-param__label-row",children:[e.jsx("label",{htmlFor:"ai-temp",children:"TEMPERATURE"}),e.jsx("span",{className:"model-param__value",children:a.aiTemperature.toFixed(1)})]}),e.jsx("input",{id:"ai-temp",type:"range",min:0,max:2,step:.1,value:a.aiTemperature,onChange:i=>t({...a,aiTemperature:parseFloat(i.target.value)}),className:"model-param__slider"})]}),e.jsxs("div",{className:"model-param",children:[e.jsx("div",{className:"model-param__label-row",children:e.jsx("label",{htmlFor:"ai-max-tokens",children:"MAX TOKENS"})}),e.jsx("div",{className:"setting-input-wrapper",children:e.jsx("input",{id:"ai-max-tokens",type:"number",min:256,step:128,value:a.aiMaxTokens,onChange:i=>t({...a,aiMaxTokens:parseInt(i.target.value,10)||0})})})]}),e.jsxs("div",{className:"model-param",children:[e.jsxs("div",{className:"model-param__label-row",children:[e.jsx("label",{htmlFor:"ai-top-p",children:"TOP P"}),e.jsx("span",{className:"model-param__value",children:a.aiTopP.toFixed(2)})]}),e.jsx("input",{id:"ai-top-p",type:"range",min:0,max:1,step:.01,value:a.aiTopP,onChange:i=>t({...a,aiTopP:parseFloat(i.target.value)}),className:"model-param__slider"})]})]}),e.jsxs("button",{type:"button",className:"test-connection-btn",onClick:w,disabled:f||!(o!=null&&o.isConfigured),children:[f?e.jsx(k,{size:14,className:"animate-spin"}):e.jsx(U,{size:14}),e.jsx("span",{children:"Test Connection"})]})]})]})}),(M||x)&&e.jsx(z,{onSave:C,onDiscard:()=>t(h),isSaving:x,isDirty:M,saveLabel:"Save Configuration"})]})};export{ee as AISettings};
@@ -1 +0,0 @@
1
- import{m as ie,r as a,j as e,v as F,K as L,p as ne}from"./index-BrVV0Kla.js";/* empty css */import{T as re,a as le,b as $,c as l,d as oe,e as o}from"./Table-B3EUgBi6.js";import{F as m}from"./FieldGroup-DE3u01Nu.js";import{P as z}from"./page-header-C0pnt4xz.js";import{M as O}from"./Modal-BJcFdiBP.js";import{S as ce}from"./shield-alert-BfoPJ8q_.js";import{P as g}from"./plus-BObE-_z6.js";import{T as de}from"./trash-2-CE5TRHb2.js";import{C as me}from"./check-BkT38An9.js";import{C as pe}from"./copy-CEcFYYHm.js";const H=["read","sessions","devices","admin"],M={"7d":"7 days","30d":"30 days","90d":"90 days","1y":"1 year",never:"No expiry"},he={"7d":7,"30d":30,"90d":90,"1y":365};function B(i){return i==="never"?null:new Date(Date.now()+he[i]*864e5).toISOString()}function U(i){if(!i)return"Never";const n=Date.now()-new Date(i).getTime();return n<6e4?"Just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:`${Math.floor(n/864e5)}d ago`}const Se=()=>{const{toast:i}=ie(),[n,v]=a.useState([]),[b,W]=a.useState([]),[Y,w]=a.useState(!0),[q,N]=a.useState(!1),[J,d]=a.useState(!1),[r,y]=a.useState(null),[k,C]=a.useState(null),[S,T]=a.useState(!1),[p,_]=a.useState(""),[j,A]=a.useState({read:!0,sessions:!0,devices:!1,admin:!1}),[I,R]=a.useState(300),[P,D]=a.useState(""),[h,E]=a.useState("30d"),[x,K]=a.useState(!1),X=s=>{var t;return s?((t=b.find(c=>c.id===s))==null?void 0:t.name)||s.slice(0,8):"Shared"},f=async()=>{w(!0);try{const[s,t]=await Promise.all([fetch("/xenon/api/apikeys",{credentials:"include"}),fetch("/xenon/api/teams",{credentials:"include"})]);if(s.status===403){N(!0),v([]);return}if(!s.ok)throw new Error(`HTTP ${s.status}`);v(await s.json()),t.ok&&W(await t.json()),N(!1)}catch(s){i(`Failed to load API keys: ${s.message}`,"error")}finally{w(!1)}};a.useEffect(()=>{f()},[]);const G=()=>{_(""),A({read:!0,sessions:!0,devices:!1,admin:!1}),R(300),D(""),E("30d")},Q=async()=>{const s=H.filter(t=>j[t]);if(!p.trim()){i("Key name is required","error");return}if(s.length===0){i("Select at least one scope","error");return}K(!0);try{const t=await fetch("/xenon/api/apikeys",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),scopes:s,rateLimit:I,teamId:P||null,expiresAt:B(h)})});if(!t.ok)throw new Error(`HTTP ${t.status}`);const c=await t.json();d(!1),G(),y({name:p.trim(),raw:c.key}),await f()}catch(t){i(`Create failed: ${t.message}`,"error")}finally{K(!1)}},V=async s=>{C(s);try{const t=await fetch(`/xenon/api/apikeys/${s}`,{method:"DELETE",credentials:"include"});if(!t.ok)throw new Error(`HTTP ${t.status}`);i("Key revoked","success"),await f()}catch(t){i(`Revoke failed: ${t.message}`,"error")}finally{C(null)}},Z=async s=>{try{await navigator.clipboard.writeText(s),T(!0),setTimeout(()=>T(!1),1500)}catch{i("Copy failed — select the text manually","error")}};if(Y)return e.jsxs("div",{className:"settings-loading",children:[e.jsx(F,{className:"animate-spin",size:32}),e.jsx("span",{children:"Loading API keys…"})]});if(q)return e.jsx("div",{className:"settings-container",children:e.jsx(z,{icon:ce,title:"API Keys",subtitle:e.jsxs(e.Fragment,{children:["Your key lacks the ",e.jsx("code",{children:"admin"})," scope. Ask an administrator to issue an admin key so you can manage access for other users."]})})});const ee=n.length,se=n.filter(s=>s.scopes.includes("admin")).length,te=n.filter(s=>s.lastUsedAt&&Date.now()-new Date(s.lastUsedAt).getTime()<864e5).length;return e.jsxs("div",{className:"settings-container",children:[e.jsx(z,{icon:L,title:"API Keys",subtitle:e.jsxs(e.Fragment,{children:["Issue scoped credentials for humans (dashboard login) and machines (CI, WebDriver clients via ",e.jsx("code",{children:"xenon:accessKey"}),"). Keys are shown only once at creation — copy the value before closing the dialog."]}),action:e.jsxs("button",{type:"button",className:"page-header-action",onClick:()=>d(!0),children:[e.jsx(g,{size:16}),e.jsx("span",{children:"Create new key"})]})}),e.jsxs("div",{className:"settings-content",children:[n.length>0&&e.jsxs("div",{className:"stat-strip",children:[e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:ee}),e.jsx("div",{className:"stat-strip__label",children:"Total keys"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value stat-strip__value--accent",children:se}),e.jsx("div",{className:"stat-strip__label",children:"Admin scope"})]}),e.jsxs("div",{className:"stat-strip__cell",children:[e.jsx("div",{className:"stat-strip__value",children:te}),e.jsx("div",{className:"stat-strip__label",children:"Active in last 24h"})]})]}),n.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-state__icon",children:e.jsx(L,{size:28})}),e.jsx("h3",{className:"empty-state__title",children:"No API keys yet"}),e.jsx("p",{className:"empty-state__copy",children:"Issue your first key to authenticate WebDriver clients or CI pipelines. Keys are shown only once at creation — copy the value before closing the dialog."}),e.jsxs("button",{type:"button",className:"page-header-action empty-state__action",onClick:()=>d(!0),children:[e.jsx(g,{size:16}),e.jsx("span",{children:"Create your first key"})]})]}):e.jsx("div",{className:"data-card",children:e.jsxs(re,{children:[e.jsx(le,{children:e.jsxs($,{children:[e.jsx(l,{children:"Name"}),e.jsx(l,{children:"Team"}),e.jsx(l,{children:"Scopes"}),e.jsx(l,{children:"Rate limit"}),e.jsx(l,{children:"Last used"}),e.jsx(l,{children:"Created"}),e.jsx(l,{children:"Expires"}),e.jsx(l,{style:{textAlign:"right"},children:"Actions"})]})}),e.jsx(oe,{children:n.map(s=>e.jsxs($,{children:[e.jsxs(o,{children:[e.jsx("strong",{children:s.name}),e.jsx("div",{className:"row-meta-mono",children:s.id.slice(0,8)})]}),e.jsx(o,{children:e.jsx("span",{className:`pill-chip ${s.teamId?"pill-chip--team":"pill-chip--shared"}`,children:X(s.teamId)})}),e.jsx(o,{children:e.jsx("div",{className:"scope-chips",children:s.scopes.split(",").map(t=>{const c=t.trim(),ae=c==="admin";return e.jsx("span",{className:`pill-chip ${ae?"pill-chip--admin":"pill-chip--scope"}`,children:c},t)})})}),e.jsxs(o,{className:"row-mono",children:[s.rateLimit,"/min"]}),e.jsx(o,{className:"row-mono",children:U(s.lastUsedAt)}),e.jsx(o,{className:"row-mono",children:U(s.createdAt)}),e.jsx(o,{className:"row-mono",children:s.expiresAt?new Date(s.expiresAt).getTime()<=Date.now()?e.jsx("span",{style:{color:"var(--red)"},children:"expired"}):new Date(s.expiresAt).toLocaleDateString():"Never"}),e.jsx(o,{style:{textAlign:"right"},children:e.jsxs("button",{type:"button",className:"row-action row-action--danger",disabled:k===s.id,onClick:()=>{window.confirm(`Revoke "${s.name}"? Any client using this key will immediately fail.`)&&V(s.id)},children:[e.jsx(de,{size:13}),k===s.id?"Revoking…":"Revoke"]})})]},s.id))})]})})]}),e.jsx(O,{open:J,title:"Create API key",width:520,onClose:()=>d(!1),footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"reset-btn",onClick:()=>d(!1),disabled:x,children:"Cancel"}),e.jsxs("button",{className:"save-btn",onClick:Q,disabled:x,children:[x?e.jsx(F,{className:"animate-spin",size:18}):e.jsx(g,{size:18}),x?"Creating…":"Create key"]})]}),children:e.jsxs("div",{style:{display:"flex",flexDirection:"column"},children:[e.jsx(m,{label:"Name",htmlFor:"apikey-name",children:e.jsx("input",{id:"apikey-name",type:"text",value:p,onChange:s=>_(s.target.value),placeholder:"alice-laptop, ci-main, etc.",style:u,autoFocus:!0})}),e.jsx(m,{label:"Scopes",description:e.jsxs(e.Fragment,{children:[e.jsx("code",{children:"admin"})," grants full access including API-key management."," ",e.jsx("code",{children:"sessions"})," is required for WebDriver ",e.jsx("code",{children:"xenon:accessKey"}),"."]}),children:e.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:8},children:H.map(s=>e.jsxs("label",{style:xe,children:[e.jsx("input",{type:"checkbox",checked:j[s],onChange:t=>A({...j,[s]:t.target.checked})}),e.jsx("span",{children:s})]},s))})}),e.jsx(m,{label:"Rate limit (requests/min)",htmlFor:"apikey-ratelimit",children:e.jsx("input",{id:"apikey-ratelimit",type:"number",min:10,step:10,value:I,onChange:s=>R(parseInt(s.target.value)||300),style:u})}),e.jsx(m,{label:"Default team",description:e.jsxs(e.Fragment,{children:["Keys without a team can only reach shared-pool devices. Admins can override at session time via ",e.jsx("code",{children:"xenon:team"}),"."]}),htmlFor:"apikey-team",children:e.jsxs("select",{id:"apikey-team",value:P,onChange:s=>D(s.target.value),style:u,children:[e.jsx("option",{value:"",children:"No team (shared pool only)"}),b.map(s=>e.jsx("option",{value:s.id,children:s.name},s.id))]})}),e.jsx(m,{label:"Expires after",description:h==="never"?"Key never expires. Rotate manually when needed.":`Key will stop working on ${new Date(B(h)).toLocaleDateString()}.`,htmlFor:"apikey-expiry",children:e.jsx("select",{id:"apikey-expiry",value:h,onChange:s=>E(s.target.value),style:u,children:Object.keys(M).map(s=>e.jsx("option",{value:s,children:M[s]},s))})})]})}),e.jsx(O,{open:!!r,title:r?`Key created: ${r.name}`:"",width:560,onClose:()=>y(null),closeOnOverlayClick:!1,footer:e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:"save-btn",onClick:()=>r&&Z(r.raw),disabled:!r,children:[S?e.jsx(me,{size:18}):e.jsx(pe,{size:18}),S?"Copied":"Copy to clipboard"]}),e.jsx("button",{className:"reset-btn",onClick:()=>y(null),children:"I've saved it"})]}),children:r&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs("div",{style:{background:"var(--status-busy-bg)",border:"1px solid var(--status-busy-border)",borderRadius:6,padding:12,display:"flex",gap:8,alignItems:"flex-start"},children:[e.jsx(ne,{size:18,style:{flexShrink:0,marginTop:2}}),e.jsxs("div",{children:[e.jsx("strong",{children:"This key will not be shown again."})," Copy it now and store it in your password manager, CI secret store, or client config."]})]}),e.jsx("div",{style:{fontFamily:"monospace",padding:12,background:"rgba(0,0,0,0.3)",borderRadius:6,wordBreak:"break-all",fontSize:"0.9em"},children:r.raw})]})})]})},u={width:"100%",padding:"8px 12px",background:"rgba(0,0,0,0.3)",border:"1px solid rgba(255,255,255,0.1)",borderRadius:6,color:"inherit",fontSize:"0.95em",boxSizing:"border-box"},xe={display:"flex",alignItems:"center",gap:6,padding:"6px 12px",background:"rgba(255,255,255,0.04)",borderRadius:6,cursor:"pointer",fontFamily:"monospace",fontSize:"0.9em"};export{Se as ApiKeys};
@@ -1,21 +0,0 @@
1
- import{g as x,j as e,m as q,r,X as l,S,o as W,v as X,n as H}from"./index-BrVV0Kla.js";import{c as K,a as Z,P as J,B as D,U as Q,T as ee}from"./button-lkxVyarW.js";import{P as se}from"./page-header-C0pnt4xz.js";import{C as ae}from"./check-BkT38An9.js";import{C as te}from"./copy-CEcFYYHm.js";import{Z as re}from"./zap-BzdRuL9F.js";import{D as ie}from"./download-CaKkGvKw.js";import{T as ne}from"./trash-2-CE5TRHb2.js";/**
2
- * @license lucide-react v0.555.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const ce=[["path",{d:"M12 6.528V3a1 1 0 0 1 1-1h0",key:"11qiee"}],["path",{d:"M18.237 21A15 15 0 0 0 22 11a6 6 0 0 0-10-4.472A6 6 0 0 0 2 11a15.1 15.1 0 0 0 3.763 10 3 3 0 0 0 3.648.648 5.5 5.5 0 0 1 5.178 0A3 3 0 0 0 18.237 21",key:"110c12"}]],M=x("apple",ce);/**
7
- * @license lucide-react v0.555.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const le=[["path",{d:"m3 16 4 4 4-4",key:"1co6wj"}],["path",{d:"M7 20V4",key:"1yoxec"}],["path",{d:"M11 4h10",key:"1w87gc"}],["path",{d:"M11 8h7",key:"djye34"}],["path",{d:"M11 12h4",key:"q8tih4"}]],oe=x("arrow-down-wide-narrow",le);/**
12
- * @license lucide-react v0.555.0 - ISC
13
- *
14
- * This source code is licensed under the ISC license.
15
- * See the LICENSE file in the root directory of this source tree.
16
- */const de=[["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}],["path",{d:"M11 12h4",key:"q8tih4"}],["path",{d:"M11 16h7",key:"uosisv"}],["path",{d:"M11 20h10",key:"jvxblo"}]],me=x("arrow-up-narrow-wide",de);/**
17
- * @license lucide-react v0.555.0 - ISC
18
- *
19
- * This source code is licensed under the ISC license.
20
- * See the LICENSE file in the root directory of this source tree.
21
- */const he=[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]],T=x("rocket",he),pe=Z("badge-base",{variants:{variant:{default:"badge-variant-default",success:"badge-variant-success",warning:"badge-variant-warning",error:"badge-variant-error",outline:"badge-variant-outline",secondary:"badge-variant-secondary"}},defaultVariants:{variant:"default"}});function I({className:n,variant:u,...c}){return e.jsx("div",{className:K(pe({variant:u}),n),...c})}const be=()=>{const{toast:n,removeToast:u}=q(),[c,b]=r.useState([]),[E,R]=r.useState([]),[o,k]=r.useState(!1),[v,$]=r.useState(""),[F,w]=r.useState(!1),[L,A]=r.useState(null),[d,_]=r.useState({android:!0,ios:!0}),[y,U]=r.useState("desc"),[m,j]=r.useState(null),[g,f]=r.useState(""),h=r.useCallback(async()=>{k(!0);try{const s=await l.getApps();b(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch apps",s)}finally{k(!1)}},[]),N=r.useCallback(async()=>{try{const s=await l.getDevices();R(Array.isArray(s)?s:[])}catch(s){console.error("Failed to fetch devices",s)}},[]);r.useEffect(()=>{h(),N();const s=setInterval(N,1e4);return()=>clearInterval(s)},[h,N]);const C=async s=>{var t;const a=(t=s.target.files)==null?void 0:t[0];if(a){w(!0);try{await l.uploadApp(a),await h()}catch(i){console.error("Upload failed",i)}finally{w(!1),s.target&&(s.target.value="")}}},B=async(s,a)=>{if(window.confirm(`Permanently remove artifact "${a}"?`))try{await l.deleteApp(s),b(t=>t.filter(i=>i.id!==s))}catch(t){console.error("Delete failed",t)}},P=(s,a)=>{navigator.clipboard.writeText(s),A(`${a}-${s}`),setTimeout(()=>A(null),2e3)},G=async(s,a)=>{const t=n(`Deploying app to ${a}...`,"loading",0);try{const i=await l.installRepositoryApp(a,s);i.success?(n("App deployed successfully","success"),j(null),f("")):n(`Deployment failed: ${i.error}`,"error")}catch(i){n(`Execution Error: ${i.message}`,"error")}finally{u(t)}},p=c.filter(s=>{const a=s.name.toLowerCase().includes(v.toLowerCase())||s.packageName&&s.packageName.toLowerCase().includes(v.toLowerCase()),t=d.android&&s.platform==="android"||d.ios&&s.platform==="ios";return a&&t}).sort((s,a)=>{const t=new Date(s.createdAt).getTime(),i=new Date(a.createdAt).getTime();return y==="desc"?i-t:t-i}),O=s=>{if(!s)return"0 B";const a=1024,t=Math.floor(Math.log(s)/Math.log(a));return parseFloat((s/Math.pow(a,t)).toFixed(1))+" "+["B","KB","MB","GB"][t]},Y=s=>new Date(s).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit"}),z=s=>{_(a=>({...a,[s]:!a[s]}))},V=s=>{const a=s.toLowerCase();return a.includes("wda-signed")||a.includes("wda-resign")||a.includes("webdriveragent")};return e.jsxs("div",{className:"apps-container device-explorer-container",children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsx(se,{icon:J,title:"App Repository",subtitle:"Manage signed builds available for installation across your device fleet."}),e.jsxs("div",{className:"device-explorer-header-container",children:[e.jsxs("div",{className:"device-explorer-header-left-container",children:[e.jsx("div",{className:"device-explorer-header-entry",children:e.jsxs("div",{className:"device-explorer-header-value",children:[e.jsxs("button",{className:`device-explorer-header__platform-btn ${d.android&&"selected"}`,onClick:()=>z("android"),children:[e.jsx(S,{size:18,color:"currentColor"})," Android"]}),e.jsxs("button",{className:`device-explorer-header__platform-btn ${d.ios&&"selected"}`,onClick:()=>z("ios"),children:[e.jsx(M,{size:18,color:"currentColor"})," iOS"]})]})}),e.jsx("div",{className:"device-explorer-header-entry",children:e.jsx("div",{className:"device-explorer-header-value",children:e.jsxs("div",{className:"device-explorer-search-wrapper",children:[e.jsx(W,{size:16,color:"#94a3b8",className:"device-explorer-search-icon"}),e.jsx("input",{type:"text",className:"device-explorer-header-text-filter",placeholder:"Filter by bundle or name...",value:v,onChange:s=>$(s.target.value)})]})})}),e.jsx("div",{className:"device-explorer-header-filter-count",children:e.jsxs(I,{variant:"secondary",children:[e.jsx("span",{className:"font-bold",children:p.length})," of"," ",e.jsx("span",{className:"font-bold",children:c.length})," ",c.length===1?"artifact":"artifacts"]})})]}),e.jsxs("div",{className:"device-explorer-header-right-container",children:[e.jsx("button",{className:"icon-btn-secondary sort-btn",onClick:()=>U(s=>s==="desc"?"asc":"desc"),title:y==="desc"?"Newest First":"Oldest First",children:y==="desc"?e.jsx(oe,{size:18}):e.jsx(me,{size:18})}),e.jsxs(D,{size:"sm",variant:"default",onClick:()=>h(),disabled:o,children:[e.jsx(X,{size:14,className:`mr-1 ${o&&"animate-spin"}`}),"Refresh"]}),e.jsxs("label",{className:"upload-trigger",children:[e.jsx("input",{type:"file",accept:".apk,.ipa",onChange:C,style:{display:"none"}}),e.jsxs(D,{size:"sm",variant:"default",className:"upload-button",children:[e.jsx(Q,{size:14,className:"mr-1"}),"Upload App"]})]})]})]}),e.jsx("main",{className:"apps-registry-content",children:o&&c.length===0?e.jsxs("div",{className:"empty-data-vignette",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("p",{className:"text-muted text-xs font-bold tracking-widest",children:"SYNCING REGISTRY..."})]}):e.jsxs(e.Fragment,{children:[p.length>0&&e.jsxs("div",{className:"registry-table-header",children:[e.jsx("div",{children:"Artifact Bundle"}),e.jsx("div",{children:"Version"}),e.jsx("div",{children:"Size"}),e.jsx("div",{children:"Registry Date"}),e.jsx("div",{style:{textAlign:"right"},children:"Management"})]}),e.jsx("div",{className:"registry-list",children:p.map(s=>{const a=E.filter(t=>t.platform===s.platform&&!t.busy&&!t.offline);return e.jsxs("div",{className:`artifact-row ${s.platform}`,children:[e.jsxs("div",{className:"col-app-info",children:[e.jsx("div",{className:"app-platform-badge",children:s.platform==="android"?e.jsx(S,{size:18}):e.jsx(M,{size:18})}),e.jsxs("div",{className:"app-text-block",children:[e.jsxs("div",{className:"app-display-name",title:s.name,children:[s.name,V(s.name)&&e.jsx(I,{variant:"outline",className:"ml-2 text-[10px] h-4 py-0 border-primary text-primary",children:"WDA"})]}),e.jsxs("div",{className:"app-package-id",children:[e.jsx("code",{children:s.packageName||"internal.bundle"}),e.jsx("div",{className:"copy-hint",onClick:()=>P(s.packageName||"","pkg"),children:L===`pkg-${s.packageName}`?e.jsx(ae,{size:10,className:"text-primary"}):e.jsx(te,{size:10})})]})]})]}),e.jsx("div",{className:"col-version",children:s.version||"v1.0.0"}),e.jsx("div",{className:"col-size",children:O(s.size)}),e.jsx("div",{className:"col-timestamp",children:Y(s.createdAt)}),e.jsxs("div",{className:"col-actions",children:[e.jsx("button",{className:`instant-deploy-trigger ${m===s.id&&"active"}`,onClick:()=>{m===s.id?(j(null),f("")):j(s.id)},children:m===s.id?e.jsxs(e.Fragment,{children:[e.jsx(H,{size:12})," CANCEL"]}):e.jsxs(e.Fragment,{children:[e.jsx(re,{size:12})," DEPLOY"]})}),m===s.id&&e.jsx("div",{className:"deployment-flyout",children:a.length>0?e.jsxs("div",{className:"deploy-actions-group",children:[e.jsxs("select",{className:"target-device-select",autoFocus:!0,value:g,onChange:t=>f(t.target.value),children:[e.jsx("option",{value:"",children:"SELECT TARGET..."}),a.map(t=>e.jsxs("option",{value:t.udid,children:[t.name.toUpperCase()," (",t.udid,")"]},t.udid))]}),e.jsx("button",{className:"confirm-deploy-btn",disabled:!g,onClick:()=>G(s.id,g),title:"Confirm Deployment",children:e.jsx(T,{size:14})})]}):e.jsx("div",{className:"target-device-select empty",children:"NO TARGETS"})}),e.jsx("button",{className:"utility-icon-btn",onClick:()=>window.open(`/xenon/api/apps/${s.id}/download`,"_blank"),children:e.jsx(ie,{size:14})}),e.jsx("button",{className:"utility-icon-btn danger",onClick:()=>B(s.id,s.name),children:e.jsx(ne,{size:14})})]})]},s.id)})}),p.length===0&&!o&&e.jsxs("div",{className:"empty-registry-technical",children:[e.jsx("div",{className:"empty-icon-container",children:e.jsx(ee,{size:48,className:"text-primary opacity-40 animate-pulse"})}),e.jsx("h2",{className:"empty-title brand-font",children:"Centralized Artifact Registry"}),e.jsxs("p",{className:"empty-description",children:["The Xenon Registry is a secure, high-performance vault for your mobile binaries. Upload your ",e.jsx("code",{className:"text-primary",children:".apk"})," or"," ",e.jsx("code",{className:"text-primary",children:".ipa"}),"artifacts to enable rapid deployment, version tracking, and instant installation across your entire device fleet."]}),e.jsx("div",{className:"empty-actions",children:e.jsxs("label",{className:"upload-trigger-massive",children:[e.jsx("input",{type:"file",accept:".apk,.ipa",onChange:C,style:{display:"none"}}),e.jsxs("div",{className:"massive-upload-content",children:[e.jsx(T,{size:24,className:"mb-2"}),e.jsx("span",{children:"Ingest Your First Artifact"})]})]})})]})]})}),F&&e.jsx("div",{className:"upload-overlay-technical",children:e.jsxs("div",{className:"upload-card-technical",children:[e.jsx("div",{className:"processing-loader"}),e.jsx("h2",{className:"brand-font",style:{fontSize:"20px",marginBottom:"8px"},children:"Artifact Ingestion"}),e.jsx("p",{className:"text-muted text-xs",children:"VERIFYING CHECKSUM & DEPLOYING TO REGISTRY..."})]})})]})};export{be as default};
@@ -1 +0,0 @@
1
- .apps-container{display:flex;flex-direction:column;height:100%;width:100%}.apps-registry-content{flex:1;overflow-y:auto;padding:0 24px 24px;background:var(--bg)}.registry-table-header{display:grid;grid-template-columns:3fr 1fr 1fr 1.5fr 1.5fr;padding:12px 24px;border-bottom:2px solid var(--border);color:var(--text-dim);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;background:#0003;font-family:JetBrains Mono,monospace}.registry-list{display:flex;flex-direction:column}.artifact-row{display:grid;grid-template-columns:3fr 1fr 1fr 1.5fr 1.5fr;align-items:center;padding:12px 24px;background:#0000001a;border-bottom:1px solid var(--border);transition:all .2s ease;position:relative}.artifact-row:hover{background:#ffffff05}.artifact-row.active{background:#00ff880d;border-left:3px solid var(--green)}.col-app-info{display:flex;align-items:center;gap:16px;min-width:0}.app-platform-badge{width:32px;height:32px;background:#0006;border:1px solid var(--border);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--text-dim)}.artifact-row.android .app-platform-badge{color:var(--green);border-color:#0f83}.artifact-row.ios .app-platform-badge{color:var(--text);border-color:var(--border)}.app-text-block{display:flex;flex-direction:column;min-width:0}.app-display-name{font-size:13px;font-weight:700;color:var(--text);font-family:Outfit,sans-serif;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase}.app-package-id{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);opacity:.8;display:flex;align-items:center;gap:6px}.col-version{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--green);font-weight:600}.col-size{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-muted)}.col-timestamp{font-size:11px;color:var(--text-dim);font-family:JetBrains Mono,monospace;text-transform:uppercase}.col-actions{display:flex;align-items:center;justify-content:flex-end;gap:12px}.instant-deploy-trigger{height:28px;background:#00ff880d;border:1px solid var(--green);border-radius:6px;padding:0 12px;display:flex;align-items:center;gap:8px;color:var(--green);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;transition:all .2s;cursor:pointer}.instant-deploy-trigger:hover:not(:disabled){background:var(--green);color:var(--bg);box-shadow:0 0 20px #0f83}.utility-icon-btn{width:28px;height:28px;background:#0000004d;border:1px solid var(--border);border-radius:6px;display:flex;align-items:center;justify-content:center;color:var(--text-dim);transition:all .2s}.utility-icon-btn:hover{border-color:var(--border);color:var(--text)}.utility-icon-btn.danger:hover{color:var(--status-error-fg)}.device-explorer-header-container{display:flex;justify-content:space-between;align-items:center;padding:12px 24px;background:#0f0f1a66;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);z-index:100;gap:16px;flex-wrap:wrap}.device-explorer-header-left-container{display:flex;align-items:center;gap:24px;flex:1;min-width:0;flex-wrap:wrap}.device-explorer-header-right-container{display:flex;align-items:center;gap:12px}.device-explorer-header-filter-count{margin-left:8px}@media (max-width: 900px){.device-explorer-header-container{flex-direction:column;align-items:stretch;padding:12px 16px}.device-explorer-header-left-container{flex-direction:column;align-items:stretch;gap:12px}.device-explorer-header-left-container>*{width:100%;min-width:0}.device-explorer-header-right-container{justify-content:flex-end;flex-wrap:wrap}}.icon-btn-secondary{width:32px;height:32px;background:#ffffff08;border:1px solid var(--border);border-radius:6px;display:flex;align-items:center;justify-content:center;color:var(--text-dim);cursor:pointer;transition:all .2s ease}.icon-btn-secondary:hover{background:#ffffff14;color:var(--text);border-color:var(--border)}.deployment-flyout{position:absolute;top:50%;padding:6px;right:180px;transform:translateY(-50%);background:var(--surface);border:1px solid var(--green);border-radius:8px;box-shadow:0 10px 40px #0009;z-index:110;display:flex;gap:4px;animation:slideInRight .2s cubic-bezier(.16,1,.3,1)}@keyframes slideInRight{0%{opacity:0;transform:translateY(-50%) translate(10px)}to{opacity:1;transform:translateY(-50%) translate(0)}}.target-device-select{height:32px;background:#00000040;border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:11px;font-weight:600;padding:0 12px;min-width:280px;outline:none;cursor:pointer;transition:all .2s ease;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center}.target-device-select:hover{border-color:var(--green);background-color:#0006}.target-device-select option{background:var(--surface);color:var(--text);padding:8px}.target-device-select.empty{display:flex;align-items:center;justify-content:center;padding:0 20px;height:32px;font-style:italic;opacity:.5;font-size:11px}.deploy-actions-group{display:flex;align-items:center;gap:6px}.confirm-deploy-btn{width:32px;height:32px;background:var(--green);border:none;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#000;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.confirm-deploy-btn:hover:not(:disabled){background:var(--green-dim);transform:scale(1.05);box-shadow:0 0 15px var(--accent-subtle)}.confirm-deploy-btn:disabled{background:#ffffff1a;color:#fff3;cursor:not-allowed}.upload-overlay-technical{position:fixed;top:0;right:0;bottom:0;left:0;background:#020617d9;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);z-index:2000;display:flex;align-items:center;justify-content:center}.upload-card-technical{width:420px;background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:40px;text-align:center;box-shadow:0 30px 60px #0009}.processing-loader{width:40px;height:40px;border:2px solid rgba(34,197,94,.1);border-top-color:var(--green);border-radius:50%;margin:0 auto 20px;animation:spin 1s linear infinite}.empty-registry-technical{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:100px 20px;text-align:center;max-width:600px;margin:0 auto}.empty-icon-container{width:100px;height:100px;background:radial-gradient(circle,rgba(59,130,246,.1) 0%,transparent 70%);display:flex;align-items:center;justify-content:center;border-radius:50%;margin-bottom:24px}.empty-title{font-size:28px;font-weight:800;color:var(--text);margin-bottom:16px;letter-spacing:-.02em}.empty-description{font-size:14px;line-height:1.6;color:var(--text-muted);margin-bottom:40px}.empty-description code{background:#3b82f61a;padding:2px 6px;border-radius:4px;font-weight:600}.upload-trigger-massive{cursor:pointer;display:block}.massive-upload-content{display:flex;flex-direction:column;align-items:center;padding:30px 60px;background:var(--surface);border:1px solid var(--green);box-shadow:0 0 15px #00ff881a;border-radius:8px;color:var(--green);font-weight:700;font-size:16px;transition:all .3s cubic-bezier(.4,0,.2,1);box-shadow:0 0 0 transparent}.massive-upload-content:hover{background:#3b82f60d;transform:translateY(-4px);box-shadow:0 10px 30px #3b82f626;border-style:solid}.massive-upload-content svg{transition:transform .3s ease}.massive-upload-content:hover svg{transform:translateY(-4px) scale(1.1)}.copy-hint{cursor:pointer;opacity:.4;transition:opacity .2s}.copy-hint:hover{opacity:1}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 1400px){.apps-registry-content{padding:var(--space-4) 24px}}.badge-base{display:inline-flex;align-items:center;gap:6px;border-radius:6px;border:1px solid transparent;padding:2px 8px;font-size:11px;font-weight:800;transition:all .2s ease;white-space:nowrap;text-transform:uppercase;letter-spacing:.05em;font-family:JetBrains Mono,monospace}.badge-variant-default{background:#0000004d;color:var(--text-dim);border-color:var(--border)}.badge-variant-success{background:#00ff880d;color:var(--green);border-color:#0f83}.badge-variant-warning{background:#ffc1070d;color:#ffc107;border-color:#ffc10733}.badge-variant-error{background:#ff4d4d0d;color:#ff4d4d;border-color:#ff4d4d33}.badge-variant-secondary{background:var(--surface);color:var(--text);border-color:var(--border)}.badge-variant-outline{background:transparent;color:var(--text-dim);border:1px solid var(--border)}.badge-variant-outline:hover{color:var(--text);border-color:var(--text-muted)}
@@ -1,6 +0,0 @@
1
- import{g as F,j as e,o as E,k as y,T as O,S as M,r as b,u as P,c as z,m as G,X}from"./index-BrVV0Kla.js";import{f as B,s as R,b as T,d as q,p as H,o as Q,S as V,h as J,a as K,u as W}from"./status-pill-outline-Cc4PF7Mg.js";import{A as Y}from"./activity-DK3R5GAb.js";import{C as Z}from"./circle-x-x7R8vTBo.js";import{C as ee}from"./circle-check--2DSsfaI.js";import{C as te}from"./clock-DIpGd4Pn.js";import{D as se}from"./download-CaKkGvKw.js";import{C as re}from"./chevron-right-WELZ1Z8v.js";import{T as ae,M as ne}from"./tablet-CaOqzQv_.js";import"./useSocket-Bkt5i-U6.js";/**
2
- * @license lucide-react v0.555.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const le=[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]],oe=F("refresh-ccw",le),ie={neutral:"bg-[var(--surface-2)] text-[var(--text-muted)] border-[var(--border)]",green:"bg-[var(--green)]/15 text-[var(--green)] border-[var(--green)]/30",red:"bg-[var(--red)]/15 text-[var(--red)] border-[var(--red)]/30",amber:"bg-[var(--amber)]/15 text-[var(--amber)] border-[var(--amber)]/30"},w=({value:t,tone:s="neutral"})=>e.jsx("span",{className:`inline-flex items-center justify-center min-w-[18px] h-[18px] px-1.5 rounded-full border text-[10px] font-mono font-medium ${ie[s]}`,children:t}),de={passed:{Icon:ee,label:"PASSED",tint:"text-[var(--green)]"},failed:{Icon:Z,label:"FAILED",tint:"text-[var(--red)]"},running:{Icon:Y,label:"RUNNING",tint:"text-[var(--amber)]"}},C=({kind:t,value:s})=>{const{Icon:r,label:i,tint:c}=de[t];return e.jsxs("div",{className:"flex-1 flex flex-col items-center gap-1 py-2 rounded-md border border-[var(--border)] bg-[var(--bg)]",children:[e.jsx(r,{className:`h-3.5 w-3.5 ${c}`}),e.jsx("span",{className:`text-[9px] font-mono font-semibold tracking-wider ${c}`,children:i}),e.jsx("span",{className:"text-sm font-semibold text-[var(--text)] tabular-nums",children:s})]})},I={all:"All time","24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days"},ce=({builds:t,selectedBuildId:s,onSelect:r,search:i,onSearchChange:c,timeFilter:x,onTimeFilterChange:m})=>{const l=t.filter(a=>{const d=(a.name??"")+" "+a.id;if(i&&!d.toLowerCase().includes(i.toLowerCase()))return!1;if(x!=="all"){const n={"24h":864e5,"7d":6048e5,"30d":2592e6},p=Date.parse(String(a.createdAt));if(!Number.isFinite(p)||Date.now()-p>n[x])return!1}return!0}),o=l.reduce((a,d)=>(a.passed+=d.passedCount||0,a.failed+=d.failedCount||0,a.running+=d.runningCount||0,a),{passed:0,failed:0,running:0});return e.jsxs("aside",{className:"w-[280px] shrink-0 border-r border-[var(--border)] bg-[var(--surface)] flex flex-col",children:[e.jsxs("div",{className:"p-3 space-y-2 border-b border-[var(--border)]",children:[e.jsxs("div",{className:"relative",children:[e.jsx(E,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx("input",{type:"text",value:i,onChange:a=>c(a.target.value),placeholder:"Find builds…",className:"w-full h-8 pl-8 pr-2 rounded-md bg-[var(--bg)] border border-[var(--border)] text-xs text-[var(--text)] placeholder:text-[var(--text-dim)] focus:outline-none focus:border-[var(--border-strong)]"})]}),e.jsx("select",{value:x,onChange:a=>m(a.target.value),className:"w-full h-8 px-2 rounded-md bg-[var(--bg)] border border-[var(--border)] text-xs text-[var(--text-muted)]",children:Object.keys(I).map(a=>e.jsx("option",{value:a,children:I[a]},a))})]}),e.jsxs("div",{className:"p-3 flex items-stretch gap-2 border-b border-[var(--border)]",children:[e.jsx(C,{kind:"passed",value:o.passed}),e.jsx(C,{kind:"failed",value:o.failed}),e.jsx(C,{kind:"running",value:o.running})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[l.length===0&&e.jsx("div",{className:"px-4 py-8 text-center text-xs text-[var(--text-dim)]",children:"No builds match."}),l.map(a=>{const d=a.id===s;return e.jsxs("button",{type:"button",onClick:()=>r(a.id),className:`w-full text-left relative px-4 py-3 border-b border-[var(--border)] transition-colors ${d?"bg-[var(--surface-2)]":"hover:bg-[var(--surface-2)]/60"}`,children:[d&&e.jsx("span",{className:"absolute left-0 top-2 bottom-2 w-[3px] rounded-r bg-[var(--green)]"}),e.jsx("div",{className:"text-xs font-semibold text-[var(--text)] truncate",children:a.name||"Unnamed build"}),e.jsxs("div",{className:"mt-1 flex items-center gap-1 font-mono text-[9px] text-[var(--text-dim)]",children:[e.jsx(te,{className:"h-3 w-3"}),B(a.createdAt)]}),e.jsxs("div",{className:"mt-1.5 flex items-center gap-1.5",children:[a.passedCount>0&&e.jsx(w,{value:a.passedCount,tone:"green"}),a.failedCount>0&&e.jsx(w,{value:a.failedCount,tone:"red"}),a.runningCount>0&&e.jsx(w,{value:a.runningCount,tone:"amber"}),a.sessionCount===0&&e.jsx("span",{className:"text-[10px] font-mono text-[var(--text-dim)]",children:"empty"})]}),e.jsx("div",{className:"mt-1 font-mono text-[9px] text-[var(--text-dim)] truncate",children:R(a.id,10,4)})]},a.id)})]})]})},xe={neutral:"bg-[var(--text-dim)]",green:"bg-[var(--green)]",red:"bg-[var(--red)]",amber:"bg-[var(--amber)]",blue:"bg-[var(--blue)]"},N=({label:t,count:s,active:r,onClick:i,tone:c="neutral",bullet:x=!0})=>e.jsxs("button",{type:"button",onClick:i,"aria-pressed":r,className:`inline-flex items-center gap-2 h-8 px-3 rounded-md border text-[11px] font-semibold uppercase tracking-wider transition-colors cursor-pointer ${r?"bg-[var(--surface-2)] border-[var(--border-strong)] text-[var(--text)]":"bg-transparent border-transparent text-[var(--text-muted)] hover:text-[var(--text)] hover:bg-[var(--surface-2)]/50"}`,children:[x&&c!=="neutral"&&e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${xe[c]}`}),e.jsx("span",{children:t}),typeof s=="number"&&e.jsx("span",{className:"font-mono text-[10px] text-[var(--text-dim)]",children:s})]}),ue=({sessions:t,active:s,onChange:r,search:i,onSearchChange:c,totalMatching:x,totalUnfiltered:m})=>{const l=T(t);return e.jsxs("div",{className:"bg-[var(--surface)]",children:[e.jsxs("div",{className:"flex items-center gap-1.5 px-4 pt-3 pb-2",children:[e.jsx(N,{label:"ALL",count:l.all,active:s==="all",onClick:()=>r("all"),tone:"neutral",bullet:!1}),e.jsx(N,{label:"PASSED",count:l.passed,active:s==="passed",onClick:()=>r("passed"),tone:"green"}),e.jsx(N,{label:"FAILED",count:l.failed,active:s==="failed",onClick:()=>r("failed"),tone:"red"}),e.jsx(N,{label:"RUNNING",count:l.running,active:s==="running",onClick:()=>r("running"),tone:"amber"})]}),e.jsxs("div",{className:"flex items-center gap-4 px-4 pb-3 border-b border-[var(--border)]",children:[e.jsxs("div",{className:"relative flex-1 max-w-xl",children:[e.jsx(E,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx("input",{type:"text",value:i,onChange:o=>c(o.target.value),placeholder:"Search sessions by ID, name, or device…",className:"w-full h-8 pl-8 pr-2 rounded-md bg-[var(--bg)] border border-[var(--border)] text-xs text-[var(--text)] placeholder:text-[var(--text-dim)] focus:outline-none focus:border-[var(--border-strong)]"})]}),e.jsxs("span",{className:"text-[10px] font-mono text-[var(--text-dim)] whitespace-nowrap",children:[x," of ",m," sessions"]})]})]})};function me(t){return(t.split("-")[0]||t).slice(0,8).toUpperCase()}const pe=({build:t,failedCount:s,selectedCount:r,onRetryFailed:i,onExport:c})=>{const x=s>0||r>0,[m,l]=y.useState(!1),o=y.useRef(null);y.useEffect(()=>{const d=n=>{o.current&&!o.current.contains(n.target)&&l(!1)};return document.addEventListener("mousedown",d),()=>document.removeEventListener("mousedown",d)},[]);const a=x?`Retry ${r||s} session${(r||s)===1?"":"s"}`:"No failed sessions to retry";return e.jsxs("header",{className:"flex items-start justify-between gap-4 px-4 py-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 text-[10px] uppercase tracking-widest text-[var(--text-dim)]",children:[e.jsx("span",{children:"Build"}),e.jsxs("span",{className:"font-mono text-[var(--green)]",title:t.id,children:["#",me(t.id)]})]}),e.jsx("h1",{className:"mt-0.5 text-sm font-semibold text-[var(--text)]",children:t.name||"Unnamed build"})]}),e.jsxs("div",{className:"flex items-center gap-2",ref:o,children:[e.jsxs("button",{type:"button",onClick:i,disabled:!x,title:a,className:"inline-flex items-center gap-1.5 h-8 px-3 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors disabled:opacity-40 disabled:cursor-not-allowed",children:[e.jsx(oe,{className:"h-3.5 w-3.5"}),"Retry failed"]}),e.jsxs("div",{className:"relative",children:[e.jsxs("button",{type:"button",onClick:()=>l(d=>!d),className:"inline-flex items-center gap-1.5 h-8 px-3 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors",children:[e.jsx(se,{className:"h-3.5 w-3.5"}),"Export"]}),m&&e.jsxs("div",{className:"absolute top-full right-0 mt-1 w-40 rounded-md border border-[var(--border)] bg-[var(--surface)] shadow-lg overflow-hidden z-20",children:[e.jsx("button",{type:"button",onClick:()=>{l(!1),c("json")},className:"w-full text-left px-3 py-2 text-xs text-[var(--text)] hover:bg-[var(--surface-2)]",children:"Export as JSON"}),e.jsx("button",{type:"button",onClick:()=>{l(!1),c("csv")},className:"w-full text-left px-3 py-2 text-xs text-[var(--text)] hover:bg-[var(--surface-2)]",children:"Export as CSV"})]})]})]})]})};function fe({platform:t}){const s=(t||"").toLowerCase();return s.includes("tv")?e.jsx(O,{className:"h-3.5 w-3.5"}):s.includes("pad")||s.includes("tablet")?e.jsx(ae,{className:"h-3.5 w-3.5"}):s.includes("android")||s.includes("ios")?e.jsx(M,{className:"h-3.5 w-3.5"}):e.jsx(ne,{className:"h-3.5 w-3.5"})}function he(t){return t==="running"?{label:"RUNNING",tone:"running"}:t==="failed"?{label:"FAILED",tone:"failed"}:t==="ended"||t==="passed"?{label:"PASSED",tone:"passed"}:{label:t.toUpperCase(),tone:"offline"}}const ve=({session:t,selected:s,onToggleSelect:r,onOpen:i})=>{const c=t.status==="failed",x=he(t.status),m=q(t),l=c&&t.failure_reason?t.failure_reason:t.name??"";return e.jsxs("tr",{onClick:i,className:"group border-b border-[var(--border)] hover:bg-[var(--surface-2)] cursor-pointer transition-colors align-top",children:[e.jsx("td",{className:"px-3 py-3",onClick:o=>o.stopPropagation(),children:e.jsx("input",{type:"checkbox",checked:s,onChange:r,"aria-label":`Select session ${t.id}`})}),e.jsxs("td",{className:"px-3 py-3",children:[e.jsxs("div",{className:"font-mono text-xs text-[var(--green)]",title:t.id,children:["#",R(t.id,14,4)]}),l&&e.jsx("div",{className:"mt-0.5 text-[11px] text-[var(--text-muted)] truncate max-w-[420px]",title:l,children:l})]}),e.jsxs("td",{className:"px-3 py-3",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-[var(--text)]",children:[e.jsx(fe,{platform:t.device_platform}),e.jsx("span",{className:"truncate max-w-[160px]",children:m})]}),t.node_id&&e.jsxs("div",{className:"mt-0.5 font-mono text-[10px] text-[var(--text-dim)]",children:["node-",t.node_id]})]}),e.jsxs("td",{className:"px-3 py-3",children:[e.jsx("div",{className:"text-xs text-[var(--text)]",children:H(t)}),t.device_version&&e.jsx("div",{className:"mt-0.5 font-mono text-[10px] text-[var(--text-dim)]",children:Q(t)})]}),e.jsx("td",{className:"px-3 py-3",children:e.jsx(V,{label:x.label,tone:x.tone})}),e.jsx("td",{className:"px-3 py-3 font-mono text-[11px] text-[var(--text-muted)] whitespace-nowrap",children:B(t.startTime)}),e.jsx("td",{className:"px-3 py-3 font-mono text-[11px] text-[var(--text-muted)] whitespace-nowrap text-right",children:J(K(t))}),e.jsx("td",{className:"px-3 py-3 text-right",children:e.jsx(re,{className:"inline h-4 w-4 text-[var(--text-dim)] group-hover:text-[var(--text)]"})})]})};function be(t,s){return s==="all"?!0:s==="passed"?t.status==="ended"||t.status==="passed":s==="failed"?t.status==="failed":s==="running"?t.status==="running":!0}const ge=({sessions:t,statusFilter:s,searchQuery:r,selectedIds:i,onToggleSelect:c,onToggleSelectAll:x,onOpenRow:m,buildHasNoSessions:l})=>{const o=b.useMemo(()=>{const n=r.trim().toLowerCase();return t.filter(p=>!(!be(p,s)||n&&!(p.id+" "+(p.name??"")+" "+(p.device_name??"")+" "+(p.device_platform??"")+" "+(p.device_version??"")+" "+(p.node_id??"")).toLowerCase().includes(n)))},[t,s,r]);if(l)return e.jsx("div",{className:"px-4 py-12 text-center text-xs text-[var(--text-dim)]",children:"No sessions in this build yet. Trigger one from your test runner."});if(o.length===0)return e.jsx("div",{className:"px-4 py-12 text-center text-xs text-[var(--text-dim)]",children:"No sessions match the current filters."});const a=o.length>0&&o.every(n=>i.has(n.id)),d=o.some(n=>i.has(n.id));return e.jsx("div",{className:"flex-1 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-left",children:[e.jsx("thead",{className:"sticky top-0 bg-[var(--surface)] border-b border-[var(--border)] z-10",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-3 py-2 w-[36px]",children:e.jsx("input",{type:"checkbox","aria-label":"Select all visible",checked:a,ref:n=>{n&&(n.indeterminate=d&&!a)},onChange:()=>x(o.map(n=>n.id))})}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium",children:"Session"}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium",children:"Device · Node"}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium",children:"Platform"}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium",children:"Status"}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium",children:"Start Time"}),e.jsx("th",{className:"px-3 py-2 text-[10px] uppercase tracking-wider text-[var(--text-dim)] font-medium text-right",children:"Duration"}),e.jsx("th",{className:"px-3 py-2 w-[32px]"})]})}),e.jsx("tbody",{children:o.map(n=>e.jsx(ve,{session:n,selected:i.has(n.id),onToggleSelect:()=>c(n.id),onOpen:()=>m(n)},n.id))})]})})},Be=()=>{const t=P(),{buildId:s}=z(),r=W(),{toast:i}=G(),[c,x]=b.useState("all"),[m,l]=b.useState("all"),[o,a]=b.useState(""),[d,n]=b.useState(new Set);y.useEffect(()=>{s&&s!==r.selectedBuildId&&(r.selectBuild(s),n(new Set))},[s,r]);const p=u=>t(`/builds/${u}`),S=u=>t(`/builds/${r.selectedBuildId}/sessions/${u.id}`),A=b.useCallback(u=>{n(f=>{const h=new Set(f);return h.has(u)?h.delete(u):h.add(u),h})},[]),D=b.useCallback(u=>{n(f=>{const h=u.length>0&&u.every(v=>f.has(v)),g=new Set(f);return h?u.forEach(v=>g.delete(v)):u.forEach(v=>g.add(v)),g})},[]),k=r.builds.find(u=>u.id===r.selectedBuildId)||null,$=T(r.sessions),U=()=>{i("Bulk retry lands in a future release.","info")},_=async u=>{if(r.selectedBuildId)try{const f=d.size>0?Array.from(d):void 0,{blob:h,filename:g}=await X.exportBuild(r.selectedBuildId,u,f),v=URL.createObjectURL(h),j=document.createElement("a");j.href=v,j.download=g,document.body.appendChild(j),j.click(),document.body.removeChild(j),URL.revokeObjectURL(v);const L=f?f.length:"all";i(`Exported ${L} session${L===1?"":"s"} as ${u.toUpperCase()}.`,"success")}catch(f){const h=f instanceof Error?f.message:String(f);i(`Export failed: ${h}`,"error")}};return e.jsxs("div",{className:"flex h-full",children:[e.jsx(ce,{builds:r.builds,selectedBuildId:r.selectedBuildId,onSelect:p,search:r.searchQuery,onSearchChange:r.setSearchQuery,timeFilter:c,onTimeFilterChange:x}),e.jsx("section",{className:"flex-1 flex flex-col min-w-0",children:k?e.jsxs(e.Fragment,{children:[e.jsx(pe,{build:k,failedCount:$.failed,selectedCount:d.size,onRetryFailed:U,onExport:_}),e.jsx(ue,{sessions:r.sessions,active:m,onChange:l,search:o,onSearchChange:a,totalMatching:r.sessions.length,totalUnfiltered:r.sessions.length}),e.jsx(ge,{sessions:r.sessions,statusFilter:m,searchQuery:o,selectedIds:d,onToggleSelect:A,onToggleSelectAll:D,onOpenRow:S,buildHasNoSessions:r.sessions.length===0})]}):e.jsx("div",{className:"flex-1 flex items-center justify-center text-xs text-[var(--text-dim)]",children:"Select a build from the left to see its sessions."})})]})};export{Be as BuildsPage,Be as default};