@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.
Files changed (228) hide show
  1. package/README.md +446 -0
  2. package/lib/package.json +207 -0
  3. package/lib/public/assets/Layouts-7IT8aFLI.js +11 -0
  4. package/lib/public/assets/Layouts-DPMls9vh.css +1 -0
  5. package/lib/public/assets/ai-settings-BbnfgdEx.js +11 -0
  6. package/lib/public/assets/apps-CRMrI4_p.js +16 -0
  7. package/lib/public/assets/apps-CcM77dgg.css +1 -0
  8. package/lib/public/assets/badge-B1nKs8zj.css +1 -0
  9. package/lib/public/assets/badge-CSvl5xIU.js +11 -0
  10. package/lib/public/assets/button-CJlKn4PZ.css +1 -0
  11. package/lib/public/assets/button-CvLaGFYj.js +26 -0
  12. package/lib/public/assets/calendar-6w-D6Oaw.js +6 -0
  13. package/lib/public/assets/clock-DcdeWBPr.js +6 -0
  14. package/lib/public/assets/cpu-DiSoXT9n.js +6 -0
  15. package/lib/public/assets/device-explorer-CajM63OJ.js +193 -0
  16. package/lib/public/assets/device-explorer-CxdUAoTL.css +1 -0
  17. package/lib/public/assets/index-ByQwMN5T.js +174 -0
  18. package/lib/public/assets/index-C1DBaoSh.js +1 -0
  19. package/lib/public/assets/index-qzCez_kk.css +1 -0
  20. package/lib/public/assets/lock-B23ibZmo.js +6 -0
  21. package/lib/public/assets/maintenance-settings-CirzA6yG.js +6 -0
  22. package/lib/public/assets/mouse-pointer-2-Cz76SHFb.js +6 -0
  23. package/lib/public/assets/plus-BBwlIevt.js +6 -0
  24. package/lib/public/assets/session-dashboard-C2k7FFv_.css +1 -0
  25. package/lib/public/assets/session-dashboard-HPDtwPOZ.js +62 -0
  26. package/lib/public/assets/settings-DrZsZwdc.js +1 -0
  27. package/lib/public/assets/trash-2-DQpvzJec.js +6 -0
  28. package/lib/public/assets/useSocket-Dxsqae2a.js +16 -0
  29. package/lib/public/assets/webhook-settings-CDPgsgkb.css +1 -0
  30. package/lib/public/assets/webhook-settings-Cp-B4Nrw.js +1 -0
  31. package/lib/public/assets/zap-DovP6iow.js +6 -0
  32. package/lib/public/favicon.ico +0 -0
  33. package/lib/public/favicon.png +0 -0
  34. package/lib/public/favicon.svg +9 -0
  35. package/lib/public/index.html +46 -0
  36. package/lib/public/logo.svg +17 -0
  37. package/lib/public/logo192.png +0 -0
  38. package/lib/public/logo512.png +0 -0
  39. package/lib/public/manifest.json +25 -0
  40. package/lib/public/robots.txt +3 -0
  41. package/lib/schema.json +348 -0
  42. package/lib/src/InternalHttpClient.js +212 -0
  43. package/lib/src/PluginContext.js +29 -0
  44. package/lib/src/XenonCapabilityManager.js +199 -0
  45. package/lib/src/app/index.js +167 -0
  46. package/lib/src/app/routers/apps.js +79 -0
  47. package/lib/src/app/routers/config.js +131 -0
  48. package/lib/src/app/routers/control.js +835 -0
  49. package/lib/src/app/routers/dashboard.js +301 -0
  50. package/lib/src/app/routers/grid.js +352 -0
  51. package/lib/src/app/routers/reservation.js +190 -0
  52. package/lib/src/app/routers/webhook.js +83 -0
  53. package/lib/src/app/swagger-docs.js +203 -0
  54. package/lib/src/app/swagger.js +366 -0
  55. package/lib/src/chromeUtils.js +148 -0
  56. package/lib/src/commands/handle.js +19 -0
  57. package/lib/src/commands/index.js +8 -0
  58. package/lib/src/config.js +73 -0
  59. package/lib/src/dashboard/asset-manager.js +84 -0
  60. package/lib/src/dashboard/commands.js +284 -0
  61. package/lib/src/dashboard/event-manager.js +699 -0
  62. package/lib/src/dashboard/services/app-service.js +134 -0
  63. package/lib/src/dashboard/services/failure-analysis-service.js +173 -0
  64. package/lib/src/dashboard/services/session-service.js +113 -0
  65. package/lib/src/data-service/CircuitBreaker.js +83 -0
  66. package/lib/src/data-service/config-service.js +155 -0
  67. package/lib/src/data-service/db.js +122 -0
  68. package/lib/src/data-service/device-service.js +320 -0
  69. package/lib/src/data-service/device-store.interface.js +2 -0
  70. package/lib/src/data-service/device-store.js +345 -0
  71. package/lib/src/data-service/pending-sessions-service.js +25 -0
  72. package/lib/src/data-service/pluginArgs.js +25 -0
  73. package/lib/src/data-service/prisma-service.js +31 -0
  74. package/lib/src/data-service/prisma-store.js +385 -0
  75. package/lib/src/data-service/queue-service.js +150 -0
  76. package/lib/src/data-service/web-config-service.js +130 -0
  77. package/lib/src/device-managers/AndroidDeviceManager.js +1155 -0
  78. package/lib/src/device-managers/ChromeDriverManager.js +68 -0
  79. package/lib/src/device-managers/HealthMonitorService.js +325 -0
  80. package/lib/src/device-managers/IOSDeviceManager.js +351 -0
  81. package/lib/src/device-managers/NodeDevices.js +82 -0
  82. package/lib/src/device-managers/android/AndroidStreamService.js +370 -0
  83. package/lib/src/device-managers/android/DeviceLockManager.js +45 -0
  84. package/lib/src/device-managers/cloud/CapabilityManager.js +26 -0
  85. package/lib/src/device-managers/cloud/Devices.js +86 -0
  86. package/lib/src/device-managers/iOSTracker.js +44 -0
  87. package/lib/src/device-managers/index.js +89 -0
  88. package/lib/src/device-managers/ios/IOSDiscoveryService.js +268 -0
  89. package/lib/src/device-managers/ios/IOSStreamService.js +893 -0
  90. package/lib/src/device-managers/ios/WDAClient.js +866 -0
  91. package/lib/src/device-utils.js +663 -0
  92. package/lib/src/enums/Capabilities.js +8 -0
  93. package/lib/src/enums/Cloud.js +11 -0
  94. package/lib/src/enums/Platform.js +9 -0
  95. package/lib/src/enums/SessionType.js +9 -0
  96. package/lib/src/enums/SocketEvents.js +15 -0
  97. package/lib/src/helpers/UniversalMjpegProxy.js +273 -0
  98. package/lib/src/helpers/index.js +229 -0
  99. package/lib/src/index.js +95 -0
  100. package/lib/src/interceptors/CommandInterceptor.js +524 -0
  101. package/lib/src/interfaces/ICloudManager.js +2 -0
  102. package/lib/src/interfaces/IDevice.js +2 -0
  103. package/lib/src/interfaces/IDeviceFilterOptions.js +2 -0
  104. package/lib/src/interfaces/IDeviceManager.js +2 -0
  105. package/lib/src/interfaces/IOptions.js +2 -0
  106. package/lib/src/interfaces/IPluginArgs.js +55 -0
  107. package/lib/src/interfaces/ISessionCapability.js +2 -0
  108. package/lib/src/logger.js +225 -0
  109. package/lib/src/plugin.js +244 -0
  110. package/lib/src/prisma.js +12 -0
  111. package/lib/src/profiling/AndroidAppProfiler.js +213 -0
  112. package/lib/src/proxy/wd-command-proxy.js +221 -0
  113. package/lib/src/scripts/generate-database-migration.js +59 -0
  114. package/lib/src/scripts/initialize-database.js +55 -0
  115. package/lib/src/scripts/install-go-ios.js +66 -0
  116. package/lib/src/scripts/prepare-prisma.js +89 -0
  117. package/lib/src/services/AICommandService.js +143 -0
  118. package/lib/src/services/AIService.js +466 -0
  119. package/lib/src/services/CleanupService.js +141 -0
  120. package/lib/src/services/EventBus.js +74 -0
  121. package/lib/src/services/InspectorService.js +395 -0
  122. package/lib/src/services/MetricsService.js +134 -0
  123. package/lib/src/services/NetworkConditioningService.js +173 -0
  124. package/lib/src/services/NotificationService.js +163 -0
  125. package/lib/src/services/RequestLogService.js +252 -0
  126. package/lib/src/services/ResourceIsolationService.js +122 -0
  127. package/lib/src/services/SecurityService.js +120 -0
  128. package/lib/src/services/ServerManager.js +284 -0
  129. package/lib/src/services/SessionHeartbeatService.js +158 -0
  130. package/lib/src/services/SessionLifecycleService.js +572 -0
  131. package/lib/src/services/SocketClient.js +71 -0
  132. package/lib/src/services/SocketServer.js +87 -0
  133. package/lib/src/services/TracingService.js +132 -0
  134. package/lib/src/services/VideoPipelineService.js +220 -0
  135. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +333 -0
  136. package/lib/src/services/healing/HealEtalonService.js +98 -0
  137. package/lib/src/services/healing/HealedLocatorGenerator.js +132 -0
  138. package/lib/src/services/healing/HealingOrchestrator.js +165 -0
  139. package/lib/src/services/healing/LlmHealingProvider.js +77 -0
  140. package/lib/src/services/healing/OcrHealingProvider.js +119 -0
  141. package/lib/src/services/healing/ResilioTreeHealingProvider.js +100 -0
  142. package/lib/src/services/healing/VisualAiHealingProvider.js +90 -0
  143. package/lib/src/services/healing/types.js +12 -0
  144. package/lib/src/services/omni-vision/OmniVisionService.js +718 -0
  145. package/lib/src/services/omni-vision/VisionAssertionService.js +68 -0
  146. package/lib/src/sessions/CloudSession.js +42 -0
  147. package/lib/src/sessions/LocalSession.js +313 -0
  148. package/lib/src/sessions/RemoteSession.js +287 -0
  149. package/lib/src/sessions/SessionManager.js +238 -0
  150. package/lib/src/sessions/XenonSession.js +44 -0
  151. package/lib/src/types/CLIArgs.js +2 -0
  152. package/lib/src/types/CloudArgs.js +2 -0
  153. package/lib/src/types/CloudSchema.js +131 -0
  154. package/lib/src/types/DeviceType.js +2 -0
  155. package/lib/src/types/DeviceUpdate.js +2 -0
  156. package/lib/src/types/IOSDevice.js +2 -0
  157. package/lib/src/types/Platform.js +2 -0
  158. package/lib/src/types/SessionStatus.js +11 -0
  159. package/lib/src/validators/CapabilityValidator.js +93 -0
  160. package/lib/test/e2e/android/conf.spec.js +43 -0
  161. package/lib/test/e2e/android/conf2.spec.js +44 -0
  162. package/lib/test/e2e/android/conf3.spec.js +44 -0
  163. package/lib/test/e2e/e2ehelper.js +113 -0
  164. package/lib/test/e2e/hubnode/forward-request.spec.js +224 -0
  165. package/lib/test/e2e/hubnode/hubnode.spec.js +214 -0
  166. package/lib/test/e2e/ios/conf1.spec.js +39 -0
  167. package/lib/test/e2e/ios/conf2.spec.js +39 -0
  168. package/lib/test/e2e/plugin-harness.js +236 -0
  169. package/lib/test/e2e/plugin.spec.js +97 -0
  170. package/lib/test/e2e/telemetry_verification.spec.js +83 -0
  171. package/lib/test/e2e/video-recording-test.spec.js +63 -0
  172. package/lib/test/helpers/test-container.js +112 -0
  173. package/lib/test/integration/androidDevices.spec.js +137 -0
  174. package/lib/test/integration/cliArgs.js +73 -0
  175. package/lib/test/integration/ios/01iOSSimulator.spec.js +291 -0
  176. package/lib/test/integration/ios/02iOSDevices.spec.js +75 -0
  177. package/lib/test/integration/testHelpers.js +74 -0
  178. package/lib/test/unit/AndroidDeviceManager.spec.js +178 -0
  179. package/lib/test/unit/ChromeDriverManager.spec.js +26 -0
  180. package/lib/test/unit/CleanupService.spec.js +21 -0
  181. package/lib/test/unit/DeviceModel.spec.js +157 -0
  182. package/lib/test/unit/FuzzyXmlHealingProvider.test.js +294 -0
  183. package/lib/test/unit/GetAdbOriginal.js +42 -0
  184. package/lib/test/unit/HealingCascade.test.js +128 -0
  185. package/lib/test/unit/IOSDeviceManager.spec.js +261 -0
  186. package/lib/test/unit/RemoteIOs.spec.js +78 -0
  187. package/lib/test/unit/ResilioTreeHealingProvider.test.js +96 -0
  188. package/lib/test/unit/commands.spec.js +27 -0
  189. package/lib/test/unit/config.spec.js +27 -0
  190. package/lib/test/unit/device-service.spec.js +307 -0
  191. package/lib/test/unit/device-utils.spec.js +313 -0
  192. package/lib/test/unit/fixtures/device.config.js +4 -0
  193. package/lib/test/unit/fixtures/devices.js +89 -0
  194. package/lib/test/unit/helpers.spec.js +62 -0
  195. package/lib/test/unit/omni-vision.spec.js +100 -0
  196. package/lib/test/unit/plugin.spec.js +133 -0
  197. package/lib/tsconfig.tsbuildinfo +1 -0
  198. package/package.json +207 -0
  199. package/prisma/data.db +0 -0
  200. package/prisma/dev.db +0 -0
  201. package/prisma/dev.db-journal +0 -0
  202. package/prisma/migrations/20231011074725_initial_tables/migration.sql +47 -0
  203. package/prisma/migrations/20231226115334_update_session_log/migration.sql +2 -0
  204. package/prisma/migrations/20251204113710_add_video_recording_enabled/migration.sql +29 -0
  205. package/prisma/migrations/20251204132449_add_log_table/migration.sql +11 -0
  206. package/prisma/migrations/20251205050111_add_profiling_support/migration.sql +47 -0
  207. package/prisma/migrations/20251205050947_add_is_error_field/migration.sql +24 -0
  208. package/prisma/migrations/20260126201337_add_app_model/migration.sql +18 -0
  209. package/prisma/migrations/20260130115722_add_performance_trace_and_xenon_sync/migration.sql +2 -0
  210. package/prisma/migrations/20260130135114_add_device_models/migration.sql +57 -0
  211. package/prisma/migrations/20260130140655_make_systemport_optional/migration.sql +45 -0
  212. package/prisma/migrations/20260130140932_make_device_fields_optional/migration.sql +45 -0
  213. package/prisma/migrations/20260130141040_final_schema_fix/migration.sql +45 -0
  214. package/prisma/migrations/20260130143234_add_device_health_fields/migration.sql +4 -0
  215. package/prisma/migrations/20260130144921_add_failure_category/migration.sql +2 -0
  216. package/prisma/migrations/20260131151456_add_webhook_config/migration.sql +10 -0
  217. package/prisma/migrations/20260201094507_add_device_tags/migration.sql +11 -0
  218. package/prisma/migrations/20260201103410_add_managed_process/migration.sql +15 -0
  219. package/prisma/migrations/20260201140637_add_web_config/migration.sql +22 -0
  220. package/prisma/migrations/20260201162232_add_session_progress/migration.sql +2 -0
  221. package/prisma/migrations/20260201174231_add_total_healed_count/migration.sql +2 -0
  222. package/prisma/migrations/migration_lock.toml +3 -0
  223. package/prisma/schema.prisma +210 -0
  224. package/schema.json +348 -0
  225. package/scripts/build-xenon.sh +32 -0
  226. package/scripts/dev/debug-gemini.ts +44 -0
  227. package/scripts/generate-types-from-schema.js +86 -0
  228. package/scripts/install-compatible-driver.js +39 -0
@@ -0,0 +1,366 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.swaggerSpec = void 0;
7
+ exports.setupSwagger = setupSwagger;
8
+ const swagger_jsdoc_1 = __importDefault(require("swagger-jsdoc"));
9
+ const swagger_ui_express_1 = __importDefault(require("swagger-ui-express"));
10
+ const swaggerDefinition = {
11
+ openapi: '3.0.0',
12
+ servers: [
13
+ {
14
+ url: '/xenon',
15
+ description: 'Local Grid Node Registry',
16
+ },
17
+ ],
18
+ info: {
19
+ title: 'Xenon API',
20
+ version: '1.0.0',
21
+ description: `
22
+ # Xenon Edge • Intelligent Infrastructure API
23
+ **The foundation for autonomous mobile device orchestration.**
24
+
25
+ Xenon's high-performance API provides programmatic access to the core orchestration engine, enabling complex automation workflows for distributed device farms.
26
+
27
+ ### Key Capabilities:
28
+ * **Elastic Device Grid**: Real-time discovery and state management of physical nodes.
29
+ * **Autonomous Sessions**: Self-healing Appium session management with automated retries.
30
+ * **Deep Control**: Direct low-latency interaction logic (Input injection, thermal monitoring).
31
+ * **Security Protocol**: Industrial-grade isolation for sensitive test environments.
32
+
33
+ ---
34
+ Currently operating in **OSS Mode**. Future releases will support **Xenon Identity (JWT)** for secure fleet-wide propagation.
35
+ `,
36
+ contact: {
37
+ name: 'Xenon Architecture Team',
38
+ url: 'https://github.com/xenon-platform/xenon',
39
+ },
40
+ license: {
41
+ name: 'ISC License',
42
+ url: 'https://opensource.org/licenses/ISC',
43
+ },
44
+ },
45
+ tags: [
46
+ { name: 'Devices', description: 'Real-time grid discovery' },
47
+ { name: 'Sessions', description: 'Orchestration & Logs' },
48
+ { name: 'Builds', description: 'Telemetry tracking' },
49
+ { name: 'Control', description: 'Direct interaction engine' },
50
+ { name: 'Reservations', description: 'Resource locking' },
51
+ { name: 'Applications', description: 'Artifact management' },
52
+ { name: 'Grid', description: 'Cluster topology' },
53
+ { name: 'Webhooks', description: 'Event propagation' },
54
+ { name: 'Configuration', description: 'Edge node parameters' },
55
+ ],
56
+ components: {
57
+ schemas: {
58
+ Device: {
59
+ type: 'object',
60
+ properties: {
61
+ udid: {
62
+ type: 'string',
63
+ description: 'Unique identity',
64
+ example: '00008110-00084CE80E51401E',
65
+ },
66
+ name: { type: 'string', example: 'iPhone 14 Pro' },
67
+ platform: { type: 'string', enum: ['ios', 'android'] },
68
+ host: { type: 'string', example: '192.168.1.100' },
69
+ busy: { type: 'boolean' },
70
+ session_id: { type: 'string', nullable: true },
71
+ state: { type: 'string' },
72
+ sdk: { type: 'string', example: '17.0' },
73
+ deviceType: { type: 'string' },
74
+ },
75
+ },
76
+ // ... (rest of schemas remain same for internal completeness)
77
+ Session: {
78
+ type: 'object',
79
+ properties: {
80
+ id: { type: 'string' },
81
+ name: { type: 'string' },
82
+ status: { type: 'string', enum: ['running', 'success', 'failed'] },
83
+ device_udid: { type: 'string' },
84
+ device_name: { type: 'string' },
85
+ device_platform: { type: 'string' },
86
+ createdAt: { type: 'string', format: 'date-time' },
87
+ },
88
+ },
89
+ Build: {
90
+ type: 'object',
91
+ properties: {
92
+ id: { type: 'string' },
93
+ name: { type: 'string' },
94
+ sessionCount: { type: 'integer' },
95
+ passedCount: { type: 'integer' },
96
+ failedCount: { type: 'integer' },
97
+ runningCount: { type: 'integer' },
98
+ createdAt: { type: 'string', format: 'date-time' },
99
+ },
100
+ },
101
+ Reservation: {
102
+ type: 'object',
103
+ properties: {
104
+ udid: { type: 'string' },
105
+ host: { type: 'string' },
106
+ reservedBy: { type: 'string' },
107
+ reservedUntil: { type: 'integer' },
108
+ reservationReason: { type: 'string' },
109
+ remainingMs: { type: 'integer' },
110
+ },
111
+ },
112
+ App: {
113
+ type: 'object',
114
+ properties: {
115
+ id: { type: 'string' },
116
+ name: { type: 'string' },
117
+ filename: { type: 'string' },
118
+ filepath: { type: 'string' },
119
+ platform: { type: 'string', enum: ['ios', 'android'] },
120
+ uploadedAt: { type: 'string', format: 'date-time' },
121
+ },
122
+ },
123
+ WebhookConfig: {
124
+ type: 'object',
125
+ properties: {
126
+ id: { type: 'string' },
127
+ url: { type: 'string', format: 'uri' },
128
+ events: { type: 'array', items: { type: 'string' } },
129
+ type: { type: 'string', enum: ['slack', 'webhook'] },
130
+ },
131
+ },
132
+ LocatorSuggestion: {
133
+ type: 'object',
134
+ properties: {
135
+ strategy: { type: 'string' },
136
+ value: { type: 'string' },
137
+ priority: { type: 'integer' },
138
+ isUnique: { type: 'boolean' },
139
+ },
140
+ },
141
+ InspectorNode: {
142
+ type: 'object',
143
+ properties: {
144
+ id: { type: 'string' },
145
+ type: { type: 'string' },
146
+ text: { type: 'string' },
147
+ path: { type: 'string' },
148
+ rect: {
149
+ type: 'object',
150
+ properties: {
151
+ x: { type: 'number' },
152
+ y: { type: 'number' },
153
+ width: { type: 'number' },
154
+ height: { type: 'number' },
155
+ },
156
+ },
157
+ attributes: { type: 'object', additionalProperties: true },
158
+ locators: {
159
+ type: 'array',
160
+ items: { $ref: '#/components/schemas/LocatorSuggestion' },
161
+ },
162
+ children: {
163
+ type: 'array',
164
+ items: { $ref: '#/components/schemas/InspectorNode' },
165
+ },
166
+ },
167
+ },
168
+ InspectorSnapshot: {
169
+ type: 'object',
170
+ properties: {
171
+ udid: { type: 'string' },
172
+ platform: { type: 'string' },
173
+ screenshot: { type: 'string', description: 'Base64 encoded screenshot' },
174
+ root: { $ref: '#/components/schemas/InspectorNode' },
175
+ },
176
+ },
177
+ Error: {
178
+ type: 'object',
179
+ properties: {
180
+ error: { type: 'boolean', example: true },
181
+ message: { type: 'string' },
182
+ },
183
+ },
184
+ Success: {
185
+ type: 'object',
186
+ properties: {
187
+ success: { type: 'boolean', example: true },
188
+ },
189
+ },
190
+ },
191
+ },
192
+ };
193
+ const path_1 = __importDefault(require("path"));
194
+ // @ts-ignore - Types will be available after package install
195
+ const options = {
196
+ swaggerDefinition,
197
+ apis: [
198
+ // Load from compiled JS (execution runtime)
199
+ path_1.default.join(__dirname, 'swagger-docs.js'),
200
+ path_1.default.join(__dirname, 'routers', '*.js'),
201
+ // Fallback to TS source (development environment)
202
+ path_1.default.join(__dirname, '..', '..', '..', 'src', 'app', 'swagger-docs.ts'),
203
+ path_1.default.join(__dirname, '..', '..', '..', 'src', 'app', 'routers', '*.ts'),
204
+ ],
205
+ };
206
+ const swaggerSpec = (0, swagger_jsdoc_1.default)(options);
207
+ exports.swaggerSpec = swaggerSpec;
208
+ function setupSwagger(app, basePath = '/xenon') {
209
+ // Serve Swagger UI at /xenon/api-docs
210
+ app.use('/api-docs', swagger_ui_express_1.default.serve, swagger_ui_express_1.default.setup(swaggerSpec, {
211
+ customCss: `
212
+ /* Xenon Ultimate V2 • High-Integrity API Documentation */
213
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap');
214
+
215
+ :root {
216
+ --xenon-bg: #020617;
217
+ --xenon-surface: #0f172a;
218
+ --xenon-surface-hover: #1e293b;
219
+ --xenon-border: rgba(255, 255, 255, 0.05);
220
+ --xenon-border-bright: rgba(255, 255, 255, 0.12);
221
+ --xenon-emerald: #22c55e;
222
+ --xenon-emerald-glow: rgba(34, 197, 94, 0.2);
223
+ --xenon-blue: #38bdf8;
224
+ --xenon-blue-glow: rgba(56, 189, 248, 0.2);
225
+ --xenon-amber: #fbbf24;
226
+ --xenon-amber-glow: rgba(251, 191, 36, 0.2);
227
+ --xenon-crimson: #f43f5e;
228
+ --xenon-crimson-glow: rgba(244, 63, 94, 0.2);
229
+ --xenon-text: #f8fafc;
230
+ --xenon-text-dim: #94a3b8;
231
+ --xenon-text-dark: #475569;
232
+ }
233
+
234
+ body { background: var(--xenon-bg) !important; margin: 0; font-family: 'Inter', sans-serif !important; -webkit-font-smoothing: antialiased; }
235
+ .swagger-ui { background: var(--xenon-bg) !important; color: var(--xenon-text) !important; padding-bottom: 80px; }
236
+
237
+ /* Layout & Spacing */
238
+ .swagger-ui .wrapper { max-width: 1100px; padding: 0 40px; }
239
+ .swagger-ui .topbar { display: none; }
240
+
241
+ /* Header & Info */
242
+ .swagger-ui .info { margin: 80px 0 40px 0; }
243
+ .swagger-ui .info .title {
244
+ font-family: 'Outfit', sans-serif;
245
+ font-size: 52px;
246
+ font-weight: 800;
247
+ color: #fff !important;
248
+ letter-spacing: -0.04em;
249
+ margin-bottom: 24px;
250
+ background: linear-gradient(to bottom right, #fff 30%, var(--xenon-text-dim));
251
+ -webkit-background-clip: text;
252
+ -webkit-text-fill-color: transparent;
253
+ }
254
+ .swagger-ui .info p { font-size: 18px; color: var(--xenon-text-dim) !important; line-height: 1.8; max-width: 700px; margin-bottom: 32px; }
255
+ .swagger-ui .info code { background: #18181b; color: var(--xenon-emerald); padding: 4px 8px; border-radius: 6px; font-family: 'JetBrains Mono', monospace; font-size: 14px; }
256
+
257
+ /* Server Selection Card */
258
+ .swagger-ui .scheme-container {
259
+ background: var(--xenon-surface) !important;
260
+ border: 1px solid var(--xenon-border);
261
+ border-radius: 20px;
262
+ padding: 32px;
263
+ box-shadow: 0 20px 40px rgba(0,0,0,0.5), inset 0 1px 1px rgba(255,255,255,0.05);
264
+ margin: 40px 0;
265
+ }
266
+ .swagger-ui .servers-title { color: #fff !important; font-family: 'Outfit', sans-serif; font-size: 14px; text-transform: uppercase; letter-spacing: 0.1em; opacity: 0.5; margin-bottom: 12px; }
267
+ .swagger-ui .servers select { background: #000 !important; border: 1px solid var(--xenon-border-bright) !important; color: var(--xenon-text) !important; border-radius: 10px !important; padding: 12px !important; width: 100%; max-width: 400px; }
268
+
269
+ /* Operations & Methods */
270
+ .swagger-ui .opblock-tag {
271
+ font-family: 'Outfit', sans-serif;
272
+ border: none;
273
+ color: #fff !important;
274
+ font-size: 24px;
275
+ font-weight: 700;
276
+ margin: 60px 0 24px 0;
277
+ padding: 0;
278
+ display: flex;
279
+ align-items: center;
280
+ gap: 12px;
281
+ }
282
+ .swagger-ui .opblock-tag small { color: var(--xenon-text-dim) !important; font-size: 14px; font-weight: 400; text-transform: none; letter-spacing: 0; margin-left: auto; }
283
+
284
+ .swagger-ui .opblock {
285
+ border: 1px solid var(--xenon-border) !important;
286
+ background: var(--xenon-surface) !important;
287
+ border-radius: 16px !important;
288
+ margin-bottom: 16px !important;
289
+ box-shadow: 0 4px 12px rgba(0,0,0,0.2);
290
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
291
+ overflow: hidden;
292
+ }
293
+ .swagger-ui .opblock:hover {
294
+ border-color: var(--xenon-border-bright) !important;
295
+ transform: translateY(-2px);
296
+ box-shadow: 0 12px 24px rgba(0,0,0,0.4);
297
+ background: var(--xenon-surface-hover) !important;
298
+ }
299
+ .swagger-ui .opblock-summary { padding: 16px 24px; border-bottom: none !important; }
300
+
301
+ /* Semantic Method Glows */
302
+ .swagger-ui .opblock-summary-method {
303
+ border-radius: 8px !important;
304
+ border: none !important;
305
+ font-family: 'JetBrains Mono', monospace !important;
306
+ font-weight: 800 !important;
307
+ font-size: 13px !important;
308
+ min-width: 85px !important;
309
+ padding: 6px 0 !important;
310
+ box-shadow: inset 0 1px 1px rgba(255,255,255,0.2) !important;
311
+ }
312
+
313
+ /* GET */
314
+ .swagger-ui .opblock.opblock-get .opblock-summary-method { background: var(--xenon-blue) !important; box-shadow: 0 0 15px var(--xenon-blue-glow), inset 0 1px 1px rgba(255,255,255,0.2) !important; }
315
+ .swagger-ui .opblock.opblock-get:hover { border-color: var(--xenon-blue) !important; }
316
+ /* POST */
317
+ .swagger-ui .opblock.opblock-post .opblock-summary-method { background: var(--xenon-emerald) !important; box-shadow: 0 0 15px var(--xenon-emerald-glow), inset 0 1px 1px rgba(255,255,255,0.2) !important; }
318
+ .swagger-ui .opblock.opblock-post:hover { border-color: var(--xenon-emerald) !important; }
319
+ /* PUT */
320
+ .swagger-ui .opblock.opblock-put .opblock-summary-method { background: var(--xenon-amber) !important; box-shadow: 0 0 15px var(--xenon-amber-glow), inset 0 1px 1px rgba(255,255,255,0.2) !important; }
321
+ .swagger-ui .opblock.opblock-put:hover { border-color: var(--xenon-amber) !important; }
322
+ /* DELETE */
323
+ .swagger-ui .opblock.opblock-delete .opblock-summary-method { background: var(--xenon-crimson) !important; box-shadow: 0 0 15px var(--xenon-crimson-glow), inset 0 1px 1px rgba(255,255,255,0.2) !important; }
324
+ .swagger-ui .opblock.opblock-delete:hover { border-color: var(--xenon-crimson) !important; }
325
+
326
+ .swagger-ui .opblock-summary-path { color: #fff !important; font-family: 'JetBrains Mono', monospace !important; font-size: 16px !important; font-weight: 600 !important; }
327
+ .swagger-ui .opblock-summary-description { color: var(--xenon-text-dim) !important; font-size: 14px; margin-left: 12px; }
328
+
329
+ /* Forms & Interactive */
330
+ .swagger-ui .btn.authorize { color: var(--xenon-emerald) !important; border-color: var(--xenon-emerald) !important; background: transparent !important; border-radius: 12px; font-weight: 600; padding: 10px 24px; transition: all 0.2s; }
331
+ .swagger-ui .btn.authorize:hover { background: var(--xenon-emerald-glow) !important; transform: scale(1.02); }
332
+ .swagger-ui .btn.authorize svg { fill: var(--xenon-emerald) !important; }
333
+
334
+ .swagger-ui .btn.execute { background-color: var(--xenon-emerald) !important; border: none !important; border-radius: 12px !important; padding: 12px 32px !important; font-weight: 700 !important; letter-spacing: 0.1em; text-transform: uppercase; box-shadow: 0 8px 16px var(--xenon-emerald-glow) !important; }
335
+ .swagger-ui .btn.cancel { border-radius: 12px !important; border: 1px solid var(--xenon-border-bright) !important; color: var(--xenon-text) !important; }
336
+
337
+ .swagger-ui input[type=text], .swagger-ui select, .swagger-ui textarea { background: #000 !important; border: 1px solid var(--xenon-border-bright) !important; color: #fff !important; border-radius: 12px !important; padding: 14px !important; }
338
+
339
+ /* Models / Schemas */
340
+ .swagger-ui section.models { border: 1px solid var(--xenon-border); border-radius: 20px; background: var(--xenon-surface); margin-top: 80px; padding: 20px; }
341
+ .swagger-ui section.models h4 { color: #fff !important; font-family: 'Outfit', sans-serif; font-size: 20px; margin-bottom: 24px; border-bottom: 1px solid var(--xenon-border); padding-bottom: 12px; }
342
+ .swagger-ui .model-box { background: transparent !important; }
343
+ .swagger-ui .model-title { color: var(--xenon-emerald) !important; font-family: 'JetBrains Mono', monospace; font-size: 14px; }
344
+ .swagger-ui .prop-type { color: var(--xenon-blue) !important; }
345
+ .swagger-ui .prop-format { color: var(--xenon-text-dim) !important; font-size: 11px; }
346
+
347
+ /* Modal Overhaul */
348
+ .swagger-ui .dialog-ux .modal-ux { background: var(--xenon-bg) !important; border: 1px solid var(--xenon-border-bright) !important; border-radius: 28px; box-shadow: 0 80px 160px rgba(0,0,0,0.9); padding: 40px; }
349
+ .swagger-ui .dialog-ux .modal-ux-header h3 { font-family: 'Outfit', sans-serif; font-size: 28px; color: #fff !important; margin-bottom: 16px; }
350
+ .swagger-ui .dialog-ux .modal-ux-content h4 { color: var(--xenon-text-dim) !important; margin-top: 24px; }
351
+
352
+ /* Custom Scrollbar */
353
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
354
+ ::-webkit-scrollbar-track { background: var(--xenon-bg); }
355
+ ::-webkit-scrollbar-thumb { background: #27272a; border-radius: 5px; border: 2px solid var(--xenon-bg); }
356
+ ::-webkit-scrollbar-thumb:hover { background: #3f3f46; }
357
+ `,
358
+ customSiteTitle: 'Xenon API Documentation',
359
+ customfavIcon: '/xenon/favicon.png',
360
+ }));
361
+ // Serve raw OpenAPI spec as JSON
362
+ app.get('/api-docs.json', (req, res) => {
363
+ res.setHeader('Content-Type', 'application/json');
364
+ res.send(swaggerSpec);
365
+ });
366
+ }
@@ -0,0 +1,148 @@
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
+ exports.getModuleRoot = exports.OS = exports.getOsInfo = exports.CD_VER = exports.CD_CDN = exports.getOsName = void 0;
16
+ exports.getChromeVersion = getChromeVersion;
17
+ exports.getChromedriverBinaryPath = getChromedriverBinaryPath;
18
+ exports.retrieveData = retrieveData;
19
+ exports.generateLogPrefix = generateLogPrefix;
20
+ exports.formatCdVersion = formatCdVersion;
21
+ /* eslint-disable @typescript-eslint/no-var-requires */
22
+ const lodash_1 = __importDefault(require("lodash"));
23
+ const support_1 = require("@appium/support");
24
+ const driver_1 = require("appium/driver");
25
+ const path_1 = __importDefault(require("path"));
26
+ const axios_1 = __importDefault(require("axios"));
27
+ const teen_process_1 = require("teen_process");
28
+ const logger_1 = __importDefault(require("./logger"));
29
+ const CD_CDN = process.env.npm_config_chromedriver_cdnurl ||
30
+ process.env.CHROMEDRIVER_CDNURL ||
31
+ 'https://chromedriver.storage.googleapis.com';
32
+ exports.CD_CDN = CD_CDN;
33
+ const OS = {
34
+ linux: 'linux',
35
+ windows: 'win',
36
+ mac: 'mac',
37
+ };
38
+ exports.OS = OS;
39
+ const CD_EXECUTABLE_PREFIX = 'chromedriver';
40
+ const MODULE_NAME = 'xenon';
41
+ const CD_VER = process.env.npm_config_chromedriver_version || process.env.CHROMEDRIVER_VERSION;
42
+ exports.CD_VER = CD_VER;
43
+ const getModuleRoot = lodash_1.default.memoize(function getModuleRoot() {
44
+ if (!lodash_1.default.isFunction(support_1.node.getModuleRootSync)) {
45
+ const { existsSync, readFileSync } = require('fs');
46
+ let currentDir = path_1.default.dirname(path_1.default.resolve(__filename));
47
+ let isAtFsRoot = false;
48
+ while (!isAtFsRoot) {
49
+ const manifestPath = path_1.default.join(currentDir, 'package.json');
50
+ try {
51
+ if (existsSync(manifestPath) &&
52
+ JSON.parse(readFileSync(manifestPath, 'utf8')).name === MODULE_NAME) {
53
+ return currentDir;
54
+ }
55
+ // eslint-disable-next-line no-empty
56
+ }
57
+ catch (ign) { }
58
+ currentDir = path_1.default.dirname(currentDir);
59
+ isAtFsRoot = currentDir.length <= path_1.default.dirname(currentDir).length;
60
+ }
61
+ throw new Error(`Cannot find the root folder of the ${MODULE_NAME} Node.js module`);
62
+ }
63
+ const root = support_1.node.getModuleRootSync(MODULE_NAME, __filename);
64
+ if (!root) {
65
+ throw new Error(`Cannot find the root folder of the ${MODULE_NAME} Node.js module`);
66
+ }
67
+ return root;
68
+ });
69
+ exports.getModuleRoot = getModuleRoot;
70
+ function getChromeVersion(adb, bundleId) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const { versionName } = yield adb.getPackageInfo(bundleId);
73
+ return versionName;
74
+ });
75
+ }
76
+ const DOWNLOAD_TIMEOUT_MS = 15 * 1000;
77
+ const LATEST_VERSION = 'LATEST';
78
+ function formatCdVersion(ver) {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ return ver === LATEST_VERSION
81
+ ? (yield retrieveData(`${CD_CDN}/LATEST_RELEASE`, { timeout: DOWNLOAD_TIMEOUT_MS })).trim()
82
+ : ver;
83
+ });
84
+ }
85
+ function getChromedriverBinaryPath(dir_1) {
86
+ return __awaiter(this, arguments, void 0, function* (dir, osName = getOsName()) {
87
+ const pathSuffix = osName === OS.windows ? '.exe' : '';
88
+ logger_1.default.debug(`${CD_EXECUTABLE_PREFIX}*${pathSuffix}`);
89
+ const paths = yield support_1.fs.glob(`${CD_EXECUTABLE_PREFIX}*${pathSuffix}`, {
90
+ cwd: dir,
91
+ absolute: true,
92
+ nocase: true,
93
+ nodir: true,
94
+ });
95
+ return lodash_1.default.isEmpty(paths)
96
+ ? path_1.default.resolve(dir, `${CD_EXECUTABLE_PREFIX}${pathSuffix}`)
97
+ : lodash_1.default.first(paths);
98
+ });
99
+ }
100
+ function retrieveData(url_1, headers_1) {
101
+ return __awaiter(this, arguments, void 0, function* (url, headers, opts = {}) {
102
+ const { timeout = 5000, responseType = 'text' } = opts;
103
+ return (yield (0, axios_1.default)({
104
+ url,
105
+ headers,
106
+ timeout,
107
+ responseType,
108
+ })).data;
109
+ });
110
+ }
111
+ const getOsName = lodash_1.default.memoize(function getOsName() {
112
+ if (support_1.system.isWindows()) {
113
+ return OS.windows;
114
+ }
115
+ if (support_1.system.isMac()) {
116
+ return OS.mac;
117
+ }
118
+ return OS.linux;
119
+ });
120
+ exports.getOsName = getOsName;
121
+ const getOsInfo = lodash_1.default.memoize(function getOsInfo() {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ let systemHardware = '';
124
+ if (!support_1.system.isWindows()) {
125
+ systemHardware = (0, teen_process_1.exec)('uname', ['-m']).toString();
126
+ }
127
+ return {
128
+ name: getOsName(),
129
+ arch: yield support_1.system.arch(),
130
+ hardwareName: support_1.system.isWindows() ? null : lodash_1.default.trim(systemHardware),
131
+ };
132
+ });
133
+ });
134
+ exports.getOsInfo = getOsInfo;
135
+ // @ts-expect-error - Instantiating BaseDriver with empty options for helper access
136
+ // error TS2345: Argument of type '{}' is not assignable to parameter of type 'DriverOpts<Readonly<Record<string, Constraint>>>'
137
+ // Type '{}' is missing the following properties from type 'ServerArgs': address, allowCors, allowInsecure, basePath, and 26 more.
138
+ const getBaseDriverInstance = lodash_1.default.memoize(() => new driver_1.BaseDriver({}, false));
139
+ /**
140
+ * Generates log prefix string
141
+ *
142
+ * @param {object} obj log owner instance
143
+ * @param {string?} sessionId Optional session identifier
144
+ * @returns {string}
145
+ */
146
+ function generateLogPrefix(obj, sessionId) {
147
+ return getBaseDriverInstance().helpers.generateDriverLogPrefix(obj, sessionId);
148
+ }
@@ -0,0 +1,19 @@
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
+ exports.default = handle;
13
+ const device_service_1 = require("../data-service/device-service");
14
+ function handle(next, driver, _commandName, ..._args) {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ (0, device_service_1.updateCmdExecutedTime)(driver.sessionId);
17
+ return yield next();
18
+ });
19
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ // Note: handle() is now a class method in plugin.ts, not a command
3
+ // import handle from './handle';
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ const commands = {
6
+ // handle method removed - now implemented as class method
7
+ };
8
+ exports.default = commands;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.config = void 0;
37
+ exports.updateConfig = updateConfig;
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
40
+ const basePath = path.join(os.homedir(), '.cache', 'xenon');
41
+ exports.config = {
42
+ cacheDir: basePath,
43
+ databaseProvider: process.env.XENON_DB_PROVIDER || 'sqlite',
44
+ databaseUrl: process.env.DATABASE_URL || `file:${path.join(basePath, 'xenon.db')}`,
45
+ databasePath: path.join(basePath, 'xenon.db'),
46
+ sessionAssetsPath: path.join(basePath, 'assets', 'sessions'),
47
+ appsPath: path.join(basePath, 'apps'),
48
+ takeScreenshotsFor: [
49
+ 'click',
50
+ 'setUrl',
51
+ 'setValue',
52
+ 'performActions',
53
+ 'clear',
54
+ 'swipe',
55
+ 'scroll',
56
+ 'dragAndDrop',
57
+ 'back',
58
+ 'forward',
59
+ ],
60
+ aiProvider: process.env.XENON_AI_PROVIDER || 'gemini',
61
+ aiModel: process.env.XENON_AI_MODEL,
62
+ aiBaseUrl: process.env.XENON_AI_BASE_URL,
63
+ geminiApiKey: process.env.XENON_GEMINI_API_KEY || process.env.GEMINI_API_KEY,
64
+ openaiApiKey: process.env.XENON_OPENAI_API_KEY || process.env.OPENAI_API_KEY,
65
+ anthropicApiKey: process.env.XENON_ANTHROPIC_API_KEY || process.env.ANTHROPIC_API_KEY,
66
+ geminiModel: process.env.XENON_GEMINI_MODEL,
67
+ openaiModel: process.env.XENON_OPENAI_MODEL,
68
+ anthropicModel: process.env.XENON_ANTHROPIC_MODEL,
69
+ ollamaModel: process.env.XENON_OLLAMA_MODEL,
70
+ };
71
+ function updateConfig(newConfig) {
72
+ Object.assign(exports.config, newConfig);
73
+ }