launchdarkly-js-sdk-common 4.1.0 → 4.2.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.
- package/.ldrelease/config.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/__tests__/configuration-test.js +27 -21
- package/src/__tests__/diagnosticEvents-test.js +0 -2
- package/src/configuration.js +14 -9
- package/src/diagnosticEvents.js +0 -1
- package/src/index.js +1 -11
- package/src/messages.js +3 -0
- package/typings.d.ts +8 -4
package/.ldrelease/config.yml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the `launchdarkly-js-sdk-common` package will be documented in this file. Changes that affect the dependent SDKs such as `launchdarkly-js-client-sdk` should also be logged in those projects, in the next release that uses the updated version of this package. This project adheres to [Semantic Versioning](http://semver.org).
|
|
4
4
|
|
|
5
|
+
## [4.1.1] - 2022-06-07
|
|
6
|
+
### Changed:
|
|
7
|
+
- Enforce a 64 character limit for `application.id` and `application.version` configuration options.
|
|
8
|
+
|
|
9
|
+
### Fixed:
|
|
10
|
+
- Do not include deleted flags in `allFlags`.
|
|
11
|
+
|
|
12
|
+
## [4.1.0] - 2022-04-21
|
|
13
|
+
### Added:
|
|
14
|
+
- `LDOptionsBase.application`, for configuration of application metadata that may be used in LaunchDarkly analytics or other product features. This does not affect feature flag evaluations.
|
|
15
|
+
|
|
16
|
+
### Fixed:
|
|
17
|
+
- The `baseUrl`, `streamUrl`, and `eventsUrl` properties now work properly regardless of whether the URL string has a trailing slash. Previously, a trailing slash would cause request URL paths to have double slashes.
|
|
18
|
+
|
|
5
19
|
## [4.0.3] - 2022-02-16
|
|
6
20
|
### Fixed:
|
|
7
21
|
- If the SDK receives invalid JSON data from a streaming connection (possibly as a result of the connection being cut off), it now uses its regular error-handling logic: the error is emitted as an `error` event or, if there are no `error` event listeners, it is logged. Previously, it would be thrown as an unhandled exception.
|
package/package.json
CHANGED
|
@@ -44,26 +44,24 @@ describe('configuration', () => {
|
|
|
44
44
|
await listener.expectNoErrors();
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// });
|
|
66
|
-
// }
|
|
47
|
+
function checkDeprecated(oldName, newName, value) {
|
|
48
|
+
const desc = newName
|
|
49
|
+
? 'allows "' + oldName + '" as a deprecated equivalent to "' + newName + '"'
|
|
50
|
+
: 'warns that "' + oldName + '" is deprecated';
|
|
51
|
+
it(desc, async () => {
|
|
52
|
+
const listener = errorListener();
|
|
53
|
+
const config0 = {};
|
|
54
|
+
config0[oldName] = value;
|
|
55
|
+
const config1 = configuration.validate(config0, listener.emitter, null, listener.logger);
|
|
56
|
+
if (newName) {
|
|
57
|
+
expect(config1[newName]).toBe(value);
|
|
58
|
+
expect(config1[oldName]).toBeUndefined();
|
|
59
|
+
} else {
|
|
60
|
+
expect(config1[oldName]).toEqual(value);
|
|
61
|
+
}
|
|
62
|
+
await listener.expectWarningOnly(messages.deprecated(oldName, newName));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
67
65
|
|
|
68
66
|
function checkBooleanProperty(name) {
|
|
69
67
|
it('enforces boolean type and default for "' + name + '"', async () => {
|
|
@@ -103,13 +101,14 @@ describe('configuration', () => {
|
|
|
103
101
|
checkBooleanProperty('allAttributesPrivate');
|
|
104
102
|
checkBooleanProperty('sendLDHeaders');
|
|
105
103
|
checkBooleanProperty('inlineUsersInEvents');
|
|
106
|
-
checkBooleanProperty('allowFrequentDuplicateEvents');
|
|
107
104
|
checkBooleanProperty('sendEventsOnlyForVariation');
|
|
108
105
|
checkBooleanProperty('useReport');
|
|
109
106
|
checkBooleanProperty('evaluationReasons');
|
|
110
107
|
checkBooleanProperty('diagnosticOptOut');
|
|
111
108
|
checkBooleanProperty('streaming');
|
|
112
109
|
|
|
110
|
+
checkDeprecated('allowFrequentDuplicateEvents', undefined, true);
|
|
111
|
+
|
|
113
112
|
function checkNumericProperty(name, validValue) {
|
|
114
113
|
it('enforces numeric type and default for "' + name + '"', async () => {
|
|
115
114
|
await expectDefault(name);
|
|
@@ -230,6 +229,13 @@ describe('configuration', () => {
|
|
|
230
229
|
await listener.expectWarningOnly(messages.invalidTagValue('application.id'));
|
|
231
230
|
});
|
|
232
231
|
|
|
232
|
+
it('logs a warning when a tag value is too long', async () => {
|
|
233
|
+
const listener = errorListener();
|
|
234
|
+
const configIn = { application: { id: 'a'.repeat(65), version: 'b'.repeat(64) } };
|
|
235
|
+
expect(configuration.validate(configIn, listener.emitter, null, listener.logger).application.id).toBeUndefined();
|
|
236
|
+
await listener.expectWarningOnly(messages.tagValueTooLong('application.id'));
|
|
237
|
+
});
|
|
238
|
+
|
|
233
239
|
it('handles a valid application version', async () => {
|
|
234
240
|
const listener = errorListener();
|
|
235
241
|
const configIn = { application: { version: 'test-version' } };
|
|
@@ -101,7 +101,6 @@ describe('DiagnosticsManager', () => {
|
|
|
101
101
|
};
|
|
102
102
|
const defaultConfigInEvent = {
|
|
103
103
|
allAttributesPrivate: false,
|
|
104
|
-
allowFrequentDuplicateEvents: false,
|
|
105
104
|
autoAliasingOptOut: false,
|
|
106
105
|
bootstrapMode: false,
|
|
107
106
|
customBaseURI: false,
|
|
@@ -189,7 +188,6 @@ describe('DiagnosticsManager', () => {
|
|
|
189
188
|
it('sends init event on start() with custom config', async () => {
|
|
190
189
|
const configAndResultValues = [
|
|
191
190
|
[{ allAttributesPrivate: true }, { allAttributesPrivate: true }],
|
|
192
|
-
[{ allowFrequentDuplicateEvents: true }, { allowFrequentDuplicateEvents: true }],
|
|
193
191
|
[{ bootstrap: {} }, { bootstrapMode: true }],
|
|
194
192
|
[{ baseUrl: 'http://other' }, { customBaseURI: true }],
|
|
195
193
|
[{ eventsUrl: 'http://other' }, { customEventsURI: true }],
|
package/src/configuration.js
CHANGED
|
@@ -48,24 +48,28 @@ const allowedTagCharacters = /^(\w|\.|-)+$/;
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Verify that a value meets the requirements for a tag value.
|
|
51
|
-
* @param {Object} config
|
|
52
51
|
* @param {string} tagValue
|
|
52
|
+
* @param {Object} logger
|
|
53
53
|
*/
|
|
54
|
-
function validateTagValue(name,
|
|
54
|
+
function validateTagValue(name, tagValue, logger) {
|
|
55
55
|
if (typeof tagValue !== 'string' || !tagValue.match(allowedTagCharacters)) {
|
|
56
56
|
logger.warn(messages.invalidTagValue(name));
|
|
57
57
|
return undefined;
|
|
58
58
|
}
|
|
59
|
+
if (tagValue.length > 64) {
|
|
60
|
+
logger.warn(messages.tagValueTooLong(name));
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
59
63
|
return tagValue;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
function applicationConfigValidator(name,
|
|
66
|
+
function applicationConfigValidator(name, value, logger) {
|
|
63
67
|
const validated = {};
|
|
64
68
|
if (value.id) {
|
|
65
|
-
validated.id = validateTagValue(`${name}.id`,
|
|
69
|
+
validated.id = validateTagValue(`${name}.id`, value.id, logger);
|
|
66
70
|
}
|
|
67
71
|
if (value.version) {
|
|
68
|
-
validated.version = validateTagValue(`${name}.version`,
|
|
72
|
+
validated.version = validateTagValue(`${name}.version`, value.version, logger);
|
|
69
73
|
}
|
|
70
74
|
return validated;
|
|
71
75
|
}
|
|
@@ -74,9 +78,10 @@ function validate(options, emitter, extraOptionDefs, logger) {
|
|
|
74
78
|
const optionDefs = utils.extend({ logger: { default: logger } }, baseOptionDefs, extraOptionDefs);
|
|
75
79
|
|
|
76
80
|
const deprecatedOptions = {
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
81
|
+
// The property name is the deprecated name, and the property value is the preferred name if
|
|
82
|
+
// any, or null/undefined if there is no replacement. This should be removed, along with
|
|
83
|
+
// the option, in the next major version.
|
|
84
|
+
allowFrequentDuplicateEvents: undefined,
|
|
80
85
|
};
|
|
81
86
|
|
|
82
87
|
function checkDeprecatedOptions(config) {
|
|
@@ -136,7 +141,7 @@ function validate(options, emitter, extraOptionDefs, logger) {
|
|
|
136
141
|
const expectedType = optionDef.type || typeDescForValue(optionDef.default);
|
|
137
142
|
const validator = optionDef.validator;
|
|
138
143
|
if (validator) {
|
|
139
|
-
const validated = validator(name, config
|
|
144
|
+
const validated = validator(name, config[name], logger);
|
|
140
145
|
if (validated !== undefined) {
|
|
141
146
|
ret[name] = validated;
|
|
142
147
|
} else {
|
package/src/diagnosticEvents.js
CHANGED
|
@@ -201,7 +201,6 @@ function DiagnosticsManager(
|
|
|
201
201
|
usingSecureMode: !!config.hash,
|
|
202
202
|
bootstrapMode: !!config.bootstrap,
|
|
203
203
|
fetchGoalsDisabled: !config.fetchGoals,
|
|
204
|
-
allowFrequentDuplicateEvents: !!config.allowFrequentDuplicateEvents,
|
|
205
204
|
sendEventsOnlyForVariation: !!config.sendEventsOnlyForVariation,
|
|
206
205
|
autoAliasingOptOut: !!config.autoAliasingOptOut,
|
|
207
206
|
};
|
package/src/index.js
CHANGED
|
@@ -63,7 +63,6 @@ function initialize(env, user, specifiedOptions, platform, extraOptionDefs) {
|
|
|
63
63
|
|
|
64
64
|
const requestor = Requestor(platform, options, environment);
|
|
65
65
|
|
|
66
|
-
const seenRequests = {};
|
|
67
66
|
let flags = {};
|
|
68
67
|
let useLocalStorage;
|
|
69
68
|
let streamActive;
|
|
@@ -181,15 +180,6 @@ function initialize(env, user, specifiedOptions, platform, extraOptionDefs) {
|
|
|
181
180
|
const user = ident.getUser();
|
|
182
181
|
const now = new Date();
|
|
183
182
|
const value = detail ? detail.value : null;
|
|
184
|
-
if (!options.allowFrequentDuplicateEvents) {
|
|
185
|
-
const cacheKey = JSON.stringify(value) + (user && user.key ? user.key : '') + key; // see below
|
|
186
|
-
const cached = seenRequests[cacheKey];
|
|
187
|
-
// cache TTL is five minutes
|
|
188
|
-
if (cached && now - cached < 300000) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
seenRequests[cacheKey] = now;
|
|
192
|
-
}
|
|
193
183
|
|
|
194
184
|
const event = {
|
|
195
185
|
kind: 'feature',
|
|
@@ -313,7 +303,7 @@ function initialize(env, user, specifiedOptions, platform, extraOptionDefs) {
|
|
|
313
303
|
}
|
|
314
304
|
|
|
315
305
|
for (const key in flags) {
|
|
316
|
-
if (utils.objectHasOwnProperty(flags, key)) {
|
|
306
|
+
if (utils.objectHasOwnProperty(flags, key) && !flags[key].deleted) {
|
|
317
307
|
results[key] = variationDetailInternal(key, null, !options.sendEventsOnlyForVariation).value;
|
|
318
308
|
}
|
|
319
309
|
}
|
package/src/messages.js
CHANGED
|
@@ -182,6 +182,8 @@ const debugPostingDiagnosticEvent = function(event) {
|
|
|
182
182
|
|
|
183
183
|
const invalidTagValue = name => `Config option "${name}" must only contain letters, numbers, ., _ or -.`;
|
|
184
184
|
|
|
185
|
+
const tagValueTooLong = name => `Value of "${name}" was longer than 64 characters and was discarded.`;
|
|
186
|
+
|
|
185
187
|
module.exports = {
|
|
186
188
|
bootstrapInvalid,
|
|
187
189
|
bootstrapOldFormat,
|
|
@@ -217,6 +219,7 @@ module.exports = {
|
|
|
217
219
|
streamClosing,
|
|
218
220
|
streamConnecting,
|
|
219
221
|
streamError,
|
|
222
|
+
tagValueTooLong,
|
|
220
223
|
unknownCustomEventKey,
|
|
221
224
|
unknownOption,
|
|
222
225
|
userNotSpecified,
|
package/typings.d.ts
CHANGED
|
@@ -173,10 +173,13 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
173
173
|
inlineUsersInEvents?: boolean;
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
|
-
*
|
|
177
|
-
* evaluated with the same value within the last five minutes.
|
|
176
|
+
* This option is deprecated, and setting it has no effect.
|
|
178
177
|
*
|
|
179
|
-
*
|
|
178
|
+
* The behavior is now to allow frequent duplicate events.
|
|
179
|
+
*
|
|
180
|
+
* This is not a problem because most events will be summarized, and
|
|
181
|
+
* events which are not summarized are important to the operation of features such as
|
|
182
|
+
* experimentation.
|
|
180
183
|
*/
|
|
181
184
|
allowFrequentDuplicateEvents?: boolean;
|
|
182
185
|
|
|
@@ -701,7 +704,8 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
701
704
|
alias(user: LDUser, previousUser: LDUser): void;
|
|
702
705
|
|
|
703
706
|
/**
|
|
704
|
-
* Returns a map of all available flags to the current user's values.
|
|
707
|
+
* Returns a map of all available flags to the current user's values. This will send analytics
|
|
708
|
+
* events unless [[LDOptions.sendEventsOnlyForVariation]] is true.
|
|
705
709
|
*
|
|
706
710
|
* @returns
|
|
707
711
|
* An object in which each key is a feature flag key and each value is the flag value.
|