Skip to content

Commit a00682c

Browse files
authored
prepare 2.10.0 release (#149)
1 parent 73598dd commit a00682c

40 files changed

+2445
-2072
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
All notable changes to the LaunchDarkly client-side JavaScript SDKs will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org).
55

6+
## [2.10.0] - 2019-04-19
7+
### Added:
8+
- Generated TypeDoc documentation for all types, properties, and methods is now available online at [https://launchdarkly.github.io/js-client/](https://launchdarkly.github.io/js-client/). Currently this will only be for the latest released version.
9+
- The SDK now allows you to specify an anonymous user without a key (i.e. the `anonymous` property is `true`, and there is no `key` property). In that case, the SDK will generate a UUID and send that as the user key. It will also cache this generated key in local storage (if local storage is available) so that anonymous users in the same browser will always get the same key.
10+
11+
### Fixed:
12+
- Setting user attributes to non-string values when a string was expected would prevent evaluations and analytics events from working. The SDK will now convert attribute values to strings as needed.
13+
614
## [2.9.7] - 2019-04-16
715
### Fixed:
816
- If there are pending analytics events when the page is being closed, the SDK normally attempts to deliver them by making a synchronous HTTP request. Chrome, as of version 73, does not allow this and logs an error. An upcoming release will change how events are sent, but as a temporary measure to avoid these errors, the SDK will now simply discard any pending events when the page is being closed _if_ the browser is Chrome version 73 or higher. In other browsers, there is no change. Note that this means that in Chrome 73, some events may be lost; that was already the case. The purpose of this patch is simply to avoid triggering errors. ([#178](https://github.com/launchdarkly/js-client-private/pull/178))

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ var user = { key: 'user.example.com' };
118118
var client = LDClient.initialize('YOUR_CLIENT_SIDE_ID', user);
119119
```
120120

121-
The user object can contain any of the properties described [here](https://docs.launchdarkly.com/docs/targeting-users). The SDK always has a single current user; you can change it after initialization (see "Changing users").
121+
The user object can contain any of the properties described [here](https://docs.launchdarkly.com/docs/targeting-users). The SDK always has a single current user; you can change it after initialization (see "Changing users"). If you want the SDK to generate a unique key for the user, omit the `key` property and set the `anonymous` property to `true`.
122122

123123
The client is initialized asynchronously, so if you want to determine when the client is ready to evaluate feature flags, use the `ready` event, or the Promise-based method `waitForInitialization()`:
124124

@@ -305,7 +305,7 @@ client.identify(newUser, hash, function() {
305305

306306
For an additional overview with code samples, see the online [JavaScript SDK Reference](https://docs.launchdarkly.com/docs/js-sdk-reference).
307307

308-
The authoritative full description of all properties and methods is in the TypeScript declaration files for [`ldclient-js`](https://github.com/launchdarkly/js-client/blob/master/packages/ldclient-js/typings.d.ts) and [`ldclient-js-common`](https://github.com/launchdarkly/js-client/blob/master/packages/ldclient-js-common/typings.d.ts) (a common package used by LaunchDarkly's JavaScript, React, and Electron SDKs).
308+
The authoritative full description of all properties, types, and methods is the [online TypeScript documentation](https://launchdarkly.github.io/js-client/). If you are not using TypeScript, then the types are only for your information and are not enforced, although the properties and methods are still the same as described in the documentation.
309309

310310
For examples of using the SDK in a simple JavaScript application, see [`hello-js`](https://github.com/launchdarkly/hello-js) and [`hello-bootstrap`](https://github.com/launchdarkly/hello-bootstrap).
311311

azure-pipelines.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
jobs:
2+
- job: build
3+
pool:
4+
vmImage: 'vs2017-win2016'
5+
steps:
6+
- task: PowerShell@2
7+
displayName: 'install dependencies'
8+
inputs:
9+
targetType: inline
10+
script: |
11+
node --version
12+
npm install
13+
- task: PowerShell@2
14+
displayName: 'build'
15+
inputs:
16+
targetType: inline
17+
script: npm run build
18+
- task: PowerShell@2
19+
displayName: 'test'
20+
inputs:
21+
targetType: inline
22+
script: npm test

docs/typedoc.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
// the properties are equivalent to the command-line options described here:
44
// https://typedoc.org/api/
55

6+
let version = process.env.VERSION;
7+
if (!version) {
8+
const package = require('../packages/ldclient-js/package.json');
9+
version = package.version;
10+
}
11+
612
module.exports = {
713
out: './build/html',
8-
name: 'LaunchDarkly JavaScript SDK',
14+
name: 'LaunchDarkly JavaScript SDK (' + version + ')',
915
readme: 'none', // don't add a home page with a copy of README.md
1016
mode: 'file', // don't treat "typings.d.ts" itself as a parent module
1117
includeDeclarations: true, // allows it to process a .d.ts file instead of actual TS code

packages/ldclient-js-common/package-lock.json

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ldclient-js-common/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
6161
},
6262
"dependencies": {
6363
"base64-js": "1.3.0",
64-
"fast-deep-equal": "2.0.1"
64+
"fast-deep-equal": "2.0.1",
65+
"uuid": "3.3.2"
6566
},
6667
"repository": {
6768
"type": "git",

packages/ldclient-js-common/src/EventProcessor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export default function EventProcessor(platform, options, environmentId, logger,
8383
}
8484
};
8585

86-
processor.flush = function(sync) {
86+
processor.flush = function() {
8787
if (disabled) {
8888
return Promise.resolve();
8989
}
@@ -99,7 +99,7 @@ export default function EventProcessor(platform, options, environmentId, logger,
9999
}
100100
queue = [];
101101
logger.debug(messages.debugPostingEvents(eventsToSend.length));
102-
return eventSender.sendEvents(eventsToSend, sync).then(responseInfo => {
102+
return eventSender.sendEvents(eventsToSend).then(responseInfo => {
103103
if (responseInfo) {
104104
if (responseInfo.serverTime) {
105105
lastKnownPastTime = responseInfo.serverTime;

packages/ldclient-js-common/src/EventSender.js

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@ export default function EventSender(platform, eventsUrl, environmentId, imageCre
88
const imageUrl = eventsUrl + '/a/' + environmentId + '.gif';
99
const sender = {};
1010

11-
function loadUrlUsingImage(src, onDone) {
11+
function loadUrlUsingImage(src) {
1212
const img = new window.Image();
13-
if (onDone) {
14-
img.addEventListener('load', onDone);
15-
}
1613
img.src = src;
1714
}
1815

19-
function getResponseInfo(xhr) {
20-
const ret = { status: xhr.status };
21-
const dateStr = xhr.getResponseHeader('Date');
16+
function getResponseInfo(result) {
17+
const ret = { status: result.status };
18+
const dateStr = result.header('date');
2219
if (dateStr) {
2320
const time = Date.parse(dateStr);
2421
if (time) {
@@ -28,59 +25,55 @@ export default function EventSender(platform, eventsUrl, environmentId, imageCre
2825
return ret;
2926
}
3027

31-
function sendChunk(events, usePost, sync) {
28+
function sendChunk(events, usePost) {
3229
const createImage = imageCreator || loadUrlUsingImage;
3330
const jsonBody = JSON.stringify(events);
34-
const send = onDone => {
35-
function createRequest(canRetry) {
36-
const xhr = platform.newHttpRequest();
37-
xhr.open('POST', postUrl, !sync);
38-
utils.addLDHeaders(xhr, platform);
39-
xhr.setRequestHeader('Content-Type', 'application/json');
40-
xhr.setRequestHeader('X-LaunchDarkly-Event-Schema', '3');
41-
if (!sync) {
42-
xhr.addEventListener('load', () => {
43-
if (xhr.status >= 400 && errors.isHttpErrorRecoverable(xhr.status) && canRetry) {
44-
createRequest(false).send(jsonBody);
45-
} else {
46-
onDone(getResponseInfo(xhr));
47-
}
48-
});
31+
32+
function doPostRequest(canRetry) {
33+
const headers = utils.extend(
34+
{
35+
'Content-Type': 'application/json',
36+
'X-LaunchDarkly-Event-Schema': '3',
37+
},
38+
utils.getLDHeaders(platform)
39+
);
40+
return platform
41+
.httpRequest('POST', postUrl, headers, jsonBody)
42+
.promise.then(result => {
43+
if (!result) {
44+
// This was a response from a fire-and-forget request, so we won't have a status.
45+
return;
46+
}
47+
if (result.status >= 400 && errors.isHttpErrorRecoverable(result.status) && canRetry) {
48+
return doPostRequest(false);
49+
} else {
50+
return getResponseInfo(result);
51+
}
52+
})
53+
.catch(() => {
4954
if (canRetry) {
50-
xhr.addEventListener('error', () => {
51-
createRequest(false).send(jsonBody);
52-
});
55+
return doPostRequest(false);
5356
}
54-
}
55-
return xhr;
56-
}
57-
if (usePost) {
58-
createRequest(true).send(jsonBody);
59-
} else {
60-
const src = imageUrl + '?d=' + utils.base64URLEncode(jsonBody);
61-
createImage(src, sync ? null : onDone);
62-
}
63-
};
57+
return Promise.reject();
58+
});
59+
}
6460

65-
if (sync) {
66-
send();
61+
if (usePost) {
62+
return doPostRequest(true).catch(() => {});
6763
} else {
68-
return new Promise(resolve => {
69-
send(resolve);
70-
});
64+
const src = imageUrl + '?d=' + utils.base64URLEncode(jsonBody);
65+
createImage(src);
66+
return Promise.resolve();
67+
// We do not specify an onload handler for the image because we don't want the client to wait around
68+
// for the image to load - it won't provide a server response, there's nothing to be done.
7169
}
7270
}
7371

74-
sender.sendEvents = function(events, sync) {
75-
if (!platform.newHttpRequest) {
76-
return Promise.resolve();
77-
}
78-
// Workaround for non-support of sync XHR in some browsers - https://github.com/launchdarkly/js-client/issues/147
79-
if (sync && !(platform.httpAllowsSync && platform.httpAllowsSync())) {
72+
sender.sendEvents = function(events) {
73+
if (!platform.httpRequest) {
8074
return Promise.resolve();
8175
}
8276
const canPost = platform.httpAllowsPost();
83-
const finalSync = sync === undefined ? false : sync;
8477
let chunks;
8578
if (canPost) {
8679
// no need to break up events into chunks if we can send a POST
@@ -90,9 +83,9 @@ export default function EventSender(platform, eventsUrl, environmentId, imageCre
9083
}
9184
const results = [];
9285
for (let i = 0; i < chunks.length; i++) {
93-
results.push(sendChunk(chunks[i], canPost, finalSync));
86+
results.push(sendChunk(chunks[i], canPost));
9487
}
95-
return sync ? Promise.resolve() : Promise.all(results);
88+
return Promise.all(results);
9689
};
9790

9891
return sender;

packages/ldclient-js-common/src/Identity.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import * as utils from './utils';
22

3-
function sanitizeUser(u) {
4-
const sane = utils.clone(u);
5-
if (sane.key) {
6-
sane.key = sane.key.toString();
7-
}
8-
return sane;
9-
}
10-
113
export default function Identity(initialUser, onChange) {
124
const ident = {};
135
let user;
146

157
ident.setUser = function(u) {
16-
user = sanitizeUser(u);
17-
onChange && onChange(utils.clone(user));
8+
user = utils.sanitizeUser(u);
9+
if (user && onChange) {
10+
onChange(utils.clone(user));
11+
}
1812
};
1913

2014
ident.getUser = function() {

0 commit comments

Comments
 (0)