@xenon-device-management/xenon 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +74 -0
  2. package/lib/package.json +1 -1
  3. package/lib/public/assets/{Layouts-D0WSzKOh.js → Layouts-D6IPfwoe.js} +1 -1
  4. package/lib/public/assets/{ai-settings-DQWDdNd7.js → ai-settings-CflyFKan.js} +1 -1
  5. package/lib/public/assets/{apps-1sLWHOGO.js → apps-Da4dvQ1J.js} +1 -1
  6. package/lib/public/assets/{badge-BiR1gmMm.js → badge-BNR9umdu.js} +1 -1
  7. package/lib/public/assets/{button-BVazt4Z1.js → button-hZFV1ypT.js} +1 -1
  8. package/lib/public/assets/{calendar-yMyP2_Nc.js → calendar-fehdBtun.js} +1 -1
  9. package/lib/public/assets/{clock-CsVplnJ2.js → clock-DrpxSvCL.js} +1 -1
  10. package/lib/public/assets/{cpu-DNC8n7kK.js → cpu-tuyMVZ4I.js} +1 -1
  11. package/lib/public/assets/{device-explorer-DFu8Gxj4.js → device-explorer-DOfRH3zm.js} +1 -1
  12. package/lib/public/assets/{index-S71J2rWg.js → index-BaTiUCeH.js} +18 -18
  13. package/lib/public/assets/{lock-BstCxnX6.js → lock-C6CoqSr2.js} +1 -1
  14. package/lib/public/assets/{maintenance-settings-BwfG9cu2.js → maintenance-settings-CM2oC7-i.js} +1 -1
  15. package/lib/public/assets/{mouse-pointer-2-CSn_Wnc9.js → mouse-pointer-2-CXdnjXIg.js} +1 -1
  16. package/lib/public/assets/{plus-DfjM7G6e.js → plus-B4B1Hukt.js} +1 -1
  17. package/lib/public/assets/{session-dashboard-C6ek4z65.js → session-dashboard-B5OPMTz5.js} +1 -1
  18. package/lib/public/assets/{settings-BDYP8ULf.js → settings-BTHP7fj3.js} +1 -1
  19. package/lib/public/assets/{trash-2-CZWUMK5b.js → trash-2-NJMZJ2Ol.js} +1 -1
  20. package/lib/public/assets/{useSocket-CliVeWS3.js → useSocket-Ct2wo7P2.js} +2 -2
  21. package/lib/public/assets/{webhook-settings-tPiwWf8y.js → webhook-settings-Cz35-QJ7.js} +1 -1
  22. package/lib/public/assets/{zap-ZrK5B58i.js → zap-CssSMAN5.js} +1 -1
  23. package/lib/public/index.html +1 -1
  24. package/lib/schema.json +85 -38
  25. package/lib/src/InternalHttpClient.js +69 -14
  26. package/lib/src/app/index.js +92 -24
  27. package/lib/src/app/routers/apikeys.js +33 -0
  28. package/lib/src/app/routers/apps.js +4 -0
  29. package/lib/src/app/routers/auth.js +36 -0
  30. package/lib/src/app/routers/config.js +4 -0
  31. package/lib/src/app/routers/control.js +61 -10
  32. package/lib/src/app/routers/dashboard.js +5 -6
  33. package/lib/src/app/routers/grid.js +30 -12
  34. package/lib/src/app/routers/processes.js +24 -0
  35. package/lib/src/app/routers/reservation.js +15 -0
  36. package/lib/src/app/routers/webhook.js +6 -3
  37. package/lib/src/auth/nodeSecret.js +33 -0
  38. package/lib/src/config.js +5 -0
  39. package/lib/src/data-service/prisma-store.js +17 -1
  40. package/lib/src/device-managers/AndroidDeviceManager.js +2 -2
  41. package/lib/src/device-managers/NodeDevices.js +8 -1
  42. package/lib/src/device-managers/ios/IOSDiscoveryService.js +7 -4
  43. package/lib/src/device-managers/ios/IOSStreamService.js +7 -0
  44. package/lib/src/device-managers/ios/WDAClient.js +2 -0
  45. package/lib/src/device-utils.js +29 -4
  46. package/lib/src/generated/client/edge.js +2 -2
  47. package/lib/src/generated/client/index.js +2 -2
  48. package/lib/src/generated/client/package.json +1 -1
  49. package/lib/src/generated/client/schema.prisma +3 -0
  50. package/lib/src/helpers/UniversalMjpegProxy.js +23 -0
  51. package/lib/src/index.js +10 -2
  52. package/lib/src/interceptors/CommandInterceptor.js +29 -0
  53. package/lib/src/interfaces/IPluginArgs.js +0 -1
  54. package/lib/src/logger.js +30 -2
  55. package/lib/src/logging/sessionContext.js +28 -0
  56. package/lib/src/middleware/apiKeyMiddleware.js +49 -0
  57. package/lib/src/middleware/csrfMiddleware.js +73 -0
  58. package/lib/src/middleware/nodeSecretMiddleware.js +38 -0
  59. package/lib/src/middleware/rateLimitMiddleware.js +68 -0
  60. package/lib/src/middleware/scopeGuard.js +41 -0
  61. package/lib/src/plugin.js +1 -1
  62. package/lib/src/services/AIService.js +43 -8
  63. package/lib/src/services/ApiKeyService.js +102 -0
  64. package/lib/src/services/CircuitBreaker.js +158 -0
  65. package/lib/src/services/CleanupService.js +137 -39
  66. package/lib/src/services/DeviceReconciler.js +102 -0
  67. package/lib/src/services/MetricsService.js +78 -0
  68. package/lib/src/services/PortAllocator.js +13 -0
  69. package/lib/src/services/ProcessMetricsService.js +99 -0
  70. package/lib/src/services/ProcessRegistry.js +123 -0
  71. package/lib/src/services/ServerManager.js +14 -2
  72. package/lib/src/services/SessionLifecycleService.js +80 -23
  73. package/lib/src/services/ShutdownCoordinator.js +89 -0
  74. package/lib/src/services/SocketClient.js +11 -0
  75. package/lib/src/services/SocketServer.js +109 -6
  76. package/lib/src/services/VideoPipelineService.js +2 -0
  77. package/lib/src/services/healing/HealingMetrics.js +63 -0
  78. package/lib/src/services/healing/HealingOrchestrator.js +32 -4
  79. package/lib/src/services/healing/OcrHealingProvider.js +7 -0
  80. package/lib/test/unit/ApiKeyService.test.js +101 -0
  81. package/lib/test/unit/PortAllocator.test.js +14 -0
  82. package/lib/test/unit/ProcessRegistry.test.js +70 -0
  83. package/lib/test/unit/apiKeyMiddleware.test.js +58 -0
  84. package/lib/test/unit/nodeSecretMiddleware.test.js +38 -0
  85. package/lib/test/unit/rateLimitMiddleware.test.js +37 -0
  86. package/lib/tsconfig.tsbuildinfo +1 -1
  87. package/package.json +2 -2
  88. package/prisma/migrations/20260423081701_add_session_indexes/migration.sql +8 -0
  89. package/prisma/schema.prisma +3 -0
  90. package/schema.json +85 -38
package/README.md CHANGED
@@ -421,6 +421,80 @@ npm run test:ios # iOS integration
421
421
 
422
422
  ---
423
423
 
424
+ ## 🔐 Authentication
425
+
426
+ Xenon REST endpoints under `/xenon/api/*` require an API key passed in the `X-Xenon-API-Key` header.
427
+
428
+ ### Bootstrap key
429
+
430
+ On first start, Xenon writes a one-time bootstrap key (admin-scoped) to:
431
+
432
+ ```
433
+ ~/.cache/xenon/bootstrap-key.txt (0600 permissions)
434
+ ```
435
+
436
+ The startup log prints a WARN pointing at this path. **Rotate the bootstrap key within 24 hours.**
437
+
438
+ ### Creating a permanent key
439
+
440
+ ```bash
441
+ # Create a scoped key for CI
442
+ curl -X POST \
443
+ -H "X-Xenon-API-Key: $(cat ~/.cache/xenon/bootstrap-key.txt)" \
444
+ -H 'Content-Type: application/json' \
445
+ -d '{"name":"ci","scopes":["sessions","read"],"rateLimit":600}' \
446
+ http://localhost:4723/xenon/api/apikeys
447
+
448
+ # Revoke the bootstrap key after saving the returned `key` value
449
+ curl -X DELETE \
450
+ -H "X-Xenon-API-Key: $NEW_ADMIN_KEY" \
451
+ http://localhost:4723/xenon/api/apikeys/<bootstrap-id>
452
+ ```
453
+
454
+ ### Scopes
455
+
456
+ | Scope | Access |
457
+ |-------|--------|
458
+ | `read` | GET sessions, devices, logs, apps |
459
+ | `sessions` | Create/delete sessions and reservations |
460
+ | `devices` | Block/unblock devices, install apps |
461
+ | `admin` | API key management, webhooks, node registration |
462
+
463
+ ### Hub-node channel
464
+
465
+ Set `--plugin-xenon-node-secret` (or `XENON_NODE_SECRET`) to the **same value** on both hub and node. When unset, the channel permits with a WARN (back-compat for single-node installs).
466
+
467
+ For zero-downtime secret rotation, set `XENON_NODE_SECRET` to the new secret and `XENON_NODE_SECRET_PREVIOUS` to the old one. The hub accepts either during the overlap window — flip nodes one at a time, then drop `XENON_NODE_SECRET_PREVIOUS`.
468
+
469
+ ### Local development
470
+
471
+ Pass `--plugin-xenon-auth-disabled` to skip auth entirely. A WARN is logged every 60 s as a reminder.
472
+
473
+ ---
474
+
475
+ ## 🌱 Environment Variables
476
+
477
+ Xenon reads these env vars in addition to the CLI flags. Prefer env vars for credentials so keys don't end up in shell history or config files.
478
+
479
+ | Variable | Purpose |
480
+ |----------|---------|
481
+ | `XENON_AI_PROVIDER` | AI backend: `gemini`, `openai`, `anthropic`, or `ollama`. Same as `--plugin-xenon-aiProvider`. |
482
+ | `XENON_AI_MODEL` | Override the default model for the selected provider. |
483
+ | `XENON_AI_BASE_URL` | Custom base URL (local Ollama, OpenAI-compatible gateway). |
484
+ | `XENON_GEMINI_API_KEY` / `GEMINI_API_KEY` | Gemini credentials. `XENON_`-prefixed form wins if both set. |
485
+ | `XENON_OPENAI_API_KEY` / `OPENAI_API_KEY` | OpenAI credentials. |
486
+ | `XENON_ANTHROPIC_API_KEY` / `ANTHROPIC_API_KEY` | Anthropic credentials. |
487
+ | `XENON_OPENAI_MODEL` | Alternate way to set the OpenAI model. |
488
+ | `XENON_OTEL_DEBUG` | When `true`, OpenTelemetry adds a ConsoleSpanExporter so every span is logged. Dev/tracing only. |
489
+ | `XENON_DB_PROVIDER` | `sqlite` or `postgresql`. Same as `--plugin-xenon-databaseProvider`. |
490
+ | `DATABASE_URL` | Prisma database URL. Falls back to `file:~/.cache/xenon/xenon.db`. |
491
+ | `XENON_NODE_SECRET` | Shared hub↔node secret (see above). |
492
+ | `XENON_NODE_SECRET_PREVIOUS` | Secondary secret accepted during rotation overlap. |
493
+
494
+ See [`docs/server-args.md`](docs/server-args.md) for the full CLI-flag reference and how these variables interact with config files.
495
+
496
+ ---
497
+
424
498
  ## 🤝 Contributing
425
499
 
426
500
  We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenon-device-management/xenon",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
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,4 +1,4 @@
1
- import{c,j as e,g as l}from"./index-S71J2rWg.js";/**
1
+ import{c,j as e,g as l}from"./index-BaTiUCeH.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as j,r as l,j as e,B as u,d as f,g as C,i as A,T as z}from"./index-S71J2rWg.js";import{X as x}from"./index-C1DBaoSh.js";import{A as P}from"./Layouts-D0WSzKOh.js";import{C as w}from"./cpu-DNC8n7kK.js";import{L as v}from"./lock-BstCxnX6.js";/**
1
+ import{c as j,r as l,j as e,B as u,d as f,g as C,i as A,T as z}from"./index-BaTiUCeH.js";import{X as x}from"./index-C1DBaoSh.js";import{A as P}from"./Layouts-D6IPfwoe.js";import{C as w}from"./cpu-tuyMVZ4I.js";import{L as v}from"./lock-C6CoqSr2.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as g,u as X,r,j as e,S as z,g as q,X as V}from"./index-S71J2rWg.js";import{X as c}from"./index-C1DBaoSh.js";import{S as H,B as S,D as K}from"./badge-BiR1gmMm.js";import{A as D,B as T,U as Z,C as J,a as Q,T as ee}from"./button-BVazt4Z1.js";import{Z as se}from"./zap-ZrK5B58i.js";import{T as ae}from"./trash-2-CZWUMK5b.js";/**
1
+ import{c as g,u as X,r,j as e,S as z,g as q,X as V}from"./index-BaTiUCeH.js";import{X as c}from"./index-C1DBaoSh.js";import{S as H,B as S,D as K}from"./badge-BNR9umdu.js";import{A as D,B as T,U as Z,C as J,a as Q,T as ee}from"./button-hZFV1ypT.js";import{Z as se}from"./zap-CssSMAN5.js";import{T as ae}from"./trash-2-NJMZJ2Ol.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as ye,j as Ve}from"./index-S71J2rWg.js";/**
1
+ import{c as ye,j as Ve}from"./index-BaTiUCeH.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as t,r as c,j as i}from"./index-S71J2rWg.js";import{c as r,a as u}from"./badge-BiR1gmMm.js";/**
1
+ import{c as t,r as c,j as i}from"./index-BaTiUCeH.js";import{c as r,a as u}from"./badge-BNR9umdu.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-S71J2rWg.js";/**
1
+ import{c as e}from"./index-BaTiUCeH.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c}from"./index-S71J2rWg.js";/**
1
+ import{c}from"./index-BaTiUCeH.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as h}from"./index-S71J2rWg.js";/**
1
+ import{c as h}from"./index-BaTiUCeH.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as E,r,a as At,j as e,X as tt,C as Lt,u as ft,b as nt,R as qe,S as st,d as it,e as yt,T as Tt,f as jt,L as He,g as rt}from"./index-S71J2rWg.js";import{p as lt,H as zt,C as bt,a as Ke,u as Et}from"./useSocket-CliVeWS3.js";import{X as D}from"./index-C1DBaoSh.js";import{C as Nt}from"./clock-CsVplnJ2.js";import{P as wt}from"./plus-DfjM7G6e.js";import{A as kt,T as at,C as Je,a as Ze,U as It,B as Qe}from"./button-BVazt4Z1.js";import{C as Rt}from"./cpu-DNC8n7kK.js";import{M as Mt}from"./mouse-pointer-2-CSn_Wnc9.js";import{S as Xe,D as _t,B as Pe}from"./badge-BiR1gmMm.js";import{Z as Ut}from"./zap-ZrK5B58i.js";import{L as Ft}from"./lock-BstCxnX6.js";import{T as Be}from"./trash-2-CZWUMK5b.js";/**
1
+ import{c as E,r,a as At,j as e,X as tt,C as Lt,u as ft,b as nt,R as qe,S as st,d as it,e as yt,T as Tt,f as jt,L as He,g as rt}from"./index-BaTiUCeH.js";import{p as lt,H as zt,C as bt,a as Ke,u as Et}from"./useSocket-Ct2wo7P2.js";import{X as D}from"./index-C1DBaoSh.js";import{C as Nt}from"./clock-DrpxSvCL.js";import{P as wt}from"./plus-B4B1Hukt.js";import{A as kt,T as at,C as Je,a as Ze,U as It,B as Qe}from"./button-hZFV1ypT.js";import{C as Rt}from"./cpu-tuyMVZ4I.js";import{M as Mt}from"./mouse-pointer-2-CXdnjXIg.js";import{S as Xe,D as _t,B as Pe}from"./badge-BNR9umdu.js";import{Z as Ut}from"./zap-CssSMAN5.js";import{L as Ft}from"./lock-C6CoqSr2.js";import{T as Be}from"./trash-2-NJMZJ2Ol.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.