@alwaysai/device-agent 2.0.0 → 2.0.2-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 (81) hide show
  1. package/lib/application-control/environment-variables.d.ts +4 -0
  2. package/lib/application-control/environment-variables.d.ts.map +1 -1
  3. package/lib/application-control/environment-variables.js +17 -13
  4. package/lib/application-control/environment-variables.js.map +1 -1
  5. package/lib/application-control/install.d.ts +4 -1
  6. package/lib/application-control/install.d.ts.map +1 -1
  7. package/lib/application-control/install.js +16 -1
  8. package/lib/application-control/install.js.map +1 -1
  9. package/lib/application-control/utils.d.ts.map +1 -1
  10. package/lib/application-control/utils.js +13 -0
  11. package/lib/application-control/utils.js.map +1 -1
  12. package/lib/cloud-connection/base-message-handler.d.ts +27 -0
  13. package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
  14. package/lib/cloud-connection/base-message-handler.js +72 -0
  15. package/lib/cloud-connection/base-message-handler.js.map +1 -0
  16. package/lib/cloud-connection/connection-manager.d.ts +20 -0
  17. package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
  18. package/lib/cloud-connection/connection-manager.js +164 -0
  19. package/lib/cloud-connection/connection-manager.js.map +1 -0
  20. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +7 -23
  21. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  22. package/lib/cloud-connection/device-agent-cloud-connection.js +49 -517
  23. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  24. package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
  25. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
  26. package/lib/cloud-connection/device-agent-message-handler.js +357 -0
  27. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
  28. package/lib/cloud-connection/live-updates-handler.d.ts +1 -0
  29. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  30. package/lib/cloud-connection/live-updates-handler.js +13 -10
  31. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  32. package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
  33. package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
  34. package/lib/cloud-connection/message-dispatcher.js +27 -0
  35. package/lib/cloud-connection/message-dispatcher.js.map +1 -0
  36. package/lib/cloud-connection/publisher.d.ts +3 -2
  37. package/lib/cloud-connection/publisher.d.ts.map +1 -1
  38. package/lib/cloud-connection/publisher.js +8 -4
  39. package/lib/cloud-connection/publisher.js.map +1 -1
  40. package/lib/cloud-connection/shadow-handler.d.ts +7 -0
  41. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  42. package/lib/cloud-connection/shadow-handler.js +77 -1
  43. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  44. package/lib/cloud-connection/shadow-handler.test.js +5 -2
  45. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  46. package/lib/cloud-connection/transaction-manager.d.ts +9 -4
  47. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  48. package/lib/cloud-connection/transaction-manager.js +22 -11
  49. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  50. package/lib/cloud-connection/transaction-manager.test.js +43 -14
  51. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  52. package/lib/jobs/job-handler.d.ts +23 -0
  53. package/lib/jobs/job-handler.d.ts.map +1 -0
  54. package/lib/jobs/job-handler.js +131 -0
  55. package/lib/jobs/job-handler.js.map +1 -0
  56. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
  57. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
  58. package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
  59. package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
  60. package/lib/subcommands/app/version.d.ts +2 -0
  61. package/lib/subcommands/app/version.d.ts.map +1 -1
  62. package/lib/subcommands/app/version.js +14 -2
  63. package/lib/subcommands/app/version.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/application-control/environment-variables.ts +31 -21
  66. package/src/application-control/install.ts +24 -3
  67. package/src/application-control/utils.ts +13 -0
  68. package/src/cloud-connection/base-message-handler.ts +118 -0
  69. package/src/cloud-connection/connection-manager.ts +196 -0
  70. package/src/cloud-connection/device-agent-cloud-connection.ts +104 -817
  71. package/src/cloud-connection/device-agent-message-handler.ts +642 -0
  72. package/src/cloud-connection/live-updates-handler.ts +26 -18
  73. package/src/cloud-connection/message-dispatcher.ts +33 -0
  74. package/src/cloud-connection/publisher.ts +28 -23
  75. package/src/cloud-connection/shadow-handler.test.ts +6 -2
  76. package/src/cloud-connection/shadow-handler.ts +129 -1
  77. package/src/cloud-connection/transaction-manager.test.ts +55 -24
  78. package/src/cloud-connection/transaction-manager.ts +42 -31
  79. package/src/jobs/job-handler.ts +146 -0
  80. package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
  81. package/src/subcommands/app/version.ts +20 -2
@@ -0,0 +1,146 @@
1
+ import { MessageHandler } from '../cloud-connection/message-dispatcher';
2
+ import { logger } from '../util/logger';
3
+ import {
4
+ BaseHandler,
5
+ HandlerContext
6
+ } from '../cloud-connection/base-message-handler';
7
+ import { DeviceAgentMessageHandler } from '../cloud-connection/device-agent-message-handler';
8
+
9
+ class JobState {
10
+ private static instance: JobState;
11
+ public jobInProgress = false;
12
+
13
+ // Singleton pattern
14
+ private constructor() { } // eslint-disable-line
15
+
16
+ static getInstance(): JobState {
17
+ if (!JobState.instance) {
18
+ JobState.instance = new JobState();
19
+ }
20
+ return JobState.instance;
21
+ }
22
+ }
23
+
24
+ export class JobHandler extends BaseHandler implements MessageHandler {
25
+ private readonly msgHandler: DeviceAgentMessageHandler;
26
+
27
+ constructor(handlerContext: HandlerContext) {
28
+ super(handlerContext);
29
+ this.msgHandler = new DeviceAgentMessageHandler(
30
+ handlerContext,
31
+ this.handleJobError,
32
+ this.handleJobSuccess
33
+ );
34
+ }
35
+ private readonly state = JobState.getInstance();
36
+ private jobId = '';
37
+
38
+ public async handle(message: any, topic: string): Promise<void> {
39
+ const TOPICS = this.getJobTopic();
40
+
41
+ try {
42
+ switch (topic) {
43
+ case TOPICS.NOTIFY_NEXT:
44
+ await this.notifyNext(message);
45
+ break;
46
+ case TOPICS.START_NEXT_ACCEPTED:
47
+ this.startNextAccepted(message);
48
+ break;
49
+ default:
50
+ logger.info(`No handler for topic: ${topic}`);
51
+ }
52
+ } catch (error) {
53
+ logger.error(`Error handling job for topic: ${topic}`, error);
54
+ }
55
+ }
56
+
57
+ getJobTopic() {
58
+ const TOPICS = {
59
+ NOTIFY_NEXT: `$aws/things/${this.clientId}/jobs/notify-next`,
60
+ START_NEXT: `$aws/things/${this.clientId}/jobs/start-next`,
61
+ START_NEXT_ACCEPTED: `$aws/things/${this.clientId}/jobs/start-next/accepted`,
62
+ UPDATE: `$aws/things/${this.clientId}/jobs/${this.jobId}/update`
63
+ };
64
+ return TOPICS;
65
+ }
66
+
67
+ private async notifyNext(message: any): Promise<void> {
68
+ // Triggers when a job is completed and we need to notify the next job
69
+ logger.info('Invoking NOTIFY_NEXT handler');
70
+ const TOPICS = this.getJobTopic();
71
+ this.publisher.publish(TOPICS.START_NEXT, JSON.stringify({}));
72
+ }
73
+
74
+ private startNextAccepted(message: any): void {
75
+ if (this.state.jobInProgress) {
76
+ logger.info('Job already in progress');
77
+ return;
78
+ }
79
+
80
+ this.state.jobInProgress = true;
81
+
82
+ try {
83
+ if (message.execution) {
84
+ this.processJobExecution(message.execution);
85
+ } else {
86
+ this.state.jobInProgress = false;
87
+ }
88
+ } catch (error: unknown) {
89
+ this.handleError(error);
90
+ }
91
+ this.state.jobInProgress = false;
92
+ }
93
+
94
+ private processJobExecution(execution: any): void {
95
+ logger.info('Job in progress...');
96
+ const { jobDocument, jobId } = execution;
97
+ this.jobId = jobId;
98
+ this.msgHandler.handle(jobDocument);
99
+ }
100
+
101
+ private handleError(error: unknown): void {
102
+ if (error instanceof Error) {
103
+ logger.error(`Error starting next job`, error);
104
+ this.handleJobError('', error.message);
105
+ } else {
106
+ let errorMessage: string;
107
+ if (typeof error === 'string') {
108
+ errorMessage = error;
109
+ } else if (typeof error === 'object' && error !== null) {
110
+ try {
111
+ errorMessage = JSON.stringify(error);
112
+ } catch (jsonError) {
113
+ errorMessage = 'Unknown error (failed to stringify)';
114
+ }
115
+ } else {
116
+ errorMessage = 'Unknown error';
117
+ }
118
+ logger.error(`Unexpected error: ${errorMessage}`);
119
+ this.handleJobError('', errorMessage);
120
+ }
121
+ }
122
+
123
+ private updateJobStatus(status: string, message?: string): void {
124
+ const { UPDATE } = this.getJobTopic();
125
+ const payload = {
126
+ status,
127
+ statusDetails: {
128
+ message
129
+ }
130
+ };
131
+
132
+ this.publisher.publish(UPDATE, JSON.stringify(payload));
133
+ logger.info(`Marked job ${this.jobId} as ${status}`);
134
+ // Reset the job state
135
+ this.state.jobInProgress = false;
136
+ }
137
+
138
+ private readonly handleJobSuccess = (txId: string): void => {
139
+ this.updateJobStatus('SUCCEEDED');
140
+ };
141
+
142
+ private readonly handleJobError = (_txId: string, msg: string): void => {
143
+ logger.error(`Unexpected error type: ${msg}`);
144
+ this.updateJobStatus('FAILED', `Unexpected error: ${msg}`);
145
+ };
146
+ }
@@ -0,0 +1,56 @@
1
+ import {
2
+ getUpdateDeltaStateFromMessage,
3
+ validateSecureTunnelShadowUpdate
4
+ } from '@alwaysai/device-agent-schemas';
5
+ import { MessageHandler } from '../cloud-connection/message-dispatcher';
6
+ import { logger } from '../util/logger';
7
+ import { BaseHandler } from '../cloud-connection/base-message-handler';
8
+
9
+ export class SecureTunnelMessageHandler
10
+ extends BaseHandler
11
+ implements MessageHandler<any>
12
+ {
13
+ public getNotifyTopic(): string {
14
+ return `$aws/things/${this.clientId}/tunnels/notify`;
15
+ }
16
+
17
+ public async handle(message: any, topic: string): Promise<void> {
18
+ const secureTunnelNotifyTopic = this.getNotifyTopic();
19
+ if (topic === secureTunnelNotifyTopic) {
20
+ await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
21
+ } else if (
22
+ topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta
23
+ ) {
24
+ logger.info(`Received secure tunnel update: ${JSON.stringify(message)}`);
25
+ await this.handleSecureTunnelMessage(message);
26
+ } else if (
27
+ topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted
28
+ ) {
29
+ logger.info(`Received secure tunnel deleteAccepted: ${message}`);
30
+ await this.secureTunnelHandler.destroy();
31
+ }
32
+ }
33
+
34
+ public async handleSecureTunnelMessage(payload: any): Promise<void> {
35
+ logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
36
+ const state = getUpdateDeltaStateFromMessage(payload);
37
+ if (!state) {
38
+ logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
39
+ return;
40
+ }
41
+ const valid = validateSecureTunnelShadowUpdate(state);
42
+ if (!valid) {
43
+ logger.error(
44
+ `Error validating message: ${JSON.stringify(
45
+ { payload, errors: validateSecureTunnelShadowUpdate.errors },
46
+ null,
47
+ 2
48
+ )}`
49
+ );
50
+ return;
51
+ }
52
+ const secureTunnelUpdate =
53
+ await this.secureTunnelHandler.syncShadowToDeviceState(payload);
54
+ await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
55
+ }
56
+ }
@@ -37,10 +37,26 @@ export const installAppCliLeaf = CliLeaf({
37
37
  description: 'Release Hash',
38
38
  required: false,
39
39
  hidden: true
40
+ }),
41
+ appCfg: CliStringInput({
42
+ description: 'Application Configuration',
43
+ required: false,
44
+ hidden: true
45
+ }),
46
+ envVars: CliStringInput({
47
+ description: 'Environment Variables configuration',
48
+ hidden: true,
49
+ required: false
40
50
  })
41
51
  },
42
52
  async action(_, opts) {
43
- const { project, releaseHash, 'release-hash': releaseHashNew } = opts;
53
+ const {
54
+ project,
55
+ releaseHash,
56
+ 'release-hash': releaseHashNew,
57
+ appCfg,
58
+ envVars
59
+ } = opts;
44
60
  if (releaseHash) {
45
61
  logger.warn(
46
62
  `--releaseHash is deprecated and will be removed in a future release. Please switch to --release-hash`
@@ -60,7 +76,9 @@ export const installAppCliLeaf = CliLeaf({
60
76
  payload: {
61
77
  baseCommand: keyMirrors.appVersionControl.install,
62
78
  projectId: project,
63
- appReleaseHash: releaseHashResolved
79
+ appReleaseHash: releaseHashResolved,
80
+ appCfg,
81
+ envVars
64
82
  }
65
83
  };
66
84
  await deviceAgent.handleMessage(topic, message);