@xenon-device-management/xenon 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +446 -0
- package/lib/package.json +207 -0
- package/lib/public/assets/Layouts-7IT8aFLI.js +11 -0
- package/lib/public/assets/Layouts-DPMls9vh.css +1 -0
- package/lib/public/assets/ai-settings-BbnfgdEx.js +11 -0
- package/lib/public/assets/apps-CRMrI4_p.js +16 -0
- package/lib/public/assets/apps-CcM77dgg.css +1 -0
- package/lib/public/assets/badge-B1nKs8zj.css +1 -0
- package/lib/public/assets/badge-CSvl5xIU.js +11 -0
- package/lib/public/assets/button-CJlKn4PZ.css +1 -0
- package/lib/public/assets/button-CvLaGFYj.js +26 -0
- package/lib/public/assets/calendar-6w-D6Oaw.js +6 -0
- package/lib/public/assets/clock-DcdeWBPr.js +6 -0
- package/lib/public/assets/cpu-DiSoXT9n.js +6 -0
- package/lib/public/assets/device-explorer-CajM63OJ.js +193 -0
- package/lib/public/assets/device-explorer-CxdUAoTL.css +1 -0
- package/lib/public/assets/index-ByQwMN5T.js +174 -0
- package/lib/public/assets/index-C1DBaoSh.js +1 -0
- package/lib/public/assets/index-qzCez_kk.css +1 -0
- package/lib/public/assets/lock-B23ibZmo.js +6 -0
- package/lib/public/assets/maintenance-settings-CirzA6yG.js +6 -0
- package/lib/public/assets/mouse-pointer-2-Cz76SHFb.js +6 -0
- package/lib/public/assets/plus-BBwlIevt.js +6 -0
- package/lib/public/assets/session-dashboard-C2k7FFv_.css +1 -0
- package/lib/public/assets/session-dashboard-HPDtwPOZ.js +62 -0
- package/lib/public/assets/settings-DrZsZwdc.js +1 -0
- package/lib/public/assets/trash-2-DQpvzJec.js +6 -0
- package/lib/public/assets/useSocket-Dxsqae2a.js +16 -0
- package/lib/public/assets/webhook-settings-CDPgsgkb.css +1 -0
- package/lib/public/assets/webhook-settings-Cp-B4Nrw.js +1 -0
- package/lib/public/assets/zap-DovP6iow.js +6 -0
- package/lib/public/favicon.ico +0 -0
- package/lib/public/favicon.png +0 -0
- package/lib/public/favicon.svg +9 -0
- package/lib/public/index.html +46 -0
- package/lib/public/logo.svg +17 -0
- package/lib/public/logo192.png +0 -0
- package/lib/public/logo512.png +0 -0
- package/lib/public/manifest.json +25 -0
- package/lib/public/robots.txt +3 -0
- package/lib/schema.json +348 -0
- package/lib/src/InternalHttpClient.js +212 -0
- package/lib/src/PluginContext.js +29 -0
- package/lib/src/XenonCapabilityManager.js +199 -0
- package/lib/src/app/index.js +167 -0
- package/lib/src/app/routers/apps.js +79 -0
- package/lib/src/app/routers/config.js +131 -0
- package/lib/src/app/routers/control.js +835 -0
- package/lib/src/app/routers/dashboard.js +301 -0
- package/lib/src/app/routers/grid.js +352 -0
- package/lib/src/app/routers/reservation.js +190 -0
- package/lib/src/app/routers/webhook.js +83 -0
- package/lib/src/app/swagger-docs.js +203 -0
- package/lib/src/app/swagger.js +366 -0
- package/lib/src/chromeUtils.js +148 -0
- package/lib/src/commands/handle.js +19 -0
- package/lib/src/commands/index.js +8 -0
- package/lib/src/config.js +73 -0
- package/lib/src/dashboard/asset-manager.js +84 -0
- package/lib/src/dashboard/commands.js +284 -0
- package/lib/src/dashboard/event-manager.js +699 -0
- package/lib/src/dashboard/services/app-service.js +134 -0
- package/lib/src/dashboard/services/failure-analysis-service.js +173 -0
- package/lib/src/dashboard/services/session-service.js +113 -0
- package/lib/src/data-service/CircuitBreaker.js +83 -0
- package/lib/src/data-service/config-service.js +155 -0
- package/lib/src/data-service/db.js +122 -0
- package/lib/src/data-service/device-service.js +320 -0
- package/lib/src/data-service/device-store.interface.js +2 -0
- package/lib/src/data-service/device-store.js +345 -0
- package/lib/src/data-service/pending-sessions-service.js +25 -0
- package/lib/src/data-service/pluginArgs.js +25 -0
- package/lib/src/data-service/prisma-service.js +31 -0
- package/lib/src/data-service/prisma-store.js +385 -0
- package/lib/src/data-service/queue-service.js +150 -0
- package/lib/src/data-service/web-config-service.js +130 -0
- package/lib/src/device-managers/AndroidDeviceManager.js +1155 -0
- package/lib/src/device-managers/ChromeDriverManager.js +68 -0
- package/lib/src/device-managers/HealthMonitorService.js +325 -0
- package/lib/src/device-managers/IOSDeviceManager.js +351 -0
- package/lib/src/device-managers/NodeDevices.js +82 -0
- package/lib/src/device-managers/android/AndroidStreamService.js +370 -0
- package/lib/src/device-managers/android/DeviceLockManager.js +45 -0
- package/lib/src/device-managers/cloud/CapabilityManager.js +26 -0
- package/lib/src/device-managers/cloud/Devices.js +86 -0
- package/lib/src/device-managers/iOSTracker.js +44 -0
- package/lib/src/device-managers/index.js +89 -0
- package/lib/src/device-managers/ios/IOSDiscoveryService.js +268 -0
- package/lib/src/device-managers/ios/IOSStreamService.js +893 -0
- package/lib/src/device-managers/ios/WDAClient.js +866 -0
- package/lib/src/device-utils.js +663 -0
- package/lib/src/enums/Capabilities.js +8 -0
- package/lib/src/enums/Cloud.js +11 -0
- package/lib/src/enums/Platform.js +9 -0
- package/lib/src/enums/SessionType.js +9 -0
- package/lib/src/enums/SocketEvents.js +15 -0
- package/lib/src/helpers/UniversalMjpegProxy.js +273 -0
- package/lib/src/helpers/index.js +229 -0
- package/lib/src/index.js +95 -0
- package/lib/src/interceptors/CommandInterceptor.js +524 -0
- package/lib/src/interfaces/ICloudManager.js +2 -0
- package/lib/src/interfaces/IDevice.js +2 -0
- package/lib/src/interfaces/IDeviceFilterOptions.js +2 -0
- package/lib/src/interfaces/IDeviceManager.js +2 -0
- package/lib/src/interfaces/IOptions.js +2 -0
- package/lib/src/interfaces/IPluginArgs.js +55 -0
- package/lib/src/interfaces/ISessionCapability.js +2 -0
- package/lib/src/logger.js +225 -0
- package/lib/src/plugin.js +244 -0
- package/lib/src/prisma.js +12 -0
- package/lib/src/profiling/AndroidAppProfiler.js +213 -0
- package/lib/src/proxy/wd-command-proxy.js +221 -0
- package/lib/src/scripts/generate-database-migration.js +59 -0
- package/lib/src/scripts/initialize-database.js +55 -0
- package/lib/src/scripts/install-go-ios.js +66 -0
- package/lib/src/scripts/prepare-prisma.js +89 -0
- package/lib/src/services/AICommandService.js +143 -0
- package/lib/src/services/AIService.js +466 -0
- package/lib/src/services/CleanupService.js +141 -0
- package/lib/src/services/EventBus.js +74 -0
- package/lib/src/services/InspectorService.js +395 -0
- package/lib/src/services/MetricsService.js +134 -0
- package/lib/src/services/NetworkConditioningService.js +173 -0
- package/lib/src/services/NotificationService.js +163 -0
- package/lib/src/services/RequestLogService.js +252 -0
- package/lib/src/services/ResourceIsolationService.js +122 -0
- package/lib/src/services/SecurityService.js +120 -0
- package/lib/src/services/ServerManager.js +284 -0
- package/lib/src/services/SessionHeartbeatService.js +158 -0
- package/lib/src/services/SessionLifecycleService.js +572 -0
- package/lib/src/services/SocketClient.js +71 -0
- package/lib/src/services/SocketServer.js +87 -0
- package/lib/src/services/TracingService.js +132 -0
- package/lib/src/services/VideoPipelineService.js +220 -0
- package/lib/src/services/healing/FuzzyXmlHealingProvider.js +333 -0
- package/lib/src/services/healing/HealEtalonService.js +98 -0
- package/lib/src/services/healing/HealedLocatorGenerator.js +132 -0
- package/lib/src/services/healing/HealingOrchestrator.js +165 -0
- package/lib/src/services/healing/LlmHealingProvider.js +77 -0
- package/lib/src/services/healing/OcrHealingProvider.js +119 -0
- package/lib/src/services/healing/ResilioTreeHealingProvider.js +100 -0
- package/lib/src/services/healing/VisualAiHealingProvider.js +90 -0
- package/lib/src/services/healing/types.js +12 -0
- package/lib/src/services/omni-vision/OmniVisionService.js +718 -0
- package/lib/src/services/omni-vision/VisionAssertionService.js +68 -0
- package/lib/src/sessions/CloudSession.js +42 -0
- package/lib/src/sessions/LocalSession.js +313 -0
- package/lib/src/sessions/RemoteSession.js +287 -0
- package/lib/src/sessions/SessionManager.js +238 -0
- package/lib/src/sessions/XenonSession.js +44 -0
- package/lib/src/types/CLIArgs.js +2 -0
- package/lib/src/types/CloudArgs.js +2 -0
- package/lib/src/types/CloudSchema.js +131 -0
- package/lib/src/types/DeviceType.js +2 -0
- package/lib/src/types/DeviceUpdate.js +2 -0
- package/lib/src/types/IOSDevice.js +2 -0
- package/lib/src/types/Platform.js +2 -0
- package/lib/src/types/SessionStatus.js +11 -0
- package/lib/src/validators/CapabilityValidator.js +93 -0
- package/lib/test/e2e/android/conf.spec.js +43 -0
- package/lib/test/e2e/android/conf2.spec.js +44 -0
- package/lib/test/e2e/android/conf3.spec.js +44 -0
- package/lib/test/e2e/e2ehelper.js +113 -0
- package/lib/test/e2e/hubnode/forward-request.spec.js +224 -0
- package/lib/test/e2e/hubnode/hubnode.spec.js +214 -0
- package/lib/test/e2e/ios/conf1.spec.js +39 -0
- package/lib/test/e2e/ios/conf2.spec.js +39 -0
- package/lib/test/e2e/plugin-harness.js +236 -0
- package/lib/test/e2e/plugin.spec.js +97 -0
- package/lib/test/e2e/telemetry_verification.spec.js +83 -0
- package/lib/test/e2e/video-recording-test.spec.js +63 -0
- package/lib/test/helpers/test-container.js +112 -0
- package/lib/test/integration/androidDevices.spec.js +137 -0
- package/lib/test/integration/cliArgs.js +73 -0
- package/lib/test/integration/ios/01iOSSimulator.spec.js +291 -0
- package/lib/test/integration/ios/02iOSDevices.spec.js +75 -0
- package/lib/test/integration/testHelpers.js +74 -0
- package/lib/test/unit/AndroidDeviceManager.spec.js +178 -0
- package/lib/test/unit/ChromeDriverManager.spec.js +26 -0
- package/lib/test/unit/CleanupService.spec.js +21 -0
- package/lib/test/unit/DeviceModel.spec.js +157 -0
- package/lib/test/unit/FuzzyXmlHealingProvider.test.js +294 -0
- package/lib/test/unit/GetAdbOriginal.js +42 -0
- package/lib/test/unit/HealingCascade.test.js +128 -0
- package/lib/test/unit/IOSDeviceManager.spec.js +261 -0
- package/lib/test/unit/RemoteIOs.spec.js +78 -0
- package/lib/test/unit/ResilioTreeHealingProvider.test.js +96 -0
- package/lib/test/unit/commands.spec.js +27 -0
- package/lib/test/unit/config.spec.js +27 -0
- package/lib/test/unit/device-service.spec.js +307 -0
- package/lib/test/unit/device-utils.spec.js +313 -0
- package/lib/test/unit/fixtures/device.config.js +4 -0
- package/lib/test/unit/fixtures/devices.js +89 -0
- package/lib/test/unit/helpers.spec.js +62 -0
- package/lib/test/unit/omni-vision.spec.js +100 -0
- package/lib/test/unit/plugin.spec.js +133 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +207 -0
- package/prisma/data.db +0 -0
- package/prisma/dev.db +0 -0
- package/prisma/dev.db-journal +0 -0
- package/prisma/migrations/20231011074725_initial_tables/migration.sql +47 -0
- package/prisma/migrations/20231226115334_update_session_log/migration.sql +2 -0
- package/prisma/migrations/20251204113710_add_video_recording_enabled/migration.sql +29 -0
- package/prisma/migrations/20251204132449_add_log_table/migration.sql +11 -0
- package/prisma/migrations/20251205050111_add_profiling_support/migration.sql +47 -0
- package/prisma/migrations/20251205050947_add_is_error_field/migration.sql +24 -0
- package/prisma/migrations/20260126201337_add_app_model/migration.sql +18 -0
- package/prisma/migrations/20260130115722_add_performance_trace_and_xenon_sync/migration.sql +2 -0
- package/prisma/migrations/20260130135114_add_device_models/migration.sql +57 -0
- package/prisma/migrations/20260130140655_make_systemport_optional/migration.sql +45 -0
- package/prisma/migrations/20260130140932_make_device_fields_optional/migration.sql +45 -0
- package/prisma/migrations/20260130141040_final_schema_fix/migration.sql +45 -0
- package/prisma/migrations/20260130143234_add_device_health_fields/migration.sql +4 -0
- package/prisma/migrations/20260130144921_add_failure_category/migration.sql +2 -0
- package/prisma/migrations/20260131151456_add_webhook_config/migration.sql +10 -0
- package/prisma/migrations/20260201094507_add_device_tags/migration.sql +11 -0
- package/prisma/migrations/20260201103410_add_managed_process/migration.sql +15 -0
- package/prisma/migrations/20260201140637_add_web_config/migration.sql +22 -0
- package/prisma/migrations/20260201162232_add_session_progress/migration.sql +2 -0
- package/prisma/migrations/20260201174231_add_total_healed_count/migration.sql +2 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +210 -0
- package/schema.json +348 -0
- package/scripts/build-xenon.sh +32 -0
- package/scripts/dev/debug-gemini.ts +44 -0
- package/scripts/generate-types-from-schema.js +86 -0
- package/scripts/install-compatible-driver.js +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# Xenon
|
|
2
|
+
|
|
3
|
+
<h1 align="center">
|
|
4
|
+
<br>
|
|
5
|
+
<img src="assets/xenon-logo.png" alt="Xenon" width="200">
|
|
6
|
+
<br>
|
|
7
|
+
<br>
|
|
8
|
+
Intelligent Mobile Infrastructure
|
|
9
|
+
<br>
|
|
10
|
+
</h1>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<strong>Self-healing device orchestration platform for Appium</strong>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="#features">Features</a> •
|
|
18
|
+
<a href="#quick-start">Quick Start</a> •
|
|
19
|
+
<a href="#capabilities">Capabilities</a> •
|
|
20
|
+
<a href="#api-documentation">API Docs</a> •
|
|
21
|
+
<a href="#documentation">Documentation</a> •
|
|
22
|
+
<a href="#contributing">Contributing</a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ✨ What is Xenon?
|
|
28
|
+
|
|
29
|
+
**Xenon** is an intelligent Appium plugin that transforms your mobile device lab into a **self-healing, autonomous infrastructure**. Named after the noble gas known for its stability and reliability, Xenon brings enterprise-grade device orchestration to your testing pipeline.
|
|
30
|
+
|
|
31
|
+
### Why Xenon?
|
|
32
|
+
|
|
33
|
+
| Problem | Xenon Solution |
|
|
34
|
+
|---------|----------------|
|
|
35
|
+
| Tests fail due to device state | **Auto-recovery** - Devices heal themselves |
|
|
36
|
+
| Manual device management | **Smart allocation** - Queue, reserve, prioritize |
|
|
37
|
+
| Debugging is painful | **Interactive control** - Live stream, touch, shell |
|
|
38
|
+
| No visibility into failures | **Rich artifacts** - Video, screenshots, profiling |
|
|
39
|
+
| Infrastructure silos | **Unified dashboard** - One view for all devices |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🚀 Features
|
|
44
|
+
|
|
45
|
+
### Device Orchestration
|
|
46
|
+
- ✅ **Automatic device discovery** - Android (USB + emulators), iOS (devices + simulators)
|
|
47
|
+
- ✅ **Smart session allocation** - Queue management with ETA
|
|
48
|
+
- ✅ **WebSocket-First Sync** - Real-time Hub-Node-Dashboard bidirectional sync
|
|
49
|
+
- ✅ **Device reservation** - Manual mode for debugging
|
|
50
|
+
- ✅ **Team-based quotas** - Fair resource sharing
|
|
51
|
+
|
|
52
|
+
### Interactive Control
|
|
53
|
+
- ✅ **Live streaming** - Real-time device screen in browser
|
|
54
|
+
- ✅ **Touch interaction** - Tap, swipe, scroll remotely
|
|
55
|
+
- ✅ **App management** - Install, uninstall, clear data
|
|
56
|
+
- ✅ **Interactive Shell** - Execute ADB/iOS commands directly
|
|
57
|
+
- ✅ **Device information** - Battery, storage, network status
|
|
58
|
+
|
|
59
|
+
### 🧠 AI Self-Healing (Flagship)
|
|
60
|
+
- ✅ **5-Tier Healing Orchestration** - From DOM to LLM recovery
|
|
61
|
+
- ✅ **Signature-Based Learning** - Persistent "Etalon" signatures for high-confidence recovery
|
|
62
|
+
- ✅ **Multi-Modal Fallback** - Syntactic -> OCR -> Visual AI -> LLM reasoning
|
|
63
|
+
- ✅ **Infrastructure-Free** - Works with existing LokiJS (local) or PostgreSQL (remote)
|
|
64
|
+
|
|
65
|
+
### Recording & Artifacts
|
|
66
|
+
- ✅ **Video recording** - Full session capture
|
|
67
|
+
- ✅ **Screenshot capture** - On-demand and per-command
|
|
68
|
+
- ✅ **Distributed Tracing** - OpenTelemetry spans for exact command latency
|
|
69
|
+
- ✅ **Performance profiling** - CPU, memory, FPS metrics
|
|
70
|
+
- ✅ **Log aggregation** - Appium, device, app logs
|
|
71
|
+
- ✅ **OpenTelemetry Integration** - Standardized distributed tracing for all sessions
|
|
72
|
+
|
|
73
|
+
### Intelligence (Roadmap)
|
|
74
|
+
- 🔲 **Flaky test detection** - Auto-identify unstable tests
|
|
75
|
+
- 🔲 **Error categorization** - Crash vs timeout vs element not found
|
|
76
|
+
- 🔲 **Predictive health** - USB/battery failure prediction
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## ⚡ Quick Start
|
|
81
|
+
|
|
82
|
+
### Installation
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Install Xenon plugin
|
|
86
|
+
appium plugin install xenon
|
|
87
|
+
|
|
88
|
+
# Or install from source
|
|
89
|
+
git clone https://github.com/xenon-platform/xenon.git
|
|
90
|
+
cd xenon
|
|
91
|
+
npm install
|
|
92
|
+
npm run build:all
|
|
93
|
+
appium plugin install --source=local .
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Running
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Start Appium with Xenon
|
|
100
|
+
appium server --use-plugins=xenon \
|
|
101
|
+
--plugin-xenon-platform=both \
|
|
102
|
+
--plugin-xenon-enable-dashboard
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 🔧 Configuration
|
|
106
|
+
|
|
107
|
+
Xenon supports configuration via CLI arguments or a configuration file (YAML/JSON). We recommend using a configuration file for production deployments.
|
|
108
|
+
|
|
109
|
+
### Using Configuration File (Recommended)
|
|
110
|
+
|
|
111
|
+
Create a `xenon-config.yaml` file:
|
|
112
|
+
```yaml
|
|
113
|
+
server:
|
|
114
|
+
usePlugins: ["xenon"]
|
|
115
|
+
plugin:
|
|
116
|
+
xenon:
|
|
117
|
+
platform: both
|
|
118
|
+
maxSessions: 8
|
|
119
|
+
enableDashboard: true
|
|
120
|
+
enableSelfHealing: true
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run Appium with the config:
|
|
124
|
+
```bash
|
|
125
|
+
appium server --config xenon-config.yaml
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Runtime Configuration ⚡️
|
|
129
|
+
|
|
130
|
+
You can update configuration options at runtime without restarting the server using the API:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Get current config
|
|
134
|
+
GET /xenon/api/config
|
|
135
|
+
|
|
136
|
+
# Update config (e.g. change max sessions)
|
|
137
|
+
PUT /xenon/api/config
|
|
138
|
+
{ "maxSessions": 10 }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
> **Note:** Some changes (like `platform` or `hub` URL) require a server restart to take full effect. The API response will indicate if a restart is required.
|
|
142
|
+
|
|
143
|
+
### Build & Session Retention 🧹
|
|
144
|
+
|
|
145
|
+
Xenon includes an enterprise-ready cleanup job that automatically purges older builds, sessions, and associated assets (videos/screenshots) to manage disk space.
|
|
146
|
+
|
|
147
|
+
| Option | Description | Default |
|
|
148
|
+
|--------|-------------|---------|
|
|
149
|
+
| `buildCleanupDays` | Retention period in days | `30` |
|
|
150
|
+
| `buildCleanupMaxCount` | Maximum number of builds to keep | `100` |
|
|
151
|
+
| `buildCleanupSchedule` | Cron schedule for the cleanup job | `"0 0 * * *"` |
|
|
152
|
+
| `deleteBuildAssets` | Delete video recordings and screenshots from disk | `true` |
|
|
153
|
+
|
|
154
|
+
**Example (YAML):**
|
|
155
|
+
```yaml
|
|
156
|
+
plugin:
|
|
157
|
+
xenon:
|
|
158
|
+
buildCleanupDays: 14
|
|
159
|
+
buildCleanupMaxCount: 50
|
|
160
|
+
buildCleanupSchedule: "0 0 * * *"
|
|
161
|
+
deleteBuildAssets: true
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Detailed explanation of how the retention logic works can be found in the **[Data Retention & Maintenance Guide](docs/retention.md)**.
|
|
165
|
+
|
|
166
|
+
See [docs/server-args.md](docs/server-args.md) for all available options.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 📋 Capabilities
|
|
171
|
+
|
|
172
|
+
Xenon uses the `xe:` prefix for its custom capabilities. You can also use `xenon:` as an alternative.
|
|
173
|
+
|
|
174
|
+
### Session & Build Tracking
|
|
175
|
+
|
|
176
|
+
| Capability | Description | Example |
|
|
177
|
+
|------------|-------------|---------|
|
|
178
|
+
| `xe:build` | Build name for grouping sessions | `"xe:build": "Release-v2.0"` |
|
|
179
|
+
| `xe:name` | Session name for identification | `"xe:name": "Login Test Suite"` |
|
|
180
|
+
|
|
181
|
+
### Recording & Screenshots
|
|
182
|
+
|
|
183
|
+
| Capability | Description | Default |
|
|
184
|
+
|------------|-------------|---------|
|
|
185
|
+
| `xe:record_video` | Enable video recording | `true` |
|
|
186
|
+
| `xe:screenshot_on_failure` | Capture screenshot on test failure | `true` |
|
|
187
|
+
| `xe:screenshot_on_every_command` | Capture screenshot after each command | `false` |
|
|
188
|
+
| `xe:save_device_logs` | Save device logs (logcat/syslog) | `false` |
|
|
189
|
+
|
|
190
|
+
### Device Filtering
|
|
191
|
+
|
|
192
|
+
| Capability | Description | Example |
|
|
193
|
+
|------------|-------------|---------|
|
|
194
|
+
| `appium:udids` | Comma-separated list of allowed UDIDs | `"device1,device2"` |
|
|
195
|
+
| `appium:minSDK` | Minimum OS version | `"15"` |
|
|
196
|
+
| `appium:maxSDK` | Maximum OS version | `"17"` |
|
|
197
|
+
| `appium:iPhoneOnly` | Use only iPhone simulators | `true` |
|
|
198
|
+
| `appium:iPadOnly` | Use only iPad simulators | `true` |
|
|
199
|
+
| `appium:filterByHost` | Filter by node IP address | `"192.168.0.100"` |
|
|
200
|
+
|
|
201
|
+
### Timeouts
|
|
202
|
+
|
|
203
|
+
| Capability | Description | Default |
|
|
204
|
+
|------------|-------------|---------|
|
|
205
|
+
| `appium:deviceAvailabilityTimeout` | Wait time for device availability (ms) | `180000` |
|
|
206
|
+
| `appium:deviceRetryInterval` | Polling interval for device check (ms) | `10000` |
|
|
207
|
+
|
|
208
|
+
### Example Configuration
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
const capabilities = {
|
|
212
|
+
platformName: 'iOS',
|
|
213
|
+
'appium:automationName': 'XCUITest',
|
|
214
|
+
'appium:app': '/path/to/app.ipa',
|
|
215
|
+
|
|
216
|
+
// Xenon capabilities
|
|
217
|
+
'xe:build': 'Sprint-42',
|
|
218
|
+
'xe:name': 'Login Flow Test',
|
|
219
|
+
'xe:record_video': true,
|
|
220
|
+
'xe:screenshot_on_failure': true,
|
|
221
|
+
'xe:save_device_logs': true,
|
|
222
|
+
|
|
223
|
+
// Device filtering
|
|
224
|
+
'appium:minSDK': '16',
|
|
225
|
+
'appium:iPhoneOnly': true
|
|
226
|
+
};
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Custom Execute Script Commands
|
|
230
|
+
|
|
231
|
+
Xenon supports extended control and reporting via the `xenon:` execute script namespace. These commands allow you to interact with the Xenon dashboard and session management directly from your test code.
|
|
232
|
+
|
|
233
|
+
| Command | Description | Example |
|
|
234
|
+
|---------|-------------|---------|
|
|
235
|
+
| `xenon: setSessionStatus` | Mark session as passed/failed in dashboard | `{"status": "passed", "reason": "All steps OK"}` |
|
|
236
|
+
| `xenon: setSessionName` | Update session name at runtime | `{"name": "Step 2: Payment Verification"}` |
|
|
237
|
+
| `xenon: captureEvidence` | Trigger manual screenshot with custom label | `{"reason": "Checkpoint reached", "label": "success"}` |
|
|
238
|
+
| `xenon: addTag` | Add searchable tags to the session | `{"tag": "regression"}` |
|
|
239
|
+
| `xenon: debug` | Send custom debug logs to Xenon dashboard | `{"message": "API Response: 200 OK"}` |
|
|
240
|
+
|
|
241
|
+
See [docs/capabilities.md](docs/capabilities.md) for full usage details.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 🧠 AI Self-Healing
|
|
246
|
+
|
|
247
|
+
Xenon features a best-in-class, 5-tier self-healing system that ensures your tests never fail due to minor UI changes. It automatically intercepts `NoSuchElementError` and attempts to recover the locator using increasingly advanced methods.
|
|
248
|
+
|
|
249
|
+
### 🛡️ The 5-Tier Strategy
|
|
250
|
+
|
|
251
|
+
| Tier | Provider | Mechanism | Stability |
|
|
252
|
+
|:---|:---|:---|:---|
|
|
253
|
+
| **1** | **Native** | Standard Appium `findElement` | Baseline |
|
|
254
|
+
| **2** | **Fuzzy XML**| **Weighted Signature Matching** (Dice Coefficient) | **85%+** |
|
|
255
|
+
| **3** | **OCR** | Local Text Recognition (Tesseract.js) | High |
|
|
256
|
+
| **4** | **Visual AI**| AI-powered coordinate discovery | High |
|
|
257
|
+
| **5** | **LLM** | Deep Reasoning (Gemini/OpenAI) | Absolute |
|
|
258
|
+
|
|
259
|
+
### ⚡ Signature-Based Learning (Etalon)
|
|
260
|
+
|
|
261
|
+
Xenon "learns" during every successful run. When an element is found, it captures a persistent **Element Signature (Etalon)**.
|
|
262
|
+
- **Zero Configuration**: Learning is fully automatic and backgrounded.
|
|
263
|
+
- **Persistent Memory**: Signatures are stored in your database (LokiJS or PostgreSQL).
|
|
264
|
+
- **Extreme Precision**: Even if `id`, `text`, or `class` changes, Xenon uses anchor attributes (`content-desc`, `resource-id`) from its memory to find the match with industrial-grade confidence.
|
|
265
|
+
|
|
266
|
+
### 🎛️ Control & Transparency
|
|
267
|
+
|
|
268
|
+
Xenon provides full visibility and control over its self-healing system:
|
|
269
|
+
|
|
270
|
+
- **Global Toggle**: Enable or disable healing via CLI:
|
|
271
|
+
```bash
|
|
272
|
+
appium server --use-plugins=xenon --plugin-xenon-enable-self-healing=true
|
|
273
|
+
```
|
|
274
|
+
- **Live Configuration**: Toggle self-healing directly from the **Xenon Dashboard Settings** at runtime without restarting the server.
|
|
275
|
+
- **Audit Logs**: Every healing event is recorded in the session command history. You can see:
|
|
276
|
+
- **Original Selector**: The locator that failed.
|
|
277
|
+
- **Recovered Selector**: The replacement locator found by Xenon.
|
|
278
|
+
- **Confidence Score**: The mathematical match probability (0-1.0).
|
|
279
|
+
- **Healing Tier**: Which tier (Fuzzy XML, OCR, etc.) performed the recovery.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 📖 API Documentation
|
|
284
|
+
|
|
285
|
+
Xenon provides a comprehensive REST API for device management, session control, and more.
|
|
286
|
+
|
|
287
|
+
### Swagger UI
|
|
288
|
+
|
|
289
|
+
Access interactive API documentation at:
|
|
290
|
+
```
|
|
291
|
+
http://localhost:4723/xenon/api-docs
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### OpenAPI Spec
|
|
295
|
+
|
|
296
|
+
Get the raw OpenAPI specification:
|
|
297
|
+
```
|
|
298
|
+
http://localhost:4723/xenon/api-docs.json
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### API Categories
|
|
302
|
+
|
|
303
|
+
| Category | Base Path | Description |
|
|
304
|
+
|----------|-----------|-------------|
|
|
305
|
+
| **Devices** | `/xenon/api/devices` | Device discovery and management |
|
|
306
|
+
| **Sessions** | `/xenon/api/session` | Session management and logs |
|
|
307
|
+
| **Builds** | `/xenon/api/build` | Build and test execution tracking |
|
|
308
|
+
| **Control** | `/xenon/api/control` | Interactive device control |
|
|
309
|
+
| **Reservations** | `/xenon/api/reservation` | Device reservation for exclusive use |
|
|
310
|
+
| **Applications** | `/xenon/api/apps` | App repository and installation |
|
|
311
|
+
| **Webhooks** | `/xenon/api/webhook` | Notification webhook configuration |
|
|
312
|
+
|
|
313
|
+
### Key Endpoints
|
|
314
|
+
|
|
315
|
+
#### Devices
|
|
316
|
+
```bash
|
|
317
|
+
# Get all devices
|
|
318
|
+
GET /xenon/api/devices
|
|
319
|
+
|
|
320
|
+
# Get device by platform
|
|
321
|
+
GET /xenon/api/device/{platform}
|
|
322
|
+
|
|
323
|
+
# Block/Unblock device
|
|
324
|
+
POST /xenon/api/device/{udid}/block
|
|
325
|
+
POST /xenon/api/device/{udid}/unblock
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### Control API
|
|
329
|
+
```bash
|
|
330
|
+
# Take screenshot
|
|
331
|
+
GET /xenon/api/control/{udid}/screenshot
|
|
332
|
+
|
|
333
|
+
# Tap at coordinates
|
|
334
|
+
POST /xenon/api/control/{udid}/tap
|
|
335
|
+
{ "x": 100, "y": 200 }
|
|
336
|
+
|
|
337
|
+
# Swipe gesture
|
|
338
|
+
POST /xenon/api/control/{udid}/swipe
|
|
339
|
+
{ "x": 100, "y": 500, "endX": 100, "endY": 100, "duration": 1000 }
|
|
340
|
+
|
|
341
|
+
# Type text
|
|
342
|
+
POST /xenon/api/control/{udid}/text
|
|
343
|
+
{ "text": "Hello World" }
|
|
344
|
+
|
|
345
|
+
# Execute shell command (Android)
|
|
346
|
+
POST /xenon/api/control/{udid}/shell
|
|
347
|
+
{ "command": "pm list packages" }
|
|
348
|
+
|
|
349
|
+
# Live stream
|
|
350
|
+
GET /xenon/api/control/{udid}/stream
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### Reservations
|
|
354
|
+
```bash
|
|
355
|
+
# Reserve a device
|
|
356
|
+
POST /xenon/api/reservation
|
|
357
|
+
{ "udid": "...", "host": "...", "reservedBy": "John", "duration": "2h" }
|
|
358
|
+
|
|
359
|
+
# Release reservation
|
|
360
|
+
DELETE /xenon/api/reservation/{udid}/{host}
|
|
361
|
+
|
|
362
|
+
# Extend reservation
|
|
363
|
+
POST /xenon/api/reservation/{udid}/{host}/extend
|
|
364
|
+
{ "duration": "1h" }
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 🎨 Dashboard
|
|
370
|
+
|
|
371
|
+
Access the dashboard at `http://localhost:4723/xenon/`
|
|
372
|
+
|
|
373
|
+
<p align="center">
|
|
374
|
+
<img src="assets/dashboard.png" alt="Xenon Dashboard" width="100%">
|
|
375
|
+
</p>
|
|
376
|
+
|
|
377
|
+
### Views
|
|
378
|
+
|
|
379
|
+
| View | Description |
|
|
380
|
+
|------|-------------|
|
|
381
|
+
| **Devices** | Real-time device grid with status indicators |
|
|
382
|
+
| **Sessions** | Active and historical session management |
|
|
383
|
+
| **Builds** | Test runs grouped by build identifier |
|
|
384
|
+
| **Control** | Interactive device control interface |
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## 📚 Documentation
|
|
389
|
+
|
|
390
|
+
The full documentation is available at:
|
|
391
|
+
**[https://xenon-docs.vercel.app/](https://xenon-docs.vercel.app/)**
|
|
392
|
+
|
|
393
|
+
### Quick Links
|
|
394
|
+
- [Installation Guide](docs/installation.md)
|
|
395
|
+
- [Configuration Options](docs/configuration.md)
|
|
396
|
+
- [API Reference](docs/api.md)
|
|
397
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## 🏗️ Development
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# Clone and install
|
|
405
|
+
git clone https://github.com/xenon-platform/xenon.git
|
|
406
|
+
cd xenon
|
|
407
|
+
npm install
|
|
408
|
+
|
|
409
|
+
# Build everything (Plugin + Dashboard)
|
|
410
|
+
npm run build:all
|
|
411
|
+
|
|
412
|
+
# High-velocity development loop
|
|
413
|
+
# (Auto-rebuilds and restarts Appium server)
|
|
414
|
+
npm run dev
|
|
415
|
+
|
|
416
|
+
# Run tests
|
|
417
|
+
npm run test:all # Unit tests
|
|
418
|
+
npm run test:android # Android integration
|
|
419
|
+
npm run test:ios # iOS integration
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## 🤝 Contributing
|
|
425
|
+
|
|
426
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
427
|
+
|
|
428
|
+
### Contributors
|
|
429
|
+
|
|
430
|
+
<a href="https://github.com/xenon-platform/xenon/graphs/contributors">
|
|
431
|
+
<img src="https://contrib.rocks/image?repo=xenon-platform/xenon" />
|
|
432
|
+
</a>
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## 📜 License
|
|
437
|
+
|
|
438
|
+
ISC License - See [LICENSE](LICENSE) for details.
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
<p align="center">
|
|
443
|
+
<strong>Xenon</strong> - Stable. Reliable. Intelligent.
|
|
444
|
+
<br>
|
|
445
|
+
<em>Named after Element 54 - the noble gas known for stability</em>
|
|
446
|
+
</p>
|
package/lib/package.json
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xenon-device-management/xenon",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
|
|
5
|
+
"main": "./lib/src/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./lib/src/index.js",
|
|
8
|
+
"./schema.json": "./schema.json",
|
|
9
|
+
"./package.json": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -b && npm run build:copy",
|
|
13
|
+
"build:all": "npm run build:xenon && npm run build",
|
|
14
|
+
"build:copy": "rm -rf lib/public && mkdir -p lib && cp -R src/public lib/ && cp schema.json lib/",
|
|
15
|
+
"build:schema": "node scripts/generate-types-from-schema.js",
|
|
16
|
+
"build:xenon": "sh scripts/build-xenon.sh",
|
|
17
|
+
"dev": "npm run db:migrate && npm run build && npm run plugin:reinstall && npm run server",
|
|
18
|
+
"server": "export APPIUM_HOME=/tmp/xenon-home && npx appium server -ka 800 --use-plugins=xenon -pa /wd/hub --plugin-xenon-platform=both --plugin-xenon-enable-dashboard",
|
|
19
|
+
"plugin:install": "appium plugin install --source=local $(pwd)",
|
|
20
|
+
"plugin:reinstall": "export APPIUM_HOME=/tmp/xenon-home && (appium plugin uninstall xenon || exit 0) && npm run plugin:install",
|
|
21
|
+
"test": "mocha",
|
|
22
|
+
"test:all": "NODE_ENV=test mocha \"test/unit/**/*.{spec,test}.{ts,js}\" --plugin-xenon-platform=both",
|
|
23
|
+
"test:e2e": "mocha \"test/e2e/plugin.spec.*\" --timeout 300000",
|
|
24
|
+
"test:e2e:hub": "mocha \"test/e2e/hubnode/*.spec.ts\" --plugin-xenon-platform=both --timeout 300000",
|
|
25
|
+
"test:android": "mocha \"test/integration/androidDevices.spec.ts\"",
|
|
26
|
+
"test:ios": "mocha \"test/integration/ios/*.spec.ts\"",
|
|
27
|
+
"test:coverage": "nyc npm run test",
|
|
28
|
+
"lint": "eslint . --ext .ts,.tsx --fix",
|
|
29
|
+
"format": "prettier --write \"{src,web,test}/**/*.{ts,tsx,json,md}\" --single-quote",
|
|
30
|
+
"db:migrate": "path-exists lib/src/scripts/initialize-database.js && node lib/src/scripts/initialize-database.js || ts-node src/scripts/initialize-database.ts",
|
|
31
|
+
"db:generate": "ts-node src/scripts/generate-database-migration.ts",
|
|
32
|
+
"prepublishOnly": "npm run build:all"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/xenon-platform/xenon"
|
|
37
|
+
},
|
|
38
|
+
"contributors": [
|
|
39
|
+
{
|
|
40
|
+
"name": "Rabindra Biswal",
|
|
41
|
+
"email": "rabindrabiswal1@gmail.com"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"license": "ISC",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/xenon-platform/xenon/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/xenon-platform/xenon#readme",
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@anthropic-ai/sdk": "^0.72.1",
|
|
51
|
+
"@appium/base-plugin": "^2.2.22",
|
|
52
|
+
"@appium/types": "^0.14.1",
|
|
53
|
+
"@devicefarmer/adbkit": "^3.2.5",
|
|
54
|
+
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
55
|
+
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
|
56
|
+
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
|
57
|
+
"@fortawesome/react-fontawesome": "^3.1.1",
|
|
58
|
+
"@google/generative-ai": "^0.24.1",
|
|
59
|
+
"@opentelemetry/api": "^1.9.0",
|
|
60
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
|
|
61
|
+
"@opentelemetry/resources": "^2.5.0",
|
|
62
|
+
"@opentelemetry/sdk-node": "^0.211.0",
|
|
63
|
+
"@opentelemetry/semantic-conventions": "^1.39.0",
|
|
64
|
+
"@prisma/client": "^5.4.1",
|
|
65
|
+
"@types/appium-adb": "^9.10.4",
|
|
66
|
+
"@types/express-fileupload": "^1.5.1",
|
|
67
|
+
"@types/node-persist": "^3.1.5",
|
|
68
|
+
"appium-adb": "^11.0.3",
|
|
69
|
+
"appium-chromedriver": "^5.6.19",
|
|
70
|
+
"appium-ios-device": "^2.7.6",
|
|
71
|
+
"async-lock": "^1.2.8",
|
|
72
|
+
"async-wait-until": "^2.0.12",
|
|
73
|
+
"axios": "^0.27.2",
|
|
74
|
+
"cors": "^2.8.5",
|
|
75
|
+
"download": "^8.0.0",
|
|
76
|
+
"express": "^4.17.3",
|
|
77
|
+
"express-fileupload": "^1.5.2",
|
|
78
|
+
"fast-xml-parser": "^5.3.4",
|
|
79
|
+
"fs-extra": "^11.1.1",
|
|
80
|
+
"get-port": "^5.1.1",
|
|
81
|
+
"http-proxy-agent": "7.0.0",
|
|
82
|
+
"http-proxy-middleware": "^3.0.0-beta.1",
|
|
83
|
+
"https-proxy-agent": "7.0.2",
|
|
84
|
+
"ip": "^1.1.8",
|
|
85
|
+
"jsonschema": "1.4.1",
|
|
86
|
+
"lodash": "^4.17.21",
|
|
87
|
+
"lokijs": "^1.5.12",
|
|
88
|
+
"mjpeg-proxy": "^0.3.0",
|
|
89
|
+
"node-abort-controller": "^3.1.1",
|
|
90
|
+
"node-cache": "^5.1.2",
|
|
91
|
+
"node-persist": "^3.1.3",
|
|
92
|
+
"node-schedule": "^2.1.1",
|
|
93
|
+
"node-simctl": "^7.3.13",
|
|
94
|
+
"normalize-url": "6.1.0",
|
|
95
|
+
"nyc": "^15.1.0",
|
|
96
|
+
"openai": "^6.17.0",
|
|
97
|
+
"ora": "5.4.1",
|
|
98
|
+
"path-exists-cli": "^2.0.0",
|
|
99
|
+
"prisma": "^5.4.1",
|
|
100
|
+
"ramda": "^0.28.0",
|
|
101
|
+
"reflect-metadata": "^0.1.13",
|
|
102
|
+
"resiliotree": "^1.1.3",
|
|
103
|
+
"semver": "^7.5.4",
|
|
104
|
+
"sharp": "^0.34.5",
|
|
105
|
+
"socket.io": "^4.8.3",
|
|
106
|
+
"socket.io-client": "^4.8.3",
|
|
107
|
+
"swagger-jsdoc": "^6.2.8",
|
|
108
|
+
"swagger-ui-express": "^5.0.1",
|
|
109
|
+
"tcp-port-used": "^1.0.2",
|
|
110
|
+
"tesseract.js": "^7.0.0",
|
|
111
|
+
"typedi": "^0.10.0",
|
|
112
|
+
"unzipper": "^0.10.14",
|
|
113
|
+
"usbmux": "^0.1.0",
|
|
114
|
+
"uuid": "^8.3.2",
|
|
115
|
+
"xmldom": "^0.6.0",
|
|
116
|
+
"xpath": "^0.0.34",
|
|
117
|
+
"yargs": "^17.7.2",
|
|
118
|
+
"zod": "^4.3.6"
|
|
119
|
+
},
|
|
120
|
+
"peerDependencies": {
|
|
121
|
+
"appium": "^3.1.1"
|
|
122
|
+
},
|
|
123
|
+
"devDependencies": {
|
|
124
|
+
"@appium/docutils": "^0.4.11",
|
|
125
|
+
"@appium/fake-driver": "^6.0.1",
|
|
126
|
+
"@appium/plugin-test-support": "^1.0.3",
|
|
127
|
+
"@babel/core": "7.23.9",
|
|
128
|
+
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
129
|
+
"@types/async-lock": "1.4.2",
|
|
130
|
+
"@types/bluebird": "^3.5.42",
|
|
131
|
+
"@types/chai": "4.3.10",
|
|
132
|
+
"@types/chai-as-promised": "^7.1.8",
|
|
133
|
+
"@types/express": "4.17.21",
|
|
134
|
+
"@types/fs-extra": "^11.0.0",
|
|
135
|
+
"@types/ip": "^1.1.2",
|
|
136
|
+
"@types/js-yaml": "^4.0.9",
|
|
137
|
+
"@types/lodash": "4.14.202",
|
|
138
|
+
"@types/lokijs": "1.5.14",
|
|
139
|
+
"@types/mocha": "9.1.1",
|
|
140
|
+
"@types/node-schedule": "1.3.2",
|
|
141
|
+
"@types/sinon": "^17.0.2",
|
|
142
|
+
"@types/sinon-chai": "^3.2.12",
|
|
143
|
+
"@types/swagger-jsdoc": "^6.0.4",
|
|
144
|
+
"@types/swagger-ui-express": "^4.1.8",
|
|
145
|
+
"@types/tcp-port-used": "1.0.4",
|
|
146
|
+
"@types/uuid": "8.3.4",
|
|
147
|
+
"@types/yargs": "17.0.32",
|
|
148
|
+
"@typescript-eslint/eslint-plugin": "5.62.0",
|
|
149
|
+
"@typescript-eslint/parser": "5.62.0",
|
|
150
|
+
"@wdio/types": "^8.24.2",
|
|
151
|
+
"appium": "3.1.1",
|
|
152
|
+
"appium-uiautomator2-driver": "^5.0.3",
|
|
153
|
+
"appium-xcuitest-driver": "^10.1.2",
|
|
154
|
+
"babel-eslint": "10.1.0",
|
|
155
|
+
"chai": "4.3.10",
|
|
156
|
+
"chai-as-promised": "^7.1.1",
|
|
157
|
+
"chai-exclude": "^2.1.0",
|
|
158
|
+
"dotenv": "^16.3.1",
|
|
159
|
+
"eslint": "8.52.0",
|
|
160
|
+
"eslint-config-prettier": "9.0.0",
|
|
161
|
+
"eslint-plugin-import": "2.29.1",
|
|
162
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
163
|
+
"husky": "7.0.4",
|
|
164
|
+
"js-yaml": "^4.1.0",
|
|
165
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
166
|
+
"lint-staged": "15.0.2",
|
|
167
|
+
"mocha": "9.2.2",
|
|
168
|
+
"prettier": "^3.0.3",
|
|
169
|
+
"ramda": "0.29.1",
|
|
170
|
+
"sinon": "17.0.0",
|
|
171
|
+
"sinon-chai": "^3.7.0",
|
|
172
|
+
"ts-node": "10.9.1",
|
|
173
|
+
"typescript": "^5.5.4",
|
|
174
|
+
"vite": "^4.5.0",
|
|
175
|
+
"webdriverio": "^8.20.4"
|
|
176
|
+
},
|
|
177
|
+
"appium": {
|
|
178
|
+
"pluginName": "xenon",
|
|
179
|
+
"mainClass": "XenonPlugin",
|
|
180
|
+
"schema": "schema.json"
|
|
181
|
+
},
|
|
182
|
+
"engines": {
|
|
183
|
+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
|
|
184
|
+
"npm": ">=8"
|
|
185
|
+
},
|
|
186
|
+
"lint-staged": {
|
|
187
|
+
"src/*.{js,jsx,ts,tsx,json,css,scss,md}": [
|
|
188
|
+
"npm run prettier",
|
|
189
|
+
"git add"
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
"husky": {
|
|
193
|
+
"hooks": {
|
|
194
|
+
"pre-commit": "lint-staged",
|
|
195
|
+
"pre-push": "npm run test"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"files": [
|
|
199
|
+
"lib",
|
|
200
|
+
"scripts",
|
|
201
|
+
"prisma",
|
|
202
|
+
"schema.json"
|
|
203
|
+
],
|
|
204
|
+
"typedoc": {
|
|
205
|
+
"entryPoint": "lib/src/index.js"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{c,j as e,g as l}from"./index-ByQwMN5T.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 i=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],h=c("rotate-ccw",i);/**
|
|
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 x=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],j=c("save",x),b=({onSave:o,onDiscard:d,onRestoreDefaults:t,isSaving:s,isValidating:a=!1,saveLabel:n="Save Configuration",restoreLabel:r="Restore Defaults"})=>e.jsxs("div",{className:"settings-footer",children:[e.jsx("div",{className:"footer-left",children:t&&e.jsxs("button",{className:"reset-to-defaults-btn",onClick:t,disabled:s||a,children:[e.jsx(h,{size:16}),r]})}),e.jsxs("div",{className:"footer-right",children:[e.jsx("button",{className:"reset-btn",onClick:d,disabled:s||a,children:"Discard"}),e.jsxs("button",{className:"save-btn",onClick:o,disabled:s||a,children:[s?e.jsx(l,{className:"animate-spin",size:18}):e.jsx(j,{size:18}),s?"Saving...":n]})]})]});export{b as A};
|