Skip to content

Commit c2e5f5d

Browse files
LaunchDarklyReleaseBoteli-darklyzmdavisLaunchDarklyCIbwoskow-ld
authored
prepare 3.5.1 release (#63)
* initial move of code from js-client-sdk-private * changelog note * rm obsolete comment * add npm audit helper * update babel, jest, rollup * fix rollup config * fix ES build, dependency cleanup * add Releaser metadata * Update babel config to work in `test` without `useBuiltIns` * copyedits * fix misnamed directory * use spread operator instead of Object.assign * add issue templates * add babel-eslint * add event capacity config property * re-add deprecation warning on samplingInterval * better config validation * remove rollup-plugins-node-resolve * use newer Rollup node-resolve plugin * rm rollup-plugin-includepaths (unused) * npm audit fix (handlebars dependency from jest) * comment * copyedit * use new test helpers + misc test cleanup * clean up stream testing logic * fix hash parameter * linter * clearer way to model the config option defaults/types * test improvements * change internal param name * comment * fix default logger logic * simpler way to enforce minimum values * implement diagnostic events in common JS package (#11) * add support for function type in config options * add support for function type in config options (#13) * add wrapper metadata options and fix custom header logic * lint * lint * remove image-loading logic from common code, replace it with an abstraction * add validation for options.streaming * typo * rm unused params * typo in comment * misc fixes to merged code from external PR * add event payload ID header * npm audit fix * change exact dependencies to best-compatible * standardize linting * disallow "window" and "document" * improve diag event tests + debug logging * misc cleanup * fix updating secure mode hash with identify() * don't omit streamInits.failed when it's false * clean up init state logic, prevent unhandled rejections * lint * less strict matching of json content-type header * remove unsafe usage of hasOwnProperty * console logger must tolerate console object not always existing * fix double initialization of diagnostics manager * fix TypeScript declaration for track() and add more TS compilation tests (#27) * remove startsWith usage (#28) * prevent poll caused by a stream ping from overwriting later poll for another user (#29) * upgrade jest dependency and transitive yargs-parser dependency (#30) * Add null to LDEvaluationDetail.reason type (#31) * Revert "Add null to LDEvaluationDetail.reason type (#31)" This reverts commit bcb1573. * Revert "Add null to LDEvaluationDetail.reason type (#31)" This reverts commit bcb1573. * nullable evaluation reason (#32) * adding alias event functionality (#33) * set stream read timeout * Add prepare script (#34) * add a missing typescript verification (#36) * Removed the guides link * Correct doc link (#36) * Fix typo in LDClient.on jsdoc (#37) * add inlineUsersInEvents option in TypeScript (#37) * Filter private attributes on debug event users. Send variation for debug events. * update uuid package version (#39) * use Releaser v2 config + newer CI image * First half, add the type, create the new options, add the new util method, and add tests * Second half, call the tranform util method before calling any HTTP requests * Update the transform to work on a copy of headers instead of mutating it * add comments about removing custom event warning logic in the future * revert updating of UUID dependency (#43) * Revert "update uuid package version (#39)" This reverts commit 3b2ff6c. * update package-lock.json * better error handling for local storage operations (#44) * better error handling for local storage operations * lint * fix obsolete comments * add basic logger similar to server-side Node SDK (#45) * fix exports and add validation of custom logger (#46) * remove typedoc.js file that interferes with Releaser's docs build * update typescript version * add maintenance branch * backport sc-142333 fix Co-authored-by: Eli Bishop <eli@launchdarkly.com> Co-authored-by: Zach Davis <zach@launchdarkly.com> Co-authored-by: LaunchDarklyCI <dev@launchdarkly.com> Co-authored-by: Ben Woskow <bwoskow@launchdarkly.com> Co-authored-by: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Co-authored-by: Michael Siadak <mike.siadak@gmail.com> Co-authored-by: Jeff Wen <sinchangwen@gmail.com> Co-authored-by: Andrey Krasnov <34657799+Doesntmeananything@users.noreply.github.com> Co-authored-by: Gavin Whelan <gwhelan@launchdarkly.com> Co-authored-by: LaunchDarklyReleaseBot <launchdarklyreleasebot@launchdarkly.com> Co-authored-by: Louis Chan <lchan@launchdarkly.com> Co-authored-by: Louis Chan <91093020+louis-launchdarkly@users.noreply.github.com>
1 parent a360fa1 commit c2e5f5d

File tree

6 files changed

+66
-15
lines changed

6 files changed

+66
-15
lines changed

.ldrelease/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ repo:
44
public: js-sdk-common
55
private: js-sdk-common-private
66

7+
branches:
8+
- name: master
9+
description: 4.x
10+
- name: 3.x
11+
712
publications:
813
- url: https://www.npmjs.com/package/launchdarkly-js-sdk-common
914
description: npm

docs/typedoc.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/__tests__/LDClient-streaming-test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as messages from '../messages';
12
import * as utils from '../utils';
23

34
import { AsyncQueue, eventSink, sleepAsync, withCloseable } from 'launchdarkly-js-test-helpers';
@@ -650,6 +651,38 @@ describe('LDClient streaming', () => {
650651
});
651652
});
652653

654+
describe('emits error if malformed JSON is received', () => {
655+
const doMalformedJsonEventTest = async (eventName, eventData) => {
656+
// First, verify that there isn't an unhandled rejection if we're not listening for an error
657+
await withClientAndServer({}, async client => {
658+
await client.waitForInitialization();
659+
client.setStreaming(true);
660+
661+
const stream = await expectStreamConnecting(fullStreamUrlWithUser);
662+
stream.eventSource.mockEmit(eventName, { data: eventData });
663+
});
664+
665+
// Then, repeat the test using a listener to observe the error event
666+
await withClientAndServer({}, async client => {
667+
const errorEvents = new AsyncQueue();
668+
client.on('error', e => errorEvents.add(e));
669+
670+
await client.waitForInitialization();
671+
client.setStreaming(true);
672+
673+
const stream = await expectStreamConnecting(fullStreamUrlWithUser);
674+
stream.eventSource.mockEmit(eventName, { data: eventData });
675+
676+
const e = await errorEvents.take();
677+
expect(e.message).toEqual(messages.invalidData());
678+
});
679+
};
680+
681+
it('in put event', async () => doMalformedJsonEventTest('put', '{no'));
682+
it('in patch event', async () => doMalformedJsonEventTest('patch', '{no'));
683+
it('in delete event', async () => doMalformedJsonEventTest('delete', '{no'));
684+
});
685+
653686
it('reconnects to stream if the user changes', async () => {
654687
const user2 = { key: 'user2' };
655688
const encodedUser2 = 'eyJrZXkiOiJ1c2VyMiJ9';

src/errors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const LDInvalidUserError = createCustomError('LaunchDarklyInvalidUserErro
1818
export const LDInvalidEventKeyError = createCustomError('LaunchDarklyInvalidEventKeyError');
1919
export const LDInvalidArgumentError = createCustomError('LaunchDarklyInvalidArgumentError');
2020
export const LDFlagFetchError = createCustomError('LaunchDarklyFlagFetchError');
21+
export const LDInvalidDataError = createCustomError('LaunchDarklyInvalidDataError');
2122

2223
export function isHttpErrorRecoverable(status) {
2324
if (status >= 400 && status < 500) {

src/index.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,14 @@ export function initialize(env, user, specifiedOptions, platform, extraOptionDef
386386
if (!ident.getUser()) {
387387
return;
388388
}
389+
const tryParseData = jsonData => {
390+
try {
391+
return JSON.parse(jsonData);
392+
} catch (err) {
393+
emitter.maybeReportError(new errors.LDInvalidDataError(messages.invalidData()));
394+
return undefined;
395+
}
396+
};
389397
stream.connect(ident.getUser(), hash, {
390398
ping: function() {
391399
logger.debug(messages.debugStreamPing());
@@ -404,12 +412,20 @@ export function initialize(env, user, specifiedOptions, platform, extraOptionDef
404412
});
405413
},
406414
put: function(e) {
407-
const data = JSON.parse(e.data);
415+
const data = tryParseData(e.data);
416+
if (!data) {
417+
return;
418+
}
408419
logger.debug(messages.debugStreamPut());
409-
replaceAllFlags(data); // don't wait for this Promise to be resolved
420+
replaceAllFlags(data);
421+
// Don't wait for this Promise to be resolved; note that replaceAllFlags is guaranteed
422+
// never to have an unhandled rejection
410423
},
411424
patch: function(e) {
412-
const data = JSON.parse(e.data);
425+
const data = tryParseData(e.data);
426+
if (!data) {
427+
return;
428+
}
413429
// If both the flag and the patch have a version property, then the patch version must be
414430
// greater than the flag version for us to accept the patch. If either one has no version
415431
// then the patch always succeeds.
@@ -432,7 +448,10 @@ export function initialize(env, user, specifiedOptions, platform, extraOptionDef
432448
}
433449
},
434450
delete: function(e) {
435-
const data = JSON.parse(e.data);
451+
const data = tryParseData(e.data);
452+
if (!data) {
453+
return;
454+
}
436455
if (!flags[data.key] || flags[data.key].version < data.version) {
437456
logger.debug(messages.debugStreamDelete(data.key));
438457
const mods = {};

src/messages.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export const invalidUser = function() {
6868
return 'Invalid user specified.' + docLink;
6969
};
7070

71+
export const invalidData = function() {
72+
return 'Invalid data received from LaunchDarkly; connection may have been interrupted';
73+
};
74+
7175
export const bootstrapOldFormat = function() {
7276
return (
7377
'LaunchDarkly client was initialized with bootstrap data that did not include flag metadata. ' +

0 commit comments

Comments
 (0)