@elastic/synthetics 1.0.0-beta.34 → 1.0.0-beta.36

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 (49) hide show
  1. package/dist/cli.js +5 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/common_types.d.ts +2 -1
  4. package/dist/common_types.d.ts.map +1 -1
  5. package/dist/core/browser-service.d.ts +1 -1
  6. package/dist/core/browser-service.d.ts.map +1 -1
  7. package/dist/dsl/journey.d.ts.map +1 -1
  8. package/dist/dsl/journey.js +1 -0
  9. package/dist/dsl/journey.js.map +1 -1
  10. package/dist/dsl/monitor.d.ts +2 -0
  11. package/dist/dsl/monitor.d.ts.map +1 -1
  12. package/dist/dsl/monitor.js +3 -0
  13. package/dist/dsl/monitor.js.map +1 -1
  14. package/dist/formatter/javascript.d.ts +1 -1
  15. package/dist/formatter/javascript.d.ts.map +1 -1
  16. package/dist/formatter/javascript.js +1 -1
  17. package/dist/formatter/javascript.js.map +1 -1
  18. package/dist/helpers.d.ts +1 -1
  19. package/dist/helpers.d.ts.map +1 -1
  20. package/dist/helpers.js +3 -3
  21. package/dist/helpers.js.map +1 -1
  22. package/dist/plugins/network.js +3 -3
  23. package/dist/plugins/network.js.map +1 -1
  24. package/dist/push/index.d.ts.map +1 -1
  25. package/dist/push/index.js +75 -59
  26. package/dist/push/index.js.map +1 -1
  27. package/dist/push/monitor.d.ts +5 -2
  28. package/dist/push/monitor.d.ts.map +1 -1
  29. package/dist/push/monitor.js +108 -8
  30. package/dist/push/monitor.js.map +1 -1
  31. package/dist/push/plugin.d.ts.map +1 -1
  32. package/dist/push/plugin.js +6 -2
  33. package/dist/push/plugin.js.map +1 -1
  34. package/dist/push/request.d.ts.map +1 -1
  35. package/dist/push/request.js +5 -5
  36. package/dist/push/request.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +23 -22
  39. package/src/cli.ts +5 -1
  40. package/src/common_types.ts +2 -1
  41. package/src/dsl/journey.ts +1 -0
  42. package/src/dsl/monitor.ts +5 -0
  43. package/src/formatter/javascript.ts +1 -1
  44. package/src/helpers.ts +1 -1
  45. package/src/plugins/network.ts +3 -3
  46. package/src/push/index.ts +82 -65
  47. package/src/push/monitor.ts +132 -11
  48. package/src/push/plugin.ts +6 -2
  49. package/src/push/request.ts +9 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elastic/synthetics",
3
- "version": "1.0.0-beta.34",
3
+ "version": "1.0.0-beta.36",
4
4
  "description": "Elastic synthetic monitoring agent",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -42,39 +42,40 @@
42
42
  "dependencies": {
43
43
  "@cspotcode/source-map-support": "^0.8.1",
44
44
  "@esbuild-plugins/node-resolve": "^0.1.4",
45
- "archiver": "^5.3.0",
46
- "commander": "^9.0.0",
45
+ "archiver": "^5.3.1",
46
+ "commander": "^9.4.0",
47
47
  "deepmerge": "^4.2.2",
48
48
  "enquirer": "^2.3.6",
49
- "esbuild": "^0.14.27",
49
+ "esbuild": "^0.14.54",
50
50
  "expect": "^28.1.3",
51
51
  "http-proxy": "^1.18.1",
52
- "kleur": "^4.1.4",
53
- "micromatch": "^4.0.4",
54
- "playwright-chromium": "=1.20.1",
55
- "playwright-core": "=1.20.1",
52
+ "kleur": "^4.1.5",
53
+ "micromatch": "^4.0.5",
54
+ "playwright-chromium": "=1.26.0",
55
+ "playwright-core": "=1.26.0",
56
56
  "sharp": "^0.31.0",
57
- "snakecase-keys": "^3.2.1",
58
- "sonic-boom": "^2.6.0",
59
- "ts-node": "^10.9.0",
60
- "typescript": "^4.7.4",
61
- "undici": "^5.10.0"
57
+ "snakecase-keys": "^4.0.0",
58
+ "sonic-boom": "^3.2.0",
59
+ "ts-node": "^10.9.1",
60
+ "typescript": "^4.8.3",
61
+ "undici": "^5.10.0",
62
+ "yaml": "^2.1.1"
62
63
  },
63
64
  "devDependencies": {
64
- "@types/jest": "^28.1.3",
65
- "@types/micromatch": "^4.0.1",
66
- "@types/node": "^16.11.44",
67
- "@types/sharp": "^0.28.2",
68
- "@typescript-eslint/eslint-plugin": "^5.0.0",
69
- "@typescript-eslint/parser": "^5.0.0",
70
- "eslint": "^8.0.1",
65
+ "@types/jest": "^28.1.8",
66
+ "@types/micromatch": "^4.0.2",
67
+ "@types/node": "^16.11.59",
68
+ "@types/sharp": "^0.28.6",
69
+ "@typescript-eslint/eslint-plugin": "^5.38.0",
70
+ "@typescript-eslint/parser": "^5.38.0",
71
+ "eslint": "^8.23.1",
71
72
  "husky": "^4.3.6",
72
73
  "is-positive": "3.1.0",
73
74
  "jest": "^28.1.3",
74
75
  "lint-staged": "^10.5.3",
75
- "prettier": "^2.4.1",
76
+ "prettier": "^2.7.1",
76
77
  "rimraf": "^3.0.2",
77
- "ts-jest": "^28.0.5",
78
+ "ts-jest": "^28.0.8",
78
79
  "unzipper": "^0.10.11"
79
80
  },
80
81
  "engines": {
package/src/cli.ts CHANGED
@@ -54,6 +54,7 @@ import { resolve } from 'path';
54
54
  import { Generator } from './generator';
55
55
  import { error } from './helpers';
56
56
  import { LocationsMap } from './locations/public-locations';
57
+ import { createLightweightMonitors } from './push/monitor';
57
58
 
58
59
  /* eslint-disable-next-line @typescript-eslint/no-var-requires */
59
60
  const { name, version } = require('../package.json');
@@ -184,6 +185,7 @@ program
184
185
  '--space <space>',
185
186
  'the target Kibana spaces for the pushed monitors — spaces help you organise pushed monitors.'
186
187
  )
188
+ .option('-y, --yes', 'skip all questions and run non-interactively')
187
189
  .addOption(pattern)
188
190
  .addOption(tags)
189
191
  .addOption(match)
@@ -191,7 +193,8 @@ program
191
193
  .addOption(playwrightOpts)
192
194
  .action(async (cmdOpts: PushOptions) => {
193
195
  try {
194
- await loadTestFiles({ inline: false }, [cwd()]);
196
+ const workDir = cwd();
197
+ await loadTestFiles({ inline: false, ...program.opts() }, [workDir]);
195
198
  const settings = await loadSettings();
196
199
  const options = normalizeOptions({
197
200
  ...program.opts(),
@@ -201,6 +204,7 @@ program
201
204
  validateSettings(options);
202
205
  await catchIncorrectSettings(settings, options);
203
206
  const monitors = runner.buildMonitors(options);
207
+ monitors.push(...(await createLightweightMonitors(workDir, options)));
204
208
  await push(monitors, options);
205
209
  } catch (e) {
206
210
  e && console.error(e);
@@ -241,11 +241,12 @@ export type RunOptions = BaseArgs & {
241
241
  reporter?: BuiltInReporterName | ReporterInstance;
242
242
  };
243
243
 
244
- export type PushOptions = ProjectSettings & {
244
+ export type PushOptions = Partial<ProjectSettings> & {
245
245
  auth: string;
246
246
  schedule?: MonitorConfig['schedule'];
247
247
  locations?: MonitorConfig['locations'];
248
248
  privateLocations?: MonitorConfig['privateLocations'];
249
+ yes?: boolean;
249
250
  };
250
251
 
251
252
  export type ProjectSettings = {
@@ -92,6 +92,7 @@ export class Journey {
92
92
  this.monitor = new Monitor({
93
93
  name: this.name,
94
94
  id: this.id,
95
+ type: 'browser',
95
96
  tags: this.tags ?? [],
96
97
  ...config,
97
98
  });
@@ -41,6 +41,7 @@ export const SyntheticsLocations = Object.keys(
41
41
  export type MonitorConfig = {
42
42
  id?: string;
43
43
  name?: string;
44
+ type?: string;
44
45
  tags?: string[];
45
46
  schedule?: number;
46
47
  enabled?: boolean;
@@ -73,6 +74,10 @@ export class Monitor {
73
74
  });
74
75
  }
75
76
 
77
+ get type() {
78
+ return this.config.type;
79
+ }
80
+
76
81
  setSource(source: Location) {
77
82
  this.source = source;
78
83
  }
@@ -26,7 +26,7 @@
26
26
  import {
27
27
  JavaScriptLanguageGenerator,
28
28
  JavaScriptFormatter,
29
- } from 'playwright-core/lib/server/supplements/recorder/javascript';
29
+ } from 'playwright-core/lib/server/recorder/javascript';
30
30
 
31
31
  export type Step = {
32
32
  actions: ActionInContext[];
package/src/helpers.ts CHANGED
@@ -359,7 +359,7 @@ export function done(message: string) {
359
359
  write(bold(green(`${symbols['succeeded']} ${message}`)));
360
360
  }
361
361
 
362
- export function aborted(message: string) {
362
+ export function warn(message: string) {
363
363
  write(bold(yellow(`${symbols['warning']} ${message}`)));
364
364
  }
365
365
 
@@ -283,12 +283,12 @@ export class NetworkManager {
283
283
  networkEntry.request.body = {
284
284
  bytes: sizes.requestBodySize,
285
285
  };
286
- networkEntry.response.bytes =
287
- sizes.responseHeadersSize + sizes.responseBodySize;
286
+ const transferSize = sizes.responseHeadersSize + sizes.responseBodySize;
287
+ networkEntry.transferSize = transferSize;
288
+ networkEntry.response.bytes = transferSize;
288
289
  networkEntry.response.body = {
289
290
  bytes: sizes.responseBodySize,
290
291
  };
291
- networkEntry.transferSize = sizes.responseBodySize;
292
292
  })
293
293
  );
294
294
  }
package/src/push/index.ts CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  import { readFile, writeFile } from 'fs/promises';
27
27
  import { prompt } from 'enquirer';
28
- import { bold, yellow } from 'kleur/colors';
28
+ import { bold } from 'kleur/colors';
29
29
  import {
30
30
  ok,
31
31
  formatAPIError,
@@ -40,7 +40,7 @@ import {
40
40
  apiProgress,
41
41
  write,
42
42
  error,
43
- aborted,
43
+ warn,
44
44
  indent,
45
45
  safeNDJSONParse,
46
46
  done,
@@ -49,24 +49,42 @@ import type { PushOptions, ProjectSettings } from '../common_types';
49
49
  import { findSyntheticsConfig, readConfig } from '../config';
50
50
 
51
51
  export async function push(monitors: Monitor[], options: PushOptions) {
52
- if (monitors.length === 0) {
53
- throw 'No Monitors found';
54
- }
55
- const duplicates = trackDuplicates(monitors);
56
- if (duplicates.size > 0) {
57
- throw error(formatDuplicateError(duplicates));
58
- }
52
+ let schemas: MonitorSchema[] = [];
53
+ if (monitors.length > 0) {
54
+ const duplicates = trackDuplicates(monitors);
55
+ if (duplicates.size > 0) {
56
+ throw error(formatDuplicateError(duplicates));
57
+ }
59
58
 
60
- progress(`preparing all monitors`);
61
- const schemas = await buildMonitorSchema(monitors);
59
+ progress(`preparing all monitors`);
60
+ schemas = await buildMonitorSchema(monitors);
62
61
 
63
- progress(`creating all monitors`);
64
- for (const schema of schemas) {
65
- await pushMonitors({ schemas: [schema], keepStale: true, options });
62
+ progress(`creating all monitors`);
63
+ for (const schema of schemas) {
64
+ await pushMonitors({ schemas: [schema], keepStale: true, options });
65
+ }
66
+ } else {
67
+ write('');
68
+ const { deleteAll } = await prompt<{ deleteAll: boolean }>({
69
+ type: 'confirm',
70
+ skip() {
71
+ if (options.yes) {
72
+ this.initial = process.env.TEST_OVERRIDE ?? true;
73
+ return true;
74
+ }
75
+ return false;
76
+ },
77
+ name: 'deleteAll',
78
+ message: `Pushing without any monitors will delete all monitors associated with the project.\n Do you want to continue?`,
79
+ initial: false,
80
+ });
81
+ if (!deleteAll) {
82
+ throw warn('Push command Aborted');
83
+ }
66
84
  }
67
-
68
85
  progress(`deleting all stale monitors`);
69
86
  await pushMonitors({ schemas, keepStale: false, options });
87
+
70
88
  done('Pushed');
71
89
  }
72
90
 
@@ -79,43 +97,39 @@ export async function pushMonitors({
79
97
  keepStale: boolean;
80
98
  options: PushOptions;
81
99
  }) {
82
- try {
83
- const { body, statusCode } = await createMonitors(
84
- schemas,
85
- options,
86
- keepStale
87
- );
88
- if (statusCode === 404) {
89
- throw formatNotFoundError(await body.text());
90
- }
91
- if (!ok(statusCode)) {
92
- const { error, message } = await body.json();
93
- throw formatAPIError(statusCode, error, message);
94
- }
95
- body.setEncoding('utf-8');
96
- for await (const data of body) {
97
- // Its kind of hacky for now where Kibana streams the response by
98
- // writing the data as NDJSON events (data can be interleaved), we
99
- // distinguish the final data by checking if the event was a progress vs complete event
100
- const chunks = safeNDJSONParse(data);
101
- for (const chunk of chunks) {
102
- if (typeof chunk === 'string') {
103
- // TODO: add progress back for all states once we get the fix
104
- // on kibana side
105
- keepStale && apiProgress(chunk);
106
- continue;
107
- }
108
- const { failedMonitors, failedStaleMonitors } = chunk;
109
- if (failedMonitors && failedMonitors.length > 0) {
110
- throw formatFailedMonitors(failedMonitors);
111
- }
112
- if (failedStaleMonitors.length > 0) {
113
- write(yellow(formatStaleMonitors(failedStaleMonitors)));
114
- }
100
+ const { body, statusCode } = await createMonitors(
101
+ schemas,
102
+ options,
103
+ keepStale
104
+ );
105
+ if (statusCode === 404) {
106
+ throw formatNotFoundError(await body.text());
107
+ }
108
+ if (!ok(statusCode)) {
109
+ const { error, message } = await body.json();
110
+ throw formatAPIError(statusCode, error, message);
111
+ }
112
+ body.setEncoding('utf-8');
113
+ for await (const data of body) {
114
+ // Its kind of hacky for now where Kibana streams the response by
115
+ // writing the data as NDJSON events (data can be interleaved), we
116
+ // distinguish the final data by checking if the event was a progress vs complete event
117
+ const chunks = safeNDJSONParse(data);
118
+ for (const chunk of chunks) {
119
+ if (typeof chunk === 'string') {
120
+ // TODO: add progress back for all states once we get the fix
121
+ // on kibana side
122
+ keepStale && apiProgress(chunk);
123
+ continue;
124
+ }
125
+ const { failedMonitors, failedStaleMonitors } = chunk;
126
+ if (failedMonitors && failedMonitors.length > 0) {
127
+ throw formatFailedMonitors(failedMonitors);
128
+ }
129
+ if (failedStaleMonitors.length > 0) {
130
+ throw formatStaleMonitors(failedStaleMonitors);
115
131
  }
116
132
  }
117
- } catch (e) {
118
- error(e);
119
133
  }
120
134
  }
121
135
 
@@ -149,7 +163,7 @@ const INSTALLATION_HELP = `Run 'npx @elastic/synthetics init' to create project
149
163
 
150
164
  export async function loadSettings() {
151
165
  try {
152
- const config = await readConfig('asd');
166
+ const config = await readConfig(process.env['NODE_ENV'] || 'development');
153
167
  // Missing config file, fake throw to capture as missing file
154
168
  if (Object.keys(config).length === 0) {
155
169
  throw '';
@@ -193,7 +207,7 @@ async function overrideSettings(oldValue: string, newValue: string) {
193
207
  const cwd = process.cwd();
194
208
  const configPath = await findSyntheticsConfig(cwd, cwd);
195
209
  if (!configPath) {
196
- throw aborted(`Unable to find synthetics config file: ${configPath}`);
210
+ throw warn(`Unable to find synthetics config file: ${configPath}`);
197
211
  }
198
212
  const config = await readFile(configPath, 'utf-8');
199
213
  const updatedConfig = config.replace(
@@ -209,20 +223,23 @@ export async function catchIncorrectSettings(
209
223
  ) {
210
224
  let override = !settings.id;
211
225
  if (settings.id && settings.id !== options.id) {
212
- if (process.env.TEST_OVERRIDE != null) {
213
- override = Boolean(process.env.TEST_OVERRIDE);
214
- } else {
215
- // Add an extra line to make it easier to read the prompt
216
- write('');
217
- ({ override } = await prompt<{ override: boolean }>({
218
- type: 'confirm',
219
- name: 'override',
220
- message: `Monitors were pushed under the '${settings.id}' project. Are you sure you want to push them under the new '${options.id}' (note that this will duplicate the monitors, the old ones being orphaned)`,
221
- initial: false,
222
- }));
223
- }
226
+ // Add an extra line to make it easier to read the prompt
227
+ write('');
228
+ ({ override } = await prompt<{ override: boolean }>({
229
+ type: 'confirm',
230
+ name: 'override',
231
+ skip() {
232
+ if (options.yes) {
233
+ this.initial = process.env.TEST_OVERRIDE ?? true;
234
+ return true;
235
+ }
236
+ return false;
237
+ },
238
+ message: `Monitors were pushed under the '${settings.id}' project. Are you sure you want to push them under the new '${options.id}' (note that this will duplicate the monitors, the old ones being orphaned)`,
239
+ initial: false,
240
+ }));
224
241
  if (!override) {
225
- throw aborted('Push command Aborted');
242
+ throw warn('Push command Aborted');
226
243
  }
227
244
  }
228
245
  if (override) {
@@ -23,19 +23,27 @@
23
23
  *
24
24
  */
25
25
 
26
- import { mkdir, rm } from 'fs/promises';
26
+ import { mkdir, rm, readFile } from 'fs/promises';
27
27
  import { join } from 'path';
28
+ import { LineCounter, parseDocument, YAMLSeq, YAMLMap } from 'yaml';
29
+ import { bold, red } from 'kleur/colors';
28
30
  import { Bundler } from './bundler';
29
31
  import { sendRequest } from './request';
30
- import { removeTrailingSlash, SYNTHETICS_PATH } from '../helpers';
32
+ import {
33
+ removeTrailingSlash,
34
+ SYNTHETICS_PATH,
35
+ totalist,
36
+ indent,
37
+ warn,
38
+ } from '../helpers';
31
39
  import { LocationsMap } from '../locations/public-locations';
32
40
  import { Monitor, MonitorConfig } from '../dsl/monitor';
33
41
  import { PushOptions } from '../common_types';
34
42
 
35
43
  export type MonitorSchema = Omit<MonitorConfig, 'locations'> & {
36
- content: string;
37
44
  locations: string[];
38
- filter: Monitor['filter'];
45
+ content?: string;
46
+ filter?: Monitor['filter'];
39
47
  };
40
48
 
41
49
  export type APISchema = {
@@ -60,21 +68,134 @@ export async function buildMonitorSchema(monitors: Monitor[]) {
60
68
  const schemas: MonitorSchema[] = [];
61
69
 
62
70
  for (const monitor of monitors) {
63
- const { source, config, filter } = monitor;
64
- const outPath = join(bundlePath, config.name + '.zip');
65
- const content = await bundler.build(source.file, outPath);
66
- schemas.push({
71
+ const { source, config, filter, type } = monitor;
72
+ const schema = {
67
73
  ...config,
68
- content,
69
74
  locations: translateLocation(config.locations),
70
- filter: filter,
71
- });
75
+ };
76
+ if (type === 'browser') {
77
+ const outPath = join(bundlePath, config.name + '.zip');
78
+ const content = await bundler.build(source.file, outPath);
79
+ Object.assign(schema, { content, filter });
80
+ }
81
+ schemas.push(schema);
72
82
  }
73
83
 
74
84
  await rm(bundlePath, { recursive: true });
75
85
  return schemas;
76
86
  }
77
87
 
88
+ export async function createLightweightMonitors(
89
+ workDir: string,
90
+ options: PushOptions
91
+ ) {
92
+ const lwFiles = new Set<string>();
93
+ await totalist(workDir, (rel, abs) => {
94
+ if (/.(yml|yaml)$/.test(rel)) {
95
+ lwFiles.add(abs);
96
+ }
97
+ });
98
+ // Warn users about schedule that are less than 60 seconds
99
+ if (lwFiles.size > 0) {
100
+ warn(
101
+ 'lightweight monitors schedule < 1 minute resolution are not supported, will get reset to their nearest minute interval.'
102
+ );
103
+ }
104
+
105
+ const monitors: Monitor[] = [];
106
+ for (const file of lwFiles.values()) {
107
+ const content = await readFile(file, 'utf-8');
108
+ const lineCounter = new LineCounter();
109
+ const parsedDoc = parseDocument(content, {
110
+ lineCounter,
111
+ keepSourceTokens: true,
112
+ });
113
+ // Skip other yml files that are not relevant
114
+ const monitorSeq = parsedDoc.get('heartbeat.monitors') as YAMLSeq<YAMLMap>;
115
+ if (!monitorSeq) {
116
+ continue;
117
+ }
118
+
119
+ for (const monNode of monitorSeq.items) {
120
+ // Skip browser monitors and disabled monitors from pushing
121
+ if (
122
+ monNode.get('type') === 'browser' ||
123
+ monNode.get('enabled') === false
124
+ ) {
125
+ continue;
126
+ }
127
+ const config = monNode.toJSON();
128
+ const { line, col } = lineCounter.linePos(monNode.srcToken.offset);
129
+ try {
130
+ const mon = buildMonitorFromYaml(config, options);
131
+ mon.setSource({ file, line, column: col });
132
+ monitors.push(mon);
133
+ } catch (e) {
134
+ let outer = bold(`Aborted: ${e}\n`);
135
+ outer += indent(
136
+ `* ${config.id || config.name} - ${file}:${line}:${col}\n`
137
+ );
138
+ throw red(outer);
139
+ }
140
+ }
141
+ }
142
+ return monitors;
143
+ }
144
+
145
+ const REQUIRED_MONITOR_FIELDS = ['id', 'name'];
146
+ export function buildMonitorFromYaml(
147
+ config: MonitorConfig,
148
+ options: PushOptions
149
+ ) {
150
+ // Validate required fields
151
+ for (const field of REQUIRED_MONITOR_FIELDS) {
152
+ if (!config[field]) {
153
+ throw `Monitor ${field} is required`;
154
+ }
155
+ }
156
+ const schedule = config.schedule && parseSchedule(String(config.schedule));
157
+ const privateLocations =
158
+ config['private_locations'] || options.privateLocations;
159
+ delete config['private_locations'];
160
+
161
+ return new Monitor({
162
+ locations: options.locations,
163
+ ...config,
164
+ privateLocations,
165
+ schedule: schedule || options.schedule,
166
+ });
167
+ }
168
+
169
+ export function parseSchedule(schedule: string) {
170
+ const EVERY_SYNTAX = '@every';
171
+ if (!(schedule + '').startsWith(EVERY_SYNTAX)) {
172
+ throw `Monitor schedule format(${schedule}) not supported: use '@every' syntax instead`;
173
+ }
174
+
175
+ const duration = schedule.substring(EVERY_SYNTAX.length + 1);
176
+ // split between non-digit (\D) and a digit (\d)
177
+ const durations = duration.split(/(?<=\D)(?=\d)/g);
178
+ let minutes = 0;
179
+ for (const dur of durations) {
180
+ // split between a digit and non-digit
181
+ const [value, format] = dur.split(/(?<=\d)(?=\D)/g);
182
+ // Calculate based on the duration symbol
183
+ const scheduleValue = parseInt(value, 10);
184
+ switch (format) {
185
+ case 's':
186
+ minutes += Math.ceil(scheduleValue / 60);
187
+ break;
188
+ case 'm':
189
+ minutes += scheduleValue;
190
+ break;
191
+ case 'h':
192
+ minutes += scheduleValue * 60;
193
+ break;
194
+ }
195
+ }
196
+ return minutes;
197
+ }
198
+
78
199
  export async function createMonitors(
79
200
  monitors: MonitorSchema[],
80
201
  options: PushOptions,
@@ -27,8 +27,12 @@ import { isAbsolute, dirname, extname, join } from 'path';
27
27
  import fs from 'fs/promises';
28
28
  import * as esbuild from 'esbuild';
29
29
 
30
- const SOURCE_DIR = join(__dirname, '..', '..');
31
- const SOURCE_NODE_MODULES = join(SOURCE_DIR, 'node_modules');
30
+ // ROOT directory of the Package - /
31
+ const ROOT_DIR = join(__dirname, '..', '..');
32
+ // Source of the package - /src, /dist, etc.
33
+ const SOURCE_DIR = join(__dirname, '..');
34
+ // Node modules directory of the package - /node_modules
35
+ const SOURCE_NODE_MODULES = join(ROOT_DIR, 'node_modules');
32
36
 
33
37
  export function commonOptions(): esbuild.BuildOptions {
34
38
  return {
@@ -23,7 +23,7 @@
23
23
  *
24
24
  */
25
25
 
26
- import { bold } from 'kleur/colors';
26
+ import { bold, red, yellow } from 'kleur/colors';
27
27
  import { Dispatcher, request } from 'undici';
28
28
  import { indent, symbols } from '../helpers';
29
29
 
@@ -47,7 +47,7 @@ export async function sendRequest(options: APIRequestOptions) {
47
47
  'user-agent': `Elastic/Synthetics ${version}`,
48
48
  'kbn-xsrf': 'true',
49
49
  },
50
- headersTimeout: 60 * 1000
50
+ headersTimeout: 60 * 1000,
51
51
  });
52
52
  }
53
53
 
@@ -62,8 +62,10 @@ export type APIMonitorError = {
62
62
  };
63
63
 
64
64
  export function formatNotFoundError(message: string) {
65
- return bold(
66
- `${symbols['failed']} Please check your kibana url and try again - 404:${message}`
65
+ return red(
66
+ bold(
67
+ `${symbols['failed']} Please check your kibana url and try again - 404:${message}`
68
+ )
67
69
  );
68
70
  }
69
71
 
@@ -78,7 +80,7 @@ export function formatAPIError(
78
80
  );
79
81
  inner += indent(message, ' ');
80
82
  outer += indent(inner);
81
- return outer;
83
+ return red(outer);
82
84
  }
83
85
 
84
86
  function formatMonitorError(errors: APIMonitorError[]) {
@@ -95,10 +97,10 @@ function formatMonitorError(errors: APIMonitorError[]) {
95
97
 
96
98
  export function formatFailedMonitors(errors: APIMonitorError[]) {
97
99
  const heading = bold(`${symbols['failed']} Error\n`);
98
- return heading + formatMonitorError(errors);
100
+ return red(heading + formatMonitorError(errors));
99
101
  }
100
102
 
101
103
  export function formatStaleMonitors(errors: APIMonitorError[]) {
102
104
  const heading = bold(`${symbols['warning']} Warnings\n`);
103
- return heading + formatMonitorError(errors);
105
+ return yellow(heading + formatMonitorError(errors));
104
106
  }