askui 0.2.0 → 0.2.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 (61) hide show
  1. package/README.md +2 -2
  2. package/bin/askui-postinstall +35 -0
  3. package/dist/cjs/core/model/test-case-dto/index.js +1 -3
  4. package/dist/cjs/core/model/test-case-dto/test-step.d.ts +3 -7
  5. package/dist/cjs/core/model/test-case-dto/test-step.js +0 -12
  6. package/dist/cjs/core/ui-control-commands/control-command.d.ts +1 -0
  7. package/dist/cjs/core/ui-control-commands/control-command.js +5 -0
  8. package/dist/cjs/core/ui-control-commands/input-event.d.ts +1 -2
  9. package/dist/cjs/core/ui-control-commands/input-event.js +0 -1
  10. package/dist/cjs/execution/execution-runtime.d.ts +2 -0
  11. package/dist/cjs/execution/execution-runtime.js +27 -15
  12. package/dist/cjs/execution/inference-client.d.ts +1 -1
  13. package/dist/cjs/execution/inference-client.js +1 -1
  14. package/dist/cjs/execution/ui-control-client.d.ts +46 -1
  15. package/dist/cjs/execution/ui-control-client.js +55 -5
  16. package/dist/cjs/lib/copy-example-project.js +2 -1
  17. package/dist/cjs/lib/download-binaries.js +2 -1
  18. package/dist/cjs/lib/ui-controller-linux.js +2 -2
  19. package/dist/cjs/utils/analytics/analytics.js +7 -1
  20. package/dist/cjs/utils/analytics/installation-timestamp-create-error.d.ts +4 -0
  21. package/dist/cjs/utils/analytics/installation-timestamp-create-error.js +9 -0
  22. package/dist/cjs/utils/analytics/installation-timestamp-get-error.d.ts +4 -0
  23. package/dist/cjs/utils/analytics/installation-timestamp-get-error.js +9 -0
  24. package/dist/cjs/utils/analytics/installation-timestamp.d.ts +7 -0
  25. package/dist/cjs/utils/analytics/installation-timestamp.js +68 -0
  26. package/dist/cjs/utils/path.d.ts +1 -0
  27. package/dist/cjs/utils/path.js +11 -0
  28. package/dist/esm/core/model/test-case-dto/index.js +0 -1
  29. package/dist/esm/core/model/test-case-dto/test-step.d.ts +3 -7
  30. package/dist/esm/core/model/test-case-dto/test-step.js +1 -10
  31. package/dist/esm/core/ui-control-commands/control-command.d.ts +1 -0
  32. package/dist/esm/core/ui-control-commands/control-command.js +5 -0
  33. package/dist/esm/core/ui-control-commands/input-event.d.ts +1 -2
  34. package/dist/esm/core/ui-control-commands/input-event.js +0 -1
  35. package/dist/esm/execution/execution-runtime.d.ts +2 -0
  36. package/dist/esm/execution/execution-runtime.js +27 -15
  37. package/dist/esm/execution/inference-client.d.ts +1 -1
  38. package/dist/esm/execution/inference-client.js +1 -1
  39. package/dist/esm/execution/ui-control-client.d.ts +46 -1
  40. package/dist/esm/execution/ui-control-client.js +56 -6
  41. package/dist/esm/lib/copy-example-project.js +2 -1
  42. package/dist/esm/lib/download-binaries.js +2 -1
  43. package/dist/esm/lib/ui-controller-linux.js +2 -2
  44. package/dist/esm/utils/analytics/analytics.js +7 -1
  45. package/dist/esm/utils/analytics/installation-timestamp-create-error.d.ts +4 -0
  46. package/dist/esm/utils/analytics/installation-timestamp-create-error.js +5 -0
  47. package/dist/esm/utils/analytics/installation-timestamp-get-error.d.ts +4 -0
  48. package/dist/esm/utils/analytics/installation-timestamp-get-error.js +5 -0
  49. package/dist/esm/utils/analytics/installation-timestamp.d.ts +7 -0
  50. package/dist/esm/utils/analytics/installation-timestamp.js +61 -0
  51. package/dist/esm/utils/path.d.ts +1 -0
  52. package/dist/esm/utils/path.js +4 -0
  53. package/package.json +7 -3
  54. package/dist/cjs/utils/base_64_image/base-64-image-path-error.d.ts +0 -4
  55. package/dist/cjs/utils/base_64_image/base-64-image-path-error.js +0 -11
  56. package/dist/cjs/utils/image-resize-errors/invalid-base64-image-error.d.ts +0 -3
  57. package/dist/cjs/utils/image-resize-errors/invalid-base64-image-error.js +0 -7
  58. package/dist/esm/utils/base_64_image/base-64-image-path-error.d.ts +0 -4
  59. package/dist/esm/utils/base_64_image/base-64-image-path-error.js +0 -7
  60. package/dist/esm/utils/image-resize-errors/invalid-base64-image-error.d.ts +0 -3
  61. package/dist/esm/utils/image-resize-errors/invalid-base64-image-error.js +0 -3
package/README.md CHANGED
@@ -45,8 +45,8 @@ Visit our [documentation](https://docs.askui.com) for examples and a full list o
45
45
  ### Notes
46
46
 
47
47
  Important note for Linux users: Currently, Wayland is not supported.
48
- You can read more in our [troubleshooting chapter](https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#wayland).
49
- If you want to use the askui library libfuse2 is needed ([libfuse2 installation](https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#libfuse2)).
48
+ You can read more in our [troubleshooting chapter](https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller#wayland).
49
+ If you want to use the askui library libfuse2 is needed ([libfuse2 installation](https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller#libfuse2)).
50
50
 
51
51
  ## Example
52
52
 
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { access } = require('fs/promises');
4
+ const { join } = require('path');
5
+
6
+ async function shouldBeExecuted() {
7
+ try {
8
+ await access(join(__dirname, '../.no-askui-postinstall'));
9
+ } catch (err) {
10
+ if (err.code === 'ENOENT') {
11
+ return true;
12
+ }
13
+ // eslint-disable-next-line no-console
14
+ console.error(err);
15
+ }
16
+ return false;
17
+ }
18
+
19
+ async function createInstallationTimestamp() {
20
+ try {
21
+ const { InstallationTimestamp } = require('../dist/cjs/utils/analytics/installation-timestamp');
22
+ InstallationTimestamp.create();
23
+ } catch (err) {
24
+ // eslint-disable-next-line no-console
25
+ console.error(err);
26
+ }
27
+ }
28
+
29
+ async function main() {
30
+ if (await shouldBeExecuted()) {
31
+ await createInstallationTimestamp();
32
+ }
33
+ }
34
+
35
+ main();
@@ -1,7 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TestStep = exports.CustomElement = void 0;
3
+ exports.CustomElement = void 0;
4
4
  var custom_element_1 = require("./custom-element");
5
5
  Object.defineProperty(exports, "CustomElement", { enumerable: true, get: function () { return custom_element_1.CustomElement; } });
6
- var test_step_1 = require("./test-step");
7
- Object.defineProperty(exports, "TestStep", { enumerable: true, get: function () { return test_step_1.TestStep; } });
@@ -1,10 +1,6 @@
1
1
  import { CustomElement } from './custom-element';
2
- import { CustomElementJson } from './custom-element-json';
3
- export declare class TestStep {
2
+ export interface TestStep {
4
3
  instruction: string;
5
- customElements: CustomElement[];
6
- constructor(instruction: string, customElements?: CustomElement[]);
7
- static fromJson(step: TestStep & {
8
- customElements: CustomElementJson[];
9
- }): TestStep;
4
+ customElements?: CustomElement[];
5
+ secretText?: string | undefined;
10
6
  }
@@ -1,14 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TestStep = void 0;
4
- const custom_element_1 = require("./custom-element");
5
- class TestStep {
6
- constructor(instruction, customElements = []) {
7
- this.instruction = instruction;
8
- this.customElements = customElements;
9
- }
10
- static fromJson(step) {
11
- return new TestStep(step.instruction, (step.customElements || []).map((customELement) => custom_element_1.CustomElement.fromJson(customELement)));
12
- }
13
- }
14
- exports.TestStep = TestStep;
@@ -6,4 +6,5 @@ export declare class ControlCommand {
6
6
  tryToRepeat: boolean;
7
7
  constructor(code: ControlCommandCode, actions: Action[], tryToRepeat?: boolean);
8
8
  static fromJson(json: ControlCommand, resizeRatio?: number): ControlCommand;
9
+ setTextToBeTyped(text: string): void;
9
10
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ControlCommand = void 0;
4
4
  const action_1 = require("./action");
5
5
  const control_command_code_1 = require("./control-command-code");
6
+ const input_event_1 = require("./input-event");
6
7
  class ControlCommand {
7
8
  constructor(code, actions, tryToRepeat = false) {
8
9
  this.code = code;
@@ -12,5 +13,9 @@ class ControlCommand {
12
13
  static fromJson(json, resizeRatio = 1) {
13
14
  return new ControlCommand(control_command_code_1.ControlCommandCode[json.code], json.actions.map((action) => action_1.Action.fromJson(action, resizeRatio)), json.tryToRepeat);
14
15
  }
16
+ setTextToBeTyped(text) {
17
+ this.actions = this.actions.map((action) => ([input_event_1.InputEvent.TYPE, input_event_1.InputEvent.TYPE_TEXT].includes(action.inputEvent)
18
+ ? new action_1.Action(action.inputEvent, action.position, text) : action));
19
+ }
15
20
  }
16
21
  exports.ControlCommand = ControlCommand;
@@ -16,6 +16,5 @@ export declare enum InputEvent {
16
16
  MOUSE_MOVE = "MOUSE_MOVE",
17
17
  MOUSE_DOWN = "MOUSE_DOWN",
18
18
  MOUSE_UP = "MOUSE_UP",
19
- EXECUTE_COMMAND = "EXECUTE_COMMAND",
20
- WAIT = "WAIT"
19
+ EXECUTE_COMMAND = "EXECUTE_COMMAND"
21
20
  }
@@ -21,5 +21,4 @@ var InputEvent;
21
21
  InputEvent["MOUSE_DOWN"] = "MOUSE_DOWN";
22
22
  InputEvent["MOUSE_UP"] = "MOUSE_UP";
23
23
  InputEvent["EXECUTE_COMMAND"] = "EXECUTE_COMMAND";
24
- InputEvent["WAIT"] = "WAIT";
25
24
  })(InputEvent = exports.InputEvent || (exports.InputEvent = {}));
@@ -8,6 +8,7 @@ export declare class ExecutionRuntime {
8
8
  private inferenceClient;
9
9
  constructor(uiControllerClient: UiControllerClient, inferenceClient: InferenceClient);
10
10
  executeTestStep(step: TestStep): Promise<void>;
11
+ private requestControl;
11
12
  /**
12
13
  * @param {TestStep} step - Test step used for predicting command.
13
14
  */
@@ -20,6 +21,7 @@ export declare class ExecutionRuntime {
20
21
  * --> retry with linear back-off
21
22
  */
22
23
  private predictCommandWithRetry;
24
+ private getImageIfRequired;
23
25
  private predictCommand;
24
26
  annotateInteractively(): Promise<void>;
25
27
  takeScreenshotIfImageisNotProvided(imagePath?: string): Promise<string>;
@@ -30,6 +30,11 @@ class ExecutionRuntime {
30
30
  yield this.executeCommand(step);
31
31
  });
32
32
  }
33
+ requestControl(controlCommand) {
34
+ return __awaiter(this, void 0, void 0, function* () {
35
+ yield this.uiControllerClient.requestControl(controlCommand);
36
+ });
37
+ }
33
38
  /**
34
39
  * @param {TestStep} step - Test step used for predicting command.
35
40
  */
@@ -38,15 +43,13 @@ class ExecutionRuntime {
38
43
  return __awaiter(this, void 0, void 0, function* () {
39
44
  const controlCommand = yield this.predictCommandWithRetry(step);
40
45
  if (controlCommand.code === ui_control_commands_1.ControlCommandCode.OK) {
41
- yield this.uiControllerClient.requestControl(controlCommand);
46
+ return this.requestControl(controlCommand);
42
47
  }
43
- else if (controlCommand.tryToRepeat) {
44
- yield this.uiControllerClient.requestControl(controlCommand);
45
- this.executeCommandRepeatedly(step);
46
- }
47
- else {
48
- throw new control_command_error_1.ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
48
+ if (controlCommand.tryToRepeat) {
49
+ yield this.requestControl(controlCommand);
50
+ return this.executeCommandRepeatedly(step);
49
51
  }
52
+ throw new control_command_error_1.ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
50
53
  });
51
54
  }
52
55
  executeCommandRepeatedly(step) {
@@ -63,8 +66,8 @@ class ExecutionRuntime {
63
66
  if (controlCommand.code === ui_control_commands_1.ControlCommandCode.OK) {
64
67
  break;
65
68
  }
66
- else if (controlCommand.tryToRepeat) {
67
- yield this.uiControllerClient.requestControl(controlCommand);
69
+ if (controlCommand.tryToRepeat) {
70
+ yield this.requestControl(controlCommand);
68
71
  }
69
72
  else {
70
73
  throw new control_command_error_1.ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
@@ -94,15 +97,24 @@ class ExecutionRuntime {
94
97
  return command;
95
98
  });
96
99
  }
100
+ getImageIfRequired(instruction) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ const isImageRequired = yield this.inferenceClient.isImageRequired(instruction);
103
+ if (!isImageRequired) {
104
+ return undefined;
105
+ }
106
+ const screenshotResponse = yield this.uiControllerClient.requestScreenshot();
107
+ return screenshotResponse.data.image;
108
+ });
109
+ }
97
110
  predictCommand(step) {
98
111
  return __awaiter(this, void 0, void 0, function* () {
99
- const isImageRequired = yield this.inferenceClient.isImageRequired(step.instruction);
100
- let image;
101
- if (isImageRequired) {
102
- const screenshotResponse = yield this.uiControllerClient.requestScreenshot();
103
- image = screenshotResponse.data.image;
112
+ const image = yield this.getImageIfRequired(step.instruction);
113
+ const controlCommand = yield this.inferenceClient.predictControlCommand(step.instruction, step.customElements, image);
114
+ if (step.secretText !== undefined) {
115
+ controlCommand.setTextToBeTyped(step.secretText);
104
116
  }
105
- return this.inferenceClient.predictControlCommand(step.instruction, step.customElements, image);
117
+ return controlCommand;
106
118
  });
107
119
  }
108
120
  annotateInteractively() {
@@ -8,6 +8,6 @@ export declare class InferenceClient {
8
8
  constructor(url: string, httpClient: HttpClientGot);
9
9
  isImageRequired(instruction: string): Promise<boolean>;
10
10
  private resizeIfNeeded;
11
- predictControlCommand(instruction: string, customElements: CustomElement[], image?: string): Promise<ControlCommand>;
11
+ predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
12
12
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
13
13
  }
@@ -41,7 +41,7 @@ class InferenceClient {
41
41
  return (0, transformations_1.resizeBase64ImageWithSameRatio)(image);
42
42
  });
43
43
  }
44
- predictControlCommand(instruction, customElements, image) {
44
+ predictControlCommand(instruction, customElements = [], image) {
45
45
  return __awaiter(this, void 0, void 0, function* () {
46
46
  const resizedImage = yield this.resizeIfNeeded(customElements, image);
47
47
  const httpBody = {
@@ -1,5 +1,5 @@
1
1
  import { CustomElementJson } from '../core/model/test-case-dto';
2
- import { Executable, FluentCommand } from './dsl';
2
+ import { Exec, Executable, FluentCommand, FluentFilters } from './dsl';
3
3
  import { UiControllerClientConnectionState } from './ui-controller-client-connection-state';
4
4
  import { Annotation } from '../core/annotation/annotation';
5
5
  import { AnnotationRequest } from '../core/model/annotation-result/annotation-interface';
@@ -18,6 +18,51 @@ export declare class UiControlClient extends FluentCommand {
18
18
  annotate(annotationRequest?: AnnotationRequest): Promise<Annotation>;
19
19
  annotateInteractively(): Promise<void>;
20
20
  exec(instruction: string, customElementJson?: CustomElementJson[]): Promise<void>;
21
+ private secretText;
22
+ /**
23
+ * Types a text inside the filtered element.
24
+ *
25
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
26
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
27
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
28
+ * This should not change the quality of the prediction of the askui Inference server. In this
29
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
30
+ *
31
+ * @param {string} text - A text to type.
32
+ * @param {Object} [options]
33
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
34
+ * logs of askui nor sent over to askui Inference for prediction.
35
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
36
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
37
+ *
38
+ * @return {FluentFilters}
39
+ */
40
+ typeIn(text: string, { isSecret, secretMask }?: {
41
+ isSecret?: boolean | undefined;
42
+ secretMask?: string | undefined;
43
+ }): FluentFilters;
44
+ /**
45
+ * Types a text at the current position.
46
+ *
47
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
48
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
49
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
50
+ * This should not change the quality of the prediction of the askui Inference server. In this
51
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
52
+ *
53
+ * @param {string} text - A text to type.
54
+ * @param {Object} options
55
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
56
+ * logs of askui nor sent over to askui Inference for prediction.
57
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
58
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
59
+ *
60
+ * @return {Exec}
61
+ */
62
+ type(text: string, { isSecret, secretMask }?: {
63
+ isSecret?: boolean | undefined;
64
+ secretMask?: string | undefined;
65
+ }): Exec;
21
66
  /**
22
67
  * Waits for `<delayInMs>` ms, e.g., 1000 ms. The exact delay may be a little longer
23
68
  * than `<delayInMs>` but never shorter than that.
@@ -29,6 +29,7 @@ class UiControlClient extends dsl_1.FluentCommand {
29
29
  super();
30
30
  this.httpClient = httpClient;
31
31
  this.clientArgs = clientArgs;
32
+ this.secretText = undefined;
32
33
  }
33
34
  static build(clientArgs) {
34
35
  return __awaiter(this, void 0, void 0, function* () {
@@ -88,16 +89,15 @@ class UiControlClient extends dsl_1.FluentCommand {
88
89
  }
89
90
  });
90
91
  }
91
- exec(instruction, customElementJson) {
92
+ exec(instruction, customElementJson = []) {
92
93
  return __awaiter(this, void 0, void 0, function* () {
93
- let customElements = [];
94
- if (customElementJson !== undefined) {
95
- customElements = yield test_case_dto_1.CustomElement.fromJsonListWithImagePathOrImage(customElementJson);
96
- }
94
+ const customElements = yield test_case_dto_1.CustomElement.fromJsonListWithImagePathOrImage(customElementJson);
95
+ const { secretText } = this;
97
96
  try {
98
97
  yield this.executionRuntime.executeTestStep({
99
98
  instruction,
100
99
  customElements,
100
+ secretText,
101
101
  });
102
102
  yield this.annotateByDefault(test_case_result_dto_1.TestStepState.PASSED, customElements);
103
103
  return yield Promise.resolve();
@@ -108,6 +108,56 @@ class UiControlClient extends dsl_1.FluentCommand {
108
108
  }
109
109
  });
110
110
  }
111
+ /**
112
+ * Types a text inside the filtered element.
113
+ *
114
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
115
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
116
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
117
+ * This should not change the quality of the prediction of the askui Inference server. In this
118
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
119
+ *
120
+ * @param {string} text - A text to type.
121
+ * @param {Object} [options]
122
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
123
+ * logs of askui nor sent over to askui Inference for prediction.
124
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
125
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
126
+ *
127
+ * @return {FluentFilters}
128
+ */
129
+ typeIn(text, { isSecret = false, secretMask = '****' } = {}) {
130
+ if (isSecret) {
131
+ this.secretText = text;
132
+ return super.typeIn(secretMask);
133
+ }
134
+ return super.typeIn(text);
135
+ }
136
+ /**
137
+ * Types a text at the current position.
138
+ *
139
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
140
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
141
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
142
+ * This should not change the quality of the prediction of the askui Inference server. In this
143
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
144
+ *
145
+ * @param {string} text - A text to type.
146
+ * @param {Object} options
147
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
148
+ * logs of askui nor sent over to askui Inference for prediction.
149
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
150
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
151
+ *
152
+ * @return {Exec}
153
+ */
154
+ type(text, { isSecret = false, secretMask = '****' } = {}) {
155
+ if (isSecret) {
156
+ this.secretText = text;
157
+ return super.type(secretMask);
158
+ }
159
+ return super.type(text);
160
+ }
111
161
  /**
112
162
  * Waits for `<delayInMs>` ms, e.g., 1000 ms. The exact delay may be a little longer
113
163
  * than `<delayInMs>` but never shorter than that.
@@ -7,6 +7,7 @@ exports.init = void 0;
7
7
  const commander_1 = require("commander");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const path_2 = require("../utils/path");
10
11
  const createProgram = () => {
11
12
  const program = new commander_1.Command('askui');
12
13
  program.usage('<command> [options]');
@@ -14,7 +15,7 @@ const createProgram = () => {
14
15
  };
15
16
  function copyExampleProject() {
16
17
  const exampleProjectPath = path_1.default.join('example_projects_templates', 'typescript_jest');
17
- fs_extra_1.default.copySync(path_1.default.join(__dirname, '..', '..', exampleProjectPath), '.');
18
+ fs_extra_1.default.copySync(path_1.default.join((0, path_2.getPathToNodeModulesRoot)(), exampleProjectPath), '.');
18
19
  }
19
20
  function init(argv) {
20
21
  const args = argv || process.argv;
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const got_1 = __importDefault(require("got"));
9
9
  const os_1 = __importDefault(require("os"));
10
10
  const path_1 = __importDefault(require("path"));
11
+ const path_2 = require("../utils/path");
11
12
  const logger_1 = require("./logger");
12
13
  var SupportedPlatform;
13
14
  (function (SupportedPlatform) {
@@ -35,7 +36,7 @@ function buildBinaryNotAvailbleError(binaryVersion) {
35
36
  return new Error(`It seems that the UI Controller version "${binaryVersion}" for your system "${platform()} ${os_1.default.arch}" is not availble, Please contact as at info@askui.com for more information`);
36
37
  }
37
38
  function getBinaryPath(version) {
38
- return path_1.default.join(__dirname, '..', '..', 'release', version, ...binarySubPathsByPlatform[platform()]);
39
+ return path_1.default.join((0, path_2.getPathToNodeModulesRoot)(), 'release', version, ...binarySubPathsByPlatform[platform()]);
39
40
  }
40
41
  exports.getBinaryPath = getBinaryPath;
41
42
  function getBinaryDownloadUrl(binaryVersion) {
@@ -27,7 +27,7 @@ class UiControllerLinux extends ui_controller_facade_1.UiControllerFacade {
27
27
  const runCommand = (0, util_1.promisify)(child_process_1.exec);
28
28
  const waylandStatus = yield runCommand('echo $WAYLAND_DISPLAY');
29
29
  if (waylandStatus.stdout.trim().includes('wayland')) {
30
- throw new wayland_error_1.WaylandError('Wayland is not supported: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#wayland');
30
+ throw new wayland_error_1.WaylandError('Wayland is not supported: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller#wayland');
31
31
  }
32
32
  /* First we want to check if the user is using a debian distribution.
33
33
  * and in the following if libfuse2 is installed.
@@ -44,7 +44,7 @@ class UiControllerLinux extends ui_controller_facade_1.UiControllerFacade {
44
44
  yield runCommand('dpkg -s libfuse2 | grep Status');
45
45
  }
46
46
  catch (_a) {
47
- throw new libfuse_error_1.LibfuseError('Libfuse2 package is missing: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#libfuse2');
47
+ throw new libfuse_error_1.LibfuseError('Libfuse2 package is missing: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller#libfuse2');
48
48
  }
49
49
  });
50
50
  }
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Analytics = void 0;
16
16
  const os_1 = __importDefault(require("os"));
17
17
  const user_identifier_1 = require("./user-identifier");
18
+ const installation_timestamp_1 = require("./installation-timestamp");
18
19
  class Analytics {
19
20
  constructor() {
20
21
  this.userIdentifier = new user_identifier_1.UserIdentifier();
@@ -22,10 +23,15 @@ class Analytics {
22
23
  getAnalyticsHeaders() {
23
24
  return __awaiter(this, void 0, void 0, function* () {
24
25
  const userID = yield this.userIdentifier.userId();
25
- return {
26
+ const headers = {
26
27
  'askui-user-id': userID,
27
28
  'askui-user-agent': `os:${os_1.default.platform()};arch:${os_1.default.arch()}`,
28
29
  };
30
+ const askuiInstalledAt = yield installation_timestamp_1.InstallationTimestamp.get();
31
+ if (askuiInstalledAt) {
32
+ headers['askui-installed-at'] = askuiInstalledAt.toISOString();
33
+ }
34
+ return headers;
29
35
  });
30
36
  }
31
37
  }
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ export declare class InstallationTimestampCreateError extends Error {
3
+ constructor(err: NodeJS.ErrnoException);
4
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InstallationTimestampCreateError = void 0;
4
+ class InstallationTimestampCreateError extends Error {
5
+ constructor(err) {
6
+ super(`Installation timestamp could not be created. \n${err.message}`);
7
+ }
8
+ }
9
+ exports.InstallationTimestampCreateError = InstallationTimestampCreateError;
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ export declare class InstallationTimestampGetError extends Error {
3
+ constructor(err: NodeJS.ErrnoException);
4
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InstallationTimestampGetError = void 0;
4
+ class InstallationTimestampGetError extends Error {
5
+ constructor(err) {
6
+ super(`Installation timestamp does not exist. Try reinstalling the lib to create it. \n${err.message}`);
7
+ }
8
+ }
9
+ exports.InstallationTimestampGetError = InstallationTimestampGetError;
@@ -0,0 +1,7 @@
1
+ export declare abstract class InstallationTimestamp {
2
+ private static fileName;
3
+ private static value?;
4
+ static create(): Promise<void>;
5
+ static get(): Promise<Date | null>;
6
+ private static getFromFile;
7
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.InstallationTimestamp = void 0;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const lib_1 = require("../../lib");
19
+ const installation_timestamp_create_error_1 = require("./installation-timestamp-create-error");
20
+ const installation_timestamp_get_error_1 = require("./installation-timestamp-get-error");
21
+ const path_2 = require("../path");
22
+ class InstallationTimestamp {
23
+ static create() {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const timestamp = new Date().toISOString();
26
+ return new Promise((resolve, reject) => {
27
+ fs_1.default.writeFile(InstallationTimestamp.fileName, timestamp, { encoding: 'utf-8' }, (err) => {
28
+ if (err) {
29
+ reject(new installation_timestamp_create_error_1.InstallationTimestampCreateError(err));
30
+ }
31
+ else {
32
+ resolve();
33
+ }
34
+ });
35
+ });
36
+ });
37
+ }
38
+ static get() {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ if (InstallationTimestamp.value === undefined) {
41
+ try {
42
+ InstallationTimestamp.value = yield this.getFromFile();
43
+ }
44
+ catch (err) {
45
+ InstallationTimestamp.value = null;
46
+ lib_1.logger.warn(err.message);
47
+ }
48
+ }
49
+ return InstallationTimestamp.value;
50
+ });
51
+ }
52
+ static getFromFile() {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ return new Promise((resolve, reject) => {
55
+ fs_1.default.readFile(InstallationTimestamp.fileName, 'utf-8', (err, isoDateStr) => {
56
+ if (err) {
57
+ reject(new installation_timestamp_get_error_1.InstallationTimestampGetError(err));
58
+ }
59
+ else {
60
+ resolve(new Date(isoDateStr));
61
+ }
62
+ });
63
+ });
64
+ });
65
+ }
66
+ }
67
+ exports.InstallationTimestamp = InstallationTimestamp;
68
+ InstallationTimestamp.fileName = path_1.default.join((0, path_2.getPathToNodeModulesRoot)(), 'install-timestamp');
@@ -0,0 +1 @@
1
+ export declare function getPathToNodeModulesRoot(): string;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getPathToNodeModulesRoot = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ function getPathToNodeModulesRoot() {
9
+ return path_1.default.join(__dirname, '..', '..');
10
+ }
11
+ exports.getPathToNodeModulesRoot = getPathToNodeModulesRoot;
@@ -1,2 +1 @@
1
1
  export { CustomElement } from './custom-element';
2
- export { TestStep } from './test-step';
@@ -1,10 +1,6 @@
1
1
  import { CustomElement } from './custom-element';
2
- import { CustomElementJson } from './custom-element-json';
3
- export declare class TestStep {
2
+ export interface TestStep {
4
3
  instruction: string;
5
- customElements: CustomElement[];
6
- constructor(instruction: string, customElements?: CustomElement[]);
7
- static fromJson(step: TestStep & {
8
- customElements: CustomElementJson[];
9
- }): TestStep;
4
+ customElements?: CustomElement[];
5
+ secretText?: string | undefined;
10
6
  }
@@ -1,10 +1 @@
1
- import { CustomElement } from './custom-element';
2
- export class TestStep {
3
- constructor(instruction, customElements = []) {
4
- this.instruction = instruction;
5
- this.customElements = customElements;
6
- }
7
- static fromJson(step) {
8
- return new TestStep(step.instruction, (step.customElements || []).map((customELement) => CustomElement.fromJson(customELement)));
9
- }
10
- }
1
+ export {};
@@ -6,4 +6,5 @@ export declare class ControlCommand {
6
6
  tryToRepeat: boolean;
7
7
  constructor(code: ControlCommandCode, actions: Action[], tryToRepeat?: boolean);
8
8
  static fromJson(json: ControlCommand, resizeRatio?: number): ControlCommand;
9
+ setTextToBeTyped(text: string): void;
9
10
  }