Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@mparticle/web-sdk

Package Overview
Dependencies
Maintainers
10
Versions
115
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mparticle/web-sdk - npm Package Compare versions

Comparing version 2.19.1 to 2.19.2

2

package.json
{
"name": "@mparticle/web-sdk",
"version": "2.19.1",
"version": "2.19.2",
"description": "mParticle core SDK for web applications",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

@@ -12,31 +12,13 @@ import { Batch } from '@mparticle/event-models';

/**
* BatchUploader contains all the logic to upload batches to mParticle.
* It queues events as they come in and at set intervals turns them into batches.
* It then attempts to upload them to mParticle.
*
* These uploads happen on an interval basis using window.fetch or XHR
* requests, depending on what is available in the browser.
*
* Uploads can also be triggered on browser visibility/focus changes via an
* event listener, which then uploads to mPartice via the browser's Beacon API.
*/
export class BatchUploader {
// We upload JSON, but this content type is required to avoid a CORS preflight request
//we upload JSON, but this content type is required to avoid a CORS preflight request
static readonly CONTENT_TYPE: string = 'text/plain;charset=UTF-8';
static readonly MINIMUM_INTERVAL_MILLIS: number = 500;
uploadIntervalMillis: number;
eventsQueuedForProcessing: SDKEvent[];
batchesQueuedForProcessing: Batch[];
pendingEvents: SDKEvent[];
pendingUploads: Batch[];
mpInstance: MParticleWebSDK;
uploadUrl: string;
batchingEnabled: boolean;
private uploader: AsyncUploader;
/**
* Creates an instance of a BatchUploader
* @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
* @param {number} uploadInterval - the desired upload interval in milliseconds
*/
constructor(mpInstance: MParticleWebSDK, uploadInterval: number) {

@@ -50,4 +32,4 @@ this.mpInstance = mpInstance;

}
this.eventsQueuedForProcessing = [];
this.batchesQueuedForProcessing = [];
this.pendingEvents = [];
this.pendingUploads = [];

@@ -61,16 +43,11 @@ const { SDKConfig, devToken } = this.mpInstance._Store;

this.uploader = window.fetch
? new FetchUploader(this.uploadUrl)
: new XHRUploader(this.uploadUrl);
this.triggerUploadInterval(true, false);
setTimeout(() => {
this.prepareAndUpload(true, false);
}, this.uploadIntervalMillis);
this.addEventListeners();
}
// Adds listeners to be used trigger Navigator.sendBeacon if the browser
// loses focus for any reason, such as closing browser tab or minimizing window
private addEventListeners() {
const _this = this;
// visibility change is a document property, not window
document.addEventListener('visibilitychange', () => {

@@ -94,19 +71,5 @@ _this.prepareAndUpload(false, _this.isBeaconAvailable());

// Triggers a setTimeout for prepareAndUpload
private triggerUploadInterval(
triggerFuture: boolean = false,
useBeacon: boolean = false
): void {
setTimeout(() => {
this.prepareAndUpload(triggerFuture, useBeacon);
}, this.uploadIntervalMillis);
}
/**
* This method will queue a single Event which will eventually be processed into a Batch
* @param event event that should be queued
*/
queueEvent(event: SDKEvent): void {
if (!isEmpty(event)) {
this.eventsQueuedForProcessing.push(event);
this.pendingEvents.push(event);
this.mpInstance.Logger.verbose(

@@ -116,7 +79,5 @@ `Queuing event: ${JSON.stringify(event)}`

this.mpInstance.Logger.verbose(
`Queued event count: ${this.eventsQueuedForProcessing.length}`
`Queued event count: ${this.pendingEvents.length}`
);
// TODO: Remove this check once the v2 code path is removed
// https://go.mparticle.com/work/SQDSDKS-3720
if (

@@ -140,3 +101,3 @@ !this.batchingEnabled ||

*/
private static createNewBatches(
private static createNewUploads(
sdkEvents: SDKEvent[],

@@ -189,4 +150,5 @@ defaultUser: MParticleUser,

if (onCreateBatchCallback) {
uploadBatchObject =
onCreateBatchCallback(uploadBatchObject);
uploadBatchObject = onCreateBatchCallback(
uploadBatchObject
);
if (uploadBatchObject) {

@@ -217,12 +179,8 @@ uploadBatchObject.modified = true;

*/
private async prepareAndUpload(
triggerFuture: boolean,
useBeacon: boolean
): Promise<void> {
private async prepareAndUpload(triggerFuture: boolean, useBeacon: boolean) {
const currentUser = this.mpInstance.Identity.getCurrentUser();
const currentEvents = this.eventsQueuedForProcessing;
this.eventsQueuedForProcessing = [];
const newBatches = BatchUploader.createNewBatches(
const currentEvents = this.pendingEvents;
this.pendingEvents = [];
const newUploads = BatchUploader.createNewUploads(
currentEvents,

@@ -232,43 +190,21 @@ currentUser,

);
if (!isEmpty(newBatches)) {
this.batchesQueuedForProcessing.push(...newBatches);
if (newUploads && newUploads.length) {
this.pendingUploads.push(...newUploads);
}
const batchesToUpload = this.batchesQueuedForProcessing;
const batchesThatDidNotUpload: Batch[] = [];
this.batchesQueuedForProcessing = [];
// Create an array of promises as we try to upload each batch indvidually
const promises: Promise<Batch>[] = batchesToUpload.map((upload) => {
return this.upload(this.mpInstance.Logger, upload, useBeacon);
});
// Iterate through fulfilled promises and store any remaining batches
// for future re-transmission attempts
if (!isEmpty(promises)) {
Promise.all(promises)
.then((batchResponses) => {
batchResponses.forEach((batch) =>
!isEmpty(batch)
? batchesThatDidNotUpload.push(batch)
: null
);
})
.catch((error) => {
this.mpInstance.Logger.error(
`Error processing batches during upload attempt: ${error}`
);
})
.finally(() => {
// Any batches that did not upload should be put back into the queue for processing
if (!isEmpty(batchesThatDidNotUpload)) {
this.batchesQueuedForProcessing.unshift(
...batchesThatDidNotUpload
);
}
});
const currentUploads = this.pendingUploads;
this.pendingUploads = [];
const remainingUploads: Batch[] = await this.upload(
this.mpInstance.Logger,
currentUploads,
useBeacon
);
if (remainingUploads && remainingUploads.length) {
this.pendingUploads.unshift(...remainingUploads);
}
if (triggerFuture) {
this.triggerUploadInterval(triggerFuture, false);
setTimeout(() => {
this.prepareAndUpload(true, false);
}, this.uploadIntervalMillis);
}

@@ -279,58 +215,74 @@ }

logger: SDKLoggerApi,
batch: Batch,
_uploads: Batch[],
useBeacon: boolean
): Promise<Batch | null> {
if (isEmpty(batch) || isEmpty(batch.events)) {
): Promise<Batch[]> {
let uploader;
// Filter out any batches that don't have events
const uploads = _uploads.filter(upload => !isEmpty(upload.events));
if (isEmpty(uploads)) {
return null;
}
logger.verbose(`Uploading batches: ${JSON.stringify(batch)}`);
logger.verbose(`Uploading batches: ${JSON.stringify(uploads)}`);
logger.verbose(`Batch count: ${uploads.length}`);
const fetchPayload: fetchPayload = {
method: 'POST',
headers: {
Accept: BatchUploader.CONTENT_TYPE,
'Content-Type': 'text/plain;charset=UTF-8',
},
body: JSON.stringify(batch),
};
for (let i = 0; i < uploads.length; i++) {
const fetchPayload: fetchPayload = {
method: 'POST',
headers: {
Accept: BatchUploader.CONTENT_TYPE,
'Content-Type': 'text/plain;charset=UTF-8',
},
body: JSON.stringify(uploads[i]),
};
// TODO: Make beacon its own function
// beacon is only used on onbeforeunload onpagehide events
if (useBeacon && this.isBeaconAvailable()) {
let blob = new Blob([fetchPayload.body], {
type: 'text/plain;charset=UTF-8',
});
navigator.sendBeacon(this.uploadUrl, blob);
} else {
try {
const response = await this.uploader.upload(fetchPayload);
// TODO: Should we make this a switch statement instead?
if (response.status >= 200 && response.status < 300) {
logger.verbose(
`Upload success for request ID: ${batch.source_request_id}`
// beacon is only used on onbeforeunload onpagehide events
if (useBeacon && this.isBeaconAvailable()) {
let blob = new Blob([fetchPayload.body], {
type: 'text/plain;charset=UTF-8',
});
navigator.sendBeacon(this.uploadUrl, blob);
} else {
if (!uploader) {
if (window.fetch) {
uploader = new FetchUploader(this.uploadUrl, logger);
} else {
uploader = new XHRUploader(this.uploadUrl, logger);
}
}
try {
const response = await uploader.upload(
fetchPayload,
uploads,
i
);
return null;
} else if (response.status >= 500 || response.status === 429) {
if (response.status >= 200 && response.status < 300) {
logger.verbose(
`Upload success for request ID: ${uploads[i].source_request_id}`
);
} else if (
response.status >= 500 ||
response.status === 429
) {
logger.error(
`HTTP error status ${response.status} received`
);
//server error, add back current events and try again later
return uploads.slice(i, uploads.length);
} else if (response.status >= 401) {
logger.error(
`HTTP error status ${response.status} while uploading - please verify your API key.`
);
//if we're getting a 401, assume we'll keep getting a 401 and clear the uploads.
return null;
}
} catch (e) {
logger.error(
`HTTP error status ${response.status} received`
`Error sending event to mParticle servers. ${e}`
);
// Server error, return current batch and try again later
return batch;
} else if (response.status >= 401) {
logger.error(
`HTTP error status ${response.status} while uploading - please verify your API key.`
);
// if we're getting a 401, assume we'll keep getting a 401
// so return the upload so it can be stored for later use
return batch;
return uploads.slice(i, uploads.length);
}
} catch (error) {
logger.error(
`Error sending event to mParticle servers. ${error}`
);
return batch;
}

@@ -344,6 +296,7 @@ }

url: string;
public abstract upload(fetchPayload: fetchPayload): Promise<XHRResponse>;
logger: SDKLoggerApi;
constructor(url: string) {
constructor(url: string, logger: SDKLoggerApi) {
this.url = url;
this.logger = logger;
}

@@ -353,3 +306,7 @@ }

class FetchUploader extends AsyncUploader {
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
private async upload(
fetchPayload: fetchPayload,
uploads: Batch[],
i: number
) {
const response: XHRResponse = await fetch(this.url, fetchPayload);

@@ -361,5 +318,10 @@ return response;

class XHRUploader extends AsyncUploader {
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
private async upload(
fetchPayload: fetchPayload,
uploads: Batch[],
i: number
) {
const response: XHRResponse = await this.makeRequest(
this.url,
this.logger,
fetchPayload.body

@@ -372,2 +334,3 @@ );

url: string,
logger: SDKLoggerApi,
data: string

@@ -374,0 +337,0 @@ ): Promise<XMLHttpRequest> {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc