@microsoft/applicationinsights-offlinechannel-js 0.1.0-nightly3.2402-06
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/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +14 -0
- package/LICENSE.TXT +21 -0
- package/PRIVACY +3 -0
- package/README.md +63 -0
- package/SECURITY.md +41 -0
- package/SUPPORT.md +14 -0
- package/dist/es5/applicationinsights-offlinechannel-js.js +6391 -0
- package/dist/es5/applicationinsights-offlinechannel-js.js.map +1 -0
- package/dist/es5/applicationinsights-offlinechannel-js.min.js +6 -0
- package/dist/es5/applicationinsights-offlinechannel-js.min.js.map +1 -0
- package/dist-es5/Helpers/Utils.js +185 -0
- package/dist-es5/Helpers/Utils.js.map +1 -0
- package/dist-es5/InMemoryBatch.js +64 -0
- package/dist-es5/InMemoryBatch.js.map +1 -0
- package/dist-es5/Interfaces/IInMemoryBatch.js +8 -0
- package/dist-es5/Interfaces/IInMemoryBatch.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineBatch.js +9 -0
- package/dist-es5/Interfaces/IOfflineBatch.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineIndexDb.js +8 -0
- package/dist-es5/Interfaces/IOfflineIndexDb.js.map +1 -0
- package/dist-es5/Interfaces/IOfflineProvider.js +8 -0
- package/dist-es5/Interfaces/IOfflineProvider.js.map +1 -0
- package/dist-es5/Interfaces/ISender.js +8 -0
- package/dist-es5/Interfaces/ISender.js.map +1 -0
- package/dist-es5/OfflineBatchHandler.js +343 -0
- package/dist-es5/OfflineBatchHandler.js.map +1 -0
- package/dist-es5/OfflineChannel.js +465 -0
- package/dist-es5/OfflineChannel.js.map +1 -0
- package/dist-es5/PayloadHelper.js +62 -0
- package/dist-es5/PayloadHelper.js.map +1 -0
- package/dist-es5/Providers/IndexDbHelper.js +626 -0
- package/dist-es5/Providers/IndexDbHelper.js.map +1 -0
- package/dist-es5/Providers/IndexDbProvider.js +468 -0
- package/dist-es5/Providers/IndexDbProvider.js.map +1 -0
- package/dist-es5/Providers/WebStorageProvider.js +463 -0
- package/dist-es5/Providers/WebStorageProvider.js.map +1 -0
- package/dist-es5/Sender.js +572 -0
- package/dist-es5/Sender.js.map +1 -0
- package/dist-es5/__DynamicConstants.js +80 -0
- package/dist-es5/__DynamicConstants.js.map +1 -0
- package/dist-es5/applicationinsights-offlinechannel-js.js +11 -0
- package/dist-es5/applicationinsights-offlinechannel-js.js.map +1 -0
- package/package.json +65 -0
- package/tsconfig.json +28 -0
- package/types/applicationinsights-offlinechannel-js.d.ts +605 -0
- package/types/applicationinsights-offlinechannel-js.namespaced.d.ts +601 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Application Insights JavaScript SDK - Offline Channel, 0.1.0-nightly3.2402-06
|
|
3
|
+
* Copyright (c) Microsoft and contributors. All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import dynamicProto from "@microsoft/dynamicproto-js";
|
|
8
|
+
import { BreezeChannelIdentifier, DisabledPropertyName, utlSetStoragePrefix } from "@microsoft/applicationinsights-common";
|
|
9
|
+
import { _throwInternal, arrForEach, createProcessTelemetryContext, dumpObj, getExceptionName, getJSON, getLocation, getNavigator, getWindow, isArray, isBeaconsSupported, isFetchSupported, isXhrSupported, objKeys, onConfigChange, useXDomainRequest } from "@microsoft/applicationinsights-core-js";
|
|
10
|
+
import { createPromise, doAwaitResponse } from "@nevware21/ts-async";
|
|
11
|
+
import { isFunction, isNumber } from "@nevware21/ts-utils";
|
|
12
|
+
import { _DYN_DATA, _DYN_INITIALIZE, _DYN_IS_COMPLETELY_IDLE, _DYN_LENGTH, _DYN_ONERROR, _DYN_REASON, _DYN_REJECTED, _DYN_REPLACE, _DYN_SEND_POST, _DYN_SET_REQUEST_HEADER, _DYN_STATUS, _DYN_URL_STRING, _DYN_VALUE } from "./__DynamicConstants";
|
|
13
|
+
var DefaultOfflineIdentifier = "OfflineChannel";
|
|
14
|
+
//const FetchSyncRequestSizeLimitBytes = 65000; // approx 64kb (the current Edge, Firefox and Chrome max limit)
|
|
15
|
+
var PostChannelId = "PostChannel";
|
|
16
|
+
function _getResponseText(xhr) {
|
|
17
|
+
try {
|
|
18
|
+
return xhr.responseText;
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
// Best effort, as XHR may throw while XDR wont so just ignore
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function isOverrideFn(httpXHROverride) {
|
|
26
|
+
return httpXHROverride && httpXHROverride[_DYN_SEND_POST /* @min:%2esendPOST */];
|
|
27
|
+
}
|
|
28
|
+
function _prependTransports(theTransports, newTransports) {
|
|
29
|
+
if (newTransports) {
|
|
30
|
+
if (isNumber(newTransports)) {
|
|
31
|
+
theTransports = [newTransports].concat(theTransports);
|
|
32
|
+
}
|
|
33
|
+
else if (isArray(newTransports)) {
|
|
34
|
+
theTransports = newTransports.concat(theTransports);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return theTransports;
|
|
38
|
+
}
|
|
39
|
+
var Sender = /** @class */ (function () {
|
|
40
|
+
function Sender() {
|
|
41
|
+
var _consecutiveErrors; // How many times in a row a retryable error condition has occurred.
|
|
42
|
+
var _retryAt; // The time to retry at in milliseconds from 1970/01/01 (this makes the timer calculation easy).
|
|
43
|
+
//let _lastSend: number; // The time of the last send operation.
|
|
44
|
+
var _paused; // Flag indicating that the sending should be paused
|
|
45
|
+
var _stamp_specific_redirects;
|
|
46
|
+
var _syncFetchPayload = 0; // Keep track of the outstanding sync fetch payload total (as sync fetch has limits)
|
|
47
|
+
var _enableSendPromise;
|
|
48
|
+
var _alwaysUseCustomSend;
|
|
49
|
+
var _disableXhr;
|
|
50
|
+
var _fallbackSend;
|
|
51
|
+
var _isInitialized;
|
|
52
|
+
var _diagLog;
|
|
53
|
+
var _core;
|
|
54
|
+
var _httpInterface;
|
|
55
|
+
var _onlineChannelId;
|
|
56
|
+
var _isOneDs;
|
|
57
|
+
dynamicProto(Sender, this, function (_self, _base) {
|
|
58
|
+
var _sendCredentials = true; // for 1ds
|
|
59
|
+
_initDefaults();
|
|
60
|
+
_self.pause = function () {
|
|
61
|
+
_clearScheduledTimer();
|
|
62
|
+
_paused = true;
|
|
63
|
+
};
|
|
64
|
+
_self.resume = function () {
|
|
65
|
+
if (_paused) {
|
|
66
|
+
_paused = false;
|
|
67
|
+
_retryAt = null;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
_self.getXhrInst = function (sync) {
|
|
71
|
+
// unload events will be saved. so not return unload interface
|
|
72
|
+
return _httpInterface;
|
|
73
|
+
};
|
|
74
|
+
_self[_DYN_INITIALIZE /* @min:%2einitialize */] = function (config, core, cxt, diagLog, channelId, unloadHookContainer) {
|
|
75
|
+
_diagLog = diagLog || core.logger;
|
|
76
|
+
if (_isInitialized) {
|
|
77
|
+
_throwInternal(_diagLog, 1 /* eLoggingSeverity.CRITICAL */, 28 /* _eInternalMessageId.SenderNotInitialized */, "Sender is already initialized");
|
|
78
|
+
}
|
|
79
|
+
_core = core;
|
|
80
|
+
_consecutiveErrors = 0;
|
|
81
|
+
_retryAt = null;
|
|
82
|
+
_stamp_specific_redirects = 0;
|
|
83
|
+
// This function will be re-called whenever any referenced configuration is changed
|
|
84
|
+
var hook = onConfigChange(config, function (details) {
|
|
85
|
+
var config = details.cfg;
|
|
86
|
+
if (config.storagePrefix) {
|
|
87
|
+
utlSetStoragePrefix(config.storagePrefix);
|
|
88
|
+
}
|
|
89
|
+
var ctx = createProcessTelemetryContext(null, config, core);
|
|
90
|
+
var offlineCfg = ctx.getExtCfg(DefaultOfflineIdentifier);
|
|
91
|
+
_onlineChannelId = channelId || BreezeChannelIdentifier;
|
|
92
|
+
var senderConfig = ctx.getExtCfg(_onlineChannelId, {});
|
|
93
|
+
var offlineSenderCfg = offlineCfg.senderCfg || {};
|
|
94
|
+
if (_onlineChannelId == PostChannelId) {
|
|
95
|
+
_isOneDs = true;
|
|
96
|
+
}
|
|
97
|
+
_alwaysUseCustomSend = offlineSenderCfg.alwaysUseXhrOverride;
|
|
98
|
+
// default true
|
|
99
|
+
_enableSendPromise = !(senderConfig.enableSendPromise === false);
|
|
100
|
+
var xhrOverride = senderConfig.httpXHROverride;
|
|
101
|
+
var customInterface = isOverrideFn(xhrOverride) ? xhrOverride : null;
|
|
102
|
+
if (!customInterface && _isOneDs) {
|
|
103
|
+
var location_1 = getLocation();
|
|
104
|
+
if (location_1 && location_1.protocol && location_1.protocol.toLowerCase() === "file:") {
|
|
105
|
+
// Special case where a local html file fails with a CORS error on Chromium browsers
|
|
106
|
+
_sendCredentials = false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
var httpInterface = null;
|
|
110
|
+
var customTransPorts = offlineSenderCfg.transports || senderConfig.transports || [];
|
|
111
|
+
// User requested transport(s) values > Beacon > Fetch > XHR
|
|
112
|
+
// Beacon would be filtered out if user has set disableBeaconApi to true at _getSenderInterface
|
|
113
|
+
var theTransports = _prependTransports([1 /* TransportType.Xhr */, 2 /* TransportType.Fetch */, 3 /* TransportType.Beacon */], customTransPorts);
|
|
114
|
+
httpInterface = _getSenderInterface(theTransports, false);
|
|
115
|
+
var xhrInterface = { sendPOST: _xhrSender };
|
|
116
|
+
_fallbackSend = _xhrSender;
|
|
117
|
+
httpInterface = _alwaysUseCustomSend ? customInterface : (httpInterface || customInterface || xhrInterface);
|
|
118
|
+
_httpInterface = httpInterface || xhrInterface;
|
|
119
|
+
});
|
|
120
|
+
unloadHookContainer && unloadHookContainer.add(hook);
|
|
121
|
+
};
|
|
122
|
+
_self[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */] = function () {
|
|
123
|
+
try {
|
|
124
|
+
var senderPlugin = _core.getPlugin(_onlineChannelId).plugin;
|
|
125
|
+
if (senderPlugin && isFunction(senderPlugin[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */])) {
|
|
126
|
+
if (!senderPlugin[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */]()) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
// if can't get idle status of online sender, then isidle status only depends on offine sender idle status
|
|
133
|
+
}
|
|
134
|
+
return !_paused && _syncFetchPayload === 0;
|
|
135
|
+
};
|
|
136
|
+
_self._doTeardown = function (unloadCtx, unloadState) {
|
|
137
|
+
_initDefaults();
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* success handler
|
|
141
|
+
*/
|
|
142
|
+
function _onSuccess(res, onComplete) {
|
|
143
|
+
_doOnComplete(onComplete, 200, {}, res);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* error handler
|
|
147
|
+
*/
|
|
148
|
+
function _onError(message, onComplete) {
|
|
149
|
+
_throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 26 /* _eInternalMessageId.OnError */, "Failed to send telemetry.", { message: message });
|
|
150
|
+
_doOnComplete(onComplete, 400, {});
|
|
151
|
+
}
|
|
152
|
+
function _onNoPayloadUrl(onComplete) {
|
|
153
|
+
_onError("No endpoint url is provided for the batch", onComplete);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* partial success handler
|
|
157
|
+
*/
|
|
158
|
+
//TODO: partial success handler
|
|
159
|
+
// function _onPartialSuccess (payload: string[], results: IBackendResponse, onComplete?: OnCompleteCallback) {
|
|
160
|
+
// }
|
|
161
|
+
function _getSenderInterface(transports, syncSupport) {
|
|
162
|
+
var _a;
|
|
163
|
+
var transportType = null;
|
|
164
|
+
var sendPostFunc = null;
|
|
165
|
+
var lp = 0;
|
|
166
|
+
while (sendPostFunc == null && lp < transports[_DYN_LENGTH /* @min:%2elength */]) {
|
|
167
|
+
transportType = transports[lp];
|
|
168
|
+
if (!_disableXhr && transportType === 1 /* TransportType.Xhr */) {
|
|
169
|
+
if (useXDomainRequest()) {
|
|
170
|
+
// IE 8 and 9
|
|
171
|
+
sendPostFunc = _xdrSender;
|
|
172
|
+
}
|
|
173
|
+
else if (isXhrSupported()) {
|
|
174
|
+
sendPostFunc = _xhrSender;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (transportType === 2 /* TransportType.Fetch */ && isFetchSupported(syncSupport)) {
|
|
178
|
+
sendPostFunc = _fetchSender;
|
|
179
|
+
}
|
|
180
|
+
else if (transportType === 3 /* TransportType.Beacon */ && isBeaconsSupported()) {
|
|
181
|
+
sendPostFunc = _beaconSender;
|
|
182
|
+
}
|
|
183
|
+
lp++;
|
|
184
|
+
}
|
|
185
|
+
if (sendPostFunc) {
|
|
186
|
+
return _a = {},
|
|
187
|
+
_a[_DYN_SEND_POST /* @min:sendPOST */] = sendPostFunc,
|
|
188
|
+
_a;
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Send fetch API request
|
|
194
|
+
* @param payload - {string} - The data payload to be sent.
|
|
195
|
+
* @param oncomplete - {function} on complete function
|
|
196
|
+
* @param sync - {boolean} - not used
|
|
197
|
+
*/
|
|
198
|
+
function _fetchSender(payload, oncomplete, sync) {
|
|
199
|
+
return _doFetchSender(payload, oncomplete, false);
|
|
200
|
+
}
|
|
201
|
+
function _doOnComplete(oncomplete, status, headers, response) {
|
|
202
|
+
try {
|
|
203
|
+
oncomplete && oncomplete(status, headers, response);
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
// eslint-disable-next-line no-empty
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function _doBeaconSend(payload, oncomplete) {
|
|
210
|
+
var nav = getNavigator();
|
|
211
|
+
var url = payload[_DYN_URL_STRING /* @min:%2eurlString */];
|
|
212
|
+
if (!url) {
|
|
213
|
+
_onNoPayloadUrl(oncomplete);
|
|
214
|
+
// return true here, because we don't want to retry it with fallback sender
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
var data = payload[_DYN_DATA /* @min:%2edata */];
|
|
218
|
+
// Chrome only allows CORS-safelisted values for the sendBeacon data argument
|
|
219
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=720283
|
|
220
|
+
//const batch = buffer.batchPayloads(payload);
|
|
221
|
+
// Chrome only allows CORS-safelisted values for the sendBeacon data argument
|
|
222
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=720283
|
|
223
|
+
var plainTextBatch = new Blob([data], { type: "text/plain;charset=UTF-8" });
|
|
224
|
+
// The sendBeacon method returns true if the user agent is able to successfully queue the data for transfer. Otherwise it returns false.
|
|
225
|
+
var queued = nav.sendBeacon(url, plainTextBatch);
|
|
226
|
+
if (queued) {
|
|
227
|
+
_onSuccess(null, oncomplete);
|
|
228
|
+
}
|
|
229
|
+
return queued;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Send Beacon API request
|
|
233
|
+
* @param payload - {string} - The data payload to be sent.
|
|
234
|
+
* @param sync - {boolean} - not used
|
|
235
|
+
* Note: Beacon API does not support custom headers and we are not able to get
|
|
236
|
+
* appId from the backend for the correct correlation.
|
|
237
|
+
*/
|
|
238
|
+
function _beaconSender(payload, oncomplete, sync) {
|
|
239
|
+
var data = payload[_DYN_DATA /* @min:%2edata */];
|
|
240
|
+
if (data) {
|
|
241
|
+
// The sendBeacon method returns true if the user agent is able to successfully queue the data for transfer. Otherwise it returns false.
|
|
242
|
+
if (!_doBeaconSend(payload, oncomplete)) {
|
|
243
|
+
_fallbackSend && _fallbackSend(payload, oncomplete, true);
|
|
244
|
+
_throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 40 /* _eInternalMessageId.TransmissionFailed */, ". " + "Failed to send telemetry with Beacon API, retried with normal sender.");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Send XMLHttpRequest
|
|
251
|
+
* @param payload - {string} - The data payload to be sent.
|
|
252
|
+
* @param sync - {boolean} - Indicates if the request should be sent synchronously
|
|
253
|
+
*/
|
|
254
|
+
function _xhrSender(payload, oncomplete, sync) {
|
|
255
|
+
//let internalPayload = payload as IInternalPayloadData;
|
|
256
|
+
var thePromise;
|
|
257
|
+
var resolveFunc;
|
|
258
|
+
var rejectFunc;
|
|
259
|
+
var headers = payload.headers || {};
|
|
260
|
+
if (!sync && _enableSendPromise) {
|
|
261
|
+
thePromise = createPromise(function (resolve, reject) {
|
|
262
|
+
resolveFunc = resolve;
|
|
263
|
+
rejectFunc = reject;
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
var xhr = new XMLHttpRequest();
|
|
267
|
+
var endPointUrl = payload[_DYN_URL_STRING /* @min:%2eurlString */];
|
|
268
|
+
if (!endPointUrl) {
|
|
269
|
+
_onNoPayloadUrl(oncomplete);
|
|
270
|
+
resolveFunc && resolveFunc(false);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
xhr[DisabledPropertyName] = true;
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
// If the environment has locked down the XMLHttpRequest (preventExtensions and/or freeze), this would
|
|
278
|
+
// cause the request to fail and we no telemetry would be sent
|
|
279
|
+
}
|
|
280
|
+
xhr.open("POST", endPointUrl, !sync);
|
|
281
|
+
xhr[_DYN_SET_REQUEST_HEADER /* @min:%2esetRequestHeader */]("Content-type", "application/json");
|
|
282
|
+
arrForEach(objKeys(headers), function (headerName) {
|
|
283
|
+
xhr[_DYN_SET_REQUEST_HEADER /* @min:%2esetRequestHeader */](headerName, headers[headerName]);
|
|
284
|
+
});
|
|
285
|
+
xhr.onreadystatechange = function () {
|
|
286
|
+
var response = _getResponseText(xhr);
|
|
287
|
+
if (xhr.readyState !== 4) {
|
|
288
|
+
//TODO: this should not need, add in case
|
|
289
|
+
_handleResponse(oncomplete, xhr[_DYN_STATUS /* @min:%2estatus */], {}, response);
|
|
290
|
+
resolveFunc && resolveFunc(false);
|
|
291
|
+
}
|
|
292
|
+
_handleResponse(oncomplete, xhr[_DYN_STATUS /* @min:%2estatus */], {}, response);
|
|
293
|
+
resolveFunc && resolveFunc(true);
|
|
294
|
+
};
|
|
295
|
+
xhr[_DYN_ONERROR /* @min:%2eonerror */] = function (event) {
|
|
296
|
+
_doOnComplete(oncomplete, 400, {}, _formatErrorMessageXhr(xhr));
|
|
297
|
+
rejectFunc && rejectFunc(event);
|
|
298
|
+
};
|
|
299
|
+
xhr.ontimeout = function () {
|
|
300
|
+
_doOnComplete(oncomplete, 500, {}, _formatErrorMessageXhr(xhr));
|
|
301
|
+
resolveFunc && resolveFunc(false);
|
|
302
|
+
};
|
|
303
|
+
xhr.send(payload[_DYN_DATA /* @min:%2edata */]);
|
|
304
|
+
return thePromise;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Send fetch API request
|
|
308
|
+
* @param payload - {string} - The data payload to be sent.
|
|
309
|
+
* @param sync - {boolean} - For fetch this identifies whether we are "unloading" (false) or a normal request
|
|
310
|
+
*/
|
|
311
|
+
function _doFetchSender(payload, oncomplete, sync) {
|
|
312
|
+
var _a;
|
|
313
|
+
var endPointUrl = payload[_DYN_URL_STRING /* @min:%2eurlString */];
|
|
314
|
+
var batch = payload[_DYN_DATA /* @min:%2edata */];
|
|
315
|
+
var plainTextBatch = new Blob([batch], { type: "application/json" });
|
|
316
|
+
var thePromise;
|
|
317
|
+
var resolveFunc;
|
|
318
|
+
var rejectFunc;
|
|
319
|
+
var requestHeaders = new Headers();
|
|
320
|
+
var batchLength = batch[_DYN_LENGTH /* @min:%2elength */];
|
|
321
|
+
var ignoreResponse = false;
|
|
322
|
+
var responseHandled = false;
|
|
323
|
+
var headers = payload.headers || [];
|
|
324
|
+
//TODO: handle time out for 1ds
|
|
325
|
+
arrForEach(objKeys(headers), function (headerName) {
|
|
326
|
+
requestHeaders.append(headerName, headers[headerName]);
|
|
327
|
+
});
|
|
328
|
+
var init = (_a = {
|
|
329
|
+
method: "POST",
|
|
330
|
+
headers: requestHeaders,
|
|
331
|
+
body: plainTextBatch
|
|
332
|
+
},
|
|
333
|
+
_a[DisabledPropertyName] = true // Mark so we don't attempt to track this request
|
|
334
|
+
,
|
|
335
|
+
_a);
|
|
336
|
+
if (_sendCredentials && _isOneDs) {
|
|
337
|
+
// for 1ds, Don't send credentials when URL is file://
|
|
338
|
+
init.credentials = "include";
|
|
339
|
+
}
|
|
340
|
+
if (sync) {
|
|
341
|
+
// since offline will not trigger sync call
|
|
342
|
+
// this will not be called, add it here in case
|
|
343
|
+
init.keepalive = true;
|
|
344
|
+
ignoreResponse = true;
|
|
345
|
+
_syncFetchPayload += batchLength;
|
|
346
|
+
}
|
|
347
|
+
var request = new Request(endPointUrl, init);
|
|
348
|
+
try {
|
|
349
|
+
// Also try and tag the request (just in case the value in init is not copied over)
|
|
350
|
+
request[DisabledPropertyName] = true;
|
|
351
|
+
}
|
|
352
|
+
catch (e) {
|
|
353
|
+
// If the environment has locked down the XMLHttpRequest (preventExtensions and/or freeze), this would
|
|
354
|
+
// cause the request to fail and we no telemetry would be sent
|
|
355
|
+
}
|
|
356
|
+
if (!sync && _enableSendPromise) {
|
|
357
|
+
thePromise = createPromise(function (resolve, reject) {
|
|
358
|
+
resolveFunc = resolve;
|
|
359
|
+
rejectFunc = reject;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (!endPointUrl) {
|
|
363
|
+
_onNoPayloadUrl(oncomplete);
|
|
364
|
+
resolveFunc && resolveFunc(false);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
doAwaitResponse(fetch(request), function (result) {
|
|
369
|
+
if (sync) {
|
|
370
|
+
_syncFetchPayload -= batchLength;
|
|
371
|
+
batchLength = 0;
|
|
372
|
+
}
|
|
373
|
+
if (!responseHandled) {
|
|
374
|
+
responseHandled = true;
|
|
375
|
+
if (!result[_DYN_REJECTED /* @min:%2erejected */]) {
|
|
376
|
+
var response_1 = result[_DYN_VALUE /* @min:%2evalue */];
|
|
377
|
+
/**
|
|
378
|
+
* The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500.
|
|
379
|
+
* Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure
|
|
380
|
+
* or if anything prevented the request from completing.
|
|
381
|
+
*/
|
|
382
|
+
if (!response_1.ok) {
|
|
383
|
+
_doOnComplete(oncomplete, 400, {}, response_1.statusText);
|
|
384
|
+
resolveFunc && resolveFunc(false);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
doAwaitResponse(response_1.text(), function (resp) {
|
|
388
|
+
var status = response_1[_DYN_STATUS /* @min:%2estatus */];
|
|
389
|
+
_handleResponse(oncomplete, status, {}, response_1.statusText);
|
|
390
|
+
resolveFunc && resolveFunc(true);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
_doOnComplete(oncomplete, 400, {}, result[_DYN_REASON /* @min:%2ereason */] && result[_DYN_REASON /* @min:%2ereason */].message);
|
|
396
|
+
rejectFunc && rejectFunc(result[_DYN_REASON /* @min:%2ereason */]);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
catch (e) {
|
|
402
|
+
if (!responseHandled) {
|
|
403
|
+
_doOnComplete(oncomplete, 400, {}, dumpObj(e));
|
|
404
|
+
rejectFunc && rejectFunc(e);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (ignoreResponse && !responseHandled) {
|
|
408
|
+
// Assume success during unload processing as we most likely won't get the response
|
|
409
|
+
responseHandled = true;
|
|
410
|
+
_doOnComplete(oncomplete, 200, {});
|
|
411
|
+
resolveFunc && resolveFunc(true);
|
|
412
|
+
}
|
|
413
|
+
return thePromise;
|
|
414
|
+
}
|
|
415
|
+
function _handleResponse(oncomplete, status, headers, response) {
|
|
416
|
+
if (status == 206 && !_isOneDs) {
|
|
417
|
+
// for breeze, 206 is partially success, currently consider success
|
|
418
|
+
// TODO: handle partial success
|
|
419
|
+
_doOnComplete(oncomplete, 200, headers, response); // TODO: doc (support partial success)-> partial success add known issue (breeze)
|
|
420
|
+
}
|
|
421
|
+
else if (status == 204 && _isOneDs) {
|
|
422
|
+
// one collector
|
|
423
|
+
_doOnComplete(oncomplete, 200, headers, response);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
_doOnComplete(oncomplete, status, headers, response);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Parses the response from the backend.
|
|
431
|
+
* @param response - XMLHttpRequest or XDomainRequest response
|
|
432
|
+
*/
|
|
433
|
+
function _parseResponse(response) {
|
|
434
|
+
try {
|
|
435
|
+
if (response && response !== "") {
|
|
436
|
+
var result = getJSON().parse(response);
|
|
437
|
+
if (_isOneDs) {
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
// TODO: handle partial success
|
|
441
|
+
// if (result && result.itemsReceived && result.itemsReceived >= result.itemsAccepted &&
|
|
442
|
+
// result.itemsReceived - result.itemsAccepted === result.errors.length) {
|
|
443
|
+
// return result;
|
|
444
|
+
// }
|
|
445
|
+
if (result && result.itemsReceived) {
|
|
446
|
+
return result;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch (e) {
|
|
451
|
+
_throwInternal(_diagLog, 1 /* eLoggingSeverity.CRITICAL */, 43 /* _eInternalMessageId.InvalidBackendResponse */, "Cannot parse the response. " + getExceptionName(e), {
|
|
452
|
+
response: response
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
function _clearScheduledTimer() {
|
|
458
|
+
_retryAt = null;
|
|
459
|
+
}
|
|
460
|
+
function _formatErrorMessageXhr(xhr, message) {
|
|
461
|
+
if (xhr) {
|
|
462
|
+
return "XMLHttpRequest,Status:" + xhr[_DYN_STATUS /* @min:%2estatus */] + ",Response:" + _getResponseText(xhr) || xhr.response || "";
|
|
463
|
+
}
|
|
464
|
+
return message;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Send XDomainRequest
|
|
468
|
+
* @param payload - {string} - The data payload to be sent.
|
|
469
|
+
* @param sync - {boolean} - Indicates if the request should be sent synchronously
|
|
470
|
+
*
|
|
471
|
+
* Note: XDomainRequest does not support sync requests. This 'isAsync' parameter is added
|
|
472
|
+
* to maintain consistency with the xhrSender's contract
|
|
473
|
+
* Note: XDomainRequest does not support custom headers and we are not able to get
|
|
474
|
+
* appId from the backend for the correct correlation.
|
|
475
|
+
*/
|
|
476
|
+
function _xdrSender(payload, oncomplete, sync) {
|
|
477
|
+
// It doesn't support custom headers, so no action is taken with current requestHeaders
|
|
478
|
+
var _window = getWindow();
|
|
479
|
+
var xdr = new XDomainRequest();
|
|
480
|
+
var data = payload[_DYN_DATA /* @min:%2edata */];
|
|
481
|
+
xdr.onload = function () {
|
|
482
|
+
var response = _getResponseText(xdr);
|
|
483
|
+
if (_isOneDs) {
|
|
484
|
+
// for 1ds. we will assume onload means the request succeeded.
|
|
485
|
+
_doOnComplete(oncomplete, 200, {}, response);
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
_xdrOnLoad(xdr, oncomplete);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
xdr[_DYN_ONERROR /* @min:%2eonerror */] = function () {
|
|
492
|
+
_doOnComplete(oncomplete, 400, {}, _formatErrorMessageXdr(xdr));
|
|
493
|
+
};
|
|
494
|
+
xdr.ontimeout = function () {
|
|
495
|
+
_doOnComplete(oncomplete, 500, {});
|
|
496
|
+
};
|
|
497
|
+
xdr.onprogress = function () { };
|
|
498
|
+
// XDomainRequest requires the same protocol as the hosting page.
|
|
499
|
+
// If the protocol doesn't match, we can't send the telemetry :(.
|
|
500
|
+
var hostingProtocol = _window && _window.location && _window.location.protocol || "";
|
|
501
|
+
var endpoint = payload[_DYN_URL_STRING /* @min:%2eurlString */];
|
|
502
|
+
if (!endpoint) {
|
|
503
|
+
_onNoPayloadUrl(oncomplete);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (endpoint.lastIndexOf(hostingProtocol, 0) !== 0) {
|
|
507
|
+
_throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 40 /* _eInternalMessageId.TransmissionFailed */, ". " +
|
|
508
|
+
"Cannot send XDomain request. The endpoint URL protocol doesn't match the hosting page protocol.");
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
var endpointUrl = endpoint[_DYN_REPLACE /* @min:%2ereplace */](/^(https?:)/, "");
|
|
512
|
+
xdr.open("POST", endpointUrl);
|
|
513
|
+
xdr.send(data);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* xdr state changes
|
|
517
|
+
*/
|
|
518
|
+
function _xdrOnLoad(xdr, oncomplete) {
|
|
519
|
+
var responseText = _getResponseText(xdr);
|
|
520
|
+
if (xdr && (responseText + "" === "200" || responseText === "")) {
|
|
521
|
+
_consecutiveErrors = 0;
|
|
522
|
+
_onSuccess(responseText, oncomplete);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
var results = _parseResponse(responseText);
|
|
526
|
+
if (results && results.itemsAccepted) {
|
|
527
|
+
// TODO: onPartial success for appInsights
|
|
528
|
+
_onSuccess(responseText, oncomplete);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
_onError(_formatErrorMessageXdr(xdr), oncomplete);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function _formatErrorMessageXdr(xdr, message) {
|
|
536
|
+
if (xdr) {
|
|
537
|
+
return "XDomainRequest,Response:" + _getResponseText(xdr) || "";
|
|
538
|
+
}
|
|
539
|
+
return message;
|
|
540
|
+
}
|
|
541
|
+
// TDOD: add notification manager
|
|
542
|
+
// TODO: handler one collector "MSFPC"
|
|
543
|
+
function _initDefaults() {
|
|
544
|
+
_self._appId = null;
|
|
545
|
+
_consecutiveErrors = 0;
|
|
546
|
+
_retryAt = null;
|
|
547
|
+
_paused = false;
|
|
548
|
+
_stamp_specific_redirects = 0;
|
|
549
|
+
_syncFetchPayload = 0;
|
|
550
|
+
_disableXhr = false;
|
|
551
|
+
_isInitialized = false;
|
|
552
|
+
_fallbackSend = null;
|
|
553
|
+
_core = null;
|
|
554
|
+
_onlineChannelId = null;
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
// Removed Stub for Sender.prototype.pause.
|
|
559
|
+
// Removed Stub for Sender.prototype.resume.
|
|
560
|
+
// Removed Stub for Sender.prototype.initialize.
|
|
561
|
+
// Removed Stub for Sender.prototype.triggerSend.
|
|
562
|
+
// Removed Stub for Sender.prototype.isCompletelyIdle.
|
|
563
|
+
// Removed Stub for Sender.prototype.getXhrInst.
|
|
564
|
+
// Removed Stub for Sender.prototype._doTeardown.
|
|
565
|
+
// This is a workaround for an IE bug when using dynamicProto() with classes that don't have any
|
|
566
|
+
// non-dynamic functions or static properties/functions when using uglify-js to minify the resulting code.
|
|
567
|
+
Sender.__ieDyn=1;
|
|
568
|
+
|
|
569
|
+
return Sender;
|
|
570
|
+
}());
|
|
571
|
+
export { Sender };
|
|
572
|
+
//# sourceMappingURL=Sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sender.js.map","sources":["Sender.js"],"sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License.\r\nimport dynamicProto from \"@microsoft/dynamicproto-js\";\r\nimport { BreezeChannelIdentifier, DisabledPropertyName, utlSetStoragePrefix } from \"@microsoft/applicationinsights-common\";\r\nimport { _throwInternal, arrForEach, createProcessTelemetryContext, dumpObj, getExceptionName, getJSON, getLocation, getNavigator, getWindow, isArray, isBeaconsSupported, isFetchSupported, isXhrSupported, objKeys, onConfigChange, useXDomainRequest } from \"@microsoft/applicationinsights-core-js\";\r\nimport { createPromise, doAwaitResponse } from \"@nevware21/ts-async\";\r\nimport { isFunction, isNumber } from \"@nevware21/ts-utils\";\r\nimport { _DYN_DATA, _DYN_INITIALIZE, _DYN_IS_COMPLETELY_IDLE, _DYN_LENGTH, _DYN_ONERROR, _DYN_REASON, _DYN_REJECTED, _DYN_REPLACE, _DYN_SEND_POST, _DYN_SET_REQUEST_HEADER, _DYN_STATUS, _DYN_URL_STRING, _DYN_VALUE } from \"./__DynamicConstants\";\r\nvar DefaultOfflineIdentifier = \"OfflineChannel\";\r\n//const FetchSyncRequestSizeLimitBytes = 65000; // approx 64kb (the current Edge, Firefox and Chrome max limit)\r\nvar PostChannelId = \"PostChannel\";\r\nfunction _getResponseText(xhr) {\r\n try {\r\n return xhr.responseText;\r\n }\r\n catch (e) {\r\n // Best effort, as XHR may throw while XDR wont so just ignore\r\n }\r\n return null;\r\n}\r\nfunction isOverrideFn(httpXHROverride) {\r\n return httpXHROverride && httpXHROverride[_DYN_SEND_POST /* @min:%2esendPOST */];\r\n}\r\nfunction _prependTransports(theTransports, newTransports) {\r\n if (newTransports) {\r\n if (isNumber(newTransports)) {\r\n theTransports = [newTransports].concat(theTransports);\r\n }\r\n else if (isArray(newTransports)) {\r\n theTransports = newTransports.concat(theTransports);\r\n }\r\n }\r\n return theTransports;\r\n}\r\nvar Sender = /** @class */ (function () {\r\n function Sender() {\r\n var _consecutiveErrors; // How many times in a row a retryable error condition has occurred.\r\n var _retryAt; // The time to retry at in milliseconds from 1970/01/01 (this makes the timer calculation easy).\r\n //let _lastSend: number; // The time of the last send operation.\r\n var _paused; // Flag indicating that the sending should be paused\r\n var _stamp_specific_redirects;\r\n var _syncFetchPayload = 0; // Keep track of the outstanding sync fetch payload total (as sync fetch has limits)\r\n var _enableSendPromise;\r\n var _alwaysUseCustomSend;\r\n var _disableXhr;\r\n var _fallbackSend;\r\n var _isInitialized;\r\n var _diagLog;\r\n var _core;\r\n var _httpInterface;\r\n var _onlineChannelId;\r\n var _isOneDs;\r\n dynamicProto(Sender, this, function (_self, _base) {\r\n var _sendCredentials = true; // for 1ds\r\n _initDefaults();\r\n _self.pause = function () {\r\n _clearScheduledTimer();\r\n _paused = true;\r\n };\r\n _self.resume = function () {\r\n if (_paused) {\r\n _paused = false;\r\n _retryAt = null;\r\n }\r\n };\r\n _self.getXhrInst = function (sync) {\r\n // unload events will be saved. so not return unload interface\r\n return _httpInterface;\r\n };\r\n _self[_DYN_INITIALIZE /* @min:%2einitialize */] = function (config, core, cxt, diagLog, channelId, unloadHookContainer) {\r\n _diagLog = diagLog || core.logger;\r\n if (_isInitialized) {\r\n _throwInternal(_diagLog, 1 /* eLoggingSeverity.CRITICAL */, 28 /* _eInternalMessageId.SenderNotInitialized */, \"Sender is already initialized\");\r\n }\r\n _core = core;\r\n _consecutiveErrors = 0;\r\n _retryAt = null;\r\n _stamp_specific_redirects = 0;\r\n // This function will be re-called whenever any referenced configuration is changed\r\n var hook = onConfigChange(config, function (details) {\r\n var config = details.cfg;\r\n if (config.storagePrefix) {\r\n utlSetStoragePrefix(config.storagePrefix);\r\n }\r\n var ctx = createProcessTelemetryContext(null, config, core);\r\n var offlineCfg = ctx.getExtCfg(DefaultOfflineIdentifier);\r\n _onlineChannelId = channelId || BreezeChannelIdentifier;\r\n var senderConfig = ctx.getExtCfg(_onlineChannelId, {});\r\n var offlineSenderCfg = offlineCfg.senderCfg || {};\r\n if (_onlineChannelId == PostChannelId) {\r\n _isOneDs = true;\r\n }\r\n _alwaysUseCustomSend = offlineSenderCfg.alwaysUseXhrOverride;\r\n // default true\r\n _enableSendPromise = !(senderConfig.enableSendPromise === false);\r\n var xhrOverride = senderConfig.httpXHROverride;\r\n var customInterface = isOverrideFn(xhrOverride) ? xhrOverride : null;\r\n if (!customInterface && _isOneDs) {\r\n var location_1 = getLocation();\r\n if (location_1 && location_1.protocol && location_1.protocol.toLowerCase() === \"file:\") {\r\n // Special case where a local html file fails with a CORS error on Chromium browsers\r\n _sendCredentials = false;\r\n }\r\n }\r\n var httpInterface = null;\r\n var customTransPorts = offlineSenderCfg.transports || senderConfig.transports || [];\r\n // User requested transport(s) values > Beacon > Fetch > XHR\r\n // Beacon would be filtered out if user has set disableBeaconApi to true at _getSenderInterface\r\n var theTransports = _prependTransports([1 /* TransportType.Xhr */, 2 /* TransportType.Fetch */, 3 /* TransportType.Beacon */], customTransPorts);\r\n httpInterface = _getSenderInterface(theTransports, false);\r\n var xhrInterface = { sendPOST: _xhrSender };\r\n _fallbackSend = _xhrSender;\r\n httpInterface = _alwaysUseCustomSend ? customInterface : (httpInterface || customInterface || xhrInterface);\r\n _httpInterface = httpInterface || xhrInterface;\r\n });\r\n unloadHookContainer && unloadHookContainer.add(hook);\r\n };\r\n _self[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */] = function () {\r\n try {\r\n var senderPlugin = _core.getPlugin(_onlineChannelId).plugin;\r\n if (senderPlugin && isFunction(senderPlugin[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */])) {\r\n if (!senderPlugin[_DYN_IS_COMPLETELY_IDLE /* @min:%2eisCompletelyIdle */]()) {\r\n return false;\r\n }\r\n }\r\n }\r\n catch (e) {\r\n // if can't get idle status of online sender, then isidle status only depends on offine sender idle status\r\n }\r\n return !_paused && _syncFetchPayload === 0;\r\n };\r\n _self._doTeardown = function (unloadCtx, unloadState) {\r\n _initDefaults();\r\n };\r\n /**\r\n * success handler\r\n */\r\n function _onSuccess(res, onComplete) {\r\n _doOnComplete(onComplete, 200, {}, res);\r\n }\r\n /**\r\n * error handler\r\n */\r\n function _onError(message, onComplete) {\r\n _throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 26 /* _eInternalMessageId.OnError */, \"Failed to send telemetry.\", { message: message });\r\n _doOnComplete(onComplete, 400, {});\r\n }\r\n function _onNoPayloadUrl(onComplete) {\r\n _onError(\"No endpoint url is provided for the batch\", onComplete);\r\n }\r\n /**\r\n * partial success handler\r\n */\r\n //TODO: partial success handler\r\n // function _onPartialSuccess (payload: string[], results: IBackendResponse, onComplete?: OnCompleteCallback) {\r\n // }\r\n function _getSenderInterface(transports, syncSupport) {\r\n var _a;\r\n var transportType = null;\r\n var sendPostFunc = null;\r\n var lp = 0;\r\n while (sendPostFunc == null && lp < transports[_DYN_LENGTH /* @min:%2elength */]) {\r\n transportType = transports[lp];\r\n if (!_disableXhr && transportType === 1 /* TransportType.Xhr */) {\r\n if (useXDomainRequest()) {\r\n // IE 8 and 9\r\n sendPostFunc = _xdrSender;\r\n }\r\n else if (isXhrSupported()) {\r\n sendPostFunc = _xhrSender;\r\n }\r\n }\r\n else if (transportType === 2 /* TransportType.Fetch */ && isFetchSupported(syncSupport)) {\r\n sendPostFunc = _fetchSender;\r\n }\r\n else if (transportType === 3 /* TransportType.Beacon */ && isBeaconsSupported()) {\r\n sendPostFunc = _beaconSender;\r\n }\r\n lp++;\r\n }\r\n if (sendPostFunc) {\r\n return _a = {},\r\n _a[_DYN_SEND_POST /* @min:sendPOST */] = sendPostFunc,\r\n _a;\r\n }\r\n return null;\r\n }\r\n /**\r\n * Send fetch API request\r\n * @param payload - {string} - The data payload to be sent.\r\n * @param oncomplete - {function} on complete function\r\n * @param sync - {boolean} - not used\r\n */\r\n function _fetchSender(payload, oncomplete, sync) {\r\n return _doFetchSender(payload, oncomplete, false);\r\n }\r\n function _doOnComplete(oncomplete, status, headers, response) {\r\n try {\r\n oncomplete && oncomplete(status, headers, response);\r\n }\r\n catch (e) {\r\n // eslint-disable-next-line no-empty\r\n }\r\n }\r\n function _doBeaconSend(payload, oncomplete) {\r\n var nav = getNavigator();\r\n var url = payload[_DYN_URL_STRING /* @min:%2eurlString */];\r\n if (!url) {\r\n _onNoPayloadUrl(oncomplete);\r\n // return true here, because we don't want to retry it with fallback sender\r\n return true;\r\n }\r\n var data = payload[_DYN_DATA /* @min:%2edata */];\r\n // Chrome only allows CORS-safelisted values for the sendBeacon data argument\r\n // see: https://bugs.chromium.org/p/chromium/issues/detail?id=720283\r\n //const batch = buffer.batchPayloads(payload);\r\n // Chrome only allows CORS-safelisted values for the sendBeacon data argument\r\n // see: https://bugs.chromium.org/p/chromium/issues/detail?id=720283\r\n var plainTextBatch = new Blob([data], { type: \"text/plain;charset=UTF-8\" });\r\n // The sendBeacon method returns true if the user agent is able to successfully queue the data for transfer. Otherwise it returns false.\r\n var queued = nav.sendBeacon(url, plainTextBatch);\r\n if (queued) {\r\n _onSuccess(null, oncomplete);\r\n }\r\n return queued;\r\n }\r\n /**\r\n * Send Beacon API request\r\n * @param payload - {string} - The data payload to be sent.\r\n * @param sync - {boolean} - not used\r\n * Note: Beacon API does not support custom headers and we are not able to get\r\n * appId from the backend for the correct correlation.\r\n */\r\n function _beaconSender(payload, oncomplete, sync) {\r\n var data = payload[_DYN_DATA /* @min:%2edata */];\r\n if (data) {\r\n // The sendBeacon method returns true if the user agent is able to successfully queue the data for transfer. Otherwise it returns false.\r\n if (!_doBeaconSend(payload, oncomplete)) {\r\n _fallbackSend && _fallbackSend(payload, oncomplete, true);\r\n _throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 40 /* _eInternalMessageId.TransmissionFailed */, \". \" + \"Failed to send telemetry with Beacon API, retried with normal sender.\");\r\n }\r\n }\r\n return;\r\n }\r\n /**\r\n * Send XMLHttpRequest\r\n * @param payload - {string} - The data payload to be sent.\r\n * @param sync - {boolean} - Indicates if the request should be sent synchronously\r\n */\r\n function _xhrSender(payload, oncomplete, sync) {\r\n //let internalPayload = payload as IInternalPayloadData;\r\n var thePromise;\r\n var resolveFunc;\r\n var rejectFunc;\r\n var headers = payload.headers || {};\r\n if (!sync && _enableSendPromise) {\r\n thePromise = createPromise(function (resolve, reject) {\r\n resolveFunc = resolve;\r\n rejectFunc = reject;\r\n });\r\n }\r\n var xhr = new XMLHttpRequest();\r\n var endPointUrl = payload[_DYN_URL_STRING /* @min:%2eurlString */];\r\n if (!endPointUrl) {\r\n _onNoPayloadUrl(oncomplete);\r\n resolveFunc && resolveFunc(false);\r\n return;\r\n }\r\n try {\r\n xhr[DisabledPropertyName] = true;\r\n }\r\n catch (e) {\r\n // If the environment has locked down the XMLHttpRequest (preventExtensions and/or freeze), this would\r\n // cause the request to fail and we no telemetry would be sent\r\n }\r\n xhr.open(\"POST\", endPointUrl, !sync);\r\n xhr[_DYN_SET_REQUEST_HEADER /* @min:%2esetRequestHeader */](\"Content-type\", \"application/json\");\r\n arrForEach(objKeys(headers), function (headerName) {\r\n xhr[_DYN_SET_REQUEST_HEADER /* @min:%2esetRequestHeader */](headerName, headers[headerName]);\r\n });\r\n xhr.onreadystatechange = function () {\r\n var response = _getResponseText(xhr);\r\n if (xhr.readyState !== 4) {\r\n //TODO: this should not need, add in case\r\n _handleResponse(oncomplete, xhr[_DYN_STATUS /* @min:%2estatus */], {}, response);\r\n resolveFunc && resolveFunc(false);\r\n }\r\n _handleResponse(oncomplete, xhr[_DYN_STATUS /* @min:%2estatus */], {}, response);\r\n resolveFunc && resolveFunc(true);\r\n };\r\n xhr[_DYN_ONERROR /* @min:%2eonerror */] = function (event) {\r\n _doOnComplete(oncomplete, 400, {}, _formatErrorMessageXhr(xhr));\r\n rejectFunc && rejectFunc(event);\r\n };\r\n xhr.ontimeout = function () {\r\n _doOnComplete(oncomplete, 500, {}, _formatErrorMessageXhr(xhr));\r\n resolveFunc && resolveFunc(false);\r\n };\r\n xhr.send(payload[_DYN_DATA /* @min:%2edata */]);\r\n return thePromise;\r\n }\r\n /**\r\n * Send fetch API request\r\n * @param payload - {string} - The data payload to be sent.\r\n * @param sync - {boolean} - For fetch this identifies whether we are \"unloading\" (false) or a normal request\r\n */\r\n function _doFetchSender(payload, oncomplete, sync) {\r\n var _a;\r\n var endPointUrl = payload[_DYN_URL_STRING /* @min:%2eurlString */];\r\n var batch = payload[_DYN_DATA /* @min:%2edata */];\r\n var plainTextBatch = new Blob([batch], { type: \"application/json\" });\r\n var thePromise;\r\n var resolveFunc;\r\n var rejectFunc;\r\n var requestHeaders = new Headers();\r\n var batchLength = batch[_DYN_LENGTH /* @min:%2elength */];\r\n var ignoreResponse = false;\r\n var responseHandled = false;\r\n var headers = payload.headers || [];\r\n //TODO: handle time out for 1ds\r\n arrForEach(objKeys(headers), function (headerName) {\r\n requestHeaders.append(headerName, headers[headerName]);\r\n });\r\n var init = (_a = {\r\n method: \"POST\",\r\n headers: requestHeaders,\r\n body: plainTextBatch\r\n },\r\n _a[DisabledPropertyName] = true // Mark so we don't attempt to track this request\r\n ,\r\n _a);\r\n if (_sendCredentials && _isOneDs) {\r\n // for 1ds, Don't send credentials when URL is file://\r\n init.credentials = \"include\";\r\n }\r\n if (sync) {\r\n // since offline will not trigger sync call\r\n // this will not be called, add it here in case\r\n init.keepalive = true;\r\n ignoreResponse = true;\r\n _syncFetchPayload += batchLength;\r\n }\r\n var request = new Request(endPointUrl, init);\r\n try {\r\n // Also try and tag the request (just in case the value in init is not copied over)\r\n request[DisabledPropertyName] = true;\r\n }\r\n catch (e) {\r\n // If the environment has locked down the XMLHttpRequest (preventExtensions and/or freeze), this would\r\n // cause the request to fail and we no telemetry would be sent\r\n }\r\n if (!sync && _enableSendPromise) {\r\n thePromise = createPromise(function (resolve, reject) {\r\n resolveFunc = resolve;\r\n rejectFunc = reject;\r\n });\r\n }\r\n if (!endPointUrl) {\r\n _onNoPayloadUrl(oncomplete);\r\n resolveFunc && resolveFunc(false);\r\n return;\r\n }\r\n try {\r\n doAwaitResponse(fetch(request), function (result) {\r\n if (sync) {\r\n _syncFetchPayload -= batchLength;\r\n batchLength = 0;\r\n }\r\n if (!responseHandled) {\r\n responseHandled = true;\r\n if (!result[_DYN_REJECTED /* @min:%2erejected */]) {\r\n var response_1 = result[_DYN_VALUE /* @min:%2evalue */];\r\n /**\r\n * The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500.\r\n * Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure\r\n * or if anything prevented the request from completing.\r\n */\r\n if (!response_1.ok) {\r\n _doOnComplete(oncomplete, 400, {}, response_1.statusText);\r\n resolveFunc && resolveFunc(false);\r\n }\r\n else {\r\n doAwaitResponse(response_1.text(), function (resp) {\r\n var status = response_1[_DYN_STATUS /* @min:%2estatus */];\r\n _handleResponse(oncomplete, status, {}, response_1.statusText);\r\n resolveFunc && resolveFunc(true);\r\n });\r\n }\r\n }\r\n else {\r\n _doOnComplete(oncomplete, 400, {}, result[_DYN_REASON /* @min:%2ereason */] && result[_DYN_REASON /* @min:%2ereason */].message);\r\n rejectFunc && rejectFunc(result[_DYN_REASON /* @min:%2ereason */]);\r\n }\r\n }\r\n });\r\n }\r\n catch (e) {\r\n if (!responseHandled) {\r\n _doOnComplete(oncomplete, 400, {}, dumpObj(e));\r\n rejectFunc && rejectFunc(e);\r\n }\r\n }\r\n if (ignoreResponse && !responseHandled) {\r\n // Assume success during unload processing as we most likely won't get the response\r\n responseHandled = true;\r\n _doOnComplete(oncomplete, 200, {});\r\n resolveFunc && resolveFunc(true);\r\n }\r\n return thePromise;\r\n }\r\n function _handleResponse(oncomplete, status, headers, response) {\r\n if (status == 206 && !_isOneDs) {\r\n // for breeze, 206 is partially success, currently consider success\r\n // TODO: handle partial success\r\n _doOnComplete(oncomplete, 200, headers, response); // TODO: doc (support partial success)-> partial success add known issue (breeze)\r\n }\r\n else if (status == 204 && _isOneDs) {\r\n // one collector\r\n _doOnComplete(oncomplete, 200, headers, response);\r\n }\r\n else {\r\n _doOnComplete(oncomplete, status, headers, response);\r\n }\r\n }\r\n /**\r\n * Parses the response from the backend.\r\n * @param response - XMLHttpRequest or XDomainRequest response\r\n */\r\n function _parseResponse(response) {\r\n try {\r\n if (response && response !== \"\") {\r\n var result = getJSON().parse(response);\r\n if (_isOneDs) {\r\n return result;\r\n }\r\n // TODO: handle partial success\r\n // if (result && result.itemsReceived && result.itemsReceived >= result.itemsAccepted &&\r\n // result.itemsReceived - result.itemsAccepted === result.errors.length) {\r\n // return result;\r\n // }\r\n if (result && result.itemsReceived) {\r\n return result;\r\n }\r\n }\r\n }\r\n catch (e) {\r\n _throwInternal(_diagLog, 1 /* eLoggingSeverity.CRITICAL */, 43 /* _eInternalMessageId.InvalidBackendResponse */, \"Cannot parse the response. \" + getExceptionName(e), {\r\n response: response\r\n });\r\n }\r\n return null;\r\n }\r\n function _clearScheduledTimer() {\r\n _retryAt = null;\r\n }\r\n function _formatErrorMessageXhr(xhr, message) {\r\n if (xhr) {\r\n return \"XMLHttpRequest,Status:\" + xhr[_DYN_STATUS /* @min:%2estatus */] + \",Response:\" + _getResponseText(xhr) || xhr.response || \"\";\r\n }\r\n return message;\r\n }\r\n /**\r\n * Send XDomainRequest\r\n * @param payload - {string} - The data payload to be sent.\r\n * @param sync - {boolean} - Indicates if the request should be sent synchronously\r\n *\r\n * Note: XDomainRequest does not support sync requests. This 'isAsync' parameter is added\r\n * to maintain consistency with the xhrSender's contract\r\n * Note: XDomainRequest does not support custom headers and we are not able to get\r\n * appId from the backend for the correct correlation.\r\n */\r\n function _xdrSender(payload, oncomplete, sync) {\r\n // It doesn't support custom headers, so no action is taken with current requestHeaders\r\n var _window = getWindow();\r\n var xdr = new XDomainRequest();\r\n var data = payload[_DYN_DATA /* @min:%2edata */];\r\n xdr.onload = function () {\r\n var response = _getResponseText(xdr);\r\n if (_isOneDs) {\r\n // for 1ds. we will assume onload means the request succeeded.\r\n _doOnComplete(oncomplete, 200, {}, response);\r\n }\r\n else {\r\n _xdrOnLoad(xdr, oncomplete);\r\n }\r\n };\r\n xdr[_DYN_ONERROR /* @min:%2eonerror */] = function () {\r\n _doOnComplete(oncomplete, 400, {}, _formatErrorMessageXdr(xdr));\r\n };\r\n xdr.ontimeout = function () {\r\n _doOnComplete(oncomplete, 500, {});\r\n };\r\n xdr.onprogress = function () { };\r\n // XDomainRequest requires the same protocol as the hosting page.\r\n // If the protocol doesn't match, we can't send the telemetry :(.\r\n var hostingProtocol = _window && _window.location && _window.location.protocol || \"\";\r\n var endpoint = payload[_DYN_URL_STRING /* @min:%2eurlString */];\r\n if (!endpoint) {\r\n _onNoPayloadUrl(oncomplete);\r\n return;\r\n }\r\n if (endpoint.lastIndexOf(hostingProtocol, 0) !== 0) {\r\n _throwInternal(_diagLog, 2 /* eLoggingSeverity.WARNING */, 40 /* _eInternalMessageId.TransmissionFailed */, \". \" +\r\n \"Cannot send XDomain request. The endpoint URL protocol doesn't match the hosting page protocol.\");\r\n return;\r\n }\r\n var endpointUrl = endpoint[_DYN_REPLACE /* @min:%2ereplace */](/^(https?:)/, \"\");\r\n xdr.open(\"POST\", endpointUrl);\r\n xdr.send(data);\r\n }\r\n /**\r\n * xdr state changes\r\n */\r\n function _xdrOnLoad(xdr, oncomplete) {\r\n var responseText = _getResponseText(xdr);\r\n if (xdr && (responseText + \"\" === \"200\" || responseText === \"\")) {\r\n _consecutiveErrors = 0;\r\n _onSuccess(responseText, oncomplete);\r\n }\r\n else {\r\n var results = _parseResponse(responseText);\r\n if (results && results.itemsAccepted) {\r\n // TODO: onPartial success for appInsights\r\n _onSuccess(responseText, oncomplete);\r\n }\r\n else {\r\n _onError(_formatErrorMessageXdr(xdr), oncomplete);\r\n }\r\n }\r\n }\r\n function _formatErrorMessageXdr(xdr, message) {\r\n if (xdr) {\r\n return \"XDomainRequest,Response:\" + _getResponseText(xdr) || \"\";\r\n }\r\n return message;\r\n }\r\n // TDOD: add notification manager\r\n // TODO: handler one collector \"MSFPC\"\r\n function _initDefaults() {\r\n _self._appId = null;\r\n _consecutiveErrors = 0;\r\n _retryAt = null;\r\n _paused = false;\r\n _stamp_specific_redirects = 0;\r\n _syncFetchPayload = 0;\r\n _disableXhr = false;\r\n _isInitialized = false;\r\n _fallbackSend = null;\r\n _core = null;\r\n _onlineChannelId = null;\r\n }\r\n });\r\n }\r\n /**\r\n * Pause the sending (transmission) of events, this will cause all events to be batched only until the maximum limits are\r\n * hit at which point new events are dropped. Will also cause events to NOT be sent during page unload, so if Session storage\r\n * is disabled events will be lost.\r\n */\r\n Sender.prototype.pause = function () {\r\n // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging\r\n };\r\n /**\r\n * Resume the sending (transmission) of events, this will restart the timer and any batched events will be sent using the normal\r\n * send interval.\r\n */\r\n Sender.prototype.resume = function () {\r\n // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging\r\n };\r\n Sender.prototype.initialize = function (config, core, cxt, diagLog, channelId, unloadHookContainer) {\r\n // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging\r\n };\r\n /**\r\n * Trigger the immediate send of buffered data; If executing asynchronously (the default) this may (not required) return\r\n * an [IPromise](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html) that will resolve once the\r\n * send is complete. The actual implementation of the `IPromise` will be a native Promise (if supported) or the default\r\n * as supplied by [ts-async library](https://github.com/nevware21/ts-async)\r\n * @param async - Indicates if the events should be sent asynchronously\r\n * @param forcedSender - {SenderFunction} - Indicates the forcedSender, undefined if not passed\r\n * @returns - Nothing or optionally, if occurring asynchronously a [IPromise](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html)\r\n * which will be resolved (or reject) once the send is complete, the [IPromise](https://nevware21.github.io/ts-async/typedoc/interfaces/IPromise.html)\r\n * should only be returned when async is true.\r\n */\r\n Sender.prototype.triggerSend = function (async, forcedSender, sendReason) {\r\n if (async === void 0) { async = true; }\r\n // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging\r\n };\r\n /**\r\n * Check if there are no active requests being sent.\r\n * @returns True if idle, false otherwise.\r\n */\r\n Sender.prototype.isCompletelyIdle = function () {\r\n // @DynamicProtoStub - DO NOT add any code as this will be removed during packaging\r\n return false;\r\n };\r\n /**\r\n * Get current xhr instance\r\n */\r\n Sender.prototype.getXhrInst = function (sync) {\r\n // @DynamicProtoStub - DO NOT add any code as this will be removed during packaging\r\n return null;\r\n };\r\n Sender.prototype._doTeardown = function (unloadCtx, unloadState) {\r\n // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging\r\n };\r\n return Sender;\r\n}());\r\nexport { Sender };\r\n//# sourceMappingURL=Sender.js.map"],"names":[],"mappings":";;;;AAA4D;AAC1B;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;iDAkDM,CAAC;;;;;kBACW;AAClB;AACA;AACA"}
|