@loadmill/core 0.3.50 → 0.3.53

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 (80) hide show
  1. package/dist/conf/extrema.d.ts +1 -1
  2. package/dist/conf/extrema.js +2 -2
  3. package/dist/conf/extrema.js.map +1 -1
  4. package/dist/conf/types.d.ts +12 -0
  5. package/dist/conf/validate.d.ts +2 -1
  6. package/dist/conf/validate.js +6 -1
  7. package/dist/conf/validate.js.map +1 -1
  8. package/dist/multipart-form-data/form-data-utils.js +2 -2
  9. package/dist/multipart-form-data/form-data-utils.js.map +1 -1
  10. package/dist/multipart-form-data/is-binary-file.d.ts +2 -0
  11. package/dist/multipart-form-data/is-binary-file.js +215 -0
  12. package/dist/multipart-form-data/is-binary-file.js.map +1 -0
  13. package/dist/multipart-form-data/multipart-text-to-post-form-data.d.ts +5 -1
  14. package/dist/multipart-form-data/multipart-text-to-post-form-data.js +96 -35
  15. package/dist/multipart-form-data/multipart-text-to-post-form-data.js.map +1 -1
  16. package/dist/parameters/extractions.d.ts +2 -1
  17. package/dist/parameters/extractions.js.map +1 -1
  18. package/dist/parameters/index.d.ts +1 -1
  19. package/dist/parameters/index.js +4 -0
  20. package/dist/parameters/index.js.map +1 -1
  21. package/dist/request/index.d.ts +1 -0
  22. package/dist/request/index.js.map +1 -1
  23. package/package.json +7 -2
  24. package/src/conf/defaults.ts +0 -25
  25. package/src/conf/extrema.ts +0 -35
  26. package/src/conf/index.ts +0 -95
  27. package/src/conf/notifications.ts +0 -17
  28. package/src/conf/types.ts +0 -86
  29. package/src/conf/validate.ts +0 -548
  30. package/src/distributed-logger-reporter.ts +0 -19
  31. package/src/echo/firehose.ts +0 -64
  32. package/src/echo/index.ts +0 -4
  33. package/src/echo/stats.ts +0 -84
  34. package/src/har/index.ts +0 -81
  35. package/src/multipart-form-data/form-data-utils.ts +0 -81
  36. package/src/multipart-form-data/multipart-text-to-post-form-data.ts +0 -89
  37. package/src/parameters/extractions.ts +0 -51
  38. package/src/parameters/extractors/cheerio-extractor.ts +0 -57
  39. package/src/parameters/extractors/expression-extractor.ts +0 -13
  40. package/src/parameters/extractors/extractor.ts +0 -3
  41. package/src/parameters/extractors/header-extractor.ts +0 -24
  42. package/src/parameters/extractors/index.ts +0 -10
  43. package/src/parameters/extractors/json-path-extractor.ts +0 -63
  44. package/src/parameters/extractors/parametrized-extractor.ts +0 -27
  45. package/src/parameters/extractors/regex-extractor.ts +0 -18
  46. package/src/parameters/extractors/regex-matcher.ts +0 -17
  47. package/src/parameters/extractors/ws-extractor.ts +0 -91
  48. package/src/parameters/generate-random.ts +0 -114
  49. package/src/parameters/index.ts +0 -621
  50. package/src/parameters/json-path-utils.ts +0 -20
  51. package/src/parameters/operators/binary-operator.ts +0 -23
  52. package/src/parameters/operators/index.ts +0 -39
  53. package/src/parameters/parameter-functions/boolean-parameter-functions.ts +0 -24
  54. package/src/parameters/parameter-functions/crypto.ts +0 -55
  55. package/src/parameters/parameter-functions/json-schema.ts +0 -29
  56. package/src/parameters/parameter-functions/numeric-input-parameter-functions.ts +0 -22
  57. package/src/parameters/parameter-functions/numeric-parameter-functions.ts +0 -37
  58. package/src/parameters/parameter-functions/parameter-function-utils.ts +0 -55
  59. package/src/parameters/parameter-functions/parameter-function.ts +0 -7
  60. package/src/parameters/parameter-functions/parameter-functions.ts +0 -54
  61. package/src/parameters/parameter-functions/random-parameter-functions.ts +0 -22
  62. package/src/parameters/parameter-functions/textual-parameter-functions.ts +0 -464
  63. package/src/parameters/parameter-regex-providers.ts +0 -78
  64. package/src/parameters/resolvers/random-parameters-resolver.ts +0 -8
  65. package/src/parameters/type.ts +0 -7
  66. package/src/parameters/value-utils.ts +0 -47
  67. package/src/request/index.ts +0 -525
  68. package/src/schema/json-schema-generator.ts +0 -76
  69. package/test/conf/validate.spec.js +0 -141
  70. package/test/har/is-har.spec.js +0 -33
  71. package/test/multipart-form-data/form-data-utils.spec.ts +0 -121
  72. package/test/multipart-form-data/resources/multipart-form-data-file-text-content.json +0 -5
  73. package/test/parameters/builtin-functions.spec.js +0 -85
  74. package/test/parameters/json-path-utils.spec.ts +0 -50
  75. package/test/parameters/parameter-functions.spec.js +0 -48
  76. package/test/parameters/parameter-utils.spec.js +0 -185
  77. package/test/parameters/regex-functions.spec.ts +0 -57
  78. package/test/parameters/value-utils.spec.js +0 -73
  79. package/test/schema/json-schema-generator.spec.js +0 -227
  80. package/tsconfig.json +0 -9
@@ -1,548 +0,0 @@
1
- import URI from 'urijs';
2
- import jsonpath from 'jsonpath';
3
- import validator from 'validator';
4
- import { validateHeaderName } from 'http-headers-validation';
5
- import isEmpty from 'lodash/isEmpty';
6
- import uniq from 'lodash/uniq';
7
- import {
8
- isReservedHeader,
9
- supportedMethods,
10
- ALLOWED_RESPONSE_STATUSES,
11
- EXCLUDES
12
- } from '../request';
13
- import { NotificationMode, NotificationTypes } from './types';
14
- import { Parameters, parameterUtils, LEGAL_PARAM_CHARS, CAPTURE_REGEX, MAX_PARAM_ARRAY_SIZE } from '../parameters';
15
- import * as cronUtils from '@loadmill/universal/dist/cron-utils';
16
- import * as enumUtils from '@loadmill/universal/dist/enum-utils';
17
- import isBoolean from 'lodash/isBoolean';
18
-
19
- export const validate = {
20
- invalid: invalid,
21
-
22
- positive(value, name: string) {
23
- if (typeof value !== 'number' || value <= 0) {
24
- return invalid(name, 'Must be a positive number');
25
- }
26
- },
27
-
28
- email(value, name: string) {
29
- if (!validator.isEmail(value)) {
30
- return invalid(name, 'invalid email');
31
- }
32
- },
33
-
34
- integer(
35
- value,
36
- name: string | false,
37
- min: number = 0,
38
- max: number = Number.MAX_SAFE_INTEGER
39
- ) {
40
- if (!Number.isSafeInteger(Number(value))) {
41
- return invalid(name, 'Must be an integer');
42
- }
43
-
44
- if (value < min) {
45
- return invalid(name, 'Cannot be less than ' + min);
46
- }
47
-
48
- if (max < value) {
49
- return invalid(name, 'Cannot be more than ' + max);
50
- }
51
- },
52
-
53
- nonemptyArray(value, name: string) {
54
- const message = 'Must be a nonempty array';
55
- let res = array(value, name, message);
56
-
57
- if (!res && isEmpty(value)) {
58
- res = invalid(name, message);
59
- }
60
-
61
- return res;
62
- },
63
-
64
- array: array,
65
-
66
- string: string,
67
-
68
- jsonFormat: jsonFormat,
69
-
70
- isTrue: isTrue,
71
-
72
- uuid(value, name: string) {
73
- if (!validator.isUUID(value)) {
74
- return invalid(name, 'Must be a valid UUID');
75
- }
76
- },
77
-
78
- nonemptyString: nonemptyString,
79
-
80
- stringIfExists(value, name: string, message: string = 'Must be a string') {
81
- if (value != null) {
82
- return string(value, name, message);
83
- }
84
- },
85
-
86
- notification(notification) {
87
- const { email, destination, notifyWhen } = notification;
88
- let res;
89
-
90
- if (email) {
91
- res = this.email(email, 'destination');
92
- } else if (destination.type === NotificationTypes.EMAIL) {
93
- res = this.email(destination.target, 'destination');
94
- }
95
-
96
- if (!res) {
97
- if (!NotificationMode.hasOwnProperty(notifyWhen)) {
98
- res = {
99
- value: `Must be one of [${enumUtils.stringValues(NotificationMode)}]`,
100
- };
101
- }
102
- }
103
- return res;
104
- },
105
-
106
- parameter(name: string, value: string | string[]) {
107
- const nameName = 'name';
108
- let res = validate.parameterName(name, nameName);
109
-
110
- //todo itay: perhaps limit length as well
111
- if (!res) {
112
- const valid = Array.isArray(value)
113
- ? !isEmpty(value) && isEmpty(value.filter((item) => string(item)))
114
- : !string(value);
115
-
116
- if (!valid) {
117
- res = { value: 'Must be a string or a nonempty string array' };
118
- } else if (Array.isArray(value) && value.length > MAX_PARAM_ARRAY_SIZE) {
119
- res = {
120
- value: `No more than ${MAX_PARAM_ARRAY_SIZE} possible values are allowed`,
121
- };
122
- }
123
- }
124
-
125
- return res;
126
- },
127
-
128
- hasOnlyAcceptableCharacters: hasOnlyAcceptableCharacters,
129
-
130
- parameterDoesntExist: parameterDoesntExist,
131
-
132
- extractedValue: extractedValue,
133
-
134
- isUrl: isUrl,
135
-
136
- url(url: string, name = 'url') {
137
- let res = nonemptyString(url, name, 'Required');
138
-
139
- if (!res) {
140
- res = isUrl(url, name);
141
- if (!res) {
142
- const uriObj = new URI(url);
143
-
144
- const hostname = uriObj.hostname();
145
-
146
- if (!uriObj.protocol() || !hostname) {
147
- res = invalid(name, 'Missing protocol or host name');
148
- }
149
- }
150
- }
151
-
152
- return res;
153
- },
154
-
155
- isUrlLocalHost(url: string, name = 'url') {
156
- const uriObj = new URI(url);
157
- const hostname = uriObj.hostname();
158
- if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.includes('ngrok')) {
159
- return invalid(
160
- name,
161
- 'Note: to test a local API use the Loadmill local agent - '
162
- );
163
- }
164
- },
165
-
166
- isMethodSupported(method) {
167
- return supportedMethods.hasOwnProperty(method);
168
- },
169
-
170
- isHttpStatusSupported(expectedHttpStatus) {
171
- return ALLOWED_RESPONSE_STATUSES.hasOwnProperty(expectedHttpStatus);
172
- },
173
-
174
- method(method) {
175
- if (!validate.isMethodSupported(method)) {
176
- return invalid('method', 'Not a valid HTTP method');
177
- }
178
- },
179
-
180
- expectedHttpStatus(expectedHttpStatus) {
181
- if (!validate.isHttpStatusSupported(expectedHttpStatus)) {
182
- return invalid(
183
- 'expectedStatus',
184
- 'Not a valid HTTP response status option'
185
- );
186
- }
187
- },
188
-
189
- header(_headerName: string, headerValue: string) {
190
- let res: any = headerName(_headerName);
191
-
192
- if (!res) {
193
- res = string(headerValue, 'value');
194
- }
195
-
196
- return res;
197
- },
198
-
199
- headerName: headerName,
200
-
201
- mimeType(value: string, name: string) {
202
- return string(value, name);
203
- },
204
-
205
- regex(value: string, name = 'regex') {
206
- const message = 'Invalid JS regular expression';
207
- let res = nonemptyString(value, name, 'Required');
208
-
209
- if (!res && !parameterUtils.isParametrized(value)) {
210
- try {
211
- RegExp(value);
212
- } catch (e) {
213
- // log.debug('regex parse error:', e);
214
- res = invalid(name, message);
215
- }
216
- }
217
-
218
- return res;
219
- },
220
-
221
- regexCapture(value: string, name = 'regex') {
222
- const message = 'Warning - your regex doesn\'t contain a capturing group';
223
- const withoutQuotes = value.replace(/^'/, '').replace(/'$/, '');
224
- const captureRegex = CAPTURE_REGEX;
225
-
226
- let res;
227
- try {
228
- const captures = withoutQuotes.match(captureRegex);
229
- if (!captures) {
230
- res = invalid(name, message);
231
- }
232
- }
233
- catch { }
234
-
235
- return res;
236
- },
237
-
238
- jsonPath(value: string) {
239
- const name = 'jsonPath';
240
- const message = 'Invalid JSONPath expression';
241
- let res = nonemptyString(value, name, 'Required');
242
-
243
- if (!res && !parameterUtils.isParametrized(value)) {
244
- try {
245
- jsonpath.parse(value);
246
- } catch (e) {
247
- // log.debug('jsonPath parse error:', e);
248
- res = invalid(name, message);
249
- }
250
- }
251
-
252
- return res;
253
- },
254
-
255
- jQuery(value, name = 'jQuery') {
256
- let query, attr;
257
-
258
- if (typeof value === 'string') {
259
- query = value;
260
- } else if (value == null) {
261
- return invalid(name, 'Must not be null');
262
- } else {
263
- attr = value.attr;
264
- query = value.query;
265
- }
266
-
267
- //todo itay: figure out how to validate using Cheerio
268
- const queryRes = nonemptyString(query, 'query', 'Required');
269
-
270
- if (queryRes) {
271
- return { [name]: queryRes };
272
- } else {
273
- const attrRes = attr != null && string(attr, 'attr');
274
-
275
- if (attrRes) {
276
- return { [name]: attrRes };
277
- }
278
- }
279
- },
280
-
281
- externalIntegration(integration) {
282
- const { description, domain, username, token, project } = integration;
283
- const res = Object.assign(
284
- {},
285
- validate.string(description, 'description'),
286
- validate.url(domain, 'domain'),
287
- validate.nonemptyString(username, 'username'),
288
- validate.nonemptyString(token, 'token'),
289
- validate.nonemptyString(project, 'project')
290
- );
291
- return res;
292
- },
293
-
294
- validateCron(cron: string) {
295
- let res;
296
- const name = 'cron error';
297
- try {
298
- if (!cron) {
299
- res = invalid(name, `Empty - ${cron}`);
300
- }
301
- else {
302
- cronUtils.parseCron(cron);
303
- if (!cronUtils.isAllowedExpression(cron)) {
304
- res = invalid(name, `Cron is not allowed - ${cron}`);
305
- }
306
- else if (isCronHasTooManyTokens(cron)) {
307
- res = invalid(name, `Too many tokens - ${cron}`);
308
- }
309
- }
310
- } catch (err) {
311
- res = invalid(name, 'Can\'t parse cron expression');
312
- }
313
-
314
- return res;
315
- },
316
-
317
- validateParameterNames(names: string[]) {
318
- return Object.assign(
319
- {},
320
- ...names.map((name, index) => validate.parameterName(name, '' + index))
321
- );
322
- },
323
-
324
- validateObjOrArray<T>(
325
- name: string,
326
- objOrArray: T | T[],
327
- singleValidation,
328
- ) {
329
- let res;
330
-
331
- if (Array.isArray(objOrArray)) {
332
- objOrArray.forEach((obj, index) => {
333
- const temp = singleValidation(obj);
334
-
335
- if (temp) {
336
- res = { ...res, [index]: temp };
337
- }
338
- });
339
- } else {
340
- res = singleValidation(objOrArray);
341
- }
342
-
343
- if (res) {
344
- return { [name]: res };
345
- }
346
- },
347
-
348
- parameterName(
349
- parameterName: string,
350
- fieldName: string | false
351
- ) {
352
- let res = nonemptyString(
353
- parameterName,
354
- fieldName,
355
- 'Parameter name can\'t be empty'
356
- );
357
-
358
- if (!res) {
359
- const firstChar = parameterName.charAt(0);
360
-
361
- if (validator.isNumeric(firstChar)) {
362
- res = invalid(fieldName, `May not start with '${firstChar}'`);
363
- } else {
364
- res = hasOnlyAcceptableCharacters(parameterName, fieldName);
365
- }
366
- }
367
-
368
- return res;
369
- },
370
-
371
- label(labelParams) {
372
- const { description, color } = labelParams;
373
- const res = Object.assign(
374
- {},
375
- string(description, 'description'),
376
- isColor(color),
377
- );
378
- return res;
379
- },
380
-
381
- boolean(value, name: string) {
382
- if (!isBoolean(value)) {
383
- return invalid(name, 'Must be a boolean');
384
- }
385
- }
386
- };
387
-
388
- function hasOnlyAcceptableCharacters(value: string, fieldName: string | false) {
389
- const invalidMatch = new RegExp(`.*([^${LEGAL_PARAM_CHARS}]).*`).exec(value);
390
-
391
- if (invalidMatch != null) {
392
- return invalid(fieldName, `Unacceptable character: '${invalidMatch[1]}'`);
393
- }
394
- }
395
-
396
- function parameterDoesntExist(
397
- parameterName,
398
- entityName: string,
399
- collection: Array<Parameters>
400
- ) {
401
- if (!parameterName || isEmpty(collection)) {
402
- return;
403
- }
404
-
405
- const entityExists = collection.some(
406
- (e) => e[parameterName] || e[parameterName] === ''
407
- );
408
-
409
- if (entityExists) {
410
- return invalid(entityName, `${entityName} ${parameterName} already exists`);
411
- }
412
- }
413
-
414
- function extractedValue(extractedVal: string, fieldName: string | false) {
415
- let res = nonemptyString(
416
- extractedVal,
417
- fieldName,
418
- 'Extracted value can\'t be empty'
419
- );
420
-
421
- if (!res) {
422
- const invalidMatch = new RegExp('{|}|[$]').exec(extractedVal);
423
-
424
- if (invalidMatch != null) {
425
- return invalid(fieldName, `Unacceptable character: '${invalidMatch}'`);
426
- }
427
-
428
- const hasBannedWords = EXCLUDES.some((ex) => ex === extractedVal.trim());
429
- if (hasBannedWords) {
430
- res = invalid(
431
- fieldName,
432
- 'Can\'t extract reserved HTTP words - URL, headers etc...'
433
- );
434
- }
435
- }
436
-
437
- return res;
438
- }
439
-
440
- function invalid(name: string | false, message: string): any {
441
- return name ? { [name]: message } : message;
442
- }
443
-
444
- function array(value, name: string, message: string = 'Must be an array') {
445
- if (!Array.isArray(value)) {
446
- return invalid(name, message);
447
- }
448
- }
449
-
450
- function isUrl(url: string, name: string = 'url') {
451
- if (
452
- !validator.isURL((url || ''), {
453
- require_tld: false,
454
- protocols: ['http', 'https', 'ftp', 'ws', 'wss']
455
- })
456
- ) {
457
- return invalid(name, 'Invalid URL');
458
- }
459
- }
460
-
461
- function nonemptyString(
462
- value,
463
- name: string | false,
464
- message: string = 'May not be empty'
465
- ) {
466
- if (value == null) {
467
- return invalid(name, message);
468
- }
469
-
470
- let res = string(value, name);
471
-
472
- if (!res && value.trim().length === 0) {
473
- res = invalid(name, message);
474
- }
475
-
476
- return res;
477
- }
478
-
479
- function string(
480
- value,
481
- name: string | false = 'value',
482
- message: string = 'Must be a string'
483
- ) {
484
- if (typeof value !== 'string') {
485
- return invalid(name, message);
486
- }
487
- }
488
-
489
- function jsonFormat(
490
- value: string,
491
- name: string,
492
- message: string = 'Invalid JSON format'
493
- ) {
494
- try {
495
- const withoutParams = value.replace(/\$\{.+?(?=\})\}/g, 'null');
496
- JSON.parse(withoutParams);
497
- }
498
- catch (_e) {
499
- return invalid(name, message);
500
- }
501
- }
502
-
503
- function isTrue(
504
- value,
505
- name: string,
506
- message: string = 'Must be a true boolean'
507
- ) {
508
- if (value !== true && value !== 'true') {
509
- return invalid(name, message);
510
- }
511
- }
512
-
513
- function headerName(headerName: string, nameName = 'name') {
514
- if (!headerName) {
515
- return { [nameName]: 'Required' };
516
- } else if (!validateHeaderName(headerName)) {
517
- return { [nameName]: 'Invalid header name' };
518
- } else if (isReservedHeader(headerName.toLowerCase())) {
519
- return { [nameName]: 'This header may not be set manually' };
520
- }
521
- }
522
-
523
- function isColor(value) {
524
- const isHexColor = new RegExp('^#(?:[0-9a-fA-F]{3,4}){1,2}$').test(value);
525
- if (!isHexColor) {
526
- return invalid('color', 'Must be in hex color format');
527
- }
528
- }
529
-
530
- export interface EntryValidations {
531
- [name: string]:
532
- | string
533
- | {
534
- name?: string;
535
- value?: string;
536
- };
537
- }
538
-
539
- const MAX_CRON_TOKENS = 5;
540
- const isCronHasTooManyTokens = (cron) =>
541
- cron.split(' ').length > MAX_CRON_TOKENS;
542
-
543
- export const gitBranchName = (branchName: string) => {
544
- const validation = branchName.match(/^[./]|\.\.|@{|[/.]$|^@$|[~^:\x00-\x20\x7F\s?*[\\]/g); // eslint-disable-line
545
- if (validation) {
546
- return 'Invalid characters: ' + uniq(validation.map(c => c == ' ' ? '(space)' : c)).join(' ');
547
- }
548
- };
@@ -1,19 +0,0 @@
1
- import superagent from 'superagent';
2
-
3
- const url = process.env.DISTRIBUTED_LOGGER_URL || 'https://loadmill-distributed-logger.herokuapp.com/agent-events/report';
4
-
5
- export const distributedLoggerReporter = {
6
-
7
- async report (body: string) {
8
- if (process.env.STOP_REPORT === 'true') {
9
- return;
10
- }
11
- try {
12
- await superagent
13
- .post(url)
14
- .type('text/plain')
15
- .send(body);
16
- }
17
- catch {}
18
- }
19
- };
@@ -1,64 +0,0 @@
1
- import { FirehoseClient, PutRecordBatchCommand } from '@aws-sdk/client-firehose';
2
- import { CognitoIdentity } from '@aws-sdk/client-cognito-identity';
3
-
4
- const FIREHOSE_API_VERSION = '2015-08-04';
5
- const REGION = 'us-east-1';
6
- const STREAM_NAME = 'fhs-test1';
7
-
8
- let firehose: FirehoseClient;
9
- const cognito = new CognitoIdentity({ region: REGION });
10
-
11
- export class FirehoseRecords {
12
- records;
13
-
14
- constructor() {
15
- this.clearRecords();
16
- }
17
-
18
- addRecord(record) {
19
- const enc = new TextEncoder(); // always utf-8
20
- const encodedRecord = enc.encode(`${JSON.stringify(record)}\n`);
21
- this.records.push({ Data: encodedRecord });
22
- }
23
-
24
- async pushRecords() {
25
- try {
26
-
27
- if (!this.records.length) {
28
- return;
29
- }
30
-
31
- const identity = await cognito.getId({ IdentityPoolId: 'us-east-1:79372411-2664-431b-aa0b-aad9f938f6e9' });
32
- const credentialResponse = await cognito.getCredentialsForIdentity({ IdentityId: identity.IdentityId });
33
- firehose = new FirehoseClient({
34
- region: REGION,
35
- apiVersion: FIREHOSE_API_VERSION,
36
- credentials: {
37
- accessKeyId: credentialResponse.Credentials!.AccessKeyId!,
38
- secretAccessKey:credentialResponse.Credentials!.SecretKey!,
39
- sessionToken:credentialResponse.Credentials!.SessionToken!,
40
- expiration:credentialResponse.Credentials!.Expiration!
41
- }
42
- });
43
-
44
- const command = new PutRecordBatchCommand({
45
- Records: this.records,
46
- DeliveryStreamName: STREAM_NAME
47
- });
48
-
49
- await firehose.send(command);
50
- }
51
- catch (err) {
52
- // eslint-disable-next-line no-console
53
- console.error(err);
54
- }
55
- finally {
56
- this.clearRecords();
57
- }
58
- }
59
-
60
- clearRecords() {
61
- this.records = [];
62
- }
63
-
64
- }
package/src/echo/index.ts DELETED
@@ -1,4 +0,0 @@
1
- import { Stats } from './stats';
2
- import { FirehoseRecords } from './firehose';
3
-
4
- export { Stats, FirehoseRecords };
package/src/echo/stats.ts DELETED
@@ -1,84 +0,0 @@
1
- import isUUID from 'validator/lib/isUUID';
2
-
3
- const isNumber = s => /^[0-9]+$/.test(s);
4
-
5
- const standardizePath = path => {
6
- const parts = path.slice(1).split('/');
7
- let newPath = '';
8
-
9
- parts.forEach(part => {
10
- newPath += (isUUID(part) || isNumber(part)) ? '/{param}' : `/${part}`;
11
- });
12
-
13
- return newPath;
14
- };
15
-
16
- const updateKey = (obj, key, shouldIncr, value) => {
17
- obj[key] = shouldIncr ? (obj[key] || 0) + value : value;
18
- };
19
-
20
- export class Stats {
21
-
22
- stats;
23
-
24
- constructor() {
25
- this.stats = {
26
- lmCode: -1,
27
- totalRequests: 0,
28
- totalResponseTime: 0,
29
- requestsCounter: {},
30
- requestsResponseTime: {},
31
- isNewSession: false,
32
- totalNewSessions: 0
33
- };
34
- }
35
-
36
- updateStats(key, shouldIncr, value:any = 0, subKey = '') {
37
- if (key && value) {
38
- if (subKey) {
39
- updateKey(this.stats[key], subKey, shouldIncr, value);
40
- } else {
41
- updateKey(this.stats, key, shouldIncr, value);
42
- }
43
- }
44
- }
45
-
46
- addRequest(request, responseTime) {
47
- const convertedPath = standardizePath(new URL(request.url).pathname);
48
-
49
- this.updateStats('totalRequests', true, 1);
50
- this.updateStats('totalResponseTime', true, parseInt(responseTime, 10));
51
- this.updateStats('requestsCounter', true, 1, `${request.method}:${convertedPath}`);
52
- this.updateStats('requestsResponseTime', true, parseInt(responseTime, 10), `${request.method}:${convertedPath}`);
53
- }
54
-
55
- clearStats() {
56
- this.stats.totalRequests = 0;
57
- this.stats.totalResponseTime = 0;
58
- this.stats.requestsCounter = {};
59
- this.stats.requestsResponseTime = {};
60
- this.stats.isNewSession = false;
61
- this.stats.totalNewSessions = 0;
62
- }
63
-
64
- async push(url) {
65
- let isPushed = false;
66
- if (this.stats.totalRequests > 0) {
67
- // eslint-disable-next-line no-undef
68
- const res = await fetch(`${url}/stats`, {
69
- method: 'POST',
70
- body: JSON.stringify(this.stats),
71
- headers: {
72
- 'Content-Type': 'application/json',
73
- Accept: 'application/json'
74
- }
75
- });
76
- if (res.ok) {
77
- this.clearStats();
78
- isPushed = true;
79
- }
80
- }
81
-
82
- return isPushed;
83
- }
84
- }