@alwaysai/device-agent 0.0.7 → 0.0.9

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 (77) hide show
  1. package/lib/application-control/backup.d.ts.map +1 -1
  2. package/lib/application-control/backup.js +2 -0
  3. package/lib/application-control/backup.js.map +1 -1
  4. package/lib/application-control/config.d.ts +17 -0
  5. package/lib/application-control/config.d.ts.map +1 -0
  6. package/lib/application-control/config.js +62 -0
  7. package/lib/application-control/config.js.map +1 -0
  8. package/lib/application-control/environment-variables.d.ts.map +1 -1
  9. package/lib/application-control/environment-variables.js +6 -14
  10. package/lib/application-control/environment-variables.js.map +1 -1
  11. package/lib/application-control/index.d.ts +2 -1
  12. package/lib/application-control/index.d.ts.map +1 -1
  13. package/lib/application-control/index.js +6 -1
  14. package/lib/application-control/index.js.map +1 -1
  15. package/lib/application-control/install.d.ts +16 -10
  16. package/lib/application-control/install.d.ts.map +1 -1
  17. package/lib/application-control/install.js +95 -57
  18. package/lib/application-control/install.js.map +1 -1
  19. package/lib/application-control/models.d.ts +3 -0
  20. package/lib/application-control/models.d.ts.map +1 -1
  21. package/lib/application-control/models.js +96 -20
  22. package/lib/application-control/models.js.map +1 -1
  23. package/lib/application-control/status.d.ts +3 -2
  24. package/lib/application-control/status.d.ts.map +1 -1
  25. package/lib/application-control/status.js +8 -6
  26. package/lib/application-control/status.js.map +1 -1
  27. package/lib/application-control/utils.d.ts +5 -0
  28. package/lib/application-control/utils.d.ts.map +1 -1
  29. package/lib/application-control/utils.js +47 -13
  30. package/lib/application-control/utils.js.map +1 -1
  31. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +42 -15
  32. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  33. package/lib/cloud-connection/device-agent-cloud-connection.js +357 -195
  34. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  35. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  36. package/lib/infrastructure/agent-config.js +7 -18
  37. package/lib/infrastructure/agent-config.js.map +1 -1
  38. package/lib/infrastructure/agent-config.test.js +47 -0
  39. package/lib/infrastructure/agent-config.test.js.map +1 -1
  40. package/lib/subcommands/app/app.js +1 -1
  41. package/lib/subcommands/app/app.js.map +1 -1
  42. package/lib/subcommands/login.d.ts.map +1 -1
  43. package/lib/subcommands/login.js +4 -3
  44. package/lib/subcommands/login.js.map +1 -1
  45. package/lib/util/copy-dir.d.ts.map +1 -1
  46. package/lib/util/copy-dir.js +3 -1
  47. package/lib/util/copy-dir.js.map +1 -1
  48. package/lib/util/run-in-dir.d.ts +2 -0
  49. package/lib/util/run-in-dir.d.ts.map +1 -0
  50. package/lib/util/run-in-dir.js +17 -0
  51. package/lib/util/run-in-dir.js.map +1 -0
  52. package/lib/util/sleep.d.ts +2 -0
  53. package/lib/util/sleep.d.ts.map +1 -0
  54. package/lib/util/sleep.js +9 -0
  55. package/lib/util/sleep.js.map +1 -0
  56. package/package.json +4 -3
  57. package/src/application-control/backup.ts +3 -0
  58. package/src/application-control/config.ts +61 -0
  59. package/src/application-control/environment-variables.ts +6 -12
  60. package/src/application-control/index.ts +5 -0
  61. package/src/application-control/install.ts +147 -68
  62. package/src/application-control/models.ts +136 -23
  63. package/src/application-control/status.ts +19 -9
  64. package/src/application-control/utils.ts +58 -13
  65. package/src/cloud-connection/device-agent-cloud-connection.ts +459 -216
  66. package/src/infrastructure/agent-config.test.ts +56 -0
  67. package/src/infrastructure/agent-config.ts +10 -19
  68. package/src/subcommands/app/app.ts +1 -1
  69. package/src/subcommands/login.ts +6 -4
  70. package/src/util/copy-dir.ts +3 -1
  71. package/src/util/run-in-dir.ts +15 -0
  72. package/src/util/sleep.ts +5 -0
  73. package/lib/util/run-cli-cmd.d.ts +0 -5
  74. package/lib/util/run-cli-cmd.d.ts.map +0 -1
  75. package/lib/util/run-cli-cmd.js +0 -24
  76. package/lib/util/run-cli-cmd.js.map +0 -1
  77. package/src/util/run-cli-cmd.ts +0 -18
@@ -95,7 +95,9 @@ describe('Test Agent Config', () => {
95
95
  const version = 'im-a-version';
96
96
 
97
97
  await configFile.setAppInstalling({ projectId, version });
98
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version);
98
99
  await configFile.setAppInstalled({ projectId, version });
100
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version);
99
101
  await configFile.setAppUninstalled({ projectId });
100
102
  const apps = await configFile.getApps();
101
103
  expect(apps).toEqual([]);
@@ -110,9 +112,13 @@ describe('Test Agent Config', () => {
110
112
  test('Set and get backup', async () => {
111
113
  const projectId = 'add-me';
112
114
  const version = 'im-a-version';
115
+ const version2 = 'newer-version';
113
116
 
117
+ // first installation, we use the version
114
118
  await configFile.setAppInstalling({ projectId, version });
119
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version);
115
120
  await configFile.setAppInstalled({ projectId, version });
121
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version);
116
122
  const backup1 = await configFile.getAppBackup({ projectId });
117
123
  expect(backup1).toBeNull();
118
124
  await configFile.setAppBackup({ projectId });
@@ -138,6 +144,56 @@ describe('Test Agent Config', () => {
138
144
  });
139
145
  const backup2 = await configFile.getAppBackup({ projectId });
140
146
  expect(backup2).toEqual({ version });
147
+
148
+ await configFile.setAppInstalling({ projectId, version: version2 });
149
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version);
150
+ await configFile.setAppInstalled({ projectId, version: version2 });
151
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version2);
152
+ const backup3 = await configFile.getAppBackup({ projectId });
153
+ expect(backup3).toEqual({ version });
154
+ });
155
+
156
+ test('Test app rollback', async () => {
157
+ const projectId = 'add-me';
158
+ const version1 = 'original-version';
159
+ const version2 = 'newer-version';
160
+ await configFile.setAppInstalling({ projectId, version: version1 });
161
+ await configFile.setAppInstalled({ projectId, version: version1 });
162
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version1);
163
+ expect(await configFile.getAppBackup({ projectId })).toBeNull();
164
+
165
+ // next installation - verify app is present and ready
166
+ expect(await configFile.isAppPresent({ projectId })).toBe(true);
167
+ expect(await configFile.isAppReady({ projectId })).toBe(true);
168
+
169
+ // test to see if app has backup
170
+ await configFile.setAppBackup({ projectId });
171
+ const expectedBackupVersion = (await configFile.getAppBackup({ projectId }))
172
+ ?.version;
173
+ expect(expectedBackupVersion).toEqual(version1);
174
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version1);
175
+
176
+ // simulate second version install
177
+ await configFile.setAppInstalling({ projectId, version: version2 });
178
+ const newExpectedBackupVersion = (await configFile.getAppBackup({ projectId }))
179
+ ?.version;
180
+ expect(newExpectedBackupVersion).toEqual(version1);
181
+ await configFile.setAppInstalled({ projectId, version: version2 });
182
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version2);
183
+
184
+ // simulate the rollback step: set the version that we will roll back to
185
+ await configFile.setAppInstalling({ projectId, version: version1 });
186
+
187
+ // test state during rollback
188
+ expect(await configFile.isAppReady({ projectId })).toEqual(false);
189
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version2);
190
+
191
+ // test final state of rolled-back app
192
+ await configFile.setAppInstalled({ projectId, version: version1 });
193
+ const finalBackupVersion = (await configFile.getAppBackup({ projectId }))?.version;
194
+ expect(finalBackupVersion).toEqual(version1);
195
+ expect(await configFile.isAppReady({ projectId })).toEqual(true);
196
+ expect(await configFile.getAppVersion({ projectId })).toEqual(version1);
141
197
  });
142
198
  });
143
199
  });
@@ -2,7 +2,6 @@ import { ConfigFileSchema } from '@alwaysai/config-nodejs';
2
2
  import { JSONSchemaType } from 'ajv';
3
3
  import { homedir } from 'os';
4
4
  import { join } from 'path';
5
- import { ALWAYSAI_DEVICE_AGENT_MODE } from '../environment';
6
5
 
7
6
  export interface AppBackupConfig {
8
7
  version: string;
@@ -134,17 +133,16 @@ export function AgentConfigFile(dir = ALWAYSAI_CONFIG_DIR) {
134
133
 
135
134
  async function setAppInstalling(props: { projectId: string; version: string }) {
136
135
  const { projectId, version } = props;
136
+
137
137
  const app = await getApp({ projectId });
138
138
  if (app) {
139
139
  await removeApp({ projectId });
140
140
  const config = configFile.read();
141
- config.applications.push({
142
- projectId,
143
- version,
144
- ready: false,
145
- });
141
+ // NOTE: do not update the version for an existing app until it is installed
142
+ config.applications.push({ ...app, ...{ ready: false } });
146
143
  configFile.write(config);
147
144
  } else {
145
+ // NOTE: for a brand-new app, we need to specify the version
148
146
  const config = configFile.read();
149
147
  config.applications.push({
150
148
  projectId,
@@ -161,21 +159,14 @@ export function AgentConfigFile(dir = ALWAYSAI_CONFIG_DIR) {
161
159
  if (app) {
162
160
  await removeApp({ projectId });
163
161
  const config = configFile.read();
164
- app.version = version;
165
- config.applications.push({
166
- projectId,
167
- version,
168
- ready: true,
169
- });
162
+ config.applications.push({ ...app, ...{ version, ready: true } });
170
163
  configFile.write(config);
171
164
  } else {
172
- const config = configFile.read();
173
- config.applications.push({
174
- projectId,
175
- version,
176
- ready: true,
177
- });
178
- configFile.write(config);
165
+ // NOTE: we should never be setting an app as installed
166
+ // if it doesn't exist (setAppInstalling was never called)
167
+ throw new Error(
168
+ `App ${projectId} was not previously configured and could not be set to installed!`,
169
+ );
179
170
  }
180
171
  }
181
172
 
@@ -91,7 +91,7 @@ export const installAppCliLeaf = CliLeaf({
91
91
  if (releaseHash === undefined) {
92
92
  throw new CliTerseError('This application has not been published yet');
93
93
  }
94
- await installApp({ projectId: project, releaseHash });
94
+ await installApp({ projectId: project, appReleaseHash: releaseHash });
95
95
  },
96
96
  });
97
97
 
@@ -1,6 +1,6 @@
1
- import { CliLeaf, CliStringInput, CliUsageError } from '@alwaysai/alwayscli';
1
+ import { CliLeaf, CliStringInput } from '@alwaysai/alwayscli';
2
+ import { alwaysaiUserLoginYesComponent } from 'alwaysai/lib/components/user';
2
3
  import { writeCertificateAndToken } from '../infrastructure/certificates-and-tokens';
3
- import { runCliCmd } from '../util/run-cli-cmd';
4
4
 
5
5
  export const loginCliLeaf = CliLeaf({
6
6
  name: 'login',
@@ -21,8 +21,10 @@ export const loginCliLeaf = CliLeaf({
21
21
  },
22
22
  async action(_, opts) {
23
23
  const { email, password, device } = opts;
24
- await runCliCmd({
25
- cmd: ['user', 'login', '--yes', '--email', email, '--password', password],
24
+
25
+ await alwaysaiUserLoginYesComponent({
26
+ alwaysaiUserEmail: email,
27
+ alwaysaiUserPassword: password,
26
28
  });
27
29
  if (device) {
28
30
  await writeCertificateAndToken({ deviceUuid: device });
@@ -6,5 +6,7 @@ export async function copyDir(props: { srcPath: string; destPath: string }) {
6
6
  const allFileNames = await src.readdir();
7
7
  const dest = JsSpawner({ path: destPath });
8
8
  await dest.mkdirp();
9
- await dest.untar(await src.tar(...allFileNames));
9
+ if (allFileNames.length) {
10
+ await dest.untar(await src.tar(...allFileNames));
11
+ }
10
12
  }
@@ -0,0 +1,15 @@
1
+ export async function runInDir<T extends any[], R extends any>(
2
+ func: (...args: T) => R,
3
+ args: T,
4
+ dir: string,
5
+ ) {
6
+ const origCwd = process.cwd();
7
+ let out: R;
8
+ try {
9
+ process.chdir(dir);
10
+ out = await func(...args);
11
+ } finally {
12
+ process.chdir(origCwd);
13
+ }
14
+ return out;
15
+ }
@@ -0,0 +1,5 @@
1
+ export default function sleep(ms: number) {
2
+ return new Promise((resolve) => {
3
+ setTimeout(resolve, ms);
4
+ });
5
+ }
@@ -1,5 +0,0 @@
1
- export declare function runCliCmd(props: {
2
- cmd: string[];
3
- cwd?: string;
4
- }): Promise<void>;
5
- //# sourceMappingURL=run-cli-cmd.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-cli-cmd.d.ts","sourceRoot":"","sources":["../../src/util/run-cli-cmd.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAerF"}
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runCliCmd = void 0;
4
- const alwaysai = require("alwaysai");
5
- async function runCliCmd(props) {
6
- const { cmd, cwd } = props;
7
- const origCwd = process.cwd();
8
- try {
9
- if (cwd) {
10
- process.chdir(cwd);
11
- }
12
- await alwaysai.aai(...cmd);
13
- }
14
- catch (err) {
15
- throw err;
16
- }
17
- finally {
18
- if (cwd) {
19
- process.chdir(origCwd);
20
- }
21
- }
22
- }
23
- exports.runCliCmd = runCliCmd;
24
- //# sourceMappingURL=run-cli-cmd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-cli-cmd.js","sourceRoot":"","sources":["../../src/util/run-cli-cmd.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AAE9B,KAAK,UAAU,SAAS,CAAC,KAAsC;IACpE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9B,IAAI;QACF,IAAI,GAAG,EAAE;YACP,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACpB;QACD,MAAM,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;KAC5B;IAAC,OAAO,GAAG,EAAE;QACZ,MAAM,GAAG,CAAC;KACX;YAAS;QACR,IAAI,GAAG,EAAE;YACP,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;SACxB;KACF;AACH,CAAC;AAfD,8BAeC"}
@@ -1,18 +0,0 @@
1
- import * as alwaysai from 'alwaysai';
2
-
3
- export async function runCliCmd(props: { cmd: string[]; cwd?: string }): Promise<void> {
4
- const { cmd, cwd } = props;
5
- const origCwd = process.cwd();
6
- try {
7
- if (cwd) {
8
- process.chdir(cwd);
9
- }
10
- await alwaysai.aai(...cmd);
11
- } catch (err) {
12
- throw err;
13
- } finally {
14
- if (cwd) {
15
- process.chdir(origCwd);
16
- }
17
- }
18
- }