launchdarkly / js-client-sdk Goto Github PK
View Code? Open in Web Editor NEWLaunchDarkly Client-side SDK for Browser JavaScript
License: Other
LaunchDarkly Client-side SDK for Browser JavaScript
License: Other
I'm getting below minor warning in console. It would be great, if we can fix it.
[LaunchDarkly] "default export" is deprecated, please use "named LDClient export"
When I implement...
client.on('change', (allFlagChanges) => {
// do stuff
})
It works for about 5 minutes or so, then after a couple of failed heartbeats, it stops heartbeating and the on('change') stops working. The failure is ERR_INCOMPLETE_CHUNKED_ENCODING however the status is a 200 OK. Request URL: https://clientstream.launchdarkly.com/eval/ProbablyClientToken/ReallyReallyReallyLongToken
Is there some sort of work around for this or a way of detecting if the heartbeat is lost so I could maybe reinitialize the client or something?
I am attempting to import LDClient
into an Angular service and I'm getting an interesting error. I am following this post from the LaunchDarkly blog.
import * as LDClient from 'ldclient-js'
When I use LDClient
as the documentation suggests:
this.ldClient = LDClient.initialize('abc123def456', {...})
I get the following error in the console:
AppComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: LDClient.initialize is not a function
at new LaunchDarklyService (launchdarkly.service.ts:16)
at _createClass (core.js:10931)
at _createProviderInstance$1 (core.js:10907)
at resolveNgModuleDep (core.js:10892)
at NgModuleRef_.get (core.js:12129)
at resolveDep (core.js:12619)
at createClass (core.js:12489)
at createDirectiveInstance (core.js:12326)
at createViewNodes (core.js:13784)
at createRootView (core.js:13673)
I logged the LDClient
into the console and saw a method default
and was able to get this working by calling LDClient.default.initialize(...)
this.ldClient = LDClient.default.initialize('abc123def456', {...})
Version:
"ldclient-js": "^1.7.0"
Any idea what I'm doing wrong? Thanks!
Right now we cache flag settings for the user based on key. However, if you change user attributes we should invalidate the cache. Really, the cache setting should be for the entire user object:
https://github.com/launchdarkly/js-client/blob/master/src/index.js#L183
One thing to be careful of is that we do not want to potentially use unbounded local storage-- we should fix the number of settings / ensure that we purge stale entries somehow.
Would be great to have some typescript typings for this library! (sister of this issue)
Please add support for Bower as dependency manager.
We need it for our project where is not sutiable to use NPM.
Thanks!
Hi there,
Firstly, thanks for this great service. It's working fantastically well for us.
We have an application which involves a fair bit of user state changing - logging in and out, setting different properties, etc. For each of these changes, we want to identify(user)
to get the appropriate feature flags. I'm already bootstrapping from localStorage
during initialize()
, and I can's see a good reason why the identify()
function doesn't also make use of this cache. I'd be happy if identify()
used the last-known values from localStorage
, whilst in the background loading the fresh values from the network, populating localStorage
, and perhaps firing the change
event if there's an update.
Could this work? I may well have missed something really obvious, so apologies!
What is the recommended practice for using this SDK in a server-side rendering scenario, where XHR is not available?
Similar issue in the raven-js SDK: getsentry/sentry-javascript#951
When an error occurs, it generally is logged to console
and an error
event is emitted. When emitted, it would be great if the source error object was sent to the callback. This way the callback function can elect to do something useful with the error instead of just knowing one occurred.
An example where this could be applied, is forwarding these errors to an error collection system.
All of a sudden, we started receiving reports of clients having our app close the browser on iPads and in Chrome after logging in. We didn't add any code to intentionally close the browser, nor should it be possible.
Calling window.close()
, you see this message:
Scripts may close only the windows that were opened by it.
Today, I saw that same message coming from ldclient.es.js
for this line of code:
o.disconnect=function(){clearTimeout(l),l=null,close()}
close()
here refers to window.close()
.
I wonder if the browser can get into a strange state where window.close()
would actually close the tab you're in.
I found the same line here:
https://github.com/launchdarkly/js-client/blob/8e9b46037f253c25bdbbb3ba73aad36ee966c636/src/Stream.js#L23
Did you mean to call es.close()
or stream.close()
instead?
Also, when would a fix be put out? I'd like to get this updated asap for our users.
If you are bootstrapping from localStorage, it is possible to have a situation where both localStorage and the in-memory flags are out of sync with the latest response that the client has received.
There is a comment in the code that explains:
// We won't signal changes or update the in-memory flags unless you subscribe for changes
But, even if you do subscribe for changes as suggested, there is no code that fires off a change
event. Only localStorage is updated.
It's therefore not possible to react to these new/changed values until next refresh when the client reads from localStorage again and sees the new values.
Related: #59
Is it the caller's responsibility or the SDK's responsibility to handle localStorage errors during initialization?
I'm wondering if the call to setItem
in the catch block could possibility throw an uncaught exception.
My concern comes from the fact that we often see localStorage
throw SecurityException
s in production, especially on mobile, where it is locked when the device is locked or maybe when the user is in incognito/private browsing mode.
Right now the main file has export default { initialize, version };
export which looks a bit weird to me:
I'm using the sdk in both Chrome and Webview. and i have problems with the streaming in the Webview, the client doesn't get updates about flag changes.
When i'm looking in the network tab it seems like the difference between the two is in the webview the request for clientstream.launchdarkly.com/eval
failed.
The error message is: Failed to load resource: The request timed out.
I tried to copy the cURL that both browsers is doing:
Webview
curl 'https://clientstream.launchdarkly.com/eval/5696d9987b1f40069c00002b/eyJpZCI6IjEiLCJrZXkiOiJhZG1pbkBpbnZpc2lvbmFwcC5jb20iLCJlbWFpbCI6ImFkbWluQGludmlzaW9uYXBwLmNvbSJ9' \
-XGET \
-H 'Pragma: no-cache' \
-H 'Accept: text/event-stream' \
-H 'Cache-Control: no-cache' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) WebView'
Chrome
curl 'https://clientstream.launchdarkly.com/eval/5696d9987b1f40069c00002b/eyJpZCI6IjEiLCJrZXkiOiJhZG1pbkBpbnZpc2lvbmFwcC5jb20iLCJlbWFpbCI6ImFkbWluQGludmlzaW9uYXBwLmNvbSJ9' \
-H 'Accept: text/event-stream' \
-H 'Cache-Control: no-cache' \
-H 'Origin: https://in-v7.local.invision.works' \
-H 'Referer: https://in-v7.local.invision.works/dsm/in-vision/sample-library/folder/colors/5bed2d414871e90018cff284' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36' --compressed
The difference is in the origin and referer headers that Chrome added, I don't know if it's the problem but that's the best i can get.
The workaround that i found is to unregister and register again every couple of seconds which connect again to the stream i guess :)
Thanks for the help
We have a wrapper feature toggle component wraps around ldClient. It is basically a copy of ld-redux code with some minor changes. Upon initialisation, the following event occurs
window.ldClient.on('ready', () => { reduxStore.dispatch(setLDReady()); });
This action triggers the feature toggle component update
componentWillReceiveProps(newProps) {
if (this.isLDReady()) {
this.initialise();
if (!isEqual(newProps.userData, this.props.userData)) {
this.updateUser();
}
}
}
in the function initialise feature flag query is fired
ldClient.variation(flagNameInLd, ldDefaultValues[flagNameInLd])
And it always returns undefined - checking dev console in Launch Darkly it also shows undefined as a value.
The above code works if I put a setTimeout wrapper around reduxStore.dispatch(setLDReady());
and force a 100ms delay.
My question is, when ldClient emits the ready event, is it really ready for features to be queried? or should we be using other events?
See easylist/easylist#391 for more information.
I'm not sure what the proper solution is other than writing up a warning for users. Your code shows the ability to change baseurls so proxies can be written by end-users as a workaround as need-be.
I've also sent emails, just documenting this as far and wide as possible :)
We've been trying to debug an issue in our web app with Safari users being unable to print.
From what we can tell Safari won't print until the page has finished loading, but the event-stream connection is preventing whatever event it's watching for from ever firing. If I disconnect my network, causing the stream to end, the print dialog immediately opens.
Is event-stream possibly breaking print in Safari a known issue with any work around?
#53 now lives on the branch next
. Once the few items below are fixed, we'll publish to npm with the next
tag. (So npm install ldclient-node@next
works.)
Tasks:
prettier
max line length to 120 — 80 causes tests names to wrap in strange waysOn a remote server, on initialization, LD client calls
https://ourhostname.com/function%20()%20%7B%20[native%20code]%20%7D/events/bulk/function%20n(r)%7Bvar%20o=new%20XMLHttpRequest;return%20o.open(%22POST%22,e+%22/events/bulk/%22+n,!t),h(o),o.setRequestHeader(%22Content-Type%22,%22application/json%22),o.setRequestHeader(%22X-LaunchDarkly-Event-Schema%22,%223%22),t%7C%7C(o.addEventListener(%22load%22,function()%7B400%3C=o.status&&s(o.status)&&r?n(!1).send(u):e(function(e){var%20n={status:e.status},t=e.getResponseHeader(%22Date%22);if(t){var%20r=Date.parse(t);r&&(n.serverTime=r)}return%20n}(o))}),r&&o.addEventListener(%22error%22,function(){n(!1).send(u)})),o}
and on localhost it calls: https://localhost:1338/[object%20Object],[object%20Object]/events/bulk/true}
.
I've tracked events/bulk
down to EventSender.js
which through intermediaries is used by initialize
in index.js
.
Not sure how to fix it though. We haven't changed any code on our end, and the arguments going into our call to .initialize
seems correct.
It's possible that this is related to es5-es6 polyfills because our solution has many silently caught errors relating to es6 functions.
Separate question for a workaround of using v2.6.0:
For this project we are unfortunately using Bower (Polymer 2), with the URL for "ldclient.min" being https://app.launchdarkly.com/snippet/ldclient.min.js
.
Without some cumbersome workaround it seems we're locked to your latest version with that URL. Any easy way you know of getting a minified 2.6.0?
If you had had minified builds in the published source, we could have deep linked to v2.6.0 and probably been fine, but as it is, the only CDN I can find is at https://cdn.jsdelivr.net/npm/[email protected]/dist/ldclient.cjs.min.js
which breaks at the @
in Bower, yielding bower ldclient.min#* install ldclient.min#e-tag:W/"5769-9e
Issue:
We're trying to use the LaunchDarkly client-side SDK in a project which creates a bundle using fuse-box (https://fuse-box.org/). Unfortunately, the SDK does not work with this bundler as it includes the Base64
package which does not comply with the package.json spec for package names (https://docs.npmjs.com/creating-a-package-json-file#required-name-and-version-fields). The spec requires that packages be published under a name that is all lowercase. FuseBox fails to import any packages that don't meet this requirement.
Proposed fix:
Switch to a different base64 library which is published with a valid name.
I'd be happy to open a pull request which fixes this issue.
With other clients it's possible to subscribe to when a user changed so that way we can make a call to update our attributes from our server
The current build system seems to be around webpack. However, generally rollup works a bit better for libraries whereas webpack works super nice with applications.
Would there be interest in moving the build system to rollup? Another option then would also be to refactor all code to ES6 code while building UMD, ESM and CJS bundles.
I've done such thing quite a few times now and could offer my help just wanted to clarify first if that brings up interest.
When integrating ldclient-js with an Angular4 application, the Angular4 Testability service is not usable as the testability never becomes stable after an ldclient is initialized.
For example, window.getAllAngularTestabilities()[0].isStable()
is always false.
The testability is considered "stable" when there are no "macro tasks" still pending. According to this, The setTimeout
calls used by the ld client are macro tasks, and because the ld client uses an infinite loop of setTimeout
calls there is always a macro task pending, and therefore the testability is never stable.
A similar issue exists when using angular-google-maps with the testability service: sebholstein/angular-google-maps#815
I'm no JS expert so I'm not sure how this could be solved - do we need a separate client library that specifically targets Angular4?
I think the issue is that we abort the request too easily, without checking whether the callbacks match or not.
This happens on index.js line 91 - apparently somehow flags
is undefined when variation
is called in the callback for the ready
event. Our error tracker reports that this has happened in just a small fraction of page loads, so it's working most of the time. We're using the ldclient-js
npm module v1.1.3.
I think this is another symptom of the same problem as #27: when a request to the LaunchDarkly service returns an error, the LD script gets no flags back, and that causes problems. (This might not even be an issue with LD - it could be that the internet flickered while the request was being made.)
I have the LD client running perfectly in my SPA, except that Internet Explorer 11 doesn't like the ES6 Promise usage which is unsupported. Promise
is still being used in the ldclient.min.js
file; everything works fine in Chrome and Edge browsers.
[object Error]{description: "'Promise' i...", innerError: undefined, message: "'Promise' i...", name: "ReferenceEr...", number: -2146823279, stack: "ReferenceEr..."}
Looks like it's complaining about EventSender.js (54,9)
but I found Promise
used in other modules as well.
After looking at the docs, I wasn't able to find any guidance for this one, so please advise when you can.
Hey,
Once in a while we're receiving errors on requesting a gif.
Error: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'https://events.launchdarkly.com/a/*.gif?*
Thanks
We are trying to target users by IP address. This works for backend LD client but doesn't work for js-client.
When I send IP in ip
field among key
according to https://docs.launchdarkly.com/v2.0/docs/js-sdk-reference it works but it requires browser to fetch user's public IP somewhere.
IMHO user's public IP should be obtained by LD server when browser is asking for status of feature flags.
What is a correct way how to target js-client users by their IP address?
Hi,
The lib is currently using Sizzle, which is not a small library just to do one simple thing, getting the nodes for a specific selector (see this line)
var elements = Sizzle(selector);
Would it be possible to remove this dependency and use document.querySelectorAll
instead?
QuerySelectorAll
is widely supported now so it seems Sizzle is definitely not required.
If I do npm install [email protected]
and then ls -la node_modules/ldclient-js/
there is no src/ folder - but src is referenced in package.json:
"types": "./src/index.d.ts",
"version": "2.4.1"
Which means that our typescript builds fail when we reference LDClient in 2.4.1.
If I do npm install [email protected]
then ls -la node_modules/ldclient-js/
does have a src/ folder with the index.d.ts file in it, so our Typescript imports work fine with 2.4.0.
So I guess the npmjs publish now ignores the src folder?
If that is the case it would be very nice if you could move the index.d.ts to the dist, or somewhere else that is included in the publish and update the types property in package.json.
If local storage is enabled, launch darkly still servers the old value from local storage and updates it after the remote call is finished, hence user gets the old flag on first refresh, and is only able to get actual updated value after second refresh. And you can't ask user to refresh twice.
Didn't find an error handling section in the documentation, please let me know if I've missed it.
I'm mocking the call to initialise the client with 500
, but it still seems to emit the ready
event. Is this by design? How can I differentiate an error and success?
When I use launchdarkly on my localhost with Angular 6, that is work, but sometimes will tell me net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
. what is this mean?
on my online project, they will tell me error like this
Access to fetch at 'https://clientstream.launchdarkly.com/eval/****' from origin 'https://****' has been blocked by CORS policy: Request header field cache-control is not allowed by Access-Control-Allow-Headers in preflight response. leads:1 GET https://clientstream.launchdarkly.com/eval/**** net::ERR_ABORTED 504 (Gateway Timeout)
What can I do ? Or my network problem?Can I set Request for launchdarkly? Thanks!!!
Hi,
We have a requirement to integrate Feature Flags from two different LD projects. SDK currently supports a singleton of the SDK instance with a specified project.
Anything I can do about it?
Would like to report a possible bug on this line.
We're using Cypress in our project, and as part of it we're mocking network requests by saving setup XHR responses as fixture files. One of those XHR requests is the LaunchDarkly GET request to get our feature flags.
However, since we now read a file to serve as a mock for the request, the content-type
header as part of the response is added with charset=utf-8
which results in this value being: application/json; charset=utf-8
, thus failing the said line above.
Do you see any problem in modifying the condition to:
const contentType = xhr.getResponseHeader('Content-type');
if (xhr.status === 200 && contentType && contentType.indexOf(json) > -1) {
...
}
Tested in 2.1.2 and 2.7.1.
Hi
I have a performance issue with the the javascript client for Launch Darkly in IE 11 (Most likely earlier versions as well).
When using the client in pages with a fair amount of dom elements, reloading the page several times increases the memory usage in IE11.
Removing the LD client removes this behavior.
Maybe the cause is that the eventlisteners in index.js are not removed, which blocks the GC to clean references to the window object correctly? In that case the cleanup could be done in beforeunload.
On a page with less amount of dom elements the effect is much smaller but still noticeable.
Chrome, FireFox and Edge have no issues.
Any help is much appreciated!
We've had over 3,900 recurrences of this issue in the last week. It appears to happen in Chrome 67 and 68 on Windows.
SyntaxError: Unexpected end of JSON input
1 File "webpack:///./node_modules/ldclient-js/dist/ldclient.es.js" line 1 col 14836 in EventSource.put
function createCommonjsModule(e,t){return e(t={exports:{}},t.exports),t.exports}var base64=create...
2 File "webpack:///./node_modules/logrocket/dist/build.umd.js" line 1679 col 1 in EventSource.o
return func.apply(this, args);
Is it okay to use LDClient.initialize(env, user)
multiple times on the same page for the same env and user? I'm trying to integrate the feature flagging mechanism into a React component. If multiple components are used on the same page, it seems as if the initialize call interferes with other instances.
Here's some psuedo-code I'm putting in componentDidMount:
componentDidMount() {
const ldclient = LDClient.initialize(this.env, this.user);
ldclient.on('ready', () => {
console.log(`Getting feature flag for ${this.props.featureKey}`);
const isFeatureEnabled = ldclient.variation(this.props.featureKey, this.props.defaultValue);
this.setState({ isFeatureEnabled });
});
}
Similar to #41, the extension Privacy Badger blocks all LaunchDarkly urls making our flags useless.
In today's js world, I would expect the SDK to have support for promises instead of ready
events an so on.. Or at least in addition to..
Because the LDEventName
ts type is defined as 'ready' | 'change'
, you can't use this syntax for ldclient.on()
:
ldclient.on('change:<flag-name', cb);
The error has this stack trace:
TypeError: Cannot read property 'flagname' of undefined
at Object.u [as modifications] (/vendor/ldclient-js/ldclient.min.js:1:4074)
at f (/vendor/ldclient-js/ldclient.min.js:1:1443)
at /vendor/ldclient-js/ldclient.min.js:1:1412
at /vendor/ldclient-js/ldclient.min.js:11:22303
at XMLHttpRequest.<anonymous> (/vendor/ldclient-js/ldclient.min.js:11:22056)
I tracked it down, it looks like this happens because modifications
gets called with an undefined newObj
, which happens when updateSettings()
gets called with an undefined settings
parameter, which happens when requestor.fetchFlagSettings
tries to get settings but the response code is not 200
or the response does not have a Content-type
of application/json
due to how fetchJSON
handles those cases. Unfortunately I do not know what the faulty response was in this case as the error was recorded using an error-tracking service.
Similar to #7, IE10 does not support the variable const.
The client script contains const
coming from line of code here:
See it's appearance here: https://cdn.jsdelivr.net/npm/[email protected]/dist/ldclient.js
Would you consider changing this to var
? PR #68
Our IE 11 users started receiving errors from ldclient.js, the first happened at 1/6/18 8:57am AEST.
Message: undefined is not a function
at ? line 1, column 6475 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at Object.T.f.enqueue line 1, column 6658 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at V line 1, column 11499 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at ? line 1, column 11725 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at Object.C.n.setUser line 1, column 9492 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at C line 1, column 9547 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at Object.initialize line 1, column 11706 (https://app.launchdarkly.com/snippet/ldclient.min.js:1)
at initialize line 10, column 0 (common/launchDarkly.service.js:10)
Lots of these too:
Object doesn't support property or method 'startsWith'
Hey I'm using reactjs and our sign out doesn't actually reload the page. How can I sign out a user? I'm currently doing this, which works but seems a little hacky:
ldclient.identify({ key: '', anonymous: false });
I'm not after anonymous tracking, thus the ''
. If I pass in null
or undefined
I get a 400 from the server, if I don't pass anything the user says logged in.
Any suggestions?
Hi,
I found a little bug in the typing.d.ts and wanted to fix it myself via pull request etc.
I have tried to get myself set up (on a Windows machine), and found
Find some of the test failures below.
If anybody knows how to get the process to work, that would be great :)
Thanks,
Krischan
d:\dev\imodeljs\js-client>npm run test
> [email protected] test d:\dev\imodeljs\js-client
> NODE_ENV=test jest
'NODE_ENV' is not recognized as an internal or external command,
operable program or batch file.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] test: `NODE_ENV=test jest`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Krischan.Eberle\AppData\Roaming\npm-cache\_logs\2018-10-02T07_17_06_304Z-debug.log
d:\dev\imodeljs\js-client>npm run test
> [email protected] test d:\dev\imodeljs\js-client
> SET NODE_ENV=test & jest
FAIL src\__tests__\Stream-test.js
● Test suite failed to run
D:\dev\imodeljs\js-client\src\__tests__\Stream-test.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import EventSource, { sources } from './EventSource-mock';
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (../node_modules/jest-runtime/build/script_transformer.js:316:17)
FAIL src\__tests__\EventSender-test.js
● Test suite failed to run
D:\dev\imodeljs\js-client\src\__tests__\EventSender-test.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Base64 from 'Base64';
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (../node_modules/jest-runtime/build/script_transformer.js:316:17)
Unexpected token: u JSON.parse()
Must have been a corrupted JSON document format as once the key was set to empty string, error disappeared.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.