@mparticle/web-sdk 2.25.2 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mparticle.common.js +57 -41
- package/dist/mparticle.esm.js +57 -41
- package/dist/mparticle.js +264 -84
- package/package.json +1 -1
- package/src/apiClient.ts +2 -1
- package/src/audience.ts +9 -0
- package/src/audienceManager.ts +88 -0
- package/src/batchUploader.ts +11 -66
- package/src/constants.ts +4 -0
- package/src/identity.js +32 -2
- package/src/mp-instance.js +4 -1
- package/src/sdkRuntimeModels.ts +16 -3
- package/src/sessionManager.ts +3 -10
- package/src/store.ts +124 -1
- package/src/uploaders.ts +59 -0
package/src/batchUploader.ts
CHANGED
|
@@ -10,6 +10,12 @@ import { convertEvents } from './sdkToEventsApiConverter';
|
|
|
10
10
|
import Types from './types';
|
|
11
11
|
import { getRampNumber, isEmpty } from './utils';
|
|
12
12
|
import { SessionStorageVault, LocalStorageVault } from './vault';
|
|
13
|
+
import {
|
|
14
|
+
AsyncUploader,
|
|
15
|
+
FetchUploader,
|
|
16
|
+
XHRUploader,
|
|
17
|
+
fetchPayload
|
|
18
|
+
} from './uploaders';
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* BatchUploader contains all the logic to store/retrieve events and batches
|
|
@@ -108,11 +114,12 @@ export class BatchUploader {
|
|
|
108
114
|
_Store: { deviceId },
|
|
109
115
|
} = this.mpInstance;
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
// https://go.mparticle.com/work/SQDSDKS-6317
|
|
118
|
+
const offlineStorageFeatureFlagValue: string = getFeatureFlag(
|
|
112
119
|
Constants.FeatureFlags.OfflineStorage
|
|
113
|
-
);
|
|
120
|
+
) as string;
|
|
114
121
|
|
|
115
|
-
const offlineStoragePercentage = parseInt(
|
|
122
|
+
const offlineStoragePercentage: number = parseInt(
|
|
116
123
|
offlineStorageFeatureFlagValue,
|
|
117
124
|
10
|
|
118
125
|
);
|
|
@@ -422,66 +429,4 @@ export class BatchUploader {
|
|
|
422
429
|
}
|
|
423
430
|
return null;
|
|
424
431
|
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
abstract class AsyncUploader {
|
|
428
|
-
url: string;
|
|
429
|
-
public abstract upload(fetchPayload: fetchPayload): Promise<XHRResponse>;
|
|
430
|
-
|
|
431
|
-
constructor(url: string) {
|
|
432
|
-
this.url = url;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
class FetchUploader extends AsyncUploader {
|
|
437
|
-
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
|
|
438
|
-
const response: XHRResponse = await fetch(this.url, fetchPayload);
|
|
439
|
-
return response;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
class XHRUploader extends AsyncUploader {
|
|
444
|
-
public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
|
|
445
|
-
const response: XHRResponse = await this.makeRequest(
|
|
446
|
-
this.url,
|
|
447
|
-
fetchPayload.body
|
|
448
|
-
);
|
|
449
|
-
return response;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
private async makeRequest(
|
|
453
|
-
url: string,
|
|
454
|
-
data: string
|
|
455
|
-
): Promise<XMLHttpRequest> {
|
|
456
|
-
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
|
457
|
-
return new Promise((resolve, reject) => {
|
|
458
|
-
xhr.onreadystatechange = () => {
|
|
459
|
-
if (xhr.readyState !== 4) return;
|
|
460
|
-
|
|
461
|
-
// Process the response
|
|
462
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
463
|
-
resolve(xhr);
|
|
464
|
-
} else {
|
|
465
|
-
reject(xhr);
|
|
466
|
-
}
|
|
467
|
-
};
|
|
468
|
-
|
|
469
|
-
xhr.open('post', url);
|
|
470
|
-
xhr.send(data);
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
interface XHRResponse {
|
|
476
|
-
status: number;
|
|
477
|
-
statusText?: string;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
interface fetchPayload {
|
|
481
|
-
method: string;
|
|
482
|
-
headers: {
|
|
483
|
-
Accept: string;
|
|
484
|
-
'Content-Type': string;
|
|
485
|
-
};
|
|
486
|
-
body: string;
|
|
487
|
-
}
|
|
432
|
+
}
|
package/src/constants.ts
CHANGED
|
@@ -26,6 +26,8 @@ const Constants = {
|
|
|
26
26
|
BadKey: 'Key value cannot be object or array',
|
|
27
27
|
BadLogPurchase:
|
|
28
28
|
'Transaction attributes and a product are both required to log a purchase, https://docs.mparticle.com/?javascript#measuring-transactions',
|
|
29
|
+
AudienceAPINotEnabled:
|
|
30
|
+
'Your workspace is not enabled to retrieve user audiences.',
|
|
29
31
|
},
|
|
30
32
|
InformationMessages: {
|
|
31
33
|
CookieSearch: 'Searching for cookie',
|
|
@@ -135,6 +137,7 @@ const Constants = {
|
|
|
135
137
|
configUrl: 'jssdkcdns.mparticle.com/JS/v2/',
|
|
136
138
|
identityUrl: 'identity.mparticle.com/v1/',
|
|
137
139
|
aliasUrl: 'jssdks.mparticle.com/v1/identity/',
|
|
140
|
+
userAudienceUrl: 'nativesdks.mparticle.com/v1/',
|
|
138
141
|
},
|
|
139
142
|
Base64CookieKeys: {
|
|
140
143
|
csm: 1,
|
|
@@ -170,6 +173,7 @@ const Constants = {
|
|
|
170
173
|
OfflineStorage: 'offlineStorage',
|
|
171
174
|
DirectUrlRouting: 'directURLRouting',
|
|
172
175
|
CacheIdentity: 'cacheIdentity',
|
|
176
|
+
AudienceAPI: 'audienceAPI',
|
|
173
177
|
},
|
|
174
178
|
DefaultInstance: 'default_instance',
|
|
175
179
|
CCPAPurpose: 'data_sale_opt_out',
|
package/src/identity.js
CHANGED
|
@@ -5,15 +5,17 @@ import {
|
|
|
5
5
|
createKnownIdentities,
|
|
6
6
|
tryCacheIdentity,
|
|
7
7
|
} from './identity-utils';
|
|
8
|
+
import AudienceManager from './audienceManager';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const { Messages, HTTPCodes, FeatureFlags } = Constants;
|
|
11
|
+
const { ErrorMessages } = Messages;
|
|
11
12
|
|
|
12
13
|
const { Identify, Modify, Login, Logout } = Constants.IdentityMethods;
|
|
13
14
|
|
|
14
15
|
export default function Identity(mpInstance) {
|
|
15
16
|
var self = this;
|
|
16
17
|
this.idCache = null;
|
|
18
|
+
this.audienceManager = null;
|
|
17
19
|
|
|
18
20
|
this.checkIdentitySwap = function(
|
|
19
21
|
previousMPID,
|
|
@@ -1265,6 +1267,34 @@ export default function Identity(mpInstance) {
|
|
|
1265
1267
|
getFirstSeenTime: function() {
|
|
1266
1268
|
return mpInstance._Persistence.getFirstSeenTime(mpid);
|
|
1267
1269
|
},
|
|
1270
|
+
/**
|
|
1271
|
+
* Get user audiences
|
|
1272
|
+
* @method getuserAudiences
|
|
1273
|
+
* @param {Function} [callback] A callback function that is invoked when the user audience request completes
|
|
1274
|
+
*/
|
|
1275
|
+
getUserAudiences: function(callback) {
|
|
1276
|
+
// user audience API is feature flagged
|
|
1277
|
+
if (
|
|
1278
|
+
!mpInstance._Helpers.getFeatureFlag(
|
|
1279
|
+
FeatureFlags.AudienceAPI
|
|
1280
|
+
)
|
|
1281
|
+
) {
|
|
1282
|
+
mpInstance.Logger.error(
|
|
1283
|
+
ErrorMessages.AudienceAPINotEnabled
|
|
1284
|
+
);
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
if (self.audienceManager === null) {
|
|
1288
|
+
self.audienceManager = new AudienceManager(
|
|
1289
|
+
mpInstance._Store.SDKConfig.userAudienceUrl,
|
|
1290
|
+
mpInstance._Store.devToken,
|
|
1291
|
+
mpInstance.Logger,
|
|
1292
|
+
mpid
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
self.audienceManager.sendGetUserAudienceRequest(mpid, callback);
|
|
1297
|
+
},
|
|
1268
1298
|
};
|
|
1269
1299
|
};
|
|
1270
1300
|
|
package/src/mp-instance.js
CHANGED
|
@@ -86,6 +86,9 @@ export default function mParticleInstance(instanceName) {
|
|
|
86
86
|
this._Identity = new Identity(this);
|
|
87
87
|
this.Identity = this._Identity.IdentityAPI;
|
|
88
88
|
this.generateHash = this._Helpers.generateHash;
|
|
89
|
+
|
|
90
|
+
// https://go.mparticle.com/work/SQDSDKS-6289
|
|
91
|
+
// TODO: Replace this with Store once Store is moved earlier in the init process
|
|
89
92
|
this.getDeviceId = this._Persistence.getDeviceId;
|
|
90
93
|
|
|
91
94
|
if (typeof window !== 'undefined') {
|
|
@@ -231,7 +234,7 @@ export default function mParticleInstance(instanceName) {
|
|
|
231
234
|
self.setDeviceId(guid);
|
|
232
235
|
}, self);
|
|
233
236
|
if (queued) return;
|
|
234
|
-
this.
|
|
237
|
+
this._Store.setDeviceId(guid);
|
|
235
238
|
};
|
|
236
239
|
/**
|
|
237
240
|
* Returns a boolean for whether or not the SDKhas been fully initialized
|
package/src/sdkRuntimeModels.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import * as EventsApi from '@mparticle/event-models';
|
|
2
2
|
import { DataPlanVersion } from '@mparticle/data-planning-models';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MPConfiguration,
|
|
5
|
+
IdentityApiData,
|
|
6
|
+
MPID,
|
|
7
|
+
Callback,
|
|
8
|
+
} from '@mparticle/web-sdk';
|
|
4
9
|
import { IStore } from './store';
|
|
5
10
|
import Validators from './validators';
|
|
6
11
|
import { Dictionary, valueof } from './utils';
|
|
@@ -246,19 +251,27 @@ export interface SDKIdentityApi {
|
|
|
246
251
|
|
|
247
252
|
export interface SDKHelpersApi {
|
|
248
253
|
canLog?(): boolean;
|
|
249
|
-
createServiceUrl(
|
|
254
|
+
createServiceUrl(url: string, devToken?: string): void;
|
|
250
255
|
createXHR?(cb: () => void): XMLHttpRequest;
|
|
251
256
|
extend?(...args: any[]);
|
|
252
257
|
parseNumber?(value: string | number): number;
|
|
253
258
|
generateUniqueId();
|
|
254
259
|
generateHash?(value: string): string;
|
|
255
|
-
|
|
260
|
+
// https://go.mparticle.com/work/SQDSDKS-6317
|
|
261
|
+
getFeatureFlag?(feature: string): boolean | string; // TODO: Feature Constants should be converted to enum
|
|
256
262
|
isDelayedByIntegration?(
|
|
257
263
|
delayedIntegrations: Dictionary<boolean>,
|
|
258
264
|
timeoutStart: number,
|
|
259
265
|
now: number
|
|
260
266
|
): boolean;
|
|
261
267
|
isObject?(item: any);
|
|
268
|
+
invokeCallback?(
|
|
269
|
+
callback: Callback,
|
|
270
|
+
code: string,
|
|
271
|
+
body: string,
|
|
272
|
+
mParticleUser?: MParticleUser,
|
|
273
|
+
previousMpid?: MPID
|
|
274
|
+
): void;
|
|
262
275
|
returnConvertedBoolean(data: string | boolean | number): boolean;
|
|
263
276
|
sanitizeAttributes?(
|
|
264
277
|
attrs: Dictionary<string>,
|
package/src/sessionManager.ts
CHANGED
|
@@ -129,7 +129,7 @@ export default function SessionManager(
|
|
|
129
129
|
messageType: Types.MessageType.SessionEnd,
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
nullifySession();
|
|
132
|
+
mpInstance._Store.nullifySession();
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -175,7 +175,7 @@ export default function SessionManager(
|
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
mpInstance._Store.sessionStartDate = null;
|
|
178
|
-
nullifySession();
|
|
178
|
+
mpInstance._Store.nullifySession();
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
};
|
|
@@ -204,7 +204,7 @@ export default function SessionManager(
|
|
|
204
204
|
clearTimeout(mpInstance._Store.globalTimer);
|
|
205
205
|
};
|
|
206
206
|
|
|
207
|
-
this.startNewSessionIfNeeded = function(): void {
|
|
207
|
+
this.startNewSessionIfNeeded = function (): void {
|
|
208
208
|
if (!mpInstance._Store.webviewBridgeEnabled) {
|
|
209
209
|
const persistence = mpInstance._Persistence.getPersistence();
|
|
210
210
|
|
|
@@ -217,11 +217,4 @@ export default function SessionManager(
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
};
|
|
220
|
-
|
|
221
|
-
function nullifySession(): void {
|
|
222
|
-
mpInstance._Store.sessionId = null;
|
|
223
|
-
mpInstance._Store.dateLastEventSent = null;
|
|
224
|
-
mpInstance._Store.sessionAttributes = {};
|
|
225
|
-
mpInstance._Persistence.update();
|
|
226
|
-
}
|
|
227
220
|
}
|
package/src/store.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { isNumber, isDataPlanSlug, Dictionary, parseNumber } from './utils';
|
|
24
24
|
import { SDKConsentState } from './consent';
|
|
25
25
|
import { Kit, MPForwarder } from './forwarders.interfaces';
|
|
26
|
+
import { IPersistenceMinified } from './persistence.interfaces';
|
|
26
27
|
|
|
27
28
|
// This represents the runtime configuration of the SDK AFTER
|
|
28
29
|
// initialization has been complete and all settings and
|
|
@@ -60,6 +61,7 @@ export interface SDKConfig {
|
|
|
60
61
|
aliasUrl?: string;
|
|
61
62
|
configUrl?: string;
|
|
62
63
|
identityUrl?: string;
|
|
64
|
+
userAudienceUrl?: string;
|
|
63
65
|
isIOS?: boolean;
|
|
64
66
|
maxProducts: number;
|
|
65
67
|
requestConfig?: boolean;
|
|
@@ -162,6 +164,18 @@ export interface IStore {
|
|
|
162
164
|
integrationDelayTimeoutStart: number; // UNIX Timestamp
|
|
163
165
|
webviewBridgeEnabled?: boolean;
|
|
164
166
|
wrapperSDKInfo: WrapperSDKInfo;
|
|
167
|
+
|
|
168
|
+
persistenceData?: IPersistenceMinified;
|
|
169
|
+
|
|
170
|
+
getDeviceId?(): string;
|
|
171
|
+
setDeviceId?(deviceId: string): void;
|
|
172
|
+
|
|
173
|
+
getFirstSeenTime?(mpid: MPID): number;
|
|
174
|
+
setFirstSeenTime?(mpid: MPID, time?: number): void;
|
|
175
|
+
getLastSeenTime?(mpid: MPID): number;
|
|
176
|
+
setLastSeenTime?(mpid: MPID, time?: number): void;
|
|
177
|
+
|
|
178
|
+
nullifySession?: () => void;
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
// TODO: Merge this with SDKStoreApi in sdkRuntimeModels
|
|
@@ -214,6 +228,27 @@ export default function Store(
|
|
|
214
228
|
version: null,
|
|
215
229
|
isInfoSet: false,
|
|
216
230
|
},
|
|
231
|
+
|
|
232
|
+
// Placeholder for in-memory persistence model
|
|
233
|
+
persistenceData: {
|
|
234
|
+
cu: null,
|
|
235
|
+
gs: {
|
|
236
|
+
sid: null,
|
|
237
|
+
ie: null,
|
|
238
|
+
sa: null,
|
|
239
|
+
ss: null,
|
|
240
|
+
dt: null,
|
|
241
|
+
av: null,
|
|
242
|
+
cgid: null,
|
|
243
|
+
das: null,
|
|
244
|
+
ia: null,
|
|
245
|
+
c: null,
|
|
246
|
+
csm: null,
|
|
247
|
+
les: null,
|
|
248
|
+
ssd: null,
|
|
249
|
+
},
|
|
250
|
+
l: null,
|
|
251
|
+
},
|
|
217
252
|
};
|
|
218
253
|
|
|
219
254
|
for (var key in defaultStore) {
|
|
@@ -418,6 +453,92 @@ export default function Store(
|
|
|
418
453
|
}
|
|
419
454
|
}
|
|
420
455
|
}
|
|
456
|
+
|
|
457
|
+
this.getDeviceId = () => this.deviceId;
|
|
458
|
+
this.setDeviceId = (deviceId: string) => {
|
|
459
|
+
this.deviceId = deviceId;
|
|
460
|
+
this.persistenceData.gs.das = deviceId;
|
|
461
|
+
mpInstance._Persistence.update();
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
this.nullifySession = (): void => {
|
|
465
|
+
this.sessionId = null;
|
|
466
|
+
this.dateLastEventSent = null;
|
|
467
|
+
this.sessionAttributes = {};
|
|
468
|
+
mpInstance._Persistence.update();
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
this.getFirstSeenTime = (mpid: MPID) => {
|
|
472
|
+
if (!mpid) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (
|
|
477
|
+
this.persistenceData &&
|
|
478
|
+
this.persistenceData[mpid] &&
|
|
479
|
+
this.persistenceData[mpid].fst
|
|
480
|
+
) {
|
|
481
|
+
return this.persistenceData[mpid].fst;
|
|
482
|
+
} else {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
this.setFirstSeenTime = (mpid: MPID, _time?: number) => {
|
|
488
|
+
if (!mpid) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const time = _time || new Date().getTime();
|
|
493
|
+
|
|
494
|
+
if (this.persistenceData) {
|
|
495
|
+
if (!this.persistenceData[mpid]) {
|
|
496
|
+
this.persistenceData[mpid] = {};
|
|
497
|
+
}
|
|
498
|
+
if (!this.persistenceData[mpid].fst) {
|
|
499
|
+
this.persistenceData[mpid].fst = time;
|
|
500
|
+
mpInstance._Persistence.savePersistence(this.persistenceData);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
this.getLastSeenTime = (mpid: MPID) => {
|
|
506
|
+
if (!mpid) {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
// // https://go.mparticle.com/work/SQDSDKS-6315
|
|
510
|
+
const currentUser = mpInstance.Identity.getCurrentUser();
|
|
511
|
+
if (mpid === currentUser?.getMPID()) {
|
|
512
|
+
// if the mpid is the current user, its last seen time is the current time
|
|
513
|
+
return new Date().getTime();
|
|
514
|
+
} else if (
|
|
515
|
+
this.persistenceData &&
|
|
516
|
+
this.persistenceData[mpid] &&
|
|
517
|
+
this.persistenceData[mpid].lst
|
|
518
|
+
) {
|
|
519
|
+
return this.persistenceData[mpid].lst;
|
|
520
|
+
} else {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
this.setLastSeenTime = (mpid: MPID, _time?: number) => {
|
|
526
|
+
if (!mpid) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const time = _time || new Date().getTime();
|
|
531
|
+
|
|
532
|
+
if (this.persistenceData) {
|
|
533
|
+
if (!this.persistenceData[mpid]) {
|
|
534
|
+
this.persistenceData[mpid] = {};
|
|
535
|
+
}
|
|
536
|
+
if (!this.persistenceData[mpid].lst) {
|
|
537
|
+
this.persistenceData[mpid].lst = time;
|
|
538
|
+
mpInstance._Persistence.savePersistence(this.persistenceData);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
};
|
|
421
542
|
}
|
|
422
543
|
|
|
423
544
|
export function processFlags(
|
|
@@ -431,6 +552,7 @@ export function processFlags(
|
|
|
431
552
|
OfflineStorage,
|
|
432
553
|
DirectUrlRouting,
|
|
433
554
|
CacheIdentity,
|
|
555
|
+
AudienceAPI,
|
|
434
556
|
} = Constants.FeatureFlags;
|
|
435
557
|
|
|
436
558
|
if (!config.flags) {
|
|
@@ -446,6 +568,7 @@ export function processFlags(
|
|
|
446
568
|
flags[OfflineStorage] = config.flags[OfflineStorage] || '0';
|
|
447
569
|
flags[DirectUrlRouting] = config.flags[DirectUrlRouting] === 'True';
|
|
448
570
|
flags[CacheIdentity] = config.flags[CacheIdentity] === 'True';
|
|
571
|
+
flags[AudienceAPI] = config.flags[AudienceAPI] === 'True';
|
|
449
572
|
|
|
450
573
|
return flags;
|
|
451
574
|
}
|
|
@@ -527,4 +650,4 @@ function processDirectBaseUrls(
|
|
|
527
650
|
}
|
|
528
651
|
|
|
529
652
|
return directBaseUrls;
|
|
530
|
-
}
|
|
653
|
+
}
|
package/src/uploaders.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface fetchPayload {
|
|
2
|
+
method: string;
|
|
3
|
+
headers: {
|
|
4
|
+
Accept: string;
|
|
5
|
+
'Content-Type'?: string;
|
|
6
|
+
};
|
|
7
|
+
body?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export abstract class AsyncUploader {
|
|
11
|
+
url: string;
|
|
12
|
+
public abstract upload(
|
|
13
|
+
fetchPayload: fetchPayload,
|
|
14
|
+
url?: string
|
|
15
|
+
): Promise<Response>;
|
|
16
|
+
|
|
17
|
+
constructor(url: string) {
|
|
18
|
+
this.url = url;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class FetchUploader extends AsyncUploader {
|
|
23
|
+
public async upload(
|
|
24
|
+
fetchPayload: fetchPayload,
|
|
25
|
+
_url?: string
|
|
26
|
+
): Promise<Response> {
|
|
27
|
+
const url = _url || this.url;
|
|
28
|
+
return await fetch(url, fetchPayload);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class XHRUploader extends AsyncUploader {
|
|
33
|
+
public async upload(fetchPayload: fetchPayload): Promise<Response> {
|
|
34
|
+
const response: Response = await this.makeRequest(
|
|
35
|
+
this.url,
|
|
36
|
+
fetchPayload.body
|
|
37
|
+
);
|
|
38
|
+
return response;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private async makeRequest(url: string, data: string): Promise<Response> {
|
|
42
|
+
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
xhr.onreadystatechange = () => {
|
|
45
|
+
if (xhr.readyState !== 4) return;
|
|
46
|
+
|
|
47
|
+
// Process the response
|
|
48
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
49
|
+
resolve((xhr as unknown) as Response);
|
|
50
|
+
} else {
|
|
51
|
+
reject(xhr);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
xhr.open('post', url);
|
|
56
|
+
xhr.send(data);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|