@aiscene/aiserver 1.0.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 (169) hide show
  1. package/dist/api/callback.d.ts +7 -0
  2. package/dist/api/callback.d.ts.map +1 -0
  3. package/dist/api/callback.js +116 -0
  4. package/dist/api/callback.js.map +1 -0
  5. package/dist/api/device-api.d.ts +13 -0
  6. package/dist/api/device-api.d.ts.map +1 -0
  7. package/dist/api/device-api.js +98 -0
  8. package/dist/api/device-api.js.map +1 -0
  9. package/dist/api/task-api.d.ts +9 -0
  10. package/dist/api/task-api.d.ts.map +1 -0
  11. package/dist/api/task-api.js +47 -0
  12. package/dist/api/task-api.js.map +1 -0
  13. package/dist/config/cli.d.ts +30 -0
  14. package/dist/config/cli.d.ts.map +1 -0
  15. package/dist/config/cli.js +129 -0
  16. package/dist/config/cli.js.map +1 -0
  17. package/dist/config/index.d.ts +6 -0
  18. package/dist/config/index.d.ts.map +1 -0
  19. package/dist/config/index.js +142 -0
  20. package/dist/config/index.js.map +1 -0
  21. package/dist/config/schema.d.ts +66 -0
  22. package/dist/config/schema.d.ts.map +1 -0
  23. package/dist/config/schema.js +2 -0
  24. package/dist/config/schema.js.map +1 -0
  25. package/dist/core/event-bus.d.ts +14 -0
  26. package/dist/core/event-bus.d.ts.map +1 -0
  27. package/dist/core/event-bus.js +33 -0
  28. package/dist/core/event-bus.js.map +1 -0
  29. package/dist/core/logger.d.ts +24 -0
  30. package/dist/core/logger.d.ts.map +1 -0
  31. package/dist/core/logger.js +52 -0
  32. package/dist/core/logger.js.map +1 -0
  33. package/dist/core/types.d.ts +134 -0
  34. package/dist/core/types.d.ts.map +1 -0
  35. package/dist/core/types.js +3 -0
  36. package/dist/core/types.js.map +1 -0
  37. package/dist/debug/dump-manager.d.ts +10 -0
  38. package/dist/debug/dump-manager.d.ts.map +1 -0
  39. package/dist/debug/dump-manager.js +52 -0
  40. package/dist/debug/dump-manager.js.map +1 -0
  41. package/dist/debug/screencast.d.ts +11 -0
  42. package/dist/debug/screencast.d.ts.map +1 -0
  43. package/dist/debug/screencast.js +88 -0
  44. package/dist/debug/screencast.js.map +1 -0
  45. package/dist/debug/session-manager.d.ts +14 -0
  46. package/dist/debug/session-manager.d.ts.map +1 -0
  47. package/dist/debug/session-manager.js +76 -0
  48. package/dist/debug/session-manager.js.map +1 -0
  49. package/dist/debug/types.d.ts +76 -0
  50. package/dist/debug/types.d.ts.map +1 -0
  51. package/dist/debug/types.js +2 -0
  52. package/dist/debug/types.js.map +1 -0
  53. package/dist/debug/web-screencast.d.ts +60 -0
  54. package/dist/debug/web-screencast.d.ts.map +1 -0
  55. package/dist/debug/web-screencast.js +146 -0
  56. package/dist/debug/web-screencast.js.map +1 -0
  57. package/dist/debug/websocket-server.d.ts +27 -0
  58. package/dist/debug/websocket-server.d.ts.map +1 -0
  59. package/dist/debug/websocket-server.js +681 -0
  60. package/dist/debug/websocket-server.js.map +1 -0
  61. package/dist/device/detector.d.ts +10 -0
  62. package/dist/device/detector.d.ts.map +1 -0
  63. package/dist/device/detector.js +100 -0
  64. package/dist/device/detector.js.map +1 -0
  65. package/dist/device/heartbeat.d.ts +26 -0
  66. package/dist/device/heartbeat.d.ts.map +1 -0
  67. package/dist/device/heartbeat.js +225 -0
  68. package/dist/device/heartbeat.js.map +1 -0
  69. package/dist/device/status-manager.d.ts +15 -0
  70. package/dist/device/status-manager.d.ts.map +1 -0
  71. package/dist/device/status-manager.js +58 -0
  72. package/dist/device/status-manager.js.map +1 -0
  73. package/dist/device/types.d.ts +30 -0
  74. package/dist/device/types.d.ts.map +1 -0
  75. package/dist/device/types.js +2 -0
  76. package/dist/device/types.js.map +1 -0
  77. package/dist/executor/action-executor.d.ts +25 -0
  78. package/dist/executor/action-executor.d.ts.map +1 -0
  79. package/dist/executor/action-executor.js +261 -0
  80. package/dist/executor/action-executor.js.map +1 -0
  81. package/dist/executor/android-executor.d.ts +12 -0
  82. package/dist/executor/android-executor.d.ts.map +1 -0
  83. package/dist/executor/android-executor.js +127 -0
  84. package/dist/executor/android-executor.js.map +1 -0
  85. package/dist/executor/base.d.ts +20 -0
  86. package/dist/executor/base.d.ts.map +1 -0
  87. package/dist/executor/base.js +91 -0
  88. package/dist/executor/base.js.map +1 -0
  89. package/dist/executor/cli-executor.d.ts +12 -0
  90. package/dist/executor/cli-executor.d.ts.map +1 -0
  91. package/dist/executor/cli-executor.js +94 -0
  92. package/dist/executor/cli-executor.js.map +1 -0
  93. package/dist/executor/code-executor.d.ts +13 -0
  94. package/dist/executor/code-executor.d.ts.map +1 -0
  95. package/dist/executor/code-executor.js +52 -0
  96. package/dist/executor/code-executor.js.map +1 -0
  97. package/dist/executor/code-instrument.d.ts +12 -0
  98. package/dist/executor/code-instrument.d.ts.map +1 -0
  99. package/dist/executor/code-instrument.js +116 -0
  100. package/dist/executor/code-instrument.js.map +1 -0
  101. package/dist/executor/executor-factory.d.ts +7 -0
  102. package/dist/executor/executor-factory.d.ts.map +1 -0
  103. package/dist/executor/executor-factory.js +24 -0
  104. package/dist/executor/executor-factory.js.map +1 -0
  105. package/dist/executor/ios-executor.d.ts +10 -0
  106. package/dist/executor/ios-executor.d.ts.map +1 -0
  107. package/dist/executor/ios-executor.js +91 -0
  108. package/dist/executor/ios-executor.js.map +1 -0
  109. package/dist/executor/types.d.ts +14 -0
  110. package/dist/executor/types.d.ts.map +1 -0
  111. package/dist/executor/types.js +2 -0
  112. package/dist/executor/types.js.map +1 -0
  113. package/dist/executor/worker-entry.d.ts +2 -0
  114. package/dist/executor/worker-entry.d.ts.map +1 -0
  115. package/dist/executor/worker-entry.js +61 -0
  116. package/dist/executor/worker-entry.js.map +1 -0
  117. package/dist/index.d.ts +22 -0
  118. package/dist/index.d.ts.map +1 -0
  119. package/dist/index.js +157 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/node/service.d.ts +21 -0
  122. package/dist/node/service.d.ts.map +1 -0
  123. package/dist/node/service.js +178 -0
  124. package/dist/node/service.js.map +1 -0
  125. package/dist/node/types.d.ts +45 -0
  126. package/dist/node/types.d.ts.map +1 -0
  127. package/dist/node/types.js +3 -0
  128. package/dist/node/types.js.map +1 -0
  129. package/dist/storage/database.d.ts +6 -0
  130. package/dist/storage/database.d.ts.map +1 -0
  131. package/dist/storage/database.js +154 -0
  132. package/dist/storage/database.js.map +1 -0
  133. package/dist/storage/repositories/debug-log-repo.d.ts +29 -0
  134. package/dist/storage/repositories/debug-log-repo.d.ts.map +1 -0
  135. package/dist/storage/repositories/debug-log-repo.js +90 -0
  136. package/dist/storage/repositories/debug-log-repo.js.map +1 -0
  137. package/dist/storage/repositories/device-repo.d.ts +12 -0
  138. package/dist/storage/repositories/device-repo.d.ts.map +1 -0
  139. package/dist/storage/repositories/device-repo.js +87 -0
  140. package/dist/storage/repositories/device-repo.js.map +1 -0
  141. package/dist/storage/repositories/execution-log-repo.d.ts +9 -0
  142. package/dist/storage/repositories/execution-log-repo.d.ts.map +1 -0
  143. package/dist/storage/repositories/execution-log-repo.js +49 -0
  144. package/dist/storage/repositories/execution-log-repo.js.map +1 -0
  145. package/dist/storage/repositories/task-repo.d.ts +13 -0
  146. package/dist/storage/repositories/task-repo.d.ts.map +1 -0
  147. package/dist/storage/repositories/task-repo.js +109 -0
  148. package/dist/storage/repositories/task-repo.js.map +1 -0
  149. package/dist/task/poller.d.ts +25 -0
  150. package/dist/task/poller.d.ts.map +1 -0
  151. package/dist/task/poller.js +153 -0
  152. package/dist/task/poller.js.map +1 -0
  153. package/dist/task/queue.d.ts +13 -0
  154. package/dist/task/queue.d.ts.map +1 -0
  155. package/dist/task/queue.js +38 -0
  156. package/dist/task/queue.js.map +1 -0
  157. package/dist/task/scheduler.d.ts +25 -0
  158. package/dist/task/scheduler.d.ts.map +1 -0
  159. package/dist/task/scheduler.js +274 -0
  160. package/dist/task/scheduler.js.map +1 -0
  161. package/dist/task/types.d.ts +31 -0
  162. package/dist/task/types.d.ts.map +1 -0
  163. package/dist/task/types.js +37 -0
  164. package/dist/task/types.js.map +1 -0
  165. package/dist/web/server.d.ts +14 -0
  166. package/dist/web/server.d.ts.map +1 -0
  167. package/dist/web/server.js +478 -0
  168. package/dist/web/server.js.map +1 -0
  169. package/package.json +49 -0
package/dist/index.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @aiscene/aiserver - AI Automation Server
4
+ *
5
+ * Features:
6
+ * 1. Device detection & heartbeat with configurable polling
7
+ * 2. Task polling & scheduling with configurable interval
8
+ * 3. Unified executor (CLI/Android/iOS/Action/Code)
9
+ * 4. Debug WebSocket with real-time feedback
10
+ * 5. Web dashboard for monitoring
11
+ * 6. SQLite storage for all execution data
12
+ */
13
+ import { loadConfig } from './config/index.js';
14
+ import { initDatabase, closeDatabase } from './storage/database.js';
15
+ import { eventBus } from './core/event-bus.js';
16
+ import { createLogger } from './core/logger.js';
17
+ import { executionLogRepo } from './storage/repositories/execution-log-repo.js';
18
+ import { uploadReportFile, updateTaskStatusToServer } from './api/callback.js';
19
+ import { nodeService } from './node/service.js';
20
+ import { deviceHeartbeatService } from './device/heartbeat.js';
21
+ import { taskPollerService } from './task/poller.js';
22
+ import { DebugWebSocketServer } from './debug/websocket-server.js';
23
+ import { webServer } from './web/server.js';
24
+ const logger = createLogger('AIServer');
25
+ class AIServer {
26
+ debugWsServer;
27
+ shuttingDown = false;
28
+ constructor() {
29
+ this.debugWsServer = new DebugWebSocketServer();
30
+ }
31
+ async start() {
32
+ logger.info('Starting @aiscene/aiserver...');
33
+ // 1. Load configuration
34
+ const config = loadConfig();
35
+ logger.info('Configuration loaded');
36
+ // 2. Initialize database
37
+ initDatabase(config.storage);
38
+ logger.info('Database initialized');
39
+ // 3. Setup event listeners
40
+ this.setupEventListeners(config);
41
+ // 4. Register node and start node heartbeat
42
+ await nodeService.start(config.node);
43
+ logger.info('Node service started');
44
+ // 5. Start device heartbeat service
45
+ await deviceHeartbeatService.start(config.device, config.callback);
46
+ logger.info('Device heartbeat service started');
47
+ // 6. Start task polling service
48
+ await taskPollerService.start(config.task, config.callback);
49
+ logger.info('Task polling service started');
50
+ // 7. Start debug WebSocket server
51
+ await this.debugWsServer.start(config);
52
+ logger.info('Debug WebSocket server started');
53
+ // 8. Start web management interface
54
+ webServer.start(config.server);
55
+ logger.info('Web management interface started');
56
+ logger.info('========================================');
57
+ logger.info('@aiscene/aiserver is running!');
58
+ logger.info(` WebSocket: ws://${config.server.host}:${config.server.port}`);
59
+ logger.info(` Web UI: http://${config.server.host}:${config.server.webPort}`);
60
+ logger.info(` Node ID: ${config.task.nodeId}`);
61
+ logger.info('========================================');
62
+ }
63
+ setupEventListeners(config) {
64
+ // Log all task events to storage
65
+ eventBus.onEvent('task:log', (payload) => {
66
+ const data = payload.data;
67
+ try {
68
+ executionLogRepo.create({
69
+ taskId: data.taskId,
70
+ sessionId: data.sessionId,
71
+ level: data.level || 'info',
72
+ content: data.content,
73
+ });
74
+ }
75
+ catch {
76
+ // ignore storage errors
77
+ }
78
+ });
79
+ // Handle task completion - upload report and update status
80
+ eventBus.onEvent('task:completed', async (payload) => {
81
+ const data = payload.data;
82
+ try {
83
+ // Upload report file
84
+ if (data.reportFile) {
85
+ await uploadReportFile(data.reportFile, data.taskId, `task-${data.taskId}`, undefined, data.success, data.errorMessage, config.task.nodeId, config.callback);
86
+ }
87
+ // Update task status on server
88
+ await updateTaskStatusToServer(data.taskId, data.success, config.task.nodeId, data.errorMessage || null, config.callback);
89
+ }
90
+ catch (error) {
91
+ logger.error(`Task completion callback error: ${error.message}`);
92
+ }
93
+ });
94
+ eventBus.onEvent('task:failed', async (payload) => {
95
+ const data = payload.data;
96
+ try {
97
+ if (data.reportFile) {
98
+ await uploadReportFile(data.reportFile, data.taskId, `task-${data.taskId}`, undefined, false, data.errorMessage, config.task.nodeId, config.callback);
99
+ }
100
+ await updateTaskStatusToServer(data.taskId, false, config.task.nodeId, data.errorMessage || null, config.callback);
101
+ }
102
+ catch (error) {
103
+ logger.error(`Task failure callback error: ${error.message}`);
104
+ }
105
+ });
106
+ // Device offline events
107
+ eventBus.onEvent('device:offline', (payload) => {
108
+ const data = payload.data;
109
+ logger.warn(`Device offline: ${data.serialNumber}`);
110
+ });
111
+ eventBus.onEvent('device:online', (payload) => {
112
+ const data = payload.data;
113
+ logger.info(`Device online: ${data.serialNumber} (${data.platform})`);
114
+ });
115
+ }
116
+ async shutdown() {
117
+ if (this.shuttingDown)
118
+ return;
119
+ this.shuttingDown = true;
120
+ logger.info('Shutting down @aiscene/aiserver...');
121
+ try {
122
+ await nodeService.stop();
123
+ await this.debugWsServer.close();
124
+ await taskPollerService.stop();
125
+ await deviceHeartbeatService.stop();
126
+ webServer.close();
127
+ closeDatabase();
128
+ eventBus.removeAll();
129
+ logger.info('Shutdown complete');
130
+ }
131
+ catch (error) {
132
+ logger.error(`Shutdown error: ${error.message}`);
133
+ }
134
+ process.exit(0);
135
+ }
136
+ }
137
+ // ==================== Main ====================
138
+ const server = new AIServer();
139
+ // Graceful shutdown
140
+ process.on('SIGINT', () => server.shutdown());
141
+ process.on('SIGTERM', () => server.shutdown());
142
+ process.on('SIGHUP', () => server.shutdown());
143
+ // Unhandled error handling
144
+ process.on('uncaughtException', (error) => {
145
+ logger.error(`Uncaught exception: ${error.message}`);
146
+ logger.error(error.stack || '');
147
+ });
148
+ process.on('unhandledRejection', (reason) => {
149
+ logger.error(`Unhandled rejection: ${reason}`);
150
+ });
151
+ // Start the server
152
+ server.start().catch((error) => {
153
+ logger.error(`Failed to start server: ${error.message}`);
154
+ process.exit(1);
155
+ });
156
+ export { AIServer };
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { NodeConfig } from '../config/schema.js';
2
+ export declare class NodeService {
3
+ private heartbeatInterval;
4
+ private config;
5
+ private registered;
6
+ private startTime;
7
+ private running;
8
+ start(config: NodeConfig): Promise<void>;
9
+ /**
10
+ * Use hostname() as nodeId, consistent with the electron-shadcn reference project
11
+ */
12
+ getNodeId(): string;
13
+ register(): Promise<boolean>;
14
+ private sendHeartbeat;
15
+ private handleCommands;
16
+ isRegistered(): boolean;
17
+ getNodeName(): string;
18
+ stop(): Promise<void>;
19
+ }
20
+ export declare const nodeService: NodeService;
21
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/node/service.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAwBtD,qBAAa,WAAW;IACtB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,OAAO,CAAkB;IAE3B,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B9C;;OAEG;IACH,SAAS,IAAI,MAAM;IAIb,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;YAwDpB,aAAa;IA+C3B,OAAO,CAAC,cAAc;IAOtB,YAAY,IAAI,OAAO;IAIvB,WAAW,IAAI,MAAM;IAIf,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAuB5B;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
@@ -0,0 +1,178 @@
1
+ import axios from 'axios';
2
+ import os from 'os';
3
+ import { createLogger } from '../core/logger.js';
4
+ import { eventBus } from '../core/event-bus.js';
5
+ import { deviceRepo } from '../storage/repositories/device-repo.js';
6
+ const logger = createLogger('NodeService');
7
+ function getLocalIPAddress() {
8
+ const interfaces = os.networkInterfaces();
9
+ for (const name of Object.keys(interfaces)) {
10
+ const nets = interfaces[name];
11
+ if (!nets)
12
+ continue;
13
+ for (const net of nets) {
14
+ if (net.family === 'IPv4' && !net.internal) {
15
+ return net.address;
16
+ }
17
+ }
18
+ }
19
+ return '127.0.0.1';
20
+ }
21
+ export class NodeService {
22
+ heartbeatInterval = null;
23
+ config;
24
+ registered = false;
25
+ startTime = Date.now();
26
+ running = false;
27
+ async start(config) {
28
+ this.config = config;
29
+ this.running = true;
30
+ this.startTime = Date.now();
31
+ // Register node first
32
+ const registered = await this.register();
33
+ if (!registered) {
34
+ logger.warn('Node registration failed, will retry on next heartbeat cycle');
35
+ }
36
+ // Start heartbeat loop
37
+ this.heartbeatInterval = setInterval(async () => {
38
+ if (!this.running)
39
+ return;
40
+ // If not registered, try to register first
41
+ if (!this.registered) {
42
+ const regResult = await this.register();
43
+ if (!regResult)
44
+ return; // Skip heartbeat if registration still fails
45
+ }
46
+ await this.sendHeartbeat();
47
+ }, config.heartbeatInterval);
48
+ logger.info(`Node service started (nodeId: ${this.getNodeId()}, name: ${this.getNodeId()})`);
49
+ }
50
+ /**
51
+ * Use hostname() as nodeId, consistent with the electron-shadcn reference project
52
+ */
53
+ getNodeId() {
54
+ return os.hostname();
55
+ }
56
+ async register() {
57
+ try {
58
+ const nodeId = this.getNodeId();
59
+ const request = {
60
+ nodeId: nodeId,
61
+ nodeName: this.config.nodeName || nodeId,
62
+ ipAddress: this.config.ipAddress || getLocalIPAddress(),
63
+ port: this.config.port,
64
+ nodeType: this.config.nodeType,
65
+ version: this.config.version,
66
+ maxConcurrentTasks: this.config.maxConcurrentTasks,
67
+ weight: this.config.weight,
68
+ supportedTags: this.config.supportedTags,
69
+ environment: this.config.environment,
70
+ region: this.config.region,
71
+ description: this.config.description,
72
+ configInfo: this.config.configInfo,
73
+ };
74
+ logger.info(`Registering node: ${request.nodeId} (${request.nodeName})`);
75
+ logger.info(`Node registration request: ${JSON.stringify(request)}`);
76
+ const response = await axios.post(this.config.registerUrl, request, {
77
+ timeout: 10000,
78
+ headers: { 'Content-Type': 'application/json' },
79
+ });
80
+ if (response.status === 200 && response.data?.success) {
81
+ this.registered = true;
82
+ logger.info(`Node registered successfully: ${nodeId}`);
83
+ eventBus.emitEvent('node:registered', 'node', { nodeId });
84
+ // Send heartbeat immediately after registration (consistent with reference project)
85
+ await this.sendHeartbeat();
86
+ return true;
87
+ }
88
+ else {
89
+ logger.warn(`Node registration rejected: ${response.data?.message || 'Unknown error'}`);
90
+ return false;
91
+ }
92
+ }
93
+ catch (error) {
94
+ const axiosError = error;
95
+ if (axiosError.response) {
96
+ logger.warn(`Node registration failed (status ${axiosError.response.status}): ${JSON.stringify(axiosError.response.data)}`);
97
+ }
98
+ else {
99
+ logger.warn(`Node registration failed: ${axiosError.message}`);
100
+ }
101
+ return false;
102
+ }
103
+ }
104
+ async sendHeartbeat() {
105
+ try {
106
+ const nodeId = this.getNodeId();
107
+ // Simplified heartbeat data, consistent with the reference project
108
+ const request = {
109
+ nodeId: nodeId,
110
+ currentTaskCount: 0, // TODO: get from scheduler
111
+ status: 1, // Online
112
+ };
113
+ const response = await axios.post(this.config.heartbeatUrl, request, {
114
+ timeout: 10000,
115
+ headers: { 'Content-Type': 'application/json' },
116
+ });
117
+ if (response.status === 200 && response.data?.success) {
118
+ const onlineDevices = deviceRepo.getOnline();
119
+ logger.info(`Node heartbeat sent (nodeId: ${nodeId}, devices: ${onlineDevices.length})`);
120
+ // Handle commands from server if any
121
+ const commands = response.data?.data?.commands;
122
+ if (commands && Array.isArray(commands)) {
123
+ this.handleCommands(commands);
124
+ }
125
+ }
126
+ else {
127
+ logger.warn(`Node heartbeat rejected: ${response.data?.message || 'Unknown error'}`);
128
+ // If rejected, might need to re-register
129
+ if (response.status === 400 || response.status === 404) {
130
+ this.registered = false;
131
+ }
132
+ }
133
+ }
134
+ catch (error) {
135
+ const axiosError = error;
136
+ if (axiosError.response?.status === 400 || axiosError.response?.status === 404) {
137
+ logger.warn(`Node heartbeat failed (status ${axiosError.response.status}), marking as unregistered`);
138
+ this.registered = false;
139
+ }
140
+ else {
141
+ logger.warn(`Node heartbeat failed: ${axiosError.message}`);
142
+ }
143
+ }
144
+ }
145
+ handleCommands(commands) {
146
+ for (const cmd of commands) {
147
+ logger.info(`Received command from server: ${cmd.type}`);
148
+ eventBus.emitEvent('node:command', 'node', { type: cmd.type, payload: cmd.payload });
149
+ }
150
+ }
151
+ isRegistered() {
152
+ return this.registered;
153
+ }
154
+ getNodeName() {
155
+ return this.getNodeId();
156
+ }
157
+ async stop() {
158
+ this.running = false;
159
+ if (this.heartbeatInterval) {
160
+ clearInterval(this.heartbeatInterval);
161
+ this.heartbeatInterval = null;
162
+ }
163
+ // Try to notify server about shutdown
164
+ if (this.registered) {
165
+ try {
166
+ await axios.delete(`${this.config.registerUrl.replace('/register', '')}/${this.getNodeId()}`, { timeout: 5000 });
167
+ logger.info('Node unregistered from server');
168
+ }
169
+ catch {
170
+ logger.warn('Failed to unregister node from server');
171
+ }
172
+ }
173
+ this.registered = false;
174
+ logger.info('Node service stopped');
175
+ }
176
+ }
177
+ export const nodeService = new NodeService();
178
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/node/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export interface NodeRegistrationRequest {
2
+ nodeId: string;
3
+ nodeName: string;
4
+ ipAddress: string;
5
+ port: number;
6
+ nodeType: string;
7
+ version: string;
8
+ maxConcurrentTasks: number;
9
+ weight: number;
10
+ supportedTags: string;
11
+ environment: string;
12
+ region: string;
13
+ description: string;
14
+ configInfo?: Record<string, unknown>;
15
+ }
16
+ export interface NodeRegistrationResponse {
17
+ success: boolean;
18
+ message?: string;
19
+ data?: {
20
+ nodeId: string;
21
+ token?: string;
22
+ [key: string]: unknown;
23
+ };
24
+ }
25
+ export interface NodeHeartbeatRequest {
26
+ nodeId: string;
27
+ currentTaskCount: number;
28
+ status: number;
29
+ cpuUsage?: number;
30
+ memoryUsage?: number;
31
+ diskUsage?: number;
32
+ additionalInfo?: Record<string, unknown>;
33
+ }
34
+ export interface NodeHeartbeatResponse {
35
+ success: boolean;
36
+ message?: string;
37
+ data?: {
38
+ commands?: Array<{
39
+ type: string;
40
+ payload: Record<string, unknown>;
41
+ }>;
42
+ [key: string]: unknown;
43
+ };
44
+ }
45
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/node/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAC,CAAC;QACrE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH"}
@@ -0,0 +1,3 @@
1
+ // Node registration and heartbeat types
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/node/types.ts"],"names":[],"mappings":"AAAA,wCAAwC"}
@@ -0,0 +1,6 @@
1
+ import Database from 'better-sqlite3';
2
+ import type { StorageConfig } from '../config/schema.js';
3
+ export declare function initDatabase(config: StorageConfig): Database.Database;
4
+ export declare function getDatabase(): Database.Database;
5
+ export declare function closeDatabase(): void;
6
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAqBrE;AAqGD,wBAAgB,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAK/C;AAwBD,wBAAgB,aAAa,IAAI,IAAI,CAMpC"}
@@ -0,0 +1,154 @@
1
+ import Database from 'better-sqlite3';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { createLogger } from '../core/logger.js';
5
+ const logger = createLogger('Database');
6
+ let db = null;
7
+ export function initDatabase(config) {
8
+ if (db)
9
+ return db;
10
+ // Ensure directory exists
11
+ const dbDir = path.dirname(config.dbPath);
12
+ if (!fs.existsSync(dbDir)) {
13
+ fs.mkdirSync(dbDir, { recursive: true });
14
+ logger.info(`Created database directory: ${dbDir}`);
15
+ }
16
+ db = new Database(config.dbPath);
17
+ // Enable WAL mode for better concurrent read performance
18
+ db.pragma('journal_mode = WAL');
19
+ db.pragma('foreign_keys = ON');
20
+ // Run migrations
21
+ runMigrations(db);
22
+ logger.info(`Database initialized: ${config.dbPath}`);
23
+ return db;
24
+ }
25
+ function runMigrations(database) {
26
+ const migrationPath = path.resolve(import.meta.dirname, 'migrations', 'init.sql');
27
+ let sql;
28
+ if (fs.existsSync(migrationPath)) {
29
+ sql = fs.readFileSync(migrationPath, 'utf-8');
30
+ }
31
+ else {
32
+ // Fallback: inline the SQL if file not found (e.g., after build)
33
+ sql = `
34
+ CREATE TABLE IF NOT EXISTS devices (
35
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
36
+ serial_number TEXT UNIQUE NOT NULL,
37
+ model TEXT,
38
+ brand TEXT,
39
+ platform TEXT DEFAULT 'android',
40
+ status TEXT DEFAULT 'offline',
41
+ last_heartbeat_at DATETIME,
42
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
43
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
44
+ );
45
+ CREATE TABLE IF NOT EXISTS tasks (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ task_id TEXT UNIQUE NOT NULL,
48
+ execution_id TEXT,
49
+ type TEXT NOT NULL,
50
+ status TEXT DEFAULT 'pending',
51
+ priority INTEGER DEFAULT 0,
52
+ config TEXT,
53
+ result TEXT,
54
+ error_message TEXT,
55
+ report_file_path TEXT,
56
+ allocated_device TEXT,
57
+ started_at DATETIME,
58
+ completed_at DATETIME,
59
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
60
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
61
+ );
62
+ CREATE TABLE IF NOT EXISTS execution_logs (
63
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
64
+ task_id TEXT NOT NULL,
65
+ session_id TEXT,
66
+ level TEXT DEFAULT 'info',
67
+ content TEXT NOT NULL,
68
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
69
+ );
70
+ CREATE TABLE IF NOT EXISTS debug_sessions (
71
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
72
+ session_id TEXT UNIQUE NOT NULL,
73
+ task_id TEXT,
74
+ device_id TEXT,
75
+ platform TEXT,
76
+ status TEXT DEFAULT 'idle',
77
+ started_at DATETIME,
78
+ completed_at DATETIME,
79
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
80
+ );
81
+ CREATE TABLE IF NOT EXISTS debug_logs (
82
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
83
+ session_id TEXT NOT NULL,
84
+ type TEXT,
85
+ content TEXT NOT NULL,
86
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
87
+ );
88
+ CREATE INDEX IF NOT EXISTS idx_devices_serial ON devices(serial_number);
89
+ CREATE INDEX IF NOT EXISTS idx_devices_status ON devices(status);
90
+ CREATE INDEX IF NOT EXISTS idx_tasks_task_id ON tasks(task_id);
91
+ CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
92
+ CREATE INDEX IF NOT EXISTS idx_tasks_type ON tasks(type);
93
+ CREATE INDEX IF NOT EXISTS idx_execution_logs_task_id ON execution_logs(task_id);
94
+ CREATE INDEX IF NOT EXISTS idx_debug_sessions_session_id ON debug_sessions(session_id);
95
+ CREATE INDEX IF NOT EXISTS idx_debug_logs_session_id ON debug_logs(session_id);
96
+ `;
97
+ }
98
+ // Execute each statement separately
99
+ const statements = sql
100
+ .split(';')
101
+ .map(s => s.trim())
102
+ .filter(s => s.length > 0);
103
+ for (const stmt of statements) {
104
+ try {
105
+ database.exec(stmt + ';');
106
+ }
107
+ catch (error) {
108
+ // Ignore "already exists" errors for idempotent migrations
109
+ const msg = error.message;
110
+ if (!msg.includes('already exists')) {
111
+ logger.error(`Migration error: ${msg}`);
112
+ throw error;
113
+ }
114
+ }
115
+ }
116
+ logger.info('Database migrations completed');
117
+ // Run ALTER TABLE migrations for existing databases
118
+ runAlterMigrations(database);
119
+ }
120
+ export function getDatabase() {
121
+ if (!db) {
122
+ throw new Error('Database not initialized. Call initDatabase() first.');
123
+ }
124
+ return db;
125
+ }
126
+ /**
127
+ * Run ALTER TABLE migrations for existing databases that may lack newer columns
128
+ */
129
+ function runAlterMigrations(database) {
130
+ const alterMigrations = [
131
+ 'ALTER TABLE tasks ADD COLUMN allocated_device TEXT',
132
+ ];
133
+ for (const stmt of alterMigrations) {
134
+ try {
135
+ database.exec(stmt + ';');
136
+ logger.info(`Alter migration applied: ${stmt}`);
137
+ }
138
+ catch (error) {
139
+ // Ignore "duplicate column" errors (column already exists)
140
+ const msg = error.message;
141
+ if (!msg.includes('duplicate column name')) {
142
+ logger.warn(`Alter migration skipped: ${msg}`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ export function closeDatabase() {
148
+ if (db) {
149
+ db.close();
150
+ db = null;
151
+ logger.info('Database connection closed');
152
+ }
153
+ }
154
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface DebugLogEntry {
2
+ id?: number;
3
+ sessionId: string;
4
+ type: string;
5
+ content: string;
6
+ createdAt?: Date;
7
+ }
8
+ export interface DebugSessionRecord {
9
+ id?: number;
10
+ sessionId: string;
11
+ taskId?: string;
12
+ deviceId?: string;
13
+ platform?: string;
14
+ status: string;
15
+ startedAt?: Date;
16
+ completedAt?: Date;
17
+ createdAt?: Date;
18
+ }
19
+ export declare class DebugLogRepo {
20
+ createSession(session: Omit<DebugSessionRecord, 'id' | 'createdAt'>): void;
21
+ updateSessionStatus(sessionId: string, status: string): void;
22
+ getSession(sessionId: string): DebugSessionRecord | undefined;
23
+ getAllSessions(limit?: number): DebugSessionRecord[];
24
+ addLog(entry: Omit<DebugLogEntry, 'id' | 'createdAt'>): void;
25
+ getLogsBySession(sessionId: string, limit?: number): DebugLogEntry[];
26
+ deleteSession(sessionId: string): void;
27
+ }
28
+ export declare const debugLogRepo: DebugLogRepo;
29
+ //# sourceMappingURL=debug-log-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-log-repo.d.ts","sourceRoot":"","sources":["../../../src/storage/repositories/debug-log-repo.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAiCD,qBAAa,YAAY;IACvB,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,IAAI;IAe1E,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAW5D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAM7D,cAAc,CAAC,KAAK,GAAE,MAAY,GAAG,kBAAkB,EAAE;IAMzD,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,IAAI;IAY5D,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAa,GAAG,aAAa,EAAE;IAQ1E,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAKvC;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}