@alwaysai/device-agent 1.5.0 → 2.0.1

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 (305) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +8 -3
  3. package/lib/application-control/config.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +5 -5
  5. package/lib/application-control/environment-variables.d.ts.map +1 -1
  6. package/lib/application-control/environment-variables.js +25 -38
  7. package/lib/application-control/environment-variables.js.map +1 -1
  8. package/lib/application-control/environment-variables.test.js +27 -7
  9. package/lib/application-control/environment-variables.test.js.map +1 -1
  10. package/lib/application-control/index.d.ts +4 -4
  11. package/lib/application-control/index.d.ts.map +1 -1
  12. package/lib/application-control/index.js +1 -4
  13. package/lib/application-control/index.js.map +1 -1
  14. package/lib/application-control/install.d.ts +4 -1
  15. package/lib/application-control/install.d.ts.map +1 -1
  16. package/lib/application-control/install.js +24 -8
  17. package/lib/application-control/install.js.map +1 -1
  18. package/lib/application-control/models.d.ts +0 -11
  19. package/lib/application-control/models.d.ts.map +1 -1
  20. package/lib/application-control/models.js +5 -54
  21. package/lib/application-control/models.js.map +1 -1
  22. package/lib/application-control/utils.d.ts +0 -4
  23. package/lib/application-control/utils.d.ts.map +1 -1
  24. package/lib/application-control/utils.js +12 -22
  25. package/lib/application-control/utils.js.map +1 -1
  26. package/lib/cloud-connection/base-message-handler.d.ts +27 -0
  27. package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
  28. package/lib/cloud-connection/base-message-handler.js +72 -0
  29. package/lib/cloud-connection/base-message-handler.js.map +1 -0
  30. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  31. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  32. package/lib/cloud-connection/connection-manager.d.ts +21 -0
  33. package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
  34. package/lib/cloud-connection/connection-manager.js +158 -0
  35. package/lib/cloud-connection/connection-manager.js.map +1 -0
  36. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +9 -30
  37. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  38. package/lib/cloud-connection/device-agent-cloud-connection.js +69 -508
  39. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  40. package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
  41. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
  42. package/lib/cloud-connection/device-agent-message-handler.js +357 -0
  43. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
  44. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  45. package/lib/cloud-connection/device-agent.js +11 -9
  46. package/lib/cloud-connection/device-agent.js.map +1 -1
  47. package/lib/cloud-connection/live-updates-handler.d.ts +19 -28
  48. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  49. package/lib/cloud-connection/live-updates-handler.js +60 -172
  50. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  51. package/lib/cloud-connection/live-updates-handler.test.js +71 -165
  52. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  53. package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
  54. package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
  55. package/lib/cloud-connection/message-dispatcher.js +27 -0
  56. package/lib/cloud-connection/message-dispatcher.js.map +1 -0
  57. package/lib/cloud-connection/passthrough-handler.d.ts +4 -1
  58. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  59. package/lib/cloud-connection/passthrough-handler.js +30 -11
  60. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  61. package/lib/cloud-connection/shadow-handler.d.ts +11 -3
  62. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  63. package/lib/cloud-connection/shadow-handler.js +133 -28
  64. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  65. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  66. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  67. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  68. package/lib/cloud-connection/shadow.js +2 -1
  69. package/lib/cloud-connection/shadow.js.map +1 -1
  70. package/lib/cloud-connection/transaction-manager.d.ts +12 -3
  71. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  72. package/lib/cloud-connection/transaction-manager.js +29 -28
  73. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  74. package/lib/cloud-connection/transaction-manager.test.js +46 -5
  75. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  76. package/lib/device-control/device-control.d.ts +8 -8
  77. package/lib/device-control/device-control.d.ts.map +1 -1
  78. package/lib/device-control/device-control.js +95 -71
  79. package/lib/device-control/device-control.js.map +1 -1
  80. package/lib/docker/docker-compose.d.ts.map +1 -1
  81. package/lib/docker/docker-compose.js +2 -1
  82. package/lib/docker/docker-compose.js.map +1 -1
  83. package/lib/infrastructure/agent-config.d.ts +2 -1
  84. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  85. package/lib/infrastructure/agent-config.js +7 -7
  86. package/lib/infrastructure/agent-config.js.map +1 -1
  87. package/lib/infrastructure/agent-config.test.js +3 -1
  88. package/lib/infrastructure/agent-config.test.js.map +1 -1
  89. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  90. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  91. package/lib/infrastructure/config-check-utility.js +67 -0
  92. package/lib/infrastructure/config-check-utility.js.map +1 -0
  93. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  94. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  95. package/lib/infrastructure/config-check-utility.test.js +109 -0
  96. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  97. package/lib/infrastructure/device-certificate.d.ts +10 -0
  98. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  99. package/lib/infrastructure/device-certificate.js +47 -0
  100. package/lib/infrastructure/device-certificate.js.map +1 -0
  101. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  102. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  103. package/lib/infrastructure/device-certificate.test.js +24 -0
  104. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  105. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  106. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  107. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  108. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  109. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  110. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  111. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  112. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  113. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  114. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  115. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  116. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  117. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  118. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  119. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  120. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  121. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  122. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  123. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  124. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  125. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  126. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  127. package/lib/infrastructure/required-config-checks.js +30 -0
  128. package/lib/infrastructure/required-config-checks.js.map +1 -0
  129. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  130. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  131. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  132. package/lib/jobs/job-handler.d.ts +23 -0
  133. package/lib/jobs/job-handler.d.ts.map +1 -0
  134. package/lib/jobs/job-handler.js +131 -0
  135. package/lib/jobs/job-handler.js.map +1 -0
  136. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  137. package/lib/local-connection/rabbitmq-connection.js +14 -14
  138. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  139. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
  140. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
  141. package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
  142. package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
  143. package/lib/secure-tunneling/secure-tunneling.d.ts +9 -9
  144. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  145. package/lib/secure-tunneling/secure-tunneling.js +21 -16
  146. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  147. package/lib/secure-tunneling/secure-tunneling.test.js +11 -13
  148. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  149. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  150. package/lib/subcommands/app/analytics.js +1 -2
  151. package/lib/subcommands/app/analytics.js.map +1 -1
  152. package/lib/subcommands/app/env-vars.d.ts +4 -0
  153. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  154. package/lib/subcommands/app/env-vars.js +52 -6
  155. package/lib/subcommands/app/env-vars.js.map +1 -1
  156. package/lib/subcommands/app/index.d.ts.map +1 -1
  157. package/lib/subcommands/app/index.js +1 -3
  158. package/lib/subcommands/app/index.js.map +1 -1
  159. package/lib/subcommands/app/models.d.ts +0 -11
  160. package/lib/subcommands/app/models.d.ts.map +1 -1
  161. package/lib/subcommands/app/models.js +2 -58
  162. package/lib/subcommands/app/models.js.map +1 -1
  163. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  164. package/lib/subcommands/app/shadow.js +6 -5
  165. package/lib/subcommands/app/shadow.js.map +1 -1
  166. package/lib/subcommands/app/version.d.ts +2 -0
  167. package/lib/subcommands/app/version.d.ts.map +1 -1
  168. package/lib/subcommands/app/version.js +16 -6
  169. package/lib/subcommands/app/version.js.map +1 -1
  170. package/lib/subcommands/config.d.ts +2 -0
  171. package/lib/subcommands/config.d.ts.map +1 -0
  172. package/lib/subcommands/config.js +39 -0
  173. package/lib/subcommands/config.js.map +1 -0
  174. package/lib/subcommands/device/clean.d.ts +1 -1
  175. package/lib/subcommands/device/clean.d.ts.map +1 -1
  176. package/lib/subcommands/device/clean.js +23 -13
  177. package/lib/subcommands/device/clean.js.map +1 -1
  178. package/lib/subcommands/device/index.d.ts.map +1 -1
  179. package/lib/subcommands/device/index.js +3 -1
  180. package/lib/subcommands/device/index.js.map +1 -1
  181. package/lib/subcommands/device/init.js +8 -8
  182. package/lib/subcommands/device/init.js.map +1 -1
  183. package/lib/subcommands/device/migrate.d.ts +2 -0
  184. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  185. package/lib/subcommands/device/migrate.js +24 -0
  186. package/lib/subcommands/device/migrate.js.map +1 -0
  187. package/lib/subcommands/device/refresh.d.ts.map +1 -1
  188. package/lib/subcommands/device/refresh.js +1 -0
  189. package/lib/subcommands/device/refresh.js.map +1 -1
  190. package/lib/subcommands/index.d.ts +1 -1
  191. package/lib/subcommands/index.d.ts.map +1 -1
  192. package/lib/subcommands/index.js +3 -1
  193. package/lib/subcommands/index.js.map +1 -1
  194. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  195. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  196. package/lib/util/aai-error.d.ts +12 -0
  197. package/lib/util/aai-error.d.ts.map +1 -0
  198. package/lib/util/aai-error.js +11 -0
  199. package/lib/util/aai-error.js.map +1 -0
  200. package/lib/util/aws-regions.d.ts +2 -0
  201. package/lib/util/aws-regions.d.ts.map +1 -0
  202. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  203. package/lib/util/aws-regions.js.map +1 -0
  204. package/lib/util/check-for-updates.d.ts.map +1 -1
  205. package/lib/util/check-for-updates.js +5 -28
  206. package/lib/util/check-for-updates.js.map +1 -1
  207. package/lib/util/clean-certs.d.ts.map +1 -1
  208. package/lib/util/clean-certs.js +5 -4
  209. package/lib/util/clean-certs.js.map +1 -1
  210. package/lib/util/directories.d.ts +4 -18
  211. package/lib/util/directories.d.ts.map +1 -1
  212. package/lib/util/directories.js +18 -32
  213. package/lib/util/directories.js.map +1 -1
  214. package/lib/util/file.d.ts +4 -0
  215. package/lib/util/file.d.ts.map +1 -1
  216. package/lib/util/file.js +65 -4
  217. package/lib/util/file.js.map +1 -1
  218. package/lib/util/get-device-id.d.ts.map +1 -1
  219. package/lib/util/get-device-id.js +7 -1
  220. package/lib/util/get-device-id.js.map +1 -1
  221. package/lib/util/http-client.js +3 -3
  222. package/lib/util/http-client.js.map +1 -1
  223. package/package.json +19 -17
  224. package/readme.md +12 -32
  225. package/src/application-control/config.ts +9 -12
  226. package/src/application-control/environment-variables.test.ts +28 -7
  227. package/src/application-control/environment-variables.ts +42 -59
  228. package/src/application-control/index.ts +3 -16
  229. package/src/application-control/install.ts +39 -13
  230. package/src/application-control/models.ts +6 -87
  231. package/src/application-control/utils.ts +10 -25
  232. package/src/cloud-connection/base-message-handler.ts +118 -0
  233. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  234. package/src/cloud-connection/connection-manager.ts +187 -0
  235. package/src/cloud-connection/device-agent-cloud-connection.ts +130 -723
  236. package/src/cloud-connection/device-agent-message-handler.ts +642 -0
  237. package/src/cloud-connection/device-agent.ts +16 -7
  238. package/src/cloud-connection/live-updates-handler.test.ts +121 -189
  239. package/src/cloud-connection/live-updates-handler.ts +105 -232
  240. package/src/cloud-connection/message-dispatcher.ts +33 -0
  241. package/src/cloud-connection/passthrough-handler.ts +55 -18
  242. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  243. package/src/cloud-connection/shadow-handler.ts +224 -54
  244. package/src/cloud-connection/shadow.ts +4 -1
  245. package/src/cloud-connection/transaction-manager.test.ts +68 -6
  246. package/src/cloud-connection/transaction-manager.ts +69 -41
  247. package/src/device-control/device-control.ts +102 -70
  248. package/src/docker/docker-compose.ts +3 -2
  249. package/src/infrastructure/agent-config.test.ts +6 -2
  250. package/src/infrastructure/agent-config.ts +8 -7
  251. package/src/infrastructure/config-check-utility.test.ts +154 -0
  252. package/src/infrastructure/config-check-utility.ts +77 -0
  253. package/src/infrastructure/device-certificate.test.ts +40 -0
  254. package/src/infrastructure/device-certificate.ts +58 -0
  255. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  256. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  257. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  258. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  259. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  260. package/src/infrastructure/required-config-checks.ts +33 -0
  261. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  262. package/src/jobs/job-handler.ts +146 -0
  263. package/src/local-connection/rabbitmq-connection.ts +22 -17
  264. package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
  265. package/src/secure-tunneling/secure-tunneling.test.ts +20 -22
  266. package/src/secure-tunneling/secure-tunneling.ts +41 -29
  267. package/src/subcommands/app/analytics.ts +2 -4
  268. package/src/subcommands/app/env-vars.ts +72 -9
  269. package/src/subcommands/app/index.ts +3 -11
  270. package/src/subcommands/app/models.ts +5 -81
  271. package/src/subcommands/app/shadow.ts +6 -5
  272. package/src/subcommands/app/version.ts +23 -6
  273. package/src/subcommands/config.ts +42 -0
  274. package/src/subcommands/device/clean.ts +31 -17
  275. package/src/subcommands/device/index.ts +3 -1
  276. package/src/subcommands/device/init.ts +11 -11
  277. package/src/subcommands/device/migrate.ts +20 -0
  278. package/src/subcommands/device/refresh.ts +1 -0
  279. package/src/subcommands/index.ts +3 -1
  280. package/src/util/aai-error.ts +20 -0
  281. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  282. package/src/util/check-for-updates.ts +14 -30
  283. package/src/util/clean-certs.ts +8 -4
  284. package/src/util/directories.ts +23 -67
  285. package/src/util/file.ts +83 -3
  286. package/src/util/get-device-id.ts +7 -7
  287. package/src/util/http-client.ts +2 -2
  288. package/lib/util/cloud-mode-ready.d.ts +0 -3
  289. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  290. package/lib/util/cloud-mode-ready.js.map +0 -1
  291. package/lib/util/download-file.d.ts +0 -6
  292. package/lib/util/download-file.d.ts.map +0 -1
  293. package/lib/util/download-file.js +0 -25
  294. package/lib/util/download-file.js.map +0 -1
  295. package/lib/util/fetch-with-timeout.d.ts +0 -4
  296. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  297. package/lib/util/fetch-with-timeout.js +0 -30
  298. package/lib/util/fetch-with-timeout.js.map +0 -1
  299. package/lib/util/parsing.d.ts +0 -2
  300. package/lib/util/parsing.d.ts.map +0 -1
  301. package/lib/util/parsing.js +0 -17
  302. package/lib/util/parsing.js.map +0 -1
  303. package/src/util/download-file.ts +0 -25
  304. package/src/util/fetch-with-timeout.ts +0 -35
  305. package/src/util/parsing.ts +0 -11
@@ -1,13 +1,17 @@
1
1
  import {
2
+ EnvVars,
2
3
  ToClientStatusResponseMessage,
3
4
  generateTxId,
4
- keyMirrors
5
+ keyMirrors,
6
+ buildToClientStatusResponseMessage
5
7
  } from '@alwaysai/device-agent-schemas';
6
8
  import { TransactionManager } from './transaction-manager';
7
9
  import { v4 as uuidv4 } from 'uuid';
8
10
  import { Publisher } from './publisher';
9
11
  import { LiveUpdatesHandler } from './live-updates-handler';
10
12
  import { AppConfigUpdate, ShadowUpdate } from './shadow-handler';
13
+ import { AppContent } from './device-agent-message-handler';
14
+ import { AppConfig } from '@alwaysai/app-configuration-schemas';
11
15
 
12
16
  const mockClient = {
13
17
  publish: jest.fn()
@@ -15,8 +19,8 @@ const mockClient = {
15
19
  const clientId = 'test-client';
16
20
 
17
21
  const mockLiveUpdatesHandler = {
18
- enableTransactionStatus: jest.fn(),
19
- disableTransactionStatus: jest.fn()
22
+ enable: jest.fn(),
23
+ disable: jest.fn()
20
24
  } as any as LiveUpdatesHandler;
21
25
 
22
26
  describe('Test Transaction Manager', () => {
@@ -58,11 +62,22 @@ describe('Test Transaction Manager', () => {
58
62
  test('Start a new transaction which completes in one step', async () => {
59
63
  const txId = generateTxId();
60
64
  const projectId = generateRandomProjectId();
65
+
66
+ const successFn = (txId: string) => {
67
+ const msg = buildToClientStatusResponseMessage(
68
+ clientId,
69
+ { status: keyMirrors.statusResponse.success },
70
+ txId
71
+ );
72
+ publisher.publishToClient(msg);
73
+ };
74
+
61
75
  await txnMgr.runTransactionStep({
62
76
  func: func_complete,
63
77
  projectId,
64
78
  txId,
65
- start: true
79
+ start: true,
80
+ successFn
66
81
  });
67
82
  expect(txnMgr.isOngoingTransaction(txId)).toBe(false);
68
83
  expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(false);
@@ -188,7 +203,7 @@ describe('Test Transaction Manager', () => {
188
203
  throw new Error('Expected start transaction to fail!');
189
204
  } catch (e) {
190
205
  console.log(e);
191
- expect(e.code).toBe(txnMgr.Errors.PROJECT_ONGOING);
206
+ expect(e.code).toBe(txnMgr.Errors.PROJECT_TRANSACTION_ONGOING);
192
207
  }
193
208
  expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
194
209
  expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
@@ -198,6 +213,19 @@ describe('Test Transaction Manager', () => {
198
213
  test('Handle error in step function', async () => {
199
214
  const txId = generateTxId();
200
215
  const projectId = generateRandomProjectId();
216
+
217
+ const errorFn = (txId: string, errorMsg: string) => {
218
+ const msg = buildToClientStatusResponseMessage(
219
+ clientId,
220
+ {
221
+ status: keyMirrors.statusResponse.failure,
222
+ message: errorMsg
223
+ },
224
+ txId
225
+ );
226
+ publisher.publishToClient(msg);
227
+ };
228
+
201
229
  await txnMgr.runTransactionStep({
202
230
  func: jest.fn().mockImplementation(() => {
203
231
  throw new Error('Test error!');
@@ -205,7 +233,8 @@ describe('Test Transaction Manager', () => {
205
233
  projectId,
206
234
  txId,
207
235
  start: true,
208
- stepName: 'step1'
236
+ stepName: 'step1',
237
+ errorFn
209
238
  });
210
239
  expect(txnMgr.isOngoingTransaction(txId)).toBe(false);
211
240
  expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(false);
@@ -369,4 +398,37 @@ describe('Test Transaction Manager', () => {
369
398
  expect(txnMgr.isAnyOngoingTransaction()).toBe(false);
370
399
  expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(undefined);
371
400
  });
401
+
402
+ test('store appContent', async () => {
403
+ const txId = generateTxId();
404
+ const projectId = generateRandomProjectId();
405
+ const appCfg: AppConfig = {
406
+ models: {},
407
+ scripts: { start: 'python app.py' }
408
+ };
409
+ const envVars: EnvVars = { alwaysai: { TEST: '1' } };
410
+ const cfgUpdate: AppContent = {
411
+ projectId: projectId,
412
+ appCfg: appCfg,
413
+ envVars: envVars
414
+ };
415
+
416
+ await txnMgr.runTransactionStep({
417
+ func: func_incomplete,
418
+ projectId,
419
+ txId,
420
+ start: true
421
+ });
422
+
423
+ expect(txnMgr.getAppContentFromTxId(txId)).toEqual(undefined);
424
+
425
+ txnMgr.setAppContentToTx(txId, cfgUpdate);
426
+
427
+ expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
428
+ expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
429
+ expect(txnMgr.isOngoingTransaction(txId)).toBe(true);
430
+ expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(true);
431
+ expect(txnMgr.isAnyOngoingTransaction()).toBe(true);
432
+ expect(txnMgr.getAppContentFromTxId(txId)).toEqual(cfgUpdate);
433
+ });
372
434
  });
@@ -1,14 +1,15 @@
1
1
  import {
2
- StatusResponsePayload,
2
+ ToClientStatusResponseMessage,
3
3
  buildToClientStatusResponseMessage,
4
4
  keyMirrors
5
5
  } from '@alwaysai/device-agent-schemas';
6
6
  import { LiveUpdatesHandler } from './live-updates-handler';
7
7
  import { Publisher } from './publisher';
8
8
  import { logger } from '../util/logger';
9
- import { keyMirror } from 'alwaysai/lib/util';
9
+ import { keyMirror, stringifyError } from 'alwaysai/lib/util';
10
10
  import { CodedError } from '@carnesen/coded-error';
11
11
  import { ShadowUpdate } from './shadow-handler';
12
+ import { AppContent } from './device-agent-message-handler';
12
13
 
13
14
  interface TransactionDetails {
14
15
  txId: string;
@@ -18,19 +19,24 @@ interface TransactionDetails {
18
19
  update?: string;
19
20
  stop?: string;
20
21
  appCfgUpdate?: ShadowUpdate;
22
+ appContent?: AppContent;
21
23
  }
22
24
 
25
+ export type ErrorFunction = (txid: string, message: string) => void;
26
+
27
+ export type SuccessFunction = (txId: string) => void;
28
+
23
29
  export class TransactionManager {
24
30
  private detailsByTx: Record<string, TransactionDetails> = {};
25
31
  private detailsByProject: Record<string, TransactionDetails> = {};
26
- private liveUpdatesHandler: LiveUpdatesHandler;
32
+ private readonly liveUpdatesHandler: LiveUpdatesHandler;
27
33
  private publisher: Publisher;
28
-
29
- private startTransaction(
34
+ private async startTransaction(
30
35
  txId: string,
31
36
  projectId: string,
37
+ liveUpdatesPublishFn?: () => Promise<void>,
32
38
  stepName?: string
33
- ): void {
39
+ ): Promise<void> {
34
40
  // Check if the transaction already exists
35
41
  if (this.detailsByTx[txId]) {
36
42
  const txnDetails = this.detailsByTx[txId];
@@ -53,7 +59,7 @@ export class TransactionManager {
53
59
  null,
54
60
  2
55
61
  )}`,
56
- this.Errors.PROJECT_ONGOING
62
+ this.Errors.PROJECT_TRANSACTION_ONGOING
57
63
  );
58
64
  }
59
65
 
@@ -67,10 +73,14 @@ export class TransactionManager {
67
73
  this.detailsByTx[txId] = txDetails;
68
74
  this.detailsByProject[projectId] = txDetails;
69
75
  logger.info(`Started transaction:\n${JSON.stringify(txDetails, null, 2)}`);
70
- // send live updates
71
- void this.liveUpdatesHandler.enableTransactionStatus({
72
- txId
73
- });
76
+
77
+ if (liveUpdatesPublishFn) {
78
+ await this.liveUpdatesHandler.enable(
79
+ keyMirrors.toClientMessageType.status_response,
80
+ liveUpdatesPublishFn,
81
+ txId
82
+ );
83
+ }
74
84
  }
75
85
 
76
86
  private updateTransaction(txId: string, stepName?: string): void {
@@ -95,7 +105,7 @@ export class TransactionManager {
95
105
 
96
106
  public Errors = keyMirror({
97
107
  TRANSACTION_ONGOING: null,
98
- PROJECT_ONGOING: null,
108
+ PROJECT_TRANSACTION_ONGOING: null,
99
109
  TRANSACTION_NOT_ONGOING: null
100
110
  });
101
111
 
@@ -104,11 +114,28 @@ export class TransactionManager {
104
114
  projectId: string;
105
115
  txId: string;
106
116
  start: boolean;
117
+ liveUpdatesPublishFn?: () => Promise<void>;
107
118
  stepName?: string;
119
+ errorFn?: ErrorFunction;
120
+ successFn?: SuccessFunction;
108
121
  }) {
109
- const { func, projectId, txId, start, stepName } = props;
122
+ const {
123
+ func,
124
+ projectId,
125
+ txId,
126
+ start,
127
+ liveUpdatesPublishFn,
128
+ stepName,
129
+ errorFn,
130
+ successFn
131
+ } = props;
110
132
  if (start) {
111
- this.startTransaction(txId, projectId, stepName);
133
+ await this.startTransaction(
134
+ txId,
135
+ projectId,
136
+ liveUpdatesPublishFn,
137
+ stepName
138
+ );
112
139
  } else {
113
140
  this.updateTransaction(txId, stepName);
114
141
  }
@@ -116,36 +143,19 @@ export class TransactionManager {
116
143
  const completed = await func();
117
144
  if (completed) {
118
145
  this.completeTransaction(txId);
119
- const successStatusResponsePayload: StatusResponsePayload = {
120
- status: keyMirrors.statusResponse.success
121
- };
122
- // Send final status message
123
- const message = buildToClientStatusResponseMessage(
124
- this.publisher.getClientId(),
125
- successStatusResponsePayload,
126
- txId
127
- );
128
- this.publisher.publishToClient(message);
146
+ if (successFn) {
147
+ successFn(txId);
148
+ }
129
149
  }
130
150
  } catch (e) {
131
- const message: string = e.message;
132
151
  logger.error(
133
- `Failed to execute cmd for ${projectId}:\n${message}\n${e.stack}`
152
+ `Failed to execute cmd for ${projectId}!\n${stringifyError(e)}`
134
153
  );
135
154
 
136
155
  this.completeTransaction(txId);
137
-
138
- const failureStatusResponsePayload: StatusResponsePayload = {
139
- status: keyMirrors.statusResponse.failure,
140
- message
141
- };
142
- // Send final status message
143
- const failureStatusResponseMessage = buildToClientStatusResponseMessage(
144
- this.publisher.getClientId(),
145
- failureStatusResponsePayload,
146
- txId
147
- );
148
- this.publisher.publishToClient(failureStatusResponseMessage);
156
+ if (errorFn) {
157
+ errorFn(txId, e.message);
158
+ }
149
159
  }
150
160
  }
151
161
 
@@ -175,6 +185,10 @@ export class TransactionManager {
175
185
  return this.detailsByTx[txId]?.appCfgUpdate;
176
186
  }
177
187
 
188
+ public getAppContentFromTxId(txId: string): AppContent | undefined {
189
+ return this.detailsByTx[txId]?.appContent;
190
+ }
191
+
178
192
  public setAppCfgUpdateToTx(txId: string, appCfgUpdate: ShadowUpdate) {
179
193
  if (this.isOngoingTransaction(txId)) {
180
194
  this.detailsByTx[txId].appCfgUpdate = appCfgUpdate;
@@ -184,7 +198,20 @@ export class TransactionManager {
184
198
  );
185
199
  }
186
200
 
187
- public completeTransaction(txId: string): void {
201
+ public setAppContentToTx(txId: string, appContent: AppContent) {
202
+ if (this.isOngoingTransaction(txId)) {
203
+ logger.debug(`${txId}: Setting AppContent:${JSON.stringify(appContent)}`);
204
+ this.detailsByTx[txId].appContent = appContent;
205
+ } else
206
+ throw new Error(
207
+ `Could not set appCfgUpdate, the transaction ${txId} does not exist.`
208
+ );
209
+ }
210
+
211
+ public completeTransaction(
212
+ txId: string,
213
+ messageToPublish?: ToClientStatusResponseMessage
214
+ ): void {
188
215
  const txDetails = this.detailsByTx[txId];
189
216
  if (txDetails === undefined) {
190
217
  throw new CodedError(
@@ -199,8 +226,9 @@ export class TransactionManager {
199
226
  delete this.detailsByTx[txId];
200
227
  delete this.detailsByProject[txDetails.projectId];
201
228
 
202
- void this.liveUpdatesHandler.disableTransactionStatus({
229
+ this.liveUpdatesHandler.disable(
230
+ keyMirrors.toClientMessageType.status_response,
203
231
  txId
204
- });
232
+ );
205
233
  }
206
234
  }
@@ -4,9 +4,10 @@ import * as osu from 'node-os-utils';
4
4
  import * as si from 'systeminformation';
5
5
  import { exec } from 'child_process';
6
6
  import { promisify } from 'util';
7
- import { JsSpawner } from 'alwaysai/lib/util';
7
+ import { JsSpawner, stringifyError } from 'alwaysai/lib/util';
8
8
  import { DeviceStatsPayload } from '@alwaysai/device-agent-schemas';
9
9
  import { getDeviceAgentVersion } from '../util/check-for-updates';
10
+ import AaiError from '../util/aai-error';
10
11
 
11
12
  const exec_promise = promisify(exec);
12
13
 
@@ -14,63 +15,84 @@ const exec_promise = promisify(exec);
14
15
  export async function getCpuDetails(): Promise<
15
16
  DeviceStatsPayload['cpuDetails']
16
17
  > {
17
- const cpuFree = await osu.cpu.free();
18
- const cpuTemp = await si.cpuTemperature();
19
- const cpuDetails: DeviceStatsPayload['cpuDetails'] = {};
20
- if (cpuFree !== null) cpuDetails.usedPerc = 100 - cpuFree;
21
- if (cpuTemp?.main !== null) cpuDetails.temperature = cpuTemp.main;
22
- return cpuDetails;
18
+ let cpuFree, cpuTemp;
19
+ try {
20
+ [cpuFree, cpuTemp] = await Promise.all([
21
+ osu.cpu.free(),
22
+ si.cpuTemperature()
23
+ ]);
24
+ } catch (error) {
25
+ logger.error('Error fetching CPU details:', error);
26
+ return {};
27
+ }
28
+
29
+ return {
30
+ usedPerc: cpuFree !== null ? 100 - cpuFree : undefined,
31
+ temperature: cpuTemp?.main !== null ? cpuTemp.main : undefined
32
+ };
23
33
  }
24
34
 
25
35
  export async function getDiskDetails(): Promise<
26
36
  DeviceStatsPayload['diskDetails']
27
37
  > {
28
- // Types incorrectly specify diskname as required instead of optional
29
- // @ts-expect-error
30
- const driveInfo = await osu.drive.info();
31
- const diskDetails: DeviceStatsPayload['diskDetails'] = {};
32
- if (driveInfo?.usedGb !== null)
33
- diskDetails.usedGb = parseFloat(driveInfo.usedGb);
34
- if (driveInfo?.freeGb !== null) {
35
- diskDetails.freeGb = parseFloat(driveInfo.freeGb);
38
+ let driveInfo;
39
+ try {
40
+ // Types incorrectly specify diskname as required instead of optional
41
+ // @ts-expect-error
42
+ driveInfo = await osu.drive.info();
43
+ } catch (error) {
44
+ logger.error('Error fetching disk details:', error);
45
+ return {};
36
46
  }
37
- return diskDetails;
47
+
48
+ return {
49
+ usedGb:
50
+ driveInfo?.usedGb !== null ? parseFloat(driveInfo.usedGb) : undefined,
51
+ freeGb:
52
+ driveInfo?.freeGb !== null ? parseFloat(driveInfo.freeGb) : undefined
53
+ };
38
54
  }
39
55
 
40
56
  export async function getMemDetails(): Promise<
41
57
  DeviceStatsPayload['memDetails']
42
58
  > {
43
- const memInfo = await osu.mem.info();
44
- const memDetails: DeviceStatsPayload['memDetails'] = {};
45
- if (memInfo?.usedMemMb !== null) memDetails.usedMb = memInfo.usedMemMb;
46
- if (memInfo?.freeMemMb !== null) memDetails.freeMb = memInfo.freeMemMb;
47
- return memDetails;
59
+ let memInfo;
60
+ try {
61
+ memInfo = await osu.mem.info();
62
+ } catch (error) {
63
+ logger.error('Error fetching memory details:', error);
64
+ return {};
65
+ }
66
+ return {
67
+ usedMb: memInfo?.usedMemMb !== null ? memInfo.usedMemMb : undefined,
68
+ freeMb: memInfo?.freeMemMb !== null ? memInfo.freeMemMb : undefined
69
+ };
48
70
  }
49
71
 
50
- // System information
72
+ // System information casted to a string
51
73
  export async function getOsInfo() {
52
74
  const osInfo = await si.osInfo();
53
75
  return {
54
- platform: osInfo.platform,
55
- distro: osInfo.distro,
56
- release: osInfo.release,
57
- kernel: osInfo.kernel,
58
- architecture: osInfo.arch,
59
- hostname: osInfo.hostname
76
+ platform: String(osInfo.platform),
77
+ distro: String(osInfo.distro),
78
+ release: String(osInfo.release),
79
+ kernel: String(osInfo.kernel),
80
+ architecture: String(osInfo.arch),
81
+ hostname: String(osInfo.hostname)
60
82
  };
61
83
  }
62
84
 
63
85
  export async function getCpuInfo() {
64
86
  const cpuInfo = await si.cpu();
65
87
  return {
66
- manufacturer: cpuInfo.manufacturer,
67
- brand: cpuInfo.brand,
68
- vendor: cpuInfo.vendor,
69
- model: cpuInfo.model,
70
- cores: cpuInfo.cores,
71
- physicalCores: cpuInfo.physicalCores,
72
- efficiencyCores: cpuInfo.efficiencyCores,
73
- processors: cpuInfo.processors
88
+ manufacturer: String(cpuInfo.manufacturer),
89
+ brand: String(cpuInfo.brand),
90
+ vendor: String(cpuInfo.vendor),
91
+ model: String(cpuInfo.model),
92
+ cores: String(cpuInfo.cores),
93
+ physicalCores: String(cpuInfo.physicalCores),
94
+ efficiencyCores: String(cpuInfo.efficiencyCores),
95
+ processors: String(cpuInfo.processors)
74
96
  };
75
97
  }
76
98
 
@@ -78,11 +100,11 @@ export async function getDiskInfo() {
78
100
  const diskInfo = await si.diskLayout();
79
101
  return {
80
102
  drives: diskInfo.map((drive) => ({
81
- device: drive.device,
82
- type: drive.type,
83
- name: drive.name,
84
- vendor: drive.vendor,
85
- size: drive.size
103
+ device: String(drive.device),
104
+ type: String(drive.type),
105
+ name: String(drive.name),
106
+ vendor: String(drive.vendor),
107
+ size: String(drive.size)
86
108
  }))
87
109
  };
88
110
  }
@@ -90,14 +112,14 @@ export async function getDiskInfo() {
90
112
  export async function getDeviceInfo() {
91
113
  const deviceInfo = await si.system();
92
114
  return {
93
- manufacturer: deviceInfo.manufacturer,
94
- model: deviceInfo.model,
95
- version: deviceInfo.version,
115
+ manufacturer: String(deviceInfo.manufacturer),
116
+ model: String(deviceInfo.model),
117
+ version: String(deviceInfo.version),
96
118
  serial:
97
119
  deviceInfo.serial && deviceInfo.serial !== '-'
98
- ? deviceInfo.serial
120
+ ? String(deviceInfo.serial)
99
121
  : undefined,
100
- virtual: deviceInfo.virtual
122
+ virtual: deviceInfo.virtual // this should be a boolean
101
123
  };
102
124
  }
103
125
 
@@ -108,9 +130,9 @@ export async function getNetworkInfo() {
108
130
  ? networkInterfaces.filter((iface: any) => iface.ip4 !== '127.0.0.1')[0]
109
131
  : networkInterfaces;
110
132
  return {
111
- ipv4Address: defaultNetworkInterface.ip4,
112
- ipv6Address: defaultNetworkInterface.ip6,
113
- macAddress: defaultNetworkInterface.mac
133
+ ipv4Address: String(defaultNetworkInterface.ip4),
134
+ ipv6Address: String(defaultNetworkInterface.ip6),
135
+ macAddress: String(defaultNetworkInterface.mac)
114
136
  };
115
137
  }
116
138
 
@@ -123,9 +145,9 @@ export async function getDockerVersion() {
123
145
  args: ['info', '--format', 'json']
124
146
  })
125
147
  );
126
- return result.ClientInfo.Version;
148
+ return String(result.ClientInfo.Version);
127
149
  } catch (e) {
128
- logger.warn(`Cannot get Docker version: ${e}`);
150
+ logger.warn(`Cannot get Docker version!\n${stringifyError(e)}`);
129
151
  return 'Not found';
130
152
  }
131
153
  }
@@ -138,7 +160,7 @@ export async function getDockerComposeVersion() {
138
160
  args: ['compose', 'version']
139
161
  });
140
162
  } catch (e) {
141
- logger.warn(`Cannot get Docker Compose version: ${e}`);
163
+ logger.warn(`Cannot get Docker Compose version!\n${stringifyError(e)}`);
142
164
  return 'Not found';
143
165
  }
144
166
  }
@@ -151,7 +173,7 @@ export async function getNpmVersion() {
151
173
  args: ['--version']
152
174
  });
153
175
  } catch (e) {
154
- logger.warn(`Cannot get npm version: ${e}`);
176
+ logger.warn(`Cannot get npm version!\n${stringifyError(e)}`);
155
177
  return 'Not found';
156
178
  }
157
179
  }
@@ -164,7 +186,7 @@ export async function getNodeVersion() {
164
186
  args: ['-v']
165
187
  });
166
188
  } catch (e) {
167
- logger.warn(`Cannot get Node version: ${e}`);
189
+ logger.warn(`Cannot get Node version!\n${stringifyError(e)}`);
168
190
  return 'Not found';
169
191
  }
170
192
  }
@@ -174,7 +196,6 @@ export async function getPackageVersions() {
174
196
  // eslint-disable-next-line
175
197
  const deviceAgentSchemasJson = require('../../node_modules/@alwaysai/device-agent-schemas/package.json');
176
198
 
177
- // Concurrent asynchronous function call
178
199
  const [dockerVersion, dockerComposeVersion, nodeVersion, npmVersion] =
179
200
  await Promise.all([
180
201
  getDockerVersion(),
@@ -207,27 +228,39 @@ export async function getLastBootTime() {
207
228
 
208
229
  const tokens = latestBootStdout.trim().split(' ');
209
230
 
210
- return new Date(`${tokens[2]} ${tokens[3]} ${tokens[4]}`);
231
+ return String(new Date(`${tokens[2]} ${tokens[3]} ${tokens[4]}`));
211
232
  } catch (e) {
212
- logger.error(`Issue getting last boot time: ${e.message}`);
233
+ logger.error(`Issue getting last boot time!\n${stringifyError(e)}`);
213
234
  return undefined;
214
235
  }
215
236
  }
216
237
 
217
238
  export async function getSystemInformation(): Promise<SystemInformationShadowUpdate> {
218
239
  try {
240
+ const [os, cpu, disk, device, network, versions, lastBootTime] =
241
+ await Promise.all([
242
+ getOsInfo(),
243
+ getCpuInfo(),
244
+ getDiskInfo(),
245
+ getDeviceInfo(),
246
+ getNetworkInfo(),
247
+ getPackageVersions(),
248
+ getLastBootTime()
249
+ ]);
219
250
  const systemInfo: SystemInformationShadowUpdate = {
220
- os: await getOsInfo(),
221
- cpu: await getCpuInfo(),
222
- disk: await getDiskInfo(),
223
- device: await getDeviceInfo(),
224
- network: await getNetworkInfo(),
225
- versions: await getPackageVersions(),
226
- lastBootTime: (await getLastBootTime())?.toString()
251
+ os,
252
+ cpu,
253
+ disk,
254
+ device,
255
+ network,
256
+ versions,
257
+ lastBootTime
227
258
  };
228
259
  return systemInfo;
229
260
  } catch (e) {
230
- logger.error('There was a problem getting system information: ', e);
261
+ logger.error(
262
+ `There was a problem getting system information!\n${stringifyError(e)}`
263
+ );
231
264
  }
232
265
  return {};
233
266
  }
@@ -242,11 +275,10 @@ export async function reboot() {
242
275
  timeout: 5000
243
276
  });
244
277
  logger.info(result.stdout.trim());
245
- } catch (err) {
246
- throw new Error(
247
- `Could not reboot device. You may need to add passwordless access to '/sbin/shutdown'. ${JSON.stringify(
248
- err
249
- )}`
278
+ } catch (e) {
279
+ throw new AaiError(
280
+ "Could not reboot device. You may need to add passwordless access to '/sbin/shutdown'.",
281
+ { cause: e }
250
282
  );
251
283
  }
252
284
  }
@@ -2,7 +2,7 @@ import * as DockerComposeV1 from 'docker-compose';
2
2
  import { v2 as DockerComposeV2 } from 'docker-compose';
3
3
  import { execSync } from 'child_process';
4
4
  import { logger } from '../util/logger';
5
- import { JsSpawner } from 'alwaysai/lib/util';
5
+ import { JsSpawner, stringifyError } from 'alwaysai/lib/util';
6
6
 
7
7
  let dockerCmd = 'docker';
8
8
 
@@ -14,11 +14,12 @@ export function importDockerCompose():
14
14
  logger.debug('Using Docker Compose V2.');
15
15
  return DockerComposeV2;
16
16
  } catch (e) {
17
+ // TODO: Log this error as well
17
18
  try {
18
19
  execSync('docker-compose -v').toString();
19
20
  logger.warn('Using docker-compose V1. Please consider updating to V2.');
20
21
  } catch (e) {
21
- logger.warn(`Could not determine compose: ${e}`);
22
+ logger.warn(`Could not determine compose!\n${stringifyError(e)}`);
22
23
  }
23
24
  }
24
25
  dockerCmd = 'docker-compose';
@@ -1,7 +1,11 @@
1
+ import { getDeviceConfigPath } from 'alwaysai/lib/infrastructure';
2
+ import { join } from 'path';
1
3
  import * as tempy from 'tempy';
2
- import { AgentConfigFile } from './agent-config';
4
+ import { AGENT_CONFIG_FILE_NAME, AgentConfigFile } from './agent-config';
3
5
 
4
- const configFile = AgentConfigFile(tempy.directory());
6
+ const configFile = AgentConfigFile(
7
+ join(tempy.directory(), getDeviceConfigPath(), AGENT_CONFIG_FILE_NAME)
8
+ );
5
9
 
6
10
  describe('Test Agent Config', () => {
7
11
  beforeEach(() => {