@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,190 @@
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
+ const express_1 = __importDefault(require("express"));
16
+ const device_service_1 = require("../../data-service/device-service");
17
+ const logger_1 = __importDefault(require("../../logger"));
18
+ const router = express_1.default.Router();
19
+ // Duration options in milliseconds
20
+ const DURATION_OPTIONS = {
21
+ '1h': 60 * 60 * 1000,
22
+ '2h': 2 * 60 * 60 * 1000,
23
+ '4h': 4 * 60 * 60 * 1000,
24
+ '8h': 8 * 60 * 60 * 1000,
25
+ };
26
+ /**
27
+ * GET /api/reservation
28
+ * List all currently reserved devices
29
+ */
30
+ router.get('/', (_req, res) => __awaiter(void 0, void 0, void 0, function* () {
31
+ try {
32
+ const reservedDevices = yield (0, device_service_1.getReservedDevices)();
33
+ res.json({
34
+ success: true,
35
+ reservations: reservedDevices.map((device) => ({
36
+ udid: device.udid,
37
+ host: device.host,
38
+ name: device.name,
39
+ platform: device.platform,
40
+ reservedBy: device.reservedBy,
41
+ reservedUntil: device.reservedUntil,
42
+ reservationReason: device.reservationReason,
43
+ remainingMs: device.reservedUntil ? device.reservedUntil - Date.now() : 0,
44
+ })),
45
+ });
46
+ }
47
+ catch (error) {
48
+ logger_1.default.error(`Failed to get reservations: ${error}`);
49
+ res.status(500).json({ success: false, error: 'Failed to get reservations' });
50
+ }
51
+ }));
52
+ /**
53
+ * POST /api/reservation
54
+ * Reserve a device for exclusive use
55
+ * Body: { udid, host, reservedBy, duration, reason? }
56
+ */
57
+ router.post('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
58
+ try {
59
+ const { udid, host, reservedBy, duration, reason } = req.body;
60
+ if (!udid || !host || !reservedBy || !duration) {
61
+ return res.status(400).json({
62
+ success: false,
63
+ error: 'Missing required fields: udid, host, reservedBy, duration',
64
+ });
65
+ }
66
+ // Parse duration
67
+ let durationMs;
68
+ if (typeof duration === 'string' && DURATION_OPTIONS[duration]) {
69
+ durationMs = DURATION_OPTIONS[duration];
70
+ }
71
+ else if (typeof duration === 'number') {
72
+ durationMs = duration;
73
+ }
74
+ else {
75
+ return res.status(400).json({
76
+ success: false,
77
+ error: `Invalid duration. Use: ${Object.keys(DURATION_OPTIONS).join(', ')} or a number in milliseconds`,
78
+ });
79
+ }
80
+ // Check if device exists
81
+ const device = yield (0, device_service_1.getDevice)({ udid: [udid] });
82
+ if (!device) {
83
+ return res.status(404).json({ success: false, error: 'Device not found' });
84
+ }
85
+ // Check if device is already reserved by someone else
86
+ if ((0, device_service_1.isDeviceReserved)(device) && device.reservedBy !== reservedBy) {
87
+ return res.status(409).json({
88
+ success: false,
89
+ error: `Device is already reserved by ${device.reservedBy} until ${new Date(device.reservedUntil).toISOString()}`,
90
+ });
91
+ }
92
+ // Check if device is busy with an Appium session
93
+ if (device.busy && device.session_id) {
94
+ return res.status(409).json({
95
+ success: false,
96
+ error: 'Device is currently busy with an Appium session. Cannot reserve.',
97
+ });
98
+ }
99
+ yield (0, device_service_1.reserveDevice)(udid, host, reservedBy, durationMs, reason);
100
+ const reservedUntil = Date.now() + durationMs;
101
+ res.json({
102
+ success: true,
103
+ message: `Device ${udid} reserved for ${reservedBy}`,
104
+ reservation: {
105
+ udid,
106
+ host,
107
+ reservedBy,
108
+ reservedUntil,
109
+ reservationReason: reason,
110
+ expiresAt: new Date(reservedUntil).toISOString(),
111
+ },
112
+ });
113
+ }
114
+ catch (error) {
115
+ logger_1.default.error(`Failed to reserve device: ${error}`);
116
+ res.status(500).json({ success: false, error: 'Failed to reserve device' });
117
+ }
118
+ }));
119
+ /**
120
+ * DELETE /api/reservation/:udid/:host
121
+ * Release a device reservation
122
+ */
123
+ router.delete('/:udid/:host', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
124
+ try {
125
+ const { udid } = req.params;
126
+ const host = decodeURIComponent(req.params.host);
127
+ const device = yield (0, device_service_1.getDevice)({ udid: [udid] });
128
+ if (!device) {
129
+ return res.status(404).json({ success: false, error: 'Device not found' });
130
+ }
131
+ if (!(0, device_service_1.isDeviceReserved)(device)) {
132
+ return res.status(400).json({ success: false, error: 'Device is not reserved' });
133
+ }
134
+ yield (0, device_service_1.releaseReservation)(udid, host);
135
+ res.json({
136
+ success: true,
137
+ message: `Reservation released for device ${udid}`,
138
+ });
139
+ }
140
+ catch (error) {
141
+ logger_1.default.error(`Failed to release reservation: ${error}`);
142
+ res.status(500).json({ success: false, error: 'Failed to release reservation' });
143
+ }
144
+ }));
145
+ /**
146
+ * POST /api/reservation/:udid/:host/extend
147
+ * Extend an existing reservation
148
+ * Body: { duration }
149
+ */
150
+ router.post('/:udid/:host/extend', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
151
+ try {
152
+ const { udid } = req.params;
153
+ const host = decodeURIComponent(req.params.host);
154
+ const { duration } = req.body;
155
+ const device = yield (0, device_service_1.getDevice)({ udid: [udid] });
156
+ if (!device) {
157
+ return res.status(404).json({ success: false, error: 'Device not found' });
158
+ }
159
+ if (!(0, device_service_1.isDeviceReserved)(device)) {
160
+ return res.status(400).json({ success: false, error: 'Device is not reserved' });
161
+ }
162
+ // Parse duration
163
+ let extensionMs;
164
+ if (typeof duration === 'string' && DURATION_OPTIONS[duration]) {
165
+ extensionMs = DURATION_OPTIONS[duration];
166
+ }
167
+ else if (typeof duration === 'number') {
168
+ extensionMs = duration;
169
+ }
170
+ else {
171
+ return res.status(400).json({
172
+ success: false,
173
+ error: `Invalid duration. Use: ${Object.keys(DURATION_OPTIONS).join(', ')} or a number in milliseconds`,
174
+ });
175
+ }
176
+ // Extend from current expiry time
177
+ const newExpiry = (device.reservedUntil || Date.now()) + extensionMs;
178
+ yield (0, device_service_1.reserveDevice)(udid, host, device.reservedBy, newExpiry - Date.now(), device.reservationReason);
179
+ res.json({
180
+ success: true,
181
+ message: `Reservation extended for device ${udid}`,
182
+ newExpiresAt: new Date(newExpiry).toISOString(),
183
+ });
184
+ }
185
+ catch (error) {
186
+ logger_1.default.error(`Failed to extend reservation: ${error}`);
187
+ res.status(500).json({ success: false, error: 'Failed to extend reservation' });
188
+ }
189
+ }));
190
+ exports.default = router;
@@ -0,0 +1,83 @@
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
+ const NotificationService_1 = require("../../services/NotificationService");
16
+ const typedi_1 = require("typedi");
17
+ const logger_1 = __importDefault(require("../../logger"));
18
+ function getConfigs(req, res) {
19
+ return __awaiter(this, void 0, void 0, function* () {
20
+ try {
21
+ const configs = yield typedi_1.Container.get(NotificationService_1.NotificationService).getConfigs();
22
+ res.json(configs);
23
+ }
24
+ catch (err) {
25
+ logger_1.default.error(`Failed to get webhook configs: ${err}`);
26
+ res.status(500).json({ error: 'Failed to fetch configurations' });
27
+ }
28
+ });
29
+ }
30
+ function addConfig(req, res) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ const { url, events, type, payloadTemplate } = req.body;
33
+ if (!url || !events || !Array.isArray(events)) {
34
+ return res.status(400).json({ error: 'Invalid parameters: url and events array required' });
35
+ }
36
+ try {
37
+ const config = yield typedi_1.Container.get(NotificationService_1.NotificationService).saveConfig(url, events, type || 'slack', payloadTemplate);
38
+ res.json(config);
39
+ }
40
+ catch (err) {
41
+ logger_1.default.error(`Failed to save webhook config: ${err}`);
42
+ res.status(500).json({ error: 'Failed to save configuration' });
43
+ }
44
+ });
45
+ }
46
+ function deleteConfig(req, res) {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const { id } = req.params;
49
+ try {
50
+ yield typedi_1.Container.get(NotificationService_1.NotificationService).deleteConfig(id);
51
+ res.json({ success: true });
52
+ }
53
+ catch (err) {
54
+ logger_1.default.error(`Failed to delete webhook config: ${err}`);
55
+ res.status(500).json({ error: 'Failed to delete configuration' });
56
+ }
57
+ });
58
+ }
59
+ function testWebhook(req, res) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const { url, type } = req.body;
62
+ try {
63
+ yield typedi_1.Container.get(NotificationService_1.NotificationService).sendSlackMessage(url, 'device_new', {
64
+ udid: 'test-device-udid',
65
+ name: 'Test Device',
66
+ host: '127.0.0.1',
67
+ });
68
+ res.json({ success: true });
69
+ }
70
+ catch (err) {
71
+ res.status(500).json({ error: `Test failed: ${err}` });
72
+ }
73
+ });
74
+ }
75
+ function register(router) {
76
+ router.get('/webhook', getConfigs);
77
+ router.post('/webhook', addConfig);
78
+ router.delete('/webhook/:id', deleteConfig);
79
+ router.post('/webhook/test', testWebhook);
80
+ }
81
+ exports.default = {
82
+ register,
83
+ };
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /**
3
+ * @swagger
4
+ * /api/devices:
5
+ * get:
6
+ * summary: Get all connected devices
7
+ * description: Retrieve a list of all connected devices with their current status
8
+ * tags: [Devices]
9
+ * responses:
10
+ * 200:
11
+ * description: List of devices
12
+ * content:
13
+ * application/json:
14
+ * schema:
15
+ * type: array
16
+ * items:
17
+ * $ref: '#/components/schemas/Device'
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ /**
21
+ * @swagger
22
+ * /api/config:
23
+ * get:
24
+ * summary: Get current configuration
25
+ * description: Retrieve the current runtime configuration of the Xenon plugin
26
+ * tags: [Configuration]
27
+ * responses:
28
+ * 200:
29
+ * description: Current configuration object
30
+ * content:
31
+ * application/json:
32
+ * schema:
33
+ * type: object
34
+ * put:
35
+ * summary: Update configuration
36
+ * description: Update plugin configuration properties. Changes are persisted. Some changes may require a server restart.
37
+ * tags: [Configuration]
38
+ * requestBody:
39
+ * required: true
40
+ * content:
41
+ * application/json:
42
+ * schema:
43
+ * type: object
44
+ * description: Partial configuration object
45
+ * example:
46
+ * deviceAvailabilityTimeoutMs: 60000
47
+ * maxSessions: 5
48
+ * responses:
49
+ * 200:
50
+ * description: Configuration updated
51
+ * content:
52
+ * application/json:
53
+ * schema:
54
+ * type: object
55
+ * properties:
56
+ * success:
57
+ * type: boolean
58
+ * restartRequired:
59
+ * type: boolean
60
+ * description: True if the updated properties require a server restart
61
+ * message:
62
+ * type: string
63
+ */
64
+ /**
65
+ * @swagger
66
+ * /api/sessions/active:
67
+ * get:
68
+ * summary: Get active sessions
69
+ * description: Get statistics and list of currently active sessions in memory
70
+ * tags: [Sessions]
71
+ * responses:
72
+ * 200:
73
+ * description: Active session information
74
+ * content:
75
+ * application/json:
76
+ * schema:
77
+ * type: object
78
+ * properties:
79
+ * stats:
80
+ * type: object
81
+ * properties:
82
+ * total:
83
+ * type: number
84
+ * description: Total number of active sessions
85
+ * byType:
86
+ * type: object
87
+ * properties:
88
+ * local:
89
+ * type: number
90
+ * remote:
91
+ * type: number
92
+ * cloud:
93
+ * type: number
94
+ * sessions:
95
+ * type: array
96
+ * items:
97
+ * type: object
98
+ * properties:
99
+ * id:
100
+ * type: string
101
+ * type:
102
+ * type: string
103
+ * enum: [local, remote, cloud]
104
+ * deviceUdid:
105
+ * type: string
106
+ * deviceName:
107
+ * type: string
108
+ * platform:
109
+ * type: string
110
+ */
111
+ /**
112
+ * @swagger
113
+ * /api/logs/requests:
114
+ * get:
115
+ * summary: Get HTTP request logs
116
+ * description: Retrieve recent HTTP request logs for debugging hub-node communication
117
+ * tags: [Observability]
118
+ * parameters:
119
+ * - in: query
120
+ * name: limit
121
+ * schema:
122
+ * type: integer
123
+ * default: 50
124
+ * description: Maximum number of logs to return
125
+ * - in: query
126
+ * name: method
127
+ * schema:
128
+ * type: string
129
+ * enum: [GET, POST, PUT, DELETE]
130
+ * description: Filter by HTTP method
131
+ * - in: query
132
+ * name: url
133
+ * schema:
134
+ * type: string
135
+ * description: Filter by URL pattern (substring match)
136
+ * - in: query
137
+ * name: hasError
138
+ * schema:
139
+ * type: boolean
140
+ * description: Filter by error status (true = only errors, false = only success)
141
+ * responses:
142
+ * 200:
143
+ * description: Request logs and statistics
144
+ * content:
145
+ * application/json:
146
+ * schema:
147
+ * type: object
148
+ * properties:
149
+ * stats:
150
+ * type: object
151
+ * properties:
152
+ * totalLogged:
153
+ * type: number
154
+ * description: Total requests in buffer
155
+ * errorCount:
156
+ * type: number
157
+ * description: Number of failed requests
158
+ * avgDurationMs:
159
+ * type: number
160
+ * description: Average request duration in milliseconds
161
+ * byMethod:
162
+ * type: object
163
+ * additionalProperties:
164
+ * type: number
165
+ * byStatusCode:
166
+ * type: object
167
+ * additionalProperties:
168
+ * type: number
169
+ * logs:
170
+ * type: array
171
+ * items:
172
+ * type: object
173
+ * properties:
174
+ * timestamp:
175
+ * type: string
176
+ * format: date-time
177
+ * direction:
178
+ * type: string
179
+ * enum: [outgoing, incoming]
180
+ * method:
181
+ * type: string
182
+ * url:
183
+ * type: string
184
+ * statusCode:
185
+ * type: number
186
+ * durationMs:
187
+ * type: number
188
+ * error:
189
+ * type: string
190
+ * nullable: true
191
+ * requestBody:
192
+ * type: string
193
+ * description: Sanitized request body (sensitive data redacted)
194
+ * responseBody:
195
+ * type: string
196
+ * description: Truncated response body
197
+ */
198
+ /**
199
+ * @swagger
200
+ * tags:
201
+ * - name: Observability
202
+ * description: Debugging and monitoring endpoints
203
+ */