flagsmith-nodejs 2.4.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,7 @@ export declare const PERCENTAGE_SPLIT = "PERCENTAGE_SPLIT";
15
15
  export declare const IS_SET = "IS_SET";
16
16
  export declare const IS_NOT_SET = "IS_NOT_SET";
17
17
  export declare const MODULO = "MODULO";
18
+ export declare const IN = "IN";
18
19
  export declare const CONDITION_OPERATORS: {
19
20
  EQUAL: string;
20
21
  GREATER_THAN: string;
@@ -29,4 +30,5 @@ export declare const CONDITION_OPERATORS: {
29
30
  IS_SET: string;
30
31
  IS_NOT_SET: string;
31
32
  MODULO: string;
33
+ IN: string;
32
34
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONDITION_OPERATORS = exports.MODULO = exports.IS_NOT_SET = exports.IS_SET = exports.PERCENTAGE_SPLIT = exports.REGEX = exports.NOT_EQUAL = exports.NOT_CONTAINS = exports.GREATER_THAN_INCLUSIVE = exports.CONTAINS = exports.LESS_THAN_INCLUSIVE = exports.LESS_THAN = exports.GREATER_THAN = exports.EQUAL = exports.RULE_TYPES = exports.NONE_RULE = exports.ANY_RULE = exports.ALL_RULE = void 0;
3
+ exports.CONDITION_OPERATORS = exports.IN = exports.MODULO = exports.IS_NOT_SET = exports.IS_SET = exports.PERCENTAGE_SPLIT = exports.REGEX = exports.NOT_EQUAL = exports.NOT_CONTAINS = exports.GREATER_THAN_INCLUSIVE = exports.CONTAINS = exports.LESS_THAN_INCLUSIVE = exports.LESS_THAN = exports.GREATER_THAN = exports.EQUAL = exports.RULE_TYPES = exports.NONE_RULE = exports.ANY_RULE = exports.ALL_RULE = void 0;
4
4
  // Segment Rules
5
5
  exports.ALL_RULE = 'ALL';
6
6
  exports.ANY_RULE = 'ANY';
@@ -20,6 +20,7 @@ exports.PERCENTAGE_SPLIT = 'PERCENTAGE_SPLIT';
20
20
  exports.IS_SET = 'IS_SET';
21
21
  exports.IS_NOT_SET = 'IS_NOT_SET';
22
22
  exports.MODULO = 'MODULO';
23
+ exports.IN = 'IN';
23
24
  exports.CONDITION_OPERATORS = {
24
25
  EQUAL: exports.EQUAL,
25
26
  GREATER_THAN: exports.GREATER_THAN,
@@ -33,5 +34,6 @@ exports.CONDITION_OPERATORS = {
33
34
  PERCENTAGE_SPLIT: exports.PERCENTAGE_SPLIT,
34
35
  IS_SET: exports.IS_SET,
35
36
  IS_NOT_SET: exports.IS_NOT_SET,
36
- MODULO: exports.MODULO
37
+ MODULO: exports.MODULO,
38
+ IN: exports.IN
37
39
  };
@@ -69,6 +69,7 @@ var SegmentConditionModel = /** @class */ (function () {
69
69
  _a[constants_1.NOT_CONTAINS] = 'evaluateNotContains',
70
70
  _a[constants_1.REGEX] = 'evaluateRegex',
71
71
  _a[constants_1.MODULO] = 'evaluateModulo',
72
+ _a[constants_1.IN] = 'evaluateIn',
72
73
  _a);
73
74
  this.operator = operator;
74
75
  this.value = value;
@@ -90,7 +91,11 @@ var SegmentConditionModel = /** @class */ (function () {
90
91
  var parts = (_this.value).split("|");
91
92
  var _a = __read([parseFloat(parts[0]), parseFloat(parts[1])], 2), divisor = _a[0], reminder = _a[1];
92
93
  return traitValue % divisor === reminder;
93
- }
94
+ },
95
+ evaluateIn: function (traitValue) {
96
+ var _a;
97
+ return (_a = _this.value) === null || _a === void 0 ? void 0 : _a.split(',').includes(traitValue.toString());
98
+ },
94
99
  };
95
100
  // TODO: move this logic to the evaluator module
96
101
  if (this.EXCEPTION_OPERATOR_METHODS[this.operator]) {
@@ -1,3 +1,4 @@
1
+ import { Logger } from 'pino';
1
2
  export declare class AnalyticsProcessor {
2
3
  private analyticsEndpoint;
3
4
  private environmentKey;
@@ -6,6 +7,7 @@ export declare class AnalyticsProcessor {
6
7
  [key: string]: any;
7
8
  };
8
9
  private requestTimeoutMs;
10
+ private logger;
9
11
  /**
10
12
  * AnalyticsProcessor is used to track how often individual Flags are evaluated within
11
13
  * the Flagsmith SDK. Docs: https://docs.flagsmith.com/advanced-use/flag-analytics.
@@ -19,6 +21,7 @@ export declare class AnalyticsProcessor {
19
21
  environmentKey: string;
20
22
  baseApiUrl: string;
21
23
  requestTimeoutMs?: number;
24
+ logger?: Logger;
22
25
  });
23
26
  /**
24
27
  * Sends all the collected data to the api asynchronously and resets the timer
@@ -41,6 +41,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.AnalyticsProcessor = void 0;
43
43
  var node_fetch_1 = __importDefault(require("node-fetch"));
44
+ var pino_1 = __importDefault(require("pino"));
44
45
  var ANALYTICS_ENDPOINT = 'analytics/flags/';
45
46
  // Used to control how often we send data(in seconds)
46
47
  var ANALYTICS_TIMER = 10;
@@ -61,18 +62,23 @@ var AnalyticsProcessor = /** @class */ (function () {
61
62
  this.lastFlushed = Date.now();
62
63
  this.analyticsData = {};
63
64
  this.requestTimeoutMs = data.requestTimeoutMs || this.requestTimeoutMs;
65
+ this.logger = data.logger || (0, pino_1.default)();
64
66
  }
65
67
  /**
66
68
  * Sends all the collected data to the api asynchronously and resets the timer
67
69
  */
68
70
  AnalyticsProcessor.prototype.flush = function () {
69
71
  return __awaiter(this, void 0, void 0, function () {
72
+ var error_1;
70
73
  return __generator(this, function (_a) {
71
74
  switch (_a.label) {
72
75
  case 0:
73
76
  if (!Object.keys(this.analyticsData).length) {
74
77
  return [2 /*return*/];
75
78
  }
79
+ _a.label = 1;
80
+ case 1:
81
+ _a.trys.push([1, 3, , 4]);
76
82
  return [4 /*yield*/, (0, node_fetch_1.default)(this.analyticsEndpoint, {
77
83
  method: 'POST',
78
84
  body: JSON.stringify(this.analyticsData),
@@ -82,8 +88,16 @@ var AnalyticsProcessor = /** @class */ (function () {
82
88
  'X-Environment-Key': this.environmentKey
83
89
  }
84
90
  })];
85
- case 1:
91
+ case 2:
86
92
  _a.sent();
93
+ return [3 /*break*/, 4];
94
+ case 3:
95
+ error_1 = _a.sent();
96
+ // We don't want failing to write analytics to cause any exceptions in the main
97
+ // thread so we just swallow them here.
98
+ this.logger.warn('Failed to post analytics to Flagsmith API. Not clearing data, will retry.');
99
+ return [2 /*return*/];
100
+ case 4:
87
101
  this.analyticsData = {};
88
102
  this.lastFlushed = Date.now();
89
103
  return [2 /*return*/];
@@ -31,6 +31,7 @@ export declare class Flagsmith {
31
31
  private cache?;
32
32
  private onEnvironmentChange?;
33
33
  private analyticsProcessor?;
34
+ private logger;
34
35
  /**
35
36
  * A Flagsmith client.
36
37
  *
@@ -60,6 +61,7 @@ export declare class Flagsmith {
60
61
  @param data.defaultFlagHandler: callable which will be used in the case where
61
62
  flags cannot be retrieved from the API or a non existent feature is
62
63
  requested
64
+ @param data.logger: an instance of the pino Logger class to use for logging
63
65
  */
64
66
  constructor(data: FlagsmithConfig);
65
67
  /**
@@ -62,6 +62,9 @@ var __read = (this && this.__read) || function (o, n) {
62
62
  }
63
63
  return ar;
64
64
  };
65
+ var __importDefault = (this && this.__importDefault) || function (mod) {
66
+ return (mod && mod.__esModule) ? mod : { "default": mod };
67
+ };
65
68
  Object.defineProperty(exports, "__esModule", { value: true });
66
69
  exports.Flagsmith = exports.EnvironmentDataPollingManager = exports.Flags = exports.DefaultFlag = exports.FlagsmithClientError = exports.FlagsmithAPIError = exports.AnalyticsProcessor = void 0;
67
70
  var flagsmith_engine_1 = require("../flagsmith-engine");
@@ -74,6 +77,7 @@ var models_3 = require("./models");
74
77
  var polling_manager_1 = require("./polling_manager");
75
78
  var utils_1 = require("./utils");
76
79
  var evaluators_1 = require("../flagsmith-engine/segments/evaluators");
80
+ var pino_1 = __importDefault(require("pino"));
77
81
  var analytics_2 = require("./analytics");
78
82
  Object.defineProperty(exports, "AnalyticsProcessor", { enumerable: true, get: function () { return analytics_2.AnalyticsProcessor; } });
79
83
  var errors_2 = require("./errors");
@@ -115,6 +119,7 @@ var Flagsmith = /** @class */ (function () {
115
119
  @param data.defaultFlagHandler: callable which will be used in the case where
116
120
  flags cannot be retrieved from the API or a non existent feature is
117
121
  requested
122
+ @param data.logger: an instance of the pino Logger class to use for logging
118
123
  */
119
124
  function Flagsmith(data) {
120
125
  this.apiUrl = DEFAULT_API_URL;
@@ -137,6 +142,7 @@ var Flagsmith = /** @class */ (function () {
137
142
  this.identitiesUrl = "".concat(this.apiUrl, "identities/");
138
143
  this.environmentUrl = "".concat(this.apiUrl, "environment-document/");
139
144
  this.onEnvironmentChange = data.onEnvironmentChange;
145
+ this.logger = data.logger || (0, pino_1.default)();
140
146
  if (!!data.cache) {
141
147
  var missingMethods = ['has', 'get', 'set'].filter(function (method) { return data.cache && !data.cache[method]; });
142
148
  if (missingMethods.length > 0) {
@@ -156,7 +162,8 @@ var Flagsmith = /** @class */ (function () {
156
162
  ? new analytics_1.AnalyticsProcessor({
157
163
  environmentKey: this.environmentKey,
158
164
  baseApiUrl: this.apiUrl,
159
- requestTimeoutMs: this.requestTimeoutMs
165
+ requestTimeoutMs: this.requestTimeoutMs,
166
+ logger: this.logger
160
167
  })
161
168
  : undefined;
162
169
  }
@@ -1,6 +1,7 @@
1
1
  import { DefaultFlag, Flags } from "./models";
2
2
  import { EnvironmentModel } from "../flagsmith-engine";
3
3
  import { RequestInit } from "node-fetch";
4
+ import { Logger } from "pino";
4
5
  export interface FlagsmithCache {
5
6
  get(key: string): Promise<Flags | undefined> | undefined;
6
7
  set(key: string, value: Flags, ttl: string | number): boolean | Promise<boolean>;
@@ -22,4 +23,5 @@ export interface FlagsmithConfig {
22
23
  defaultFlagHandler?: (featureName: string) => DefaultFlag;
23
24
  cache?: FlagsmithCache;
24
25
  onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void;
26
+ logger?: Logger;
25
27
  }
@@ -1783,9 +1783,9 @@
1783
1783
  }
1784
1784
  },
1785
1785
  "node_modules/decode-uri-component": {
1786
- "version": "0.2.0",
1787
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
1788
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
1786
+ "version": "0.2.2",
1787
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
1788
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
1789
1789
  "dev": true,
1790
1790
  "optional": true,
1791
1791
  "engines": {
@@ -3923,13 +3923,10 @@
3923
3923
  "dev": true
3924
3924
  },
3925
3925
  "node_modules/json5": {
3926
- "version": "2.1.0",
3927
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
3928
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
3926
+ "version": "2.2.3",
3927
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3928
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3929
3929
  "dev": true,
3930
- "dependencies": {
3931
- "minimist": "^1.2.0"
3932
- },
3933
3930
  "bin": {
3934
3931
  "json5": "lib/cli.js"
3935
3932
  },
@@ -4114,9 +4111,9 @@
4114
4111
  }
4115
4112
  },
4116
4113
  "node_modules/minimatch": {
4117
- "version": "3.0.4",
4118
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
4119
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
4114
+ "version": "3.1.2",
4115
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
4116
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
4120
4117
  "dev": true,
4121
4118
  "dependencies": {
4122
4119
  "brace-expansion": "^1.1.7"
@@ -7515,9 +7512,9 @@
7515
7512
  }
7516
7513
  },
7517
7514
  "decode-uri-component": {
7518
- "version": "0.2.0",
7519
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
7520
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
7515
+ "version": "0.2.2",
7516
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
7517
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
7521
7518
  "dev": true,
7522
7519
  "optional": true
7523
7520
  },
@@ -9208,13 +9205,10 @@
9208
9205
  "dev": true
9209
9206
  },
9210
9207
  "json5": {
9211
- "version": "2.1.0",
9212
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
9213
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
9214
- "dev": true,
9215
- "requires": {
9216
- "minimist": "^1.2.0"
9217
- }
9208
+ "version": "2.2.3",
9209
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
9210
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
9211
+ "dev": true
9218
9212
  },
9219
9213
  "kind-of": {
9220
9214
  "version": "6.0.3",
@@ -9351,9 +9345,9 @@
9351
9345
  "dev": true
9352
9346
  },
9353
9347
  "minimatch": {
9354
- "version": "3.0.4",
9355
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
9356
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
9348
+ "version": "3.1.2",
9349
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
9350
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
9357
9351
  "dev": true,
9358
9352
  "requires": {
9359
9353
  "brace-expansion": "^1.1.7"
@@ -1750,9 +1750,9 @@
1750
1750
  }
1751
1751
  },
1752
1752
  "node_modules/decode-uri-component": {
1753
- "version": "0.2.0",
1754
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
1755
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
1753
+ "version": "0.2.2",
1754
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
1755
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
1756
1756
  "dev": true,
1757
1757
  "optional": true,
1758
1758
  "engines": {
@@ -3857,13 +3857,10 @@
3857
3857
  "dev": true
3858
3858
  },
3859
3859
  "node_modules/json5": {
3860
- "version": "2.1.0",
3861
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
3862
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
3860
+ "version": "2.2.3",
3861
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3862
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3863
3863
  "dev": true,
3864
- "dependencies": {
3865
- "minimist": "^1.2.0"
3866
- },
3867
3864
  "bin": {
3868
3865
  "json5": "lib/cli.js"
3869
3866
  },
@@ -4048,9 +4045,9 @@
4048
4045
  }
4049
4046
  },
4050
4047
  "node_modules/minimatch": {
4051
- "version": "3.0.4",
4052
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
4053
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
4048
+ "version": "3.1.2",
4049
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
4050
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
4054
4051
  "dev": true,
4055
4052
  "dependencies": {
4056
4053
  "brace-expansion": "^1.1.7"
@@ -4060,10 +4057,13 @@
4060
4057
  }
4061
4058
  },
4062
4059
  "node_modules/minimist": {
4063
- "version": "1.2.6",
4064
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
4065
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
4066
- "dev": true
4060
+ "version": "1.2.7",
4061
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
4062
+ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
4063
+ "dev": true,
4064
+ "funding": {
4065
+ "url": "https://github.com/sponsors/ljharb"
4066
+ }
4067
4067
  },
4068
4068
  "node_modules/mixin-deep": {
4069
4069
  "version": "1.3.2",
@@ -7426,9 +7426,9 @@
7426
7426
  }
7427
7427
  },
7428
7428
  "decode-uri-component": {
7429
- "version": "0.2.0",
7430
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
7431
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
7429
+ "version": "0.2.2",
7430
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
7431
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
7432
7432
  "dev": true,
7433
7433
  "optional": true
7434
7434
  },
@@ -9095,13 +9095,10 @@
9095
9095
  "dev": true
9096
9096
  },
9097
9097
  "json5": {
9098
- "version": "2.1.0",
9099
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
9100
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
9101
- "dev": true,
9102
- "requires": {
9103
- "minimist": "^1.2.0"
9104
- }
9098
+ "version": "2.2.3",
9099
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
9100
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
9101
+ "dev": true
9105
9102
  },
9106
9103
  "kind-of": {
9107
9104
  "version": "6.0.3",
@@ -9238,18 +9235,18 @@
9238
9235
  "dev": true
9239
9236
  },
9240
9237
  "minimatch": {
9241
- "version": "3.0.4",
9242
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
9243
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
9238
+ "version": "3.1.2",
9239
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
9240
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
9244
9241
  "dev": true,
9245
9242
  "requires": {
9246
9243
  "brace-expansion": "^1.1.7"
9247
9244
  }
9248
9245
  },
9249
9246
  "minimist": {
9250
- "version": "1.2.6",
9251
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
9252
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
9247
+ "version": "1.2.7",
9248
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
9249
+ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
9253
9250
  "dev": true
9254
9251
  },
9255
9252
  "mixin-deep": {
@@ -1078,15 +1078,19 @@
1078
1078
  }
1079
1079
  },
1080
1080
  "node_modules/ajv": {
1081
- "version": "6.10.2",
1082
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
1083
- "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
1081
+ "version": "6.12.6",
1082
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
1083
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
1084
1084
  "dev": true,
1085
1085
  "dependencies": {
1086
- "fast-deep-equal": "^2.0.1",
1086
+ "fast-deep-equal": "^3.1.1",
1087
1087
  "fast-json-stable-stringify": "^2.0.0",
1088
1088
  "json-schema-traverse": "^0.4.1",
1089
1089
  "uri-js": "^4.2.2"
1090
+ },
1091
+ "funding": {
1092
+ "type": "github",
1093
+ "url": "https://github.com/sponsors/epoberezkin"
1090
1094
  }
1091
1095
  },
1092
1096
  "node_modules/ansi-escapes": {
@@ -1099,9 +1103,9 @@
1099
1103
  }
1100
1104
  },
1101
1105
  "node_modules/ansi-regex": {
1102
- "version": "3.0.0",
1103
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
1104
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
1106
+ "version": "3.0.1",
1107
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
1108
+ "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
1105
1109
  "dev": true,
1106
1110
  "engines": {
1107
1111
  "node": ">=4"
@@ -1235,17 +1239,31 @@
1235
1239
  }
1236
1240
  },
1237
1241
  "node_modules/browserslist": {
1238
- "version": "4.6.6",
1239
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz",
1240
- "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==",
1242
+ "version": "4.21.4",
1243
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
1244
+ "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
1241
1245
  "dev": true,
1246
+ "funding": [
1247
+ {
1248
+ "type": "opencollective",
1249
+ "url": "https://opencollective.com/browserslist"
1250
+ },
1251
+ {
1252
+ "type": "tidelift",
1253
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1254
+ }
1255
+ ],
1242
1256
  "dependencies": {
1243
- "caniuse-lite": "^1.0.30000984",
1244
- "electron-to-chromium": "^1.3.191",
1245
- "node-releases": "^1.1.25"
1257
+ "caniuse-lite": "^1.0.30001400",
1258
+ "electron-to-chromium": "^1.4.251",
1259
+ "node-releases": "^2.0.6",
1260
+ "update-browserslist-db": "^1.0.9"
1246
1261
  },
1247
1262
  "bin": {
1248
1263
  "browserslist": "cli.js"
1264
+ },
1265
+ "engines": {
1266
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1249
1267
  }
1250
1268
  },
1251
1269
  "node_modules/bytes": {
@@ -1280,10 +1298,20 @@
1280
1298
  }
1281
1299
  },
1282
1300
  "node_modules/caniuse-lite": {
1283
- "version": "1.0.30000989",
1284
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz",
1285
- "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==",
1286
- "dev": true
1301
+ "version": "1.0.30001429",
1302
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz",
1303
+ "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==",
1304
+ "dev": true,
1305
+ "funding": [
1306
+ {
1307
+ "type": "opencollective",
1308
+ "url": "https://opencollective.com/browserslist"
1309
+ },
1310
+ {
1311
+ "type": "tidelift",
1312
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1313
+ }
1314
+ ]
1287
1315
  },
1288
1316
  "node_modules/chalk": {
1289
1317
  "version": "2.4.2",
@@ -1569,9 +1597,9 @@
1569
1597
  "dev": true
1570
1598
  },
1571
1599
  "node_modules/electron-to-chromium": {
1572
- "version": "1.3.237",
1573
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.237.tgz",
1574
- "integrity": "sha512-SPAFjDr/7iiVK2kgTluwxela6eaWjjFkS9rO/iYpB/KGXgccUom5YC7OIf19c8m8GGptWxLU0Em8xM64A/N7Fg==",
1600
+ "version": "1.4.284",
1601
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
1602
+ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
1575
1603
  "dev": true
1576
1604
  },
1577
1605
  "node_modules/emoji-regex": {
@@ -1589,6 +1617,15 @@
1589
1617
  "node": ">= 0.8"
1590
1618
  }
1591
1619
  },
1620
+ "node_modules/escalade": {
1621
+ "version": "3.1.1",
1622
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
1623
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
1624
+ "dev": true,
1625
+ "engines": {
1626
+ "node": ">=6"
1627
+ }
1628
+ },
1592
1629
  "node_modules/escape-html": {
1593
1630
  "version": "1.0.3",
1594
1631
  "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1900,9 +1937,9 @@
1900
1937
  }
1901
1938
  },
1902
1939
  "node_modules/fast-deep-equal": {
1903
- "version": "2.0.1",
1904
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
1905
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
1940
+ "version": "3.1.3",
1941
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
1942
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
1906
1943
  "dev": true
1907
1944
  },
1908
1945
  "node_modules/fast-diff": {
@@ -2420,13 +2457,10 @@
2420
2457
  "dev": true
2421
2458
  },
2422
2459
  "node_modules/json5": {
2423
- "version": "2.1.0",
2424
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
2425
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
2460
+ "version": "2.2.3",
2461
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
2462
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
2426
2463
  "dev": true,
2427
- "dependencies": {
2428
- "minimist": "^1.2.0"
2429
- },
2430
2464
  "bin": {
2431
2465
  "json5": "lib/cli.js"
2432
2466
  },
@@ -2659,13 +2693,10 @@
2659
2693
  }
2660
2694
  },
2661
2695
  "node_modules/node-releases": {
2662
- "version": "1.1.28",
2663
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.28.tgz",
2664
- "integrity": "sha512-AQw4emh6iSXnCpDiFe0phYcThiccmkNWMZnFZ+lDJjAP8J0m2fVd59duvUUyuTirQOhIAajTFkzG6FHCLBO59g==",
2665
- "dev": true,
2666
- "dependencies": {
2667
- "semver": "^5.3.0"
2668
- }
2696
+ "version": "2.0.6",
2697
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
2698
+ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
2699
+ "dev": true
2669
2700
  },
2670
2701
  "node_modules/nodemon": {
2671
2702
  "version": "2.0.19",
@@ -2878,6 +2909,12 @@
2878
2909
  "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
2879
2910
  "dev": true
2880
2911
  },
2912
+ "node_modules/picocolors": {
2913
+ "version": "1.0.0",
2914
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
2915
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
2916
+ "dev": true
2917
+ },
2881
2918
  "node_modules/picomatch": {
2882
2919
  "version": "2.3.1",
2883
2920
  "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -3404,9 +3441,9 @@
3404
3441
  }
3405
3442
  },
3406
3443
  "node_modules/strip-ansi/node_modules/ansi-regex": {
3407
- "version": "4.1.0",
3408
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
3409
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
3444
+ "version": "4.1.1",
3445
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
3446
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
3410
3447
  "dev": true,
3411
3448
  "engines": {
3412
3449
  "node": ">=6"
@@ -3628,6 +3665,32 @@
3628
3665
  "node": ">= 0.8"
3629
3666
  }
3630
3667
  },
3668
+ "node_modules/update-browserslist-db": {
3669
+ "version": "1.0.10",
3670
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
3671
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
3672
+ "dev": true,
3673
+ "funding": [
3674
+ {
3675
+ "type": "opencollective",
3676
+ "url": "https://opencollective.com/browserslist"
3677
+ },
3678
+ {
3679
+ "type": "tidelift",
3680
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
3681
+ }
3682
+ ],
3683
+ "dependencies": {
3684
+ "escalade": "^3.1.1",
3685
+ "picocolors": "^1.0.0"
3686
+ },
3687
+ "bin": {
3688
+ "browserslist-lint": "cli.js"
3689
+ },
3690
+ "peerDependencies": {
3691
+ "browserslist": ">= 4.21.0"
3692
+ }
3693
+ },
3631
3694
  "node_modules/uri-js": {
3632
3695
  "version": "4.2.2",
3633
3696
  "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -4612,12 +4675,12 @@
4612
4675
  "requires": {}
4613
4676
  },
4614
4677
  "ajv": {
4615
- "version": "6.10.2",
4616
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
4617
- "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
4678
+ "version": "6.12.6",
4679
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
4680
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
4618
4681
  "dev": true,
4619
4682
  "requires": {
4620
- "fast-deep-equal": "^2.0.1",
4683
+ "fast-deep-equal": "^3.1.1",
4621
4684
  "fast-json-stable-stringify": "^2.0.0",
4622
4685
  "json-schema-traverse": "^0.4.1",
4623
4686
  "uri-js": "^4.2.2"
@@ -4630,9 +4693,9 @@
4630
4693
  "dev": true
4631
4694
  },
4632
4695
  "ansi-regex": {
4633
- "version": "3.0.0",
4634
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
4635
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
4696
+ "version": "3.0.1",
4697
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
4698
+ "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
4636
4699
  "dev": true
4637
4700
  },
4638
4701
  "ansi-styles": {
@@ -4741,14 +4804,15 @@
4741
4804
  }
4742
4805
  },
4743
4806
  "browserslist": {
4744
- "version": "4.6.6",
4745
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz",
4746
- "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==",
4807
+ "version": "4.21.4",
4808
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
4809
+ "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
4747
4810
  "dev": true,
4748
4811
  "requires": {
4749
- "caniuse-lite": "^1.0.30000984",
4750
- "electron-to-chromium": "^1.3.191",
4751
- "node-releases": "^1.1.25"
4812
+ "caniuse-lite": "^1.0.30001400",
4813
+ "electron-to-chromium": "^1.4.251",
4814
+ "node-releases": "^2.0.6",
4815
+ "update-browserslist-db": "^1.0.9"
4752
4816
  }
4753
4817
  },
4754
4818
  "bytes": {
@@ -4774,9 +4838,9 @@
4774
4838
  "dev": true
4775
4839
  },
4776
4840
  "caniuse-lite": {
4777
- "version": "1.0.30000989",
4778
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz",
4779
- "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==",
4841
+ "version": "1.0.30001429",
4842
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz",
4843
+ "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==",
4780
4844
  "dev": true
4781
4845
  },
4782
4846
  "chalk": {
@@ -4996,9 +5060,9 @@
4996
5060
  "dev": true
4997
5061
  },
4998
5062
  "electron-to-chromium": {
4999
- "version": "1.3.237",
5000
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.237.tgz",
5001
- "integrity": "sha512-SPAFjDr/7iiVK2kgTluwxela6eaWjjFkS9rO/iYpB/KGXgccUom5YC7OIf19c8m8GGptWxLU0Em8xM64A/N7Fg==",
5063
+ "version": "1.4.284",
5064
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
5065
+ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
5002
5066
  "dev": true
5003
5067
  },
5004
5068
  "emoji-regex": {
@@ -5013,6 +5077,12 @@
5013
5077
  "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
5014
5078
  "dev": true
5015
5079
  },
5080
+ "escalade": {
5081
+ "version": "3.1.1",
5082
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
5083
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
5084
+ "dev": true
5085
+ },
5016
5086
  "escape-html": {
5017
5087
  "version": "1.0.3",
5018
5088
  "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -5248,9 +5318,9 @@
5248
5318
  }
5249
5319
  },
5250
5320
  "fast-deep-equal": {
5251
- "version": "2.0.1",
5252
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
5253
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
5321
+ "version": "3.1.3",
5322
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
5323
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
5254
5324
  "dev": true
5255
5325
  },
5256
5326
  "fast-diff": {
@@ -5658,13 +5728,10 @@
5658
5728
  "dev": true
5659
5729
  },
5660
5730
  "json5": {
5661
- "version": "2.1.0",
5662
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
5663
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
5664
- "dev": true,
5665
- "requires": {
5666
- "minimist": "^1.2.0"
5667
- }
5731
+ "version": "2.2.3",
5732
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
5733
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
5734
+ "dev": true
5668
5735
  },
5669
5736
  "levn": {
5670
5737
  "version": "0.3.0",
@@ -5835,13 +5902,10 @@
5835
5902
  }
5836
5903
  },
5837
5904
  "node-releases": {
5838
- "version": "1.1.28",
5839
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.28.tgz",
5840
- "integrity": "sha512-AQw4emh6iSXnCpDiFe0phYcThiccmkNWMZnFZ+lDJjAP8J0m2fVd59duvUUyuTirQOhIAajTFkzG6FHCLBO59g==",
5841
- "dev": true,
5842
- "requires": {
5843
- "semver": "^5.3.0"
5844
- }
5905
+ "version": "2.0.6",
5906
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
5907
+ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
5908
+ "dev": true
5845
5909
  },
5846
5910
  "nodemon": {
5847
5911
  "version": "2.0.19",
@@ -6003,6 +6067,12 @@
6003
6067
  "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
6004
6068
  "dev": true
6005
6069
  },
6070
+ "picocolors": {
6071
+ "version": "1.0.0",
6072
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
6073
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
6074
+ "dev": true
6075
+ },
6006
6076
  "picomatch": {
6007
6077
  "version": "2.3.1",
6008
6078
  "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -6411,9 +6481,9 @@
6411
6481
  },
6412
6482
  "dependencies": {
6413
6483
  "ansi-regex": {
6414
- "version": "4.1.0",
6415
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
6416
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
6484
+ "version": "4.1.1",
6485
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
6486
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
6417
6487
  "dev": true
6418
6488
  }
6419
6489
  }
@@ -6585,6 +6655,16 @@
6585
6655
  "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
6586
6656
  "dev": true
6587
6657
  },
6658
+ "update-browserslist-db": {
6659
+ "version": "1.0.10",
6660
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
6661
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
6662
+ "dev": true,
6663
+ "requires": {
6664
+ "escalade": "^3.1.1",
6665
+ "picocolors": "^1.0.0"
6666
+ }
6667
+ },
6588
6668
  "uri-js": {
6589
6669
  "version": "4.2.2",
6590
6670
  "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -2457,13 +2457,10 @@
2457
2457
  "dev": true
2458
2458
  },
2459
2459
  "node_modules/json5": {
2460
- "version": "2.1.0",
2461
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
2462
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
2460
+ "version": "2.2.3",
2461
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
2462
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
2463
2463
  "dev": true,
2464
- "dependencies": {
2465
- "minimist": "^1.2.0"
2466
- },
2467
2464
  "bin": {
2468
2465
  "json5": "lib/cli.js"
2469
2466
  },
@@ -5731,13 +5728,10 @@
5731
5728
  "dev": true
5732
5729
  },
5733
5730
  "json5": {
5734
- "version": "2.1.0",
5735
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
5736
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
5737
- "dev": true,
5738
- "requires": {
5739
- "minimist": "^1.2.0"
5740
- }
5731
+ "version": "2.2.3",
5732
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
5733
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
5734
+ "dev": true
5741
5735
  },
5742
5736
  "levn": {
5743
5737
  "version": "0.3.0",
@@ -2424,13 +2424,10 @@
2424
2424
  "dev": true
2425
2425
  },
2426
2426
  "node_modules/json5": {
2427
- "version": "2.1.0",
2428
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
2429
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
2427
+ "version": "2.2.3",
2428
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
2429
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
2430
2430
  "dev": true,
2431
- "dependencies": {
2432
- "minimist": "^1.2.0"
2433
- },
2434
2431
  "bin": {
2435
2432
  "json5": "lib/cli.js"
2436
2433
  },
@@ -5662,13 +5659,10 @@
5662
5659
  "dev": true
5663
5660
  },
5664
5661
  "json5": {
5665
- "version": "2.1.0",
5666
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
5667
- "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
5668
- "dev": true,
5669
- "requires": {
5670
- "minimist": "^1.2.0"
5671
- }
5662
+ "version": "2.2.3",
5663
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
5664
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
5665
+ "dev": true
5672
5666
  },
5673
5667
  "levn": {
5674
5668
  "version": "0.3.0",
@@ -19,6 +19,7 @@ export const PERCENTAGE_SPLIT = 'PERCENTAGE_SPLIT';
19
19
  export const IS_SET = 'IS_SET';
20
20
  export const IS_NOT_SET = 'IS_NOT_SET';
21
21
  export const MODULO = 'MODULO';
22
+ export const IN = 'IN';
22
23
 
23
24
  export const CONDITION_OPERATORS = {
24
25
  EQUAL,
@@ -33,5 +34,6 @@ export const CONDITION_OPERATORS = {
33
34
  PERCENTAGE_SPLIT,
34
35
  IS_SET,
35
36
  IS_NOT_SET,
36
- MODULO
37
+ MODULO,
38
+ IN
37
39
  };
@@ -9,6 +9,7 @@ import {
9
9
  NOT_CONTAINS,
10
10
  REGEX,
11
11
  MODULO,
12
+ IN,
12
13
  CONDITION_OPERATORS
13
14
  } from './constants';
14
15
  import { isSemver } from './util';
@@ -47,6 +48,7 @@ export class SegmentConditionModel {
47
48
  [NOT_CONTAINS]: 'evaluateNotContains',
48
49
  [REGEX]: 'evaluateRegex',
49
50
  [MODULO]: 'evaluateModulo',
51
+ [IN]: 'evaluateIn'
50
52
  };
51
53
 
52
54
  operator: string;
@@ -74,7 +76,10 @@ export class SegmentConditionModel {
74
76
  const parts = (this.value).split("|");
75
77
  const [divisor, reminder] = [parseFloat(parts[0]), parseFloat(parts[1])];
76
78
  return traitValue % divisor === reminder
77
- }
79
+ },
80
+ evaluateIn: (traitValue: any) => {
81
+ return this.value?.split(',').includes(traitValue.toString())
82
+ },
78
83
  };
79
84
 
80
85
  // TODO: move this logic to the evaluator module
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flagsmith-nodejs",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.",
5
5
  "main": "build/index.js",
6
6
  "repository": {
@@ -54,6 +54,7 @@
54
54
  "big-integer": "^1.6.51",
55
55
  "md5": "^2.3.0",
56
56
  "node-fetch": "^2.1.2",
57
+ "pino": "^8.8.0",
57
58
  "semver": "^7.3.7",
58
59
  "uuid": "^8.3.2"
59
60
  },
package/sdk/analytics.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import fetch from 'node-fetch';
2
+ import pino, { Logger } from 'pino';
2
3
 
3
4
  const ANALYTICS_ENDPOINT = 'analytics/flags/';
4
5
 
@@ -11,21 +12,24 @@ export class AnalyticsProcessor {
11
12
  private lastFlushed: number;
12
13
  analyticsData: { [key: string]: any };
13
14
  private requestTimeoutMs: number = 3000;
15
+ private logger: Logger;
16
+
14
17
  /**
15
- * AnalyticsProcessor is used to track how often individual Flags are evaluated within
18
+ * AnalyticsProcessor is used to track how often individual Flags are evaluated within
16
19
  * the Flagsmith SDK. Docs: https://docs.flagsmith.com/advanced-use/flag-analytics.
17
- *
20
+ *
18
21
  * @param data.environmentKey environment key obtained from the Flagsmith UI
19
22
  * @param data.baseApiUrl base api url to override when using self hosted version
20
23
  * @param data.requestTimeoutMs used to tell requests to stop waiting for a response after a
21
24
  given number of milliseconds
22
25
  */
23
- constructor(data: { environmentKey: string; baseApiUrl: string; requestTimeoutMs?: number }) {
26
+ constructor(data: { environmentKey: string; baseApiUrl: string; requestTimeoutMs?: number, logger?: Logger }) {
24
27
  this.analyticsEndpoint = data.baseApiUrl + ANALYTICS_ENDPOINT;
25
28
  this.environmentKey = data.environmentKey;
26
29
  this.lastFlushed = Date.now();
27
30
  this.analyticsData = {};
28
31
  this.requestTimeoutMs = data.requestTimeoutMs || this.requestTimeoutMs;
32
+ this.logger = data.logger || pino();
29
33
  }
30
34
  /**
31
35
  * Sends all the collected data to the api asynchronously and resets the timer
@@ -35,15 +39,22 @@ export class AnalyticsProcessor {
35
39
  return;
36
40
  }
37
41
 
38
- await fetch(this.analyticsEndpoint, {
39
- method: 'POST',
40
- body: JSON.stringify(this.analyticsData),
41
- timeout: this.requestTimeoutMs,
42
- headers: {
43
- 'Content-Type': 'application/json',
44
- 'X-Environment-Key': this.environmentKey
45
- }
46
- });
42
+ try {
43
+ await fetch(this.analyticsEndpoint, {
44
+ method: 'POST',
45
+ body: JSON.stringify(this.analyticsData),
46
+ timeout: this.requestTimeoutMs,
47
+ headers: {
48
+ 'Content-Type': 'application/json',
49
+ 'X-Environment-Key': this.environmentKey
50
+ }
51
+ })
52
+ } catch (error) {
53
+ // We don't want failing to write analytics to cause any exceptions in the main
54
+ // thread so we just swallow them here.
55
+ this.logger.warn('Failed to post analytics to Flagsmith API. Not clearing data, will retry.')
56
+ return;
57
+ }
47
58
 
48
59
  this.analyticsData = {};
49
60
  this.lastFlushed = Date.now();
package/sdk/index.ts CHANGED
@@ -14,6 +14,7 @@ import { generateIdentitiesData, retryFetch } from './utils';
14
14
  import { SegmentModel } from '../flagsmith-engine/segments/models';
15
15
  import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators';
16
16
  import { FlagsmithCache, FlagsmithConfig } from './types';
17
+ import pino, { Logger } from "pino";
17
18
 
18
19
  export { AnalyticsProcessor } from './analytics';
19
20
  export { FlagsmithAPIError, FlagsmithClientError } from './errors';
@@ -49,6 +50,7 @@ export class Flagsmith {
49
50
  private cache?: FlagsmithCache;
50
51
  private onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void;
51
52
  private analyticsProcessor?: AnalyticsProcessor;
53
+ private logger: Logger;
52
54
  /**
53
55
  * A Flagsmith client.
54
56
  *
@@ -78,6 +80,7 @@ export class Flagsmith {
78
80
  @param data.defaultFlagHandler: callable which will be used in the case where
79
81
  flags cannot be retrieved from the API or a non existent feature is
80
82
  requested
83
+ @param data.logger: an instance of the pino Logger class to use for logging
81
84
  */
82
85
  constructor(data: FlagsmithConfig) {
83
86
  this.agent = data.agent;
@@ -97,6 +100,7 @@ export class Flagsmith {
97
100
  this.identitiesUrl = `${this.apiUrl}identities/`;
98
101
  this.environmentUrl = `${this.apiUrl}environment-document/`;
99
102
  this.onEnvironmentChange = data.onEnvironmentChange;
103
+ this.logger = data.logger || pino();
100
104
 
101
105
  if (!!data.cache) {
102
106
  const missingMethods: string[] = ['has', 'get', 'set'].filter(method => data.cache && !data.cache[method]);
@@ -129,7 +133,8 @@ export class Flagsmith {
129
133
  ? new AnalyticsProcessor({
130
134
  environmentKey: this.environmentKey,
131
135
  baseApiUrl: this.apiUrl,
132
- requestTimeoutMs: this.requestTimeoutMs
136
+ requestTimeoutMs: this.requestTimeoutMs,
137
+ logger: this.logger
133
138
  })
134
139
  : undefined;
135
140
  }
package/sdk/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { DefaultFlag, Flags } from "./models";
2
2
  import { EnvironmentModel } from "../flagsmith-engine";
3
3
  import { RequestInit } from "node-fetch";
4
+ import { Logger } from "pino";
4
5
 
5
6
  export interface FlagsmithCache {
6
7
  get(key: string): Promise<Flags|undefined> | undefined;
@@ -22,4 +23,5 @@ export interface FlagsmithConfig {
22
23
  defaultFlagHandler?: (featureName: string) => DefaultFlag;
23
24
  cache?: FlagsmithCache,
24
25
  onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void,
26
+ logger?: Logger
25
27
  }
@@ -89,16 +89,23 @@ const conditionMatchCases: [string, string | number | boolean, string, boolean][
89
89
  [CONDITION_OPERATORS.MODULO, 35.0, "4|3", true],
90
90
  [CONDITION_OPERATORS.MODULO, "foo", "4|3", false],
91
91
  [CONDITION_OPERATORS.MODULO, 35.0, "foo|bar", false],
92
+ [CONDITION_OPERATORS.IN, "foo", "", false],
93
+ [CONDITION_OPERATORS.IN, "foo", "foo, bar", true],
94
+ [CONDITION_OPERATORS.IN, "foo", "foo", true],
95
+ [CONDITION_OPERATORS.IN, 1, "1,2,3,4", true],
96
+ [CONDITION_OPERATORS.IN, 1, "", false],
97
+ [CONDITION_OPERATORS.IN, 1, "1", true],
92
98
  ['BAD_OP', 'a', 'a', false]
93
99
  ];
94
100
 
95
101
  test('test_segment_condition_matches_trait_value', () => {
96
102
  for (const testCase of conditionMatchCases) {
103
+ const [operator, traitValue, conditionValue, expectedResult] = testCase
97
104
  expect(
98
- new SegmentConditionModel(testCase[0], testCase[2], 'foo').matchesTraitValue(
99
- testCase[1]
105
+ new SegmentConditionModel(operator, conditionValue, 'foo').matchesTraitValue(
106
+ traitValue
100
107
  )
101
- ).toBe(testCase[3]);
108
+ ).toBe(expectedResult);
102
109
  }
103
110
  });
104
111
 
@@ -1,7 +1,8 @@
1
- jest.mock('node-fetch');
2
1
  import fetch from 'node-fetch';
3
2
  import { analyticsProcessor } from './utils';
4
3
 
4
+ jest.mock('node-fetch', () => jest.fn());
5
+
5
6
  afterEach(() => {
6
7
  jest.clearAllMocks();
7
8
  });
@@ -52,3 +53,22 @@ test('test_analytics_processor_flush_early_exit_if_analytics_data_is_empty', asy
52
53
  await aP.flush();
53
54
  expect(fetch).not.toHaveBeenCalled();
54
55
  });
56
+
57
+
58
+ test('errors in fetch sending analytics data are swallowed', async () => {
59
+ // Given
60
+ // we mock the fetch function to throw and error to mimick a network failure
61
+ (fetch as jest.MockedFunction<typeof fetch>).mockRejectedValue(new Error('some error'));
62
+
63
+ // and create the processor and track a feature so there is some analytics data
64
+ const processor = analyticsProcessor();
65
+ processor.trackFeature('myFeature');
66
+
67
+ // When
68
+ // we flush the data to trigger the call to fetch
69
+ await processor.flush();
70
+
71
+ // Then
72
+ // we expect that fetch was called but the exception was handled
73
+ expect(fetch).toHaveBeenCalled();
74
+ })