Skip to content

Commit 9e45df9

Browse files
authored
Merge pull request #38 from humanmade/better-endpoint-updates
Improve endpoint updates
2 parents 19ab9fb + 6496fc2 commit 9e45df9

File tree

3 files changed

+89
-79
lines changed

3 files changed

+89
-79
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@babel/runtime": "^7.8.4",
2525
"@wordpress/babel-preset-default": "^4.10.0",
2626
"babel-loader": "^8.0.6",
27+
"deepmerge": "^4.2.2",
2728
"ua-parser-js": "^0.7.21",
2829
"webpack": "^4.41.6",
2930
"webpack-bundle-analyzer": "^3.6.0",

src/analytics.js

Lines changed: 83 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
import "./utils/polyfills";
33
import { uuid, getLanguage } from "./utils";
44
import UAParser from "ua-parser-js";
5+
import merge from 'deepmerge';
56

67
// AWS SDK.
78
import { CognitoIdentityClient } from "@aws-sdk/client-cognito-identity-browser/CognitoIdentityClient";
89
import { GetCredentialsForIdentityCommand } from "@aws-sdk/client-cognito-identity-browser/commands/GetCredentialsForIdentityCommand";
910
import { GetIdCommand } from "@aws-sdk/client-cognito-identity-browser/commands/GetIdCommand";
1011
import { PinpointClient } from "@aws-sdk/client-pinpoint-browser/PinpointClient";
1112
import { PutEventsCommand } from "@aws-sdk/client-pinpoint-browser/commands/PutEventsCommand";
12-
import { UpdateEndpointCommand } from "@aws-sdk/client-pinpoint-browser/commands/UpdateEndpointCommand";
1313

1414
const {
1515
_attributes,
@@ -122,6 +122,7 @@ const getMetrics = (extra = {}) =>
122122
...carry,
123123
[name]: Number(typeof value === 'function' ? value() : value),
124124
}), {});
125+
const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
125126

126127
/**
127128
* Initialise cognito services.
@@ -220,85 +221,81 @@ const Analytics = {
220221
return await Analytics.client;
221222
},
222223
updateEndpoint: async (endpoint = {}) => {
223-
// Get client & authenticate.
224-
const client = await Analytics.getClient();
225-
// Get endpoint ID.
226-
const UserId = Analytics.getUserId();
227-
if (!UserId) {
228-
console.error("No User ID found. Make sure to call Analytics.authenticate() first.");
229-
return;
230-
}
231-
232-
const EndpointId = UserId.replace(`${Config.CognitoRegion}:`, "");
224+
return await Analytics.flushEvents(endpoint);
225+
},
226+
getEndpoint: () => {
227+
try {
228+
const ParsedEndpoint = JSON.parse(localStorage.getItem(`aws.pinpoint.endpoint`));
229+
return ParsedEndpoint || {};
230+
} catch ( error ) {
231+
return {};
232+
};
233+
},
234+
setEndpoint: (endpoint) => localStorage.setItem(`aws.pinpoint.endpoint`, JSON.stringify(endpoint)),
235+
mergeEndpointData: (endpoint = {}) => {
236+
const Existing = Analytics.getEndpoint();
233237
const UAData = UAParser(navigator.userAgent);
234238
const EndpointData = {
235-
Address: "", // Destination for push notifications / campaigns.
236-
Attributes: {
237-
DeviceMake: [UAData.device.vendor || ""],
238-
DeviceModel: [UAData.device.model || ""],
239-
DeviceType: [UAData.device.type || ""]
240-
},
241-
ChannelType: "CUSTOM", // GCM | APNS | APNS_SANDBOX | APNS_VOIP | APNS_VOIP_SANDBOX | ADM | SMS | VOICE | EMAIL | BAIDU | CUSTOM,
239+
Attributes: {},
242240
Demographic: {
243241
AppVersion: Data.AppVersion || "",
244242
Locale: getLanguage(),
245-
Make: UAData.engine.name || "",
246-
Model: UAData.browser.name || "",
247-
ModelVersion: UAData.browser.version || "",
248-
Platform: UAData.os.name || "",
249-
PlatformVersion: UAData.os.version || ""
250243
},
251244
Location: {},
252-
EffectiveDate: new Date().toISOString(),
253245
Metrics: {},
254-
OptOut: "ALL",
255-
RequestId: uuid(),
256-
User: {
257-
UserAttributes: {},
258-
UserId: UserId
259-
}
260246
};
261247

262-
// Merge new endpoint data with defaults.
263-
const EndpointRequest = Object.entries(EndpointData).reduce((carry, [key, value]) => {
264-
if (typeof value === "object") {
265-
carry[key] = Object.assign(value, endpoint[key] || {});
266-
} else {
267-
carry[key] = endpoint[key] || value;
268-
}
269-
return carry;
270-
}, {});
271-
272-
const PrevEndpoint = Analytics.getEndpoint(UserId);
273-
if (PrevEndpoint && JSON.stringify(PrevEndpoint) === JSON.stringify(EndpointRequest)) {
274-
return EndpointRequest;
248+
// Add device attributes.
249+
if (UAData.device && UAData.device.vendor) {
250+
EndpointData.Attributes.DeviceMake = [ UAData.device.vendor ];
251+
}
252+
if (UAData.device && UAData.device.model) {
253+
EndpointData.Attributes.DeviceModel = [ UAData.device.model ];
254+
}
255+
if (UAData.device && UAData.device.type) {
256+
EndpointData.Attributes.DeviceType = [ UAData.device.type ];
275257
}
276258

277-
try {
278-
const command = new UpdateEndpointCommand({
279-
ApplicationId: Config.PinpointId,
280-
EndpointId: EndpointId,
281-
EndpointRequest: EndpointRequest
282-
});
283-
await client.send(command);
284-
Analytics.setEndpoint(UserId, EndpointRequest);
285-
return EndpointRequest;
286-
} catch (error) {
287-
console.error(error);
259+
// Add demographic data.
260+
if (UAData.engine && UAData.engine.name) {
261+
EndpointData.Demographic.Make = UAData.engine.name;
288262
}
263+
if (UAData.browser && UAData.browser.name) {
264+
EndpointData.Demographic.Model = UAData.browser.name;
265+
}
266+
if (UAData.browser && UAData.browser.version) {
267+
EndpointData.Demographic.ModelVersion = UAData.browser.version;
268+
}
269+
if (UAData.os && UAData.os.name) {
270+
EndpointData.Demographic.Platform = UAData.os.name;
271+
}
272+
if (UAData.os && UAData.os.version) {
273+
EndpointData.Demographic.PlatformVersion = UAData.os.version;
274+
}
275+
276+
// Merge new endpoint data with defaults.
277+
endpoint = merge.all([EndpointData, Existing, endpoint], {
278+
arrayMerge: overwriteMerge
279+
});
280+
281+
// Store the endpoint data.
282+
Analytics.setEndpoint(endpoint);
283+
284+
return endpoint;
289285
},
290-
getEndpoint: id => {
291-
try {
292-
const ParsedEndpoint = JSON.parse(localStorage.getItem(`aws.pinpoint.endpoint.${id}`));
293-
if (ParsedEndpoint.User.UserId === id) {
294-
return ParsedEndpoint;
295-
}
296-
} catch (error) {}
297-
return false;
298-
},
299-
setEndpoint: (id, endpoint) => localStorage.setItem(`aws.pinpoint.endpoint.${id}`, JSON.stringify(endpoint)),
300286
events: [],
301-
record: (type, data = {}, queue = true) => {
287+
record: (type, data = {}, endpoint = {}, queue = true) => {
288+
// Back compat, if endpoint is a boolean it is expected to be the value for queue.
289+
if (typeof endpoint === 'boolean') {
290+
queue = endpoint;
291+
endpoint = {};
292+
}
293+
294+
// Merge endpoint data.
295+
if ( Object.entries(endpoint).length ) {
296+
Analytics.mergeEndpointData(endpoint);
297+
}
298+
302299
const EventId = uuid();
303300
const Event = {
304301
[EventId]: {
@@ -338,12 +335,7 @@ const Analytics = {
338335
// Flush new events after 5 seconds.
339336
Analytics.timer = setTimeout(Analytics.flushEvents, 5000);
340337
},
341-
flushEvents: async () => {
342-
// Check we have events.
343-
if (!Analytics.events.length) {
344-
return;
345-
}
346-
338+
flushEvents: async (endpoint = {}) => {
347339
// Get the client.
348340
const client = await Analytics.getClient();
349341

@@ -354,12 +346,24 @@ const Analytics = {
354346
return;
355347
}
356348

349+
// Update endpoint data if provided.
350+
if ( Object.entries(endpoint).length ) {
351+
Analytics.mergeEndpointData(endpoint);
352+
}
353+
354+
// Build endpoint data.
355+
const Endpoint = Analytics.getEndpoint();
356+
Endpoint.RequestId = uuid();
357+
358+
// Reduce events to an object keyed by event ID.
357359
const Events = Analytics.events.reduce((carry, event) => ({ ...event, ...carry }), {});
360+
361+
// Build events request object.
358362
const BatchUserId = UserId.replace(`${Config.CognitoRegion}:`, "");
359363
const EventsRequest = {
360364
BatchItem: {
361365
[BatchUserId]: {
362-
Endpoint: {},
366+
Endpoint: Endpoint,
363367
Events: Events
364368
}
365369
}
@@ -382,10 +386,8 @@ const Analytics = {
382386
}
383387
};
384388

385-
/**
386-
* Set endpoint data.
387-
*/
388-
Analytics.updateEndpoint(Data.Endpoint || {});
389+
// Set initial endpoint data.
390+
Analytics.mergeEndpointData(Data.Endpoint || {});
389391

390392
// Track sessions.
391393
document.addEventListener("visibilitychange", () => {
@@ -416,12 +418,13 @@ window.addEventListener("DOMContentLoaded", () => {
416418
Analytics.record("_session.start", {
417419
attributes: getAttributes()
418420
});
419-
// Record page view event immediately.
421+
// Record page view event & create/update endpoint immediately.
420422
Analytics.record(
421423
"pageView",
422424
{
423425
attributes: getAttributes()
424426
},
427+
{},
425428
false
426429
);
427430
});
@@ -437,11 +440,12 @@ window.addEventListener("beforeunload", async () => {
437440

438441
// Expose userland API.
439442
window.Altis.Analytics.updateEndpoint = Analytics.updateEndpoint;
440-
window.Altis.Analytics.record = (type, data = {}) =>
443+
window.Altis.Analytics.record = (type, data = {}, endpoint = {}) =>
441444
Analytics.record(
442445
type,
443446
{
444447
attributes: getAttributes(data.attributes || {}),
445448
metrics: getMetrics(data.metrics || {})
446-
}
449+
},
450+
endpoint
447451
);

0 commit comments

Comments
 (0)