@datadog/browser-core
Advanced tools
Comparing version 1.21.0 to 1.24.0
@@ -5,3 +5,2 @@ import { CookieOptions } from './cookie'; | ||
allowedTracingOrigins: (string | RegExp)[]; | ||
isCollectingError: boolean; | ||
maxErrorsByMinute: number; | ||
@@ -38,3 +37,2 @@ maxInternalMonitoringMessagesPerPage: number; | ||
internalMonitoringApiKey?: string; | ||
isCollectingError?: boolean; | ||
allowedTracingOrigins?: Array<string | RegExp>; | ||
@@ -56,5 +54,2 @@ sampleRate?: number; | ||
replica?: ReplicaUserConfiguration; | ||
internalMonitoringEndpoint?: string; | ||
logsEndpoint?: string; | ||
rumEndpoint?: string; | ||
} | ||
@@ -83,4 +78,4 @@ interface ReplicaUserConfiguration { | ||
export declare function buildConfiguration(userConfiguration: UserConfiguration, buildEnv: BuildEnv): Configuration; | ||
export declare function buildCookieOptions(userConfiguration: UserConfiguration): CookieOptions; | ||
export declare function isIntakeRequest(url: string, configuration: Configuration): boolean; | ||
export declare function mustUseSecureCookie(userConfiguration: UserConfiguration): boolean; | ||
export {}; |
@@ -10,3 +10,2 @@ "use strict"; | ||
allowedTracingOrigins: [], | ||
isCollectingError: true, | ||
maxErrorsByMinute: 3000, | ||
@@ -53,3 +52,3 @@ maxInternalMonitoringMessagesPerPage: 15, | ||
: []; | ||
var configuration = tslib_1.__assign({ cookieOptions: {}, isEnabled: function (feature) { | ||
var configuration = tslib_1.__assign({ cookieOptions: buildCookieOptions(userConfiguration), isEnabled: function (feature) { | ||
return utils_1.includes(enableExperimentalFeatures, feature); | ||
@@ -63,5 +62,2 @@ }, logsEndpoint: getEndpoint('browser', transportConfiguration), proxyHost: userConfiguration.proxyHost, rumEndpoint: getEndpoint('rum', transportConfiguration), service: userConfiguration.service, traceEndpoint: getEndpoint('public-trace', transportConfiguration) }, exports.DEFAULT_CONFIGURATION); | ||
} | ||
if ('isCollectingError' in userConfiguration) { | ||
configuration.isCollectingError = !!userConfiguration.isCollectingError; | ||
} | ||
if ('sampleRate' in userConfiguration) { | ||
@@ -76,17 +72,6 @@ configuration.sampleRate = userConfiguration.sampleRate; | ||
} | ||
configuration.cookieOptions.secure = mustUseSecureCookie(userConfiguration); | ||
configuration.cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie; | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
configuration.cookieOptions.domain = cookie_1.getCurrentSite(); | ||
} | ||
if (transportConfiguration.buildMode === init_1.BuildMode.E2E_TEST) { | ||
if (userConfiguration.internalMonitoringEndpoint !== undefined) { | ||
configuration.internalMonitoringEndpoint = userConfiguration.internalMonitoringEndpoint; | ||
} | ||
if (userConfiguration.logsEndpoint !== undefined) { | ||
configuration.logsEndpoint = userConfiguration.logsEndpoint; | ||
} | ||
if (userConfiguration.rumEndpoint !== undefined) { | ||
configuration.rumEndpoint = userConfiguration.rumEndpoint; | ||
} | ||
configuration.internalMonitoringEndpoint = '<<< E2E INTERNAL MONITORING ENDPOINT >>>'; | ||
configuration.logsEndpoint = '<<< E2E LOGS ENDPOINT >>>'; | ||
configuration.rumEndpoint = '<<< E2E RUM ENDPOINT >>>'; | ||
} | ||
@@ -107,2 +92,12 @@ if (transportConfiguration.buildMode === init_1.BuildMode.STAGING) { | ||
exports.buildConfiguration = buildConfiguration; | ||
function buildCookieOptions(userConfiguration) { | ||
var cookieOptions = {}; | ||
cookieOptions.secure = mustUseSecureCookie(userConfiguration); | ||
cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie; | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
cookieOptions.domain = cookie_1.getCurrentSite(); | ||
} | ||
return cookieOptions; | ||
} | ||
exports.buildCookieOptions = buildCookieOptions; | ||
function getEndpoint(type, conf, source) { | ||
@@ -121,3 +116,3 @@ var tags = "sdk_version:" + conf.sdkVersion + | ||
function isIntakeRequest(url, configuration) { | ||
return (urlPolyfill_1.getPathName(url).indexOf('/v1/input/') === 0 && | ||
return (urlPolyfill_1.getPathName(url).indexOf('/v1/input/') !== -1 && | ||
(urlPolyfill_1.haveSameOrigin(url, configuration.logsEndpoint) || | ||
@@ -136,3 +131,2 @@ urlPolyfill_1.haveSameOrigin(url, configuration.rumEndpoint) || | ||
} | ||
exports.mustUseSecureCookie = mustUseSecureCookie; | ||
//# sourceMappingURL=configuration.js.map |
@@ -14,3 +14,3 @@ export declare const COOKIE_ACCESS_DELAY = 1000; | ||
export declare function getCookie(name: string): string | undefined; | ||
export declare function areCookiesAuthorized(useSecureCookie: boolean): boolean; | ||
export declare function areCookiesAuthorized(options: CookieOptions): boolean; | ||
/** | ||
@@ -17,0 +17,0 @@ * No API to retrieve it, number of levels for subdomain and suffix are unknown |
@@ -47,3 +47,3 @@ "use strict"; | ||
exports.getCookie = getCookie; | ||
function areCookiesAuthorized(useSecureCookie) { | ||
function areCookiesAuthorized(options) { | ||
if (document.cookie === undefined || document.cookie === null) { | ||
@@ -55,3 +55,3 @@ return false; | ||
var testCookieValue = 'test'; | ||
setCookie(testCookieName, testCookieValue, utils_1.ONE_SECOND, { secure: useSecureCookie }); | ||
setCookie(testCookieName, testCookieValue, utils_1.ONE_SECOND, options); | ||
return getCookie(testCookieName) === testCookieValue; | ||
@@ -58,0 +58,0 @@ } |
@@ -1,4 +0,4 @@ | ||
export { DEFAULT_CONFIGURATION, Configuration, UserConfiguration, isIntakeRequest, mustUseSecureCookie, } from './configuration'; | ||
export { DEFAULT_CONFIGURATION, Configuration, UserConfiguration, isIntakeRequest, buildCookieOptions, } from './configuration'; | ||
export { ErrorMessage, ErrorContext, HttpContext, ErrorOrigin, ErrorObservable } from './errorCollection'; | ||
export { BuildEnv, BuildMode, Datacenter, makeStub, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { BuildEnv, BuildMode, Datacenter, defineGlobal, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { InternalMonitoring, MonitoringMessage, monitored, monitor, addMonitoringMessage } from './internalMonitoring'; | ||
@@ -13,2 +13,4 @@ export { Observable } from './observable'; | ||
export { startFetchProxy, FetchCompleteContext, FetchStartContext, FetchProxy } from './fetchProxy'; | ||
export { BoundedBuffer } from './boundedBuffer'; | ||
export { createContextManager } from './contextManager'; | ||
export * from './specHelper'; |
@@ -7,3 +7,3 @@ "use strict"; | ||
exports.isIntakeRequest = configuration_1.isIntakeRequest; | ||
exports.mustUseSecureCookie = configuration_1.mustUseSecureCookie; | ||
exports.buildCookieOptions = configuration_1.buildCookieOptions; | ||
var errorCollection_1 = require("./errorCollection"); | ||
@@ -14,3 +14,3 @@ exports.ErrorOrigin = errorCollection_1.ErrorOrigin; | ||
exports.Datacenter = init_1.Datacenter; | ||
exports.makeStub = init_1.makeStub; | ||
exports.defineGlobal = init_1.defineGlobal; | ||
exports.makeGlobal = init_1.makeGlobal; | ||
@@ -46,3 +46,7 @@ exports.commonInit = init_1.commonInit; | ||
exports.startFetchProxy = fetchProxy_1.startFetchProxy; | ||
var boundedBuffer_1 = require("./boundedBuffer"); | ||
exports.BoundedBuffer = boundedBuffer_1.BoundedBuffer; | ||
var contextManager_1 = require("./contextManager"); | ||
exports.createContextManager = contextManager_1.createContextManager; | ||
tslib_1.__exportStar(require("./specHelper"), exports); | ||
//# sourceMappingURL=index.js.map |
import { UserConfiguration } from './configuration'; | ||
export declare function makeStub(methodName: string): void; | ||
export declare function makeGlobal<T>(stub: T): T; | ||
import { CookieOptions } from './cookie'; | ||
export declare function makeGlobal<T>(stub: T): T & { | ||
onReady(callback: () => void): void; | ||
}; | ||
export declare function defineGlobal<Global, Name extends keyof Global>(global: Global, name: Name, api: Global[Name]): void; | ||
export declare enum Datacenter { | ||
@@ -22,3 +25,3 @@ US = "us", | ||
} | ||
export declare function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv): { | ||
export declare function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv, isCollectingError: boolean): { | ||
configuration: import("./configuration").Configuration; | ||
@@ -28,3 +31,3 @@ errorObservable: import("./errorCollection").ErrorObservable; | ||
}; | ||
export declare function checkCookiesAuthorized(useSecureCookie: boolean): boolean; | ||
export declare function checkCookiesAuthorized(options: CookieOptions): boolean; | ||
export declare function checkIsNotLocalFile(): boolean; |
@@ -10,8 +10,10 @@ "use strict"; | ||
var observable_1 = require("./observable"); | ||
function makeStub(methodName) { | ||
console.warn("'" + methodName + "' not yet available, please call '.init()' first."); | ||
} | ||
exports.makeStub = makeStub; | ||
function makeGlobal(stub) { | ||
var global = tslib_1.__assign({}, stub); | ||
var global = tslib_1.__assign(tslib_1.__assign({}, stub), { | ||
// This API method is intentionally not monitored, since the only thing executed is the | ||
// user-provided 'callback'. All SDK usages executed in the callback should be monitored, and | ||
// we don't want to interfer with the user uncaught exceptions. | ||
onReady: function (callback) { | ||
callback(); | ||
} }); | ||
// Add an "hidden" property to set debug mode. We define it that way to hide it | ||
@@ -28,2 +30,10 @@ // as much as possible but of course it's not a real protection. | ||
exports.makeGlobal = makeGlobal; | ||
function defineGlobal(global, name, api) { | ||
var existingGlobalVariable = global[name]; | ||
global[name] = api; | ||
if (existingGlobalVariable && existingGlobalVariable.q) { | ||
existingGlobalVariable.q.forEach(function (fn) { return fn(); }); | ||
} | ||
} | ||
exports.defineGlobal = defineGlobal; | ||
var Datacenter; | ||
@@ -44,8 +54,6 @@ (function (Datacenter) { | ||
})(BuildMode = exports.BuildMode || (exports.BuildMode = {})); | ||
function commonInit(userConfiguration, buildEnv) { | ||
function commonInit(userConfiguration, buildEnv, isCollectingError) { | ||
var configuration = configuration_1.buildConfiguration(userConfiguration, buildEnv); | ||
var internalMonitoring = internalMonitoring_1.startInternalMonitoring(configuration); | ||
var errorObservable = configuration.isCollectingError | ||
? errorCollection_1.startErrorCollection(configuration) | ||
: new observable_1.Observable(); | ||
var errorObservable = isCollectingError ? errorCollection_1.startErrorCollection(configuration) : new observable_1.Observable(); | ||
return { | ||
@@ -58,4 +66,4 @@ configuration: configuration, | ||
exports.commonInit = commonInit; | ||
function checkCookiesAuthorized(useSecureCookie) { | ||
if (!cookie_1.areCookiesAuthorized(useSecureCookie)) { | ||
function checkCookiesAuthorized(options) { | ||
if (!cookie_1.areCookiesAuthorized(options)) { | ||
console.warn('Cookies are not authorized, we will not send any data.'); | ||
@@ -62,0 +70,0 @@ return false; |
@@ -41,3 +41,3 @@ "use strict"; | ||
function withContext(message) { | ||
return utils.deepMerge({ | ||
return utils.combine({ | ||
date: new Date().getTime(), | ||
@@ -44,0 +44,0 @@ view: { |
@@ -27,4 +27,21 @@ import { Configuration } from './configuration'; | ||
} | ||
declare class StubXhr { | ||
response: string | undefined; | ||
status: number | undefined; | ||
readyState: number; | ||
onreadystatechange: () => void; | ||
private fakeEventTarget; | ||
constructor(); | ||
open(method: string, url: string): void; | ||
send(): void; | ||
abort(): void; | ||
complete(status: number, response?: string): void; | ||
addEventListener(name: string, callback: () => void): void; | ||
private dispatchEvent; | ||
} | ||
export declare function stubXhr(): { | ||
reset(): void; | ||
}; | ||
export declare function withXhr({ setup, onComplete, }: { | ||
setup: (xhr: XMLHttpRequest) => void; | ||
setup: (xhr: StubXhr) => void; | ||
onComplete: (xhr: XMLHttpRequest) => void; | ||
@@ -34,1 +51,2 @@ }): void; | ||
export declare function restorePageVisibility(): void; | ||
export {}; |
@@ -134,2 +134,59 @@ "use strict"; | ||
exports.PerformanceObserverStubBuilder = PerformanceObserverStubBuilder; | ||
var StubXhr = /** @class */ (function () { | ||
function StubXhr() { | ||
this.response = undefined; | ||
this.status = undefined; | ||
this.readyState = XMLHttpRequest.UNSENT; | ||
this.onreadystatechange = utils_1.noop; | ||
this.fakeEventTarget = document.createElement('div'); | ||
} | ||
// tslint:disable:no-empty | ||
StubXhr.prototype.open = function (method, url) { }; | ||
StubXhr.prototype.send = function () { }; | ||
// tslint:enable:no-empty | ||
StubXhr.prototype.abort = function () { | ||
this.status = 0; | ||
}; | ||
StubXhr.prototype.complete = function (status, response) { | ||
this.response = response; | ||
this.status = status; | ||
this.readyState = XMLHttpRequest.DONE; | ||
this.onreadystatechange(); | ||
if (status >= 200 && status < 500) { | ||
this.dispatchEvent('load'); | ||
} | ||
if (status >= 500) { | ||
this.dispatchEvent('error'); | ||
} | ||
this.dispatchEvent('loadend'); | ||
}; | ||
StubXhr.prototype.addEventListener = function (name, callback) { | ||
this.fakeEventTarget.addEventListener(name, callback); | ||
}; | ||
StubXhr.prototype.dispatchEvent = function (name) { | ||
this.fakeEventTarget.dispatchEvent(createNewEvent(name)); | ||
}; | ||
return StubXhr; | ||
}()); | ||
function createNewEvent(eventName) { | ||
var event; | ||
if (typeof Event === 'function') { | ||
event = new Event(eventName); | ||
} | ||
else { | ||
event = document.createEvent('Event'); | ||
event.initEvent(eventName, true, true); | ||
} | ||
return event; | ||
} | ||
function stubXhr() { | ||
var originalXhr = XMLHttpRequest; | ||
XMLHttpRequest = StubXhr; | ||
return { | ||
reset: function () { | ||
XMLHttpRequest = originalXhr; | ||
}, | ||
}; | ||
} | ||
exports.stubXhr = stubXhr; | ||
function withXhr(_a) { | ||
@@ -136,0 +193,0 @@ var setup = _a.setup, onComplete = _a.onComplete; |
@@ -40,14 +40,6 @@ export declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||
}; | ||
/** | ||
* Performs a deep merge of objects and arrays | ||
* - arrays values are merged index by index | ||
* - objects are merged by keys | ||
* - values get replaced, unless undefined | ||
* | ||
* ⚠️ this method does not prevent infinite loops while merging circular references ⚠️ | ||
* | ||
*/ | ||
export declare function deepMerge(destination: ContextValue, ...toMerge: ContextValue[]): ContextValue; | ||
export declare function combine<A, B>(a: A, b: B): A & B; | ||
export declare function combine<A, B, C>(a: A, b: B, c: C): A & B & C; | ||
export declare function combine<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D; | ||
export declare function deepClone<T extends ContextValue>(context: T): T; | ||
interface Assignable { | ||
@@ -72,3 +64,3 @@ [key: string]: any; | ||
} | ||
export declare type ContextValue = string | number | boolean | Context | ContextArray | undefined; | ||
export declare type ContextValue = string | number | boolean | Context | ContextArray | undefined | null; | ||
export interface ContextArray extends Array<ContextValue> { | ||
@@ -119,2 +111,3 @@ } | ||
export declare function findCommaSeparatedValue(rawString: string, name: string): string | undefined; | ||
export declare function safeTruncate(candidate: string, length: number): string; | ||
export {}; |
101
cjs/utils.js
@@ -76,41 +76,75 @@ "use strict"; | ||
var isContextArray = function (value) { return Array.isArray(value); }; | ||
var isContext = function (value) { return !Array.isArray(value) && typeof value === 'object'; }; | ||
var isContext = function (value) { | ||
return !Array.isArray(value) && typeof value === 'object' && value !== null; | ||
}; | ||
/** | ||
* Performs a deep merge of objects and arrays | ||
* - arrays values are merged index by index | ||
* - objects are merged by keys | ||
* - values get replaced, unless undefined | ||
* Performs a deep merge of objects and arrays. | ||
* - Sources won't be mutated | ||
* - Object and arrays in the output value are dereferenced ("deep cloned") | ||
* - Arrays values are merged index by index | ||
* - Objects are merged by keys | ||
* - Values get replaced, unless undefined | ||
* | ||
* ⚠️ this method does not prevent infinite loops while merging circular references ⚠️ | ||
* | ||
* ⚠️ This function does not prevent infinite loops while merging circular references | ||
*/ | ||
function deepMerge(destination) { | ||
var toMerge = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
toMerge[_i - 1] = arguments[_i]; | ||
function deepMerge() { | ||
var sources = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
sources[_i] = arguments[_i]; | ||
} | ||
return toMerge.reduce(function (value1, value2) { | ||
if (isContextArray(value1) && isContextArray(value2)) { | ||
return tslib_1.__spreadArrays(Array(Math.max(value1.length, value2.length))).map(function (_, index) { | ||
return deepMerge(value1[index], value2[index]); | ||
}); | ||
var destination; | ||
for (var i = sources.length - 1; i >= 0; i -= 1) { | ||
var source = sources[i]; | ||
if (source === undefined) { | ||
// Ignore any undefined source. | ||
continue; | ||
} | ||
if (isContext(value1) && isContext(value2)) { | ||
return Object.keys(value2).reduce(function (merged, key) { | ||
var _a; | ||
return (tslib_1.__assign(tslib_1.__assign({}, merged), (_a = {}, _a[key] = deepMerge(value1[key], value2[key]), _a))); | ||
}, value1); | ||
if (destination === undefined) { | ||
// This is the first defined source. If it is "mergeable" (array or object), initialize the | ||
// destination with an empty value that will be populated with all sources sub values. Else, | ||
// just return its value. | ||
if (isContext(source)) { | ||
destination = {}; | ||
} | ||
else if (isContextArray(source)) { | ||
destination = []; | ||
} | ||
else { | ||
destination = source; | ||
break; | ||
} | ||
} | ||
return value2 === undefined ? value1 : value2; | ||
}, destination); | ||
// At this point, 'destination' is either an array or an object. If the current 'source' has | ||
// the same type we can merge it. Else, don't try to merge it or any other source. | ||
if (isContext(destination) && isContext(source)) { | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
destination[key] = deepMerge(source[key], destination[key]); | ||
} | ||
} | ||
} | ||
else if (isContextArray(destination) && isContextArray(source)) { | ||
destination.length = Math.max(destination.length, source.length); | ||
for (var index = 0; index < source.length; index += 1) { | ||
destination[index] = deepMerge(source[index], destination[index]); | ||
} | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
return destination; | ||
} | ||
exports.deepMerge = deepMerge; | ||
function combine(a) { | ||
var b = []; | ||
function combine(destination) { | ||
var toMerge = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
b[_i - 1] = arguments[_i]; | ||
toMerge[_i - 1] = arguments[_i]; | ||
} | ||
return deepMerge.apply(void 0, tslib_1.__spreadArrays([a], b)); | ||
return deepMerge.apply(void 0, tslib_1.__spreadArrays([destination], toMerge.filter(function (object) { return object !== null; }))); | ||
} | ||
exports.combine = combine; | ||
function deepClone(context) { | ||
return deepMerge(context); | ||
} | ||
exports.deepClone = deepClone; | ||
function assign(target) { | ||
@@ -172,3 +206,3 @@ var toAssign = []; | ||
} | ||
if (typeof candidate === 'object') { | ||
if (typeof candidate === 'object' && candidate !== null) { | ||
return withSnakeCaseKeys(candidate); | ||
@@ -355,2 +389,11 @@ } | ||
exports.findCommaSeparatedValue = findCommaSeparatedValue; | ||
function safeTruncate(candidate, length) { | ||
var lastChar = candidate.charCodeAt(length - 1); | ||
// check if it is the high part of a surrogate pair | ||
if (lastChar >= 0xd800 && lastChar <= 0xdbff) { | ||
return candidate.slice(0, length + 1); | ||
} | ||
return candidate.slice(0, length); | ||
} | ||
exports.safeTruncate = safeTruncate; | ||
//# sourceMappingURL=utils.js.map |
@@ -5,3 +5,2 @@ import { CookieOptions } from './cookie'; | ||
allowedTracingOrigins: (string | RegExp)[]; | ||
isCollectingError: boolean; | ||
maxErrorsByMinute: number; | ||
@@ -38,3 +37,2 @@ maxInternalMonitoringMessagesPerPage: number; | ||
internalMonitoringApiKey?: string; | ||
isCollectingError?: boolean; | ||
allowedTracingOrigins?: Array<string | RegExp>; | ||
@@ -56,5 +54,2 @@ sampleRate?: number; | ||
replica?: ReplicaUserConfiguration; | ||
internalMonitoringEndpoint?: string; | ||
logsEndpoint?: string; | ||
rumEndpoint?: string; | ||
} | ||
@@ -83,4 +78,4 @@ interface ReplicaUserConfiguration { | ||
export declare function buildConfiguration(userConfiguration: UserConfiguration, buildEnv: BuildEnv): Configuration; | ||
export declare function buildCookieOptions(userConfiguration: UserConfiguration): CookieOptions; | ||
export declare function isIntakeRequest(url: string, configuration: Configuration): boolean; | ||
export declare function mustUseSecureCookie(userConfiguration: UserConfiguration): boolean; | ||
export {}; |
@@ -8,3 +8,2 @@ import { __assign } from "tslib"; | ||
allowedTracingOrigins: [], | ||
isCollectingError: true, | ||
maxErrorsByMinute: 3000, | ||
@@ -51,3 +50,3 @@ maxInternalMonitoringMessagesPerPage: 15, | ||
: []; | ||
var configuration = __assign({ cookieOptions: {}, isEnabled: function (feature) { | ||
var configuration = __assign({ cookieOptions: buildCookieOptions(userConfiguration), isEnabled: function (feature) { | ||
return includes(enableExperimentalFeatures, feature); | ||
@@ -61,5 +60,2 @@ }, logsEndpoint: getEndpoint('browser', transportConfiguration), proxyHost: userConfiguration.proxyHost, rumEndpoint: getEndpoint('rum', transportConfiguration), service: userConfiguration.service, traceEndpoint: getEndpoint('public-trace', transportConfiguration) }, DEFAULT_CONFIGURATION); | ||
} | ||
if ('isCollectingError' in userConfiguration) { | ||
configuration.isCollectingError = !!userConfiguration.isCollectingError; | ||
} | ||
if ('sampleRate' in userConfiguration) { | ||
@@ -74,17 +70,6 @@ configuration.sampleRate = userConfiguration.sampleRate; | ||
} | ||
configuration.cookieOptions.secure = mustUseSecureCookie(userConfiguration); | ||
configuration.cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie; | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
configuration.cookieOptions.domain = getCurrentSite(); | ||
} | ||
if (transportConfiguration.buildMode === BuildMode.E2E_TEST) { | ||
if (userConfiguration.internalMonitoringEndpoint !== undefined) { | ||
configuration.internalMonitoringEndpoint = userConfiguration.internalMonitoringEndpoint; | ||
} | ||
if (userConfiguration.logsEndpoint !== undefined) { | ||
configuration.logsEndpoint = userConfiguration.logsEndpoint; | ||
} | ||
if (userConfiguration.rumEndpoint !== undefined) { | ||
configuration.rumEndpoint = userConfiguration.rumEndpoint; | ||
} | ||
configuration.internalMonitoringEndpoint = '<<< E2E INTERNAL MONITORING ENDPOINT >>>'; | ||
configuration.logsEndpoint = '<<< E2E LOGS ENDPOINT >>>'; | ||
configuration.rumEndpoint = '<<< E2E RUM ENDPOINT >>>'; | ||
} | ||
@@ -104,2 +89,11 @@ if (transportConfiguration.buildMode === BuildMode.STAGING) { | ||
} | ||
export function buildCookieOptions(userConfiguration) { | ||
var cookieOptions = {}; | ||
cookieOptions.secure = mustUseSecureCookie(userConfiguration); | ||
cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie; | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
cookieOptions.domain = getCurrentSite(); | ||
} | ||
return cookieOptions; | ||
} | ||
function getEndpoint(type, conf, source) { | ||
@@ -118,3 +112,3 @@ var tags = "sdk_version:" + conf.sdkVersion + | ||
export function isIntakeRequest(url, configuration) { | ||
return (getPathName(url).indexOf('/v1/input/') === 0 && | ||
return (getPathName(url).indexOf('/v1/input/') !== -1 && | ||
(haveSameOrigin(url, configuration.logsEndpoint) || | ||
@@ -129,5 +123,5 @@ haveSameOrigin(url, configuration.rumEndpoint) || | ||
} | ||
export function mustUseSecureCookie(userConfiguration) { | ||
function mustUseSecureCookie(userConfiguration) { | ||
return !!userConfiguration.useSecureSessionCookie || !!userConfiguration.useCrossSiteSessionCookie; | ||
} | ||
//# sourceMappingURL=configuration.js.map |
@@ -14,3 +14,3 @@ export declare const COOKIE_ACCESS_DELAY = 1000; | ||
export declare function getCookie(name: string): string | undefined; | ||
export declare function areCookiesAuthorized(useSecureCookie: boolean): boolean; | ||
export declare function areCookiesAuthorized(options: CookieOptions): boolean; | ||
/** | ||
@@ -17,0 +17,0 @@ * No API to retrieve it, number of levels for subdomain and suffix are unknown |
@@ -42,3 +42,3 @@ import { findCommaSeparatedValue, ONE_SECOND } from './utils'; | ||
} | ||
export function areCookiesAuthorized(useSecureCookie) { | ||
export function areCookiesAuthorized(options) { | ||
if (document.cookie === undefined || document.cookie === null) { | ||
@@ -50,3 +50,3 @@ return false; | ||
var testCookieValue = 'test'; | ||
setCookie(testCookieName, testCookieValue, ONE_SECOND, { secure: useSecureCookie }); | ||
setCookie(testCookieName, testCookieValue, ONE_SECOND, options); | ||
return getCookie(testCookieName) === testCookieValue; | ||
@@ -53,0 +53,0 @@ } |
@@ -1,4 +0,4 @@ | ||
export { DEFAULT_CONFIGURATION, Configuration, UserConfiguration, isIntakeRequest, mustUseSecureCookie, } from './configuration'; | ||
export { DEFAULT_CONFIGURATION, Configuration, UserConfiguration, isIntakeRequest, buildCookieOptions, } from './configuration'; | ||
export { ErrorMessage, ErrorContext, HttpContext, ErrorOrigin, ErrorObservable } from './errorCollection'; | ||
export { BuildEnv, BuildMode, Datacenter, makeStub, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { BuildEnv, BuildMode, Datacenter, defineGlobal, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { InternalMonitoring, MonitoringMessage, monitored, monitor, addMonitoringMessage } from './internalMonitoring'; | ||
@@ -13,2 +13,4 @@ export { Observable } from './observable'; | ||
export { startFetchProxy, FetchCompleteContext, FetchStartContext, FetchProxy } from './fetchProxy'; | ||
export { BoundedBuffer } from './boundedBuffer'; | ||
export { createContextManager } from './contextManager'; | ||
export * from './specHelper'; |
@@ -1,4 +0,4 @@ | ||
export { DEFAULT_CONFIGURATION, isIntakeRequest, mustUseSecureCookie, } from './configuration'; | ||
export { DEFAULT_CONFIGURATION, isIntakeRequest, buildCookieOptions, } from './configuration'; | ||
export { ErrorOrigin } from './errorCollection'; | ||
export { BuildMode, Datacenter, makeStub, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { BuildMode, Datacenter, defineGlobal, makeGlobal, commonInit, checkCookiesAuthorized, checkIsNotLocalFile, } from './init'; | ||
export { monitored, monitor, addMonitoringMessage } from './internalMonitoring'; | ||
@@ -15,3 +15,5 @@ export { Observable } from './observable'; | ||
export { startFetchProxy } from './fetchProxy'; | ||
export { BoundedBuffer } from './boundedBuffer'; | ||
export { createContextManager } from './contextManager'; | ||
export * from './specHelper'; | ||
//# sourceMappingURL=index.js.map |
import { UserConfiguration } from './configuration'; | ||
export declare function makeStub(methodName: string): void; | ||
export declare function makeGlobal<T>(stub: T): T; | ||
import { CookieOptions } from './cookie'; | ||
export declare function makeGlobal<T>(stub: T): T & { | ||
onReady(callback: () => void): void; | ||
}; | ||
export declare function defineGlobal<Global, Name extends keyof Global>(global: Global, name: Name, api: Global[Name]): void; | ||
export declare enum Datacenter { | ||
@@ -22,3 +25,3 @@ US = "us", | ||
} | ||
export declare function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv): { | ||
export declare function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv, isCollectingError: boolean): { | ||
configuration: import("./configuration").Configuration; | ||
@@ -28,3 +31,3 @@ errorObservable: import("./errorCollection").ErrorObservable; | ||
}; | ||
export declare function checkCookiesAuthorized(useSecureCookie: boolean): boolean; | ||
export declare function checkCookiesAuthorized(options: CookieOptions): boolean; | ||
export declare function checkIsNotLocalFile(): boolean; |
@@ -8,7 +8,10 @@ var _a; | ||
import { Observable } from './observable'; | ||
export function makeStub(methodName) { | ||
console.warn("'" + methodName + "' not yet available, please call '.init()' first."); | ||
} | ||
export function makeGlobal(stub) { | ||
var global = __assign({}, stub); | ||
var global = __assign(__assign({}, stub), { | ||
// This API method is intentionally not monitored, since the only thing executed is the | ||
// user-provided 'callback'. All SDK usages executed in the callback should be monitored, and | ||
// we don't want to interfer with the user uncaught exceptions. | ||
onReady: function (callback) { | ||
callback(); | ||
} }); | ||
// Add an "hidden" property to set debug mode. We define it that way to hide it | ||
@@ -24,2 +27,9 @@ // as much as possible but of course it's not a real protection. | ||
} | ||
export function defineGlobal(global, name, api) { | ||
var existingGlobalVariable = global[name]; | ||
global[name] = api; | ||
if (existingGlobalVariable && existingGlobalVariable.q) { | ||
existingGlobalVariable.q.forEach(function (fn) { return fn(); }); | ||
} | ||
} | ||
export var Datacenter; | ||
@@ -40,8 +50,6 @@ (function (Datacenter) { | ||
})(BuildMode || (BuildMode = {})); | ||
export function commonInit(userConfiguration, buildEnv) { | ||
export function commonInit(userConfiguration, buildEnv, isCollectingError) { | ||
var configuration = buildConfiguration(userConfiguration, buildEnv); | ||
var internalMonitoring = startInternalMonitoring(configuration); | ||
var errorObservable = configuration.isCollectingError | ||
? startErrorCollection(configuration) | ||
: new Observable(); | ||
var errorObservable = isCollectingError ? startErrorCollection(configuration) : new Observable(); | ||
return { | ||
@@ -53,4 +61,4 @@ configuration: configuration, | ||
} | ||
export function checkCookiesAuthorized(useSecureCookie) { | ||
if (!areCookiesAuthorized(useSecureCookie)) { | ||
export function checkCookiesAuthorized(options) { | ||
if (!areCookiesAuthorized(options)) { | ||
console.warn('Cookies are not authorized, we will not send any data.'); | ||
@@ -57,0 +65,0 @@ return false; |
@@ -38,3 +38,3 @@ import { __assign } from "tslib"; | ||
function withContext(message) { | ||
return utils.deepMerge({ | ||
return utils.combine({ | ||
date: new Date().getTime(), | ||
@@ -41,0 +41,0 @@ view: { |
@@ -27,4 +27,21 @@ import { Configuration } from './configuration'; | ||
} | ||
declare class StubXhr { | ||
response: string | undefined; | ||
status: number | undefined; | ||
readyState: number; | ||
onreadystatechange: () => void; | ||
private fakeEventTarget; | ||
constructor(); | ||
open(method: string, url: string): void; | ||
send(): void; | ||
abort(): void; | ||
complete(status: number, response?: string): void; | ||
addEventListener(name: string, callback: () => void): void; | ||
private dispatchEvent; | ||
} | ||
export declare function stubXhr(): { | ||
reset(): void; | ||
}; | ||
export declare function withXhr({ setup, onComplete, }: { | ||
setup: (xhr: XMLHttpRequest) => void; | ||
setup: (xhr: StubXhr) => void; | ||
onComplete: (xhr: XMLHttpRequest) => void; | ||
@@ -34,1 +51,2 @@ }): void; | ||
export declare function restorePageVisibility(): void; | ||
export {}; |
@@ -127,2 +127,58 @@ import { __assign, __awaiter, __generator } from "tslib"; | ||
export { PerformanceObserverStubBuilder }; | ||
var StubXhr = /** @class */ (function () { | ||
function StubXhr() { | ||
this.response = undefined; | ||
this.status = undefined; | ||
this.readyState = XMLHttpRequest.UNSENT; | ||
this.onreadystatechange = noop; | ||
this.fakeEventTarget = document.createElement('div'); | ||
} | ||
// tslint:disable:no-empty | ||
StubXhr.prototype.open = function (method, url) { }; | ||
StubXhr.prototype.send = function () { }; | ||
// tslint:enable:no-empty | ||
StubXhr.prototype.abort = function () { | ||
this.status = 0; | ||
}; | ||
StubXhr.prototype.complete = function (status, response) { | ||
this.response = response; | ||
this.status = status; | ||
this.readyState = XMLHttpRequest.DONE; | ||
this.onreadystatechange(); | ||
if (status >= 200 && status < 500) { | ||
this.dispatchEvent('load'); | ||
} | ||
if (status >= 500) { | ||
this.dispatchEvent('error'); | ||
} | ||
this.dispatchEvent('loadend'); | ||
}; | ||
StubXhr.prototype.addEventListener = function (name, callback) { | ||
this.fakeEventTarget.addEventListener(name, callback); | ||
}; | ||
StubXhr.prototype.dispatchEvent = function (name) { | ||
this.fakeEventTarget.dispatchEvent(createNewEvent(name)); | ||
}; | ||
return StubXhr; | ||
}()); | ||
function createNewEvent(eventName) { | ||
var event; | ||
if (typeof Event === 'function') { | ||
event = new Event(eventName); | ||
} | ||
else { | ||
event = document.createEvent('Event'); | ||
event.initEvent(eventName, true, true); | ||
} | ||
return event; | ||
} | ||
export function stubXhr() { | ||
var originalXhr = XMLHttpRequest; | ||
XMLHttpRequest = StubXhr; | ||
return { | ||
reset: function () { | ||
XMLHttpRequest = originalXhr; | ||
}, | ||
}; | ||
} | ||
export function withXhr(_a) { | ||
@@ -129,0 +185,0 @@ var setup = _a.setup, onComplete = _a.onComplete; |
@@ -40,14 +40,6 @@ export declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||
}; | ||
/** | ||
* Performs a deep merge of objects and arrays | ||
* - arrays values are merged index by index | ||
* - objects are merged by keys | ||
* - values get replaced, unless undefined | ||
* | ||
* ⚠️ this method does not prevent infinite loops while merging circular references ⚠️ | ||
* | ||
*/ | ||
export declare function deepMerge(destination: ContextValue, ...toMerge: ContextValue[]): ContextValue; | ||
export declare function combine<A, B>(a: A, b: B): A & B; | ||
export declare function combine<A, B, C>(a: A, b: B, c: C): A & B & C; | ||
export declare function combine<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D; | ||
export declare function deepClone<T extends ContextValue>(context: T): T; | ||
interface Assignable { | ||
@@ -72,3 +64,3 @@ [key: string]: any; | ||
} | ||
export declare type ContextValue = string | number | boolean | Context | ContextArray | undefined; | ||
export declare type ContextValue = string | number | boolean | Context | ContextArray | undefined | null; | ||
export interface ContextArray extends Array<ContextValue> { | ||
@@ -119,2 +111,3 @@ } | ||
export declare function findCommaSeparatedValue(rawString: string, name: string): string | undefined; | ||
export declare function safeTruncate(candidate: string, length: number): string; | ||
export {}; |
100
esm/utils.js
@@ -1,2 +0,2 @@ | ||
import { __assign, __spreadArrays } from "tslib"; | ||
import { __spreadArrays } from "tslib"; | ||
export var ONE_SECOND = 1000; | ||
@@ -73,39 +73,73 @@ export var ONE_MINUTE = 60 * ONE_SECOND; | ||
var isContextArray = function (value) { return Array.isArray(value); }; | ||
var isContext = function (value) { return !Array.isArray(value) && typeof value === 'object'; }; | ||
var isContext = function (value) { | ||
return !Array.isArray(value) && typeof value === 'object' && value !== null; | ||
}; | ||
/** | ||
* Performs a deep merge of objects and arrays | ||
* - arrays values are merged index by index | ||
* - objects are merged by keys | ||
* - values get replaced, unless undefined | ||
* Performs a deep merge of objects and arrays. | ||
* - Sources won't be mutated | ||
* - Object and arrays in the output value are dereferenced ("deep cloned") | ||
* - Arrays values are merged index by index | ||
* - Objects are merged by keys | ||
* - Values get replaced, unless undefined | ||
* | ||
* ⚠️ this method does not prevent infinite loops while merging circular references ⚠️ | ||
* | ||
* ⚠️ This function does not prevent infinite loops while merging circular references | ||
*/ | ||
export function deepMerge(destination) { | ||
var toMerge = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
toMerge[_i - 1] = arguments[_i]; | ||
function deepMerge() { | ||
var sources = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
sources[_i] = arguments[_i]; | ||
} | ||
return toMerge.reduce(function (value1, value2) { | ||
if (isContextArray(value1) && isContextArray(value2)) { | ||
return __spreadArrays(Array(Math.max(value1.length, value2.length))).map(function (_, index) { | ||
return deepMerge(value1[index], value2[index]); | ||
}); | ||
var destination; | ||
for (var i = sources.length - 1; i >= 0; i -= 1) { | ||
var source = sources[i]; | ||
if (source === undefined) { | ||
// Ignore any undefined source. | ||
continue; | ||
} | ||
if (isContext(value1) && isContext(value2)) { | ||
return Object.keys(value2).reduce(function (merged, key) { | ||
var _a; | ||
return (__assign(__assign({}, merged), (_a = {}, _a[key] = deepMerge(value1[key], value2[key]), _a))); | ||
}, value1); | ||
if (destination === undefined) { | ||
// This is the first defined source. If it is "mergeable" (array or object), initialize the | ||
// destination with an empty value that will be populated with all sources sub values. Else, | ||
// just return its value. | ||
if (isContext(source)) { | ||
destination = {}; | ||
} | ||
else if (isContextArray(source)) { | ||
destination = []; | ||
} | ||
else { | ||
destination = source; | ||
break; | ||
} | ||
} | ||
return value2 === undefined ? value1 : value2; | ||
}, destination); | ||
// At this point, 'destination' is either an array or an object. If the current 'source' has | ||
// the same type we can merge it. Else, don't try to merge it or any other source. | ||
if (isContext(destination) && isContext(source)) { | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
destination[key] = deepMerge(source[key], destination[key]); | ||
} | ||
} | ||
} | ||
else if (isContextArray(destination) && isContextArray(source)) { | ||
destination.length = Math.max(destination.length, source.length); | ||
for (var index = 0; index < source.length; index += 1) { | ||
destination[index] = deepMerge(source[index], destination[index]); | ||
} | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
return destination; | ||
} | ||
export function combine(a) { | ||
var b = []; | ||
export function combine(destination) { | ||
var toMerge = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
b[_i - 1] = arguments[_i]; | ||
toMerge[_i - 1] = arguments[_i]; | ||
} | ||
return deepMerge.apply(void 0, __spreadArrays([a], b)); | ||
return deepMerge.apply(void 0, __spreadArrays([destination], toMerge.filter(function (object) { return object !== null; }))); | ||
} | ||
export function deepClone(context) { | ||
return deepMerge(context); | ||
} | ||
export function assign(target) { | ||
@@ -161,3 +195,3 @@ var toAssign = []; | ||
} | ||
if (typeof candidate === 'object') { | ||
if (typeof candidate === 'object' && candidate !== null) { | ||
return withSnakeCaseKeys(candidate); | ||
@@ -326,2 +360,10 @@ } | ||
} | ||
export function safeTruncate(candidate, length) { | ||
var lastChar = candidate.charCodeAt(length - 1); | ||
// check if it is the high part of a surrogate pair | ||
if (lastChar >= 0xd800 && lastChar <= 0xdbff) { | ||
return candidate.slice(0, length + 1); | ||
} | ||
return candidate.slice(0, length); | ||
} | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@datadog/browser-core", | ||
"version": "1.21.0", | ||
"version": "1.24.0", | ||
"license": "Apache-2.0", | ||
@@ -26,3 +26,3 @@ "main": "cjs/index.js", | ||
}, | ||
"gitHead": "e3e6e905260928930528fb3d8511abb1e8113c17" | ||
"gitHead": "e161cbd59fa9c6568579036c42d1ec214e938117" | ||
} |
@@ -8,3 +8,2 @@ import { CookieOptions, getCurrentSite } from './cookie' | ||
allowedTracingOrigins: [] as Array<string | RegExp>, | ||
isCollectingError: true, | ||
maxErrorsByMinute: 3000, | ||
@@ -46,3 +45,2 @@ maxInternalMonitoringMessagesPerPage: 15, | ||
internalMonitoringApiKey?: string | ||
isCollectingError?: boolean | ||
allowedTracingOrigins?: Array<string | RegExp> | ||
@@ -68,7 +66,2 @@ sampleRate?: number | ||
replica?: ReplicaUserConfiguration | ||
// only on e2e-test build mode | ||
internalMonitoringEndpoint?: string | ||
logsEndpoint?: string | ||
rumEndpoint?: string | ||
} | ||
@@ -135,3 +128,3 @@ | ||
const configuration: Configuration = { | ||
cookieOptions: {}, | ||
cookieOptions: buildCookieOptions(userConfiguration), | ||
isEnabled: (feature: string) => { | ||
@@ -159,6 +152,2 @@ return includes(enableExperimentalFeatures, feature) | ||
if ('isCollectingError' in userConfiguration) { | ||
configuration.isCollectingError = !!userConfiguration.isCollectingError | ||
} | ||
if ('sampleRate' in userConfiguration) { | ||
@@ -176,19 +165,6 @@ configuration.sampleRate = userConfiguration.sampleRate! | ||
configuration.cookieOptions.secure = mustUseSecureCookie(userConfiguration) | ||
configuration.cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
configuration.cookieOptions.domain = getCurrentSite() | ||
} | ||
if (transportConfiguration.buildMode === BuildMode.E2E_TEST) { | ||
if (userConfiguration.internalMonitoringEndpoint !== undefined) { | ||
configuration.internalMonitoringEndpoint = userConfiguration.internalMonitoringEndpoint | ||
} | ||
if (userConfiguration.logsEndpoint !== undefined) { | ||
configuration.logsEndpoint = userConfiguration.logsEndpoint | ||
} | ||
if (userConfiguration.rumEndpoint !== undefined) { | ||
configuration.rumEndpoint = userConfiguration.rumEndpoint | ||
} | ||
configuration.internalMonitoringEndpoint = '<<< E2E INTERNAL MONITORING ENDPOINT >>>' | ||
configuration.logsEndpoint = '<<< E2E LOGS ENDPOINT >>>' | ||
configuration.rumEndpoint = '<<< E2E RUM ENDPOINT >>>' | ||
} | ||
@@ -220,2 +196,15 @@ | ||
export function buildCookieOptions(userConfiguration: UserConfiguration) { | ||
const cookieOptions: CookieOptions = {} | ||
cookieOptions.secure = mustUseSecureCookie(userConfiguration) | ||
cookieOptions.crossSite = !!userConfiguration.useCrossSiteSessionCookie | ||
if (!!userConfiguration.trackSessionAcrossSubdomains) { | ||
cookieOptions.domain = getCurrentSite() | ||
} | ||
return cookieOptions | ||
} | ||
function getEndpoint(type: string, conf: TransportConfiguration, source?: string) { | ||
@@ -238,3 +227,3 @@ const tags = | ||
return ( | ||
getPathName(url).indexOf('/v1/input/') === 0 && | ||
getPathName(url).indexOf('/v1/input/') !== -1 && | ||
(haveSameOrigin(url, configuration.logsEndpoint) || | ||
@@ -251,4 +240,4 @@ haveSameOrigin(url, configuration.rumEndpoint) || | ||
export function mustUseSecureCookie(userConfiguration: UserConfiguration) { | ||
function mustUseSecureCookie(userConfiguration: UserConfiguration) { | ||
return !!userConfiguration.useSecureSessionCookie || !!userConfiguration.useCrossSiteSessionCookie | ||
} |
@@ -60,3 +60,3 @@ import { findCommaSeparatedValue, ONE_SECOND } from './utils' | ||
export function areCookiesAuthorized(useSecureCookie: boolean): boolean { | ||
export function areCookiesAuthorized(options: CookieOptions): boolean { | ||
if (document.cookie === undefined || document.cookie === null) { | ||
@@ -68,3 +68,3 @@ return false | ||
const testCookieValue = 'test' | ||
setCookie(testCookieName, testCookieValue, ONE_SECOND, { secure: useSecureCookie }) | ||
setCookie(testCookieName, testCookieValue, ONE_SECOND, options) | ||
return getCookie(testCookieName) === testCookieValue | ||
@@ -71,0 +71,0 @@ } catch (error) { |
@@ -6,3 +6,3 @@ export { | ||
isIntakeRequest, | ||
mustUseSecureCookie, | ||
buildCookieOptions, | ||
} from './configuration' | ||
@@ -14,3 +14,3 @@ export { ErrorMessage, ErrorContext, HttpContext, ErrorOrigin, ErrorObservable } from './errorCollection' | ||
Datacenter, | ||
makeStub, | ||
defineGlobal, | ||
makeGlobal, | ||
@@ -36,3 +36,5 @@ commonInit, | ||
export { startFetchProxy, FetchCompleteContext, FetchStartContext, FetchProxy } from './fetchProxy' | ||
export { BoundedBuffer } from './boundedBuffer' | ||
export { createContextManager } from './contextManager' | ||
export * from './specHelper' |
import { buildConfiguration, UserConfiguration } from './configuration' | ||
import { areCookiesAuthorized } from './cookie' | ||
import { areCookiesAuthorized, CookieOptions } from './cookie' | ||
import { ErrorMessage, startErrorCollection } from './errorCollection' | ||
@@ -7,8 +7,13 @@ import { setDebugMode, startInternalMonitoring } from './internalMonitoring' | ||
export function makeStub(methodName: string) { | ||
console.warn(`'${methodName}' not yet available, please call '.init()' first.`) | ||
} | ||
export function makeGlobal<T>(stub: T): T & { onReady(callback: () => void): void } { | ||
const global = { | ||
...stub, | ||
export function makeGlobal<T>(stub: T): T { | ||
const global = { ...stub } | ||
// This API method is intentionally not monitored, since the only thing executed is the | ||
// user-provided 'callback'. All SDK usages executed in the callback should be monitored, and | ||
// we don't want to interfer with the user uncaught exceptions. | ||
onReady(callback: () => void) { | ||
callback() | ||
}, | ||
} | ||
@@ -27,2 +32,10 @@ // Add an "hidden" property to set debug mode. We define it that way to hide it | ||
export function defineGlobal<Global, Name extends keyof Global>(global: Global, name: Name, api: Global[Name]) { | ||
const existingGlobalVariable: { q?: Array<() => void> } | undefined = global[name] | ||
global[name] = api | ||
if (existingGlobalVariable && existingGlobalVariable.q) { | ||
existingGlobalVariable.q.forEach((fn) => fn()) | ||
} | ||
} | ||
export enum Datacenter { | ||
@@ -50,8 +63,6 @@ US = 'us', | ||
export function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv) { | ||
export function commonInit(userConfiguration: UserConfiguration, buildEnv: BuildEnv, isCollectingError: boolean) { | ||
const configuration = buildConfiguration(userConfiguration, buildEnv) | ||
const internalMonitoring = startInternalMonitoring(configuration) | ||
const errorObservable = configuration.isCollectingError | ||
? startErrorCollection(configuration) | ||
: new Observable<ErrorMessage>() | ||
const errorObservable = isCollectingError ? startErrorCollection(configuration) : new Observable<ErrorMessage>() | ||
@@ -65,4 +76,4 @@ return { | ||
export function checkCookiesAuthorized(useSecureCookie: boolean) { | ||
if (!areCookiesAuthorized(useSecureCookie)) { | ||
export function checkCookiesAuthorized(options: CookieOptions) { | ||
if (!areCookiesAuthorized(options)) { | ||
console.warn('Cookies are not authorized, we will not send any data.') | ||
@@ -69,0 +80,0 @@ return false |
@@ -70,3 +70,3 @@ // tslint:disable ban-types | ||
function withContext(message: MonitoringMessage) { | ||
return utils.deepMerge( | ||
return utils.combine( | ||
{ | ||
@@ -81,3 +81,3 @@ date: new Date().getTime(), | ||
message | ||
) as utils.Context | ||
) | ||
} | ||
@@ -84,0 +84,0 @@ |
@@ -144,2 +144,69 @@ import { Configuration } from './configuration' | ||
class StubXhr { | ||
public response: string | undefined = undefined | ||
public status: number | undefined = undefined | ||
public readyState: number = XMLHttpRequest.UNSENT | ||
public onreadystatechange: () => void = noop | ||
private fakeEventTarget: HTMLDivElement | ||
constructor() { | ||
this.fakeEventTarget = document.createElement('div') | ||
} | ||
// tslint:disable:no-empty | ||
open(method: string, url: string) {} | ||
send() {} | ||
// tslint:enable:no-empty | ||
abort() { | ||
this.status = 0 | ||
} | ||
complete(status: number, response?: string) { | ||
this.response = response | ||
this.status = status | ||
this.readyState = XMLHttpRequest.DONE | ||
this.onreadystatechange() | ||
if (status >= 200 && status < 500) { | ||
this.dispatchEvent('load') | ||
} | ||
if (status >= 500) { | ||
this.dispatchEvent('error') | ||
} | ||
this.dispatchEvent('loadend') | ||
} | ||
addEventListener(name: string, callback: () => void) { | ||
this.fakeEventTarget.addEventListener(name, callback) | ||
} | ||
private dispatchEvent(name: string) { | ||
this.fakeEventTarget.dispatchEvent(createNewEvent(name)) | ||
} | ||
} | ||
function createNewEvent(eventName: string) { | ||
let event | ||
if (typeof Event === 'function') { | ||
event = new Event(eventName) | ||
} else { | ||
event = document.createEvent('Event') | ||
event.initEvent(eventName, true, true) | ||
} | ||
return event | ||
} | ||
export function stubXhr() { | ||
const originalXhr = XMLHttpRequest | ||
XMLHttpRequest = StubXhr as any | ||
return { | ||
reset() { | ||
XMLHttpRequest = originalXhr | ||
}, | ||
} | ||
} | ||
export function withXhr({ | ||
@@ -149,3 +216,3 @@ setup, | ||
}: { | ||
setup: (xhr: XMLHttpRequest) => void | ||
setup: (xhr: StubXhr) => void | ||
onComplete: (xhr: XMLHttpRequest) => void | ||
@@ -159,3 +226,3 @@ }) { | ||
}) | ||
setup(xhr) | ||
setup((xhr as unknown) as StubXhr) | ||
} | ||
@@ -162,0 +229,0 @@ |
@@ -79,39 +79,72 @@ export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> | ||
const isContextArray = (value: ContextValue): value is ContextArray => Array.isArray(value) | ||
const isContext = (value: ContextValue): value is Context => !Array.isArray(value) && typeof value === 'object' | ||
const isContext = (value: ContextValue): value is Context => | ||
!Array.isArray(value) && typeof value === 'object' && value !== null | ||
/** | ||
* Performs a deep merge of objects and arrays | ||
* - arrays values are merged index by index | ||
* - objects are merged by keys | ||
* - values get replaced, unless undefined | ||
* Performs a deep merge of objects and arrays. | ||
* - Sources won't be mutated | ||
* - Object and arrays in the output value are dereferenced ("deep cloned") | ||
* - Arrays values are merged index by index | ||
* - Objects are merged by keys | ||
* - Values get replaced, unless undefined | ||
* | ||
* ⚠️ this method does not prevent infinite loops while merging circular references ⚠️ | ||
* | ||
* ⚠️ This function does not prevent infinite loops while merging circular references | ||
*/ | ||
export function deepMerge(destination: ContextValue, ...toMerge: ContextValue[]): ContextValue { | ||
return toMerge.reduce((value1: ContextValue, value2: ContextValue): ContextValue => { | ||
if (isContextArray(value1) && isContextArray(value2)) { | ||
return [...Array(Math.max(value1.length, value2.length))].map((_, index) => | ||
deepMerge(value1[index], value2[index]) | ||
) | ||
function deepMerge(...sources: ContextValue[]): ContextValue { | ||
let destination: ContextValue | ||
for (let i = sources.length - 1; i >= 0; i -= 1) { | ||
const source = sources[i] | ||
if (source === undefined) { | ||
// Ignore any undefined source. | ||
continue | ||
} | ||
if (isContext(value1) && isContext(value2)) { | ||
return Object.keys(value2).reduce( | ||
(merged, key) => ({ | ||
...merged, | ||
[key]: deepMerge(value1[key], value2[key]), | ||
}), | ||
value1 | ||
) | ||
if (destination === undefined) { | ||
// This is the first defined source. If it is "mergeable" (array or object), initialize the | ||
// destination with an empty value that will be populated with all sources sub values. Else, | ||
// just return its value. | ||
if (isContext(source)) { | ||
destination = {} | ||
} else if (isContextArray(source)) { | ||
destination = [] | ||
} else { | ||
destination = source | ||
break | ||
} | ||
} | ||
return value2 === undefined ? value1 : value2 | ||
}, destination) | ||
// At this point, 'destination' is either an array or an object. If the current 'source' has | ||
// the same type we can merge it. Else, don't try to merge it or any other source. | ||
if (isContext(destination) && isContext(source)) { | ||
for (const key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
destination[key] = deepMerge(source[key], destination[key]) | ||
} | ||
} | ||
} else if (isContextArray(destination) && isContextArray(source)) { | ||
destination.length = Math.max(destination.length, source.length) | ||
for (let index = 0; index < source.length; index += 1) { | ||
destination[index] = deepMerge(source[index], destination[index]) | ||
} | ||
} else { | ||
break | ||
} | ||
} | ||
return destination | ||
} | ||
export function combine<A, B>(a: A, b: B): A & B | ||
export function combine<A, B, C>(a: A, b: B, c: C): A & B & C | ||
export function combine<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D | ||
export function combine(a: Context, ...b: Context[]): Context { | ||
return deepMerge(a, ...b) as Context | ||
export function combine(destination: Context, ...toMerge: Array<Context | null>): Context { | ||
return deepMerge(destination, ...toMerge.filter((object) => object !== null)) as Context | ||
} | ||
export function deepClone<T extends ContextValue>(context: T): T { | ||
return deepMerge(context) as T | ||
} | ||
interface Assignable { | ||
@@ -165,3 +198,3 @@ [key: string]: any | ||
export type ContextValue = string | number | boolean | Context | ContextArray | undefined | ||
export type ContextValue = string | number | boolean | Context | ContextArray | undefined | null | ||
@@ -182,3 +215,3 @@ export interface ContextArray extends Array<ContextValue> {} | ||
} | ||
if (typeof candidate === 'object') { | ||
if (typeof candidate === 'object' && candidate !== null) { | ||
return withSnakeCaseKeys(candidate) | ||
@@ -376,1 +409,10 @@ } | ||
} | ||
export function safeTruncate(candidate: string, length: number) { | ||
const lastChar = candidate.charCodeAt(length - 1) | ||
// check if it is the high part of a surrogate pair | ||
if (lastChar >= 0xd800 && lastChar <= 0xdbff) { | ||
return candidate.slice(0, length + 1) | ||
} | ||
return candidate.slice(0, length) | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
511700
129
9682