mirror of
https://github.com/rxliuli/apps.apple.com.git
synced 2025-11-09 22:10:33 +00:00
729 lines
25 KiB
JavaScript
729 lines
25 KiB
JavaScript
import { AbstractEventRecorder, Delegates } from '@amp-metrics/mt-metricskit-delegates-core';
|
||
import { EventRecorder as EventRecorder$1, ImmediateEventRecorder, environment, network, logger } from '@amp-metrics/mt-event-queue';
|
||
import { reflect, backoff } from '@amp-metrics/mt-metricskit-utils-private';
|
||
|
||
/*
|
||
* src/environment.js
|
||
* mt-metricskit-delegates-web
|
||
*
|
||
* Copyright © 2022 Apple Inc. All rights reserved.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* Provides a pre-built HTML delegate to use against the metrics.system.environment delegate via metrics.system.environment.setDelegate()
|
||
* If you want to use *most* of these methods, but not *all* of them, you can set this delegate and then create your own with whichever few methods you need to
|
||
* customize additionally, and then setDelegate() *that* delegate, in order to override those methods.
|
||
* @constructor
|
||
* @param {Config} config (optional) - An instance of Config, which contains the topic and the relevant configurations for the topic.
|
||
*/
|
||
|
||
function Environment(config) {
|
||
this._config = config;
|
||
}
|
||
|
||
/**
|
||
************************************ PSEUDO-PRIVATE METHODS/IVARS ************************************
|
||
* These functions need to be accessible for ease of testing, but should not be used by clients
|
||
*/
|
||
Environment.prototype._document = function _document() {
|
||
if (typeof document != 'undefined') {
|
||
return document;
|
||
} else {
|
||
throw "metricskit-delegates-html.environment HTML delegate 'document' object not found";
|
||
}
|
||
};
|
||
|
||
Environment.prototype._window = function _window() {
|
||
if (typeof window != 'undefined') {
|
||
return window;
|
||
} else {
|
||
throw "metricskit-delegates-html.environment HTML delegate 'window' object not found";
|
||
}
|
||
};
|
||
|
||
/**
|
||
************************************ PUBLIC METHODS/IVARS ************************************
|
||
*/
|
||
|
||
/**
|
||
* The name of the browser that generated the event, it only return browser field if "browserMaps" config property exists in the topic config
|
||
* Common userAgent format: "Mozilla/5.0 (<system-information>) <platform> (<platform-details>) <extensions>"
|
||
* This implementation will read the browser identifer from the first item in the extensions part of the userAgent.
|
||
* For those browsers which do not store their browser identifier in the first item (can be configured in "specifiedBrowsers" config, see the below example),
|
||
* the function will search the defined string in the userAgent to verify if it is the case.
|
||
* It will load the browser related configurations from "browserMaps" in the topic. The config looks like
|
||
* {
|
||
* specifiedBrowsers: string[], // listing the browsers identifiers which does not located in the first item in "extensions" in userAgent.
|
||
* browserMap: Record<string, string> // map the browser identifiers to readable string. For example, Edg -> Edge, OPR -> Opera
|
||
* }
|
||
* @example Safari
|
||
* @returns {Promise<string | null> | null}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.browser = function browser() {
|
||
var userAgent = this._window().navigator.userAgent;
|
||
|
||
if (!reflect.isDefinedNonNull(this._config) || !reflect.isDefinedNonNullNonEmpty(userAgent)) {
|
||
return null;
|
||
}
|
||
|
||
return this._config.value('browserMaps').then(function (browserConfig) {
|
||
if (!reflect.isDefinedNonNull(browserConfig)) {
|
||
return null;
|
||
}
|
||
var specifiedBrowsers = browserConfig.specifiedBrowsers || [];
|
||
var browserMap = browserConfig.browserMap || {};
|
||
var browserIdentifier = null;
|
||
for (var i = 0; i < specifiedBrowsers.length; i++) {
|
||
var specifiedBrowser = specifiedBrowsers[i];
|
||
if (userAgent.indexOf(specifiedBrowser) > -1) {
|
||
browserIdentifier = specifiedBrowser;
|
||
break;
|
||
}
|
||
}
|
||
if (!reflect.isDefinedNonNull(browserIdentifier)) {
|
||
// The Named capturing group: (?<name>...) requires "ECMAScript 2018"
|
||
var matches = userAgent.match(/Mozilla\/5.0 \((.*?)\)(\s|$)((.*?)\/(.*?)(\s)\(.*\))?(.*?)\/(.*?)(\s|$)/);
|
||
if (reflect.isDefinedNonNullNonEmpty(matches) && matches.length >= 8) {
|
||
browserIdentifier = matches[7];
|
||
}
|
||
}
|
||
|
||
if (reflect.isDefinedNonNull(browserIdentifier)) {
|
||
browserIdentifier = browserIdentifier.trim();
|
||
} else {
|
||
browserIdentifier = 'unknown';
|
||
}
|
||
|
||
var browser = browserMap[browserIdentifier] || browserIdentifier;
|
||
return browser;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* The cookie string, e.g. "iTunes.cookie" (iTunes desktop), "iTunes.cookieForDefaultURL" (HTML iOS), "itms.cookie" (itml app), "document.cookie" (browser)
|
||
* NOTE: Callers should override this method if they want to supply a different cookie.
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.cookie = function cookie() {
|
||
return this._window().document.cookie;
|
||
};
|
||
|
||
/**
|
||
* The URL that represents this page.
|
||
* Typically this is a "deep link" type URL.
|
||
* If no URL is available, this field may be omitted.
|
||
* @example "https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewGrouping?cc=us&mt=8"
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.pageUrl = function pageUrl() {
|
||
return this._window().location.href;
|
||
};
|
||
|
||
/**
|
||
* The URL of the parent page, if the app is embedded in a parent context.
|
||
* Typically this is a "deep link" type URL.
|
||
* If no URL is available, or if the app is not embedded, this field may be omitted.
|
||
* @example "https://www.apple.com/blog/top-tracks.html"
|
||
* @returns {String}
|
||
* @overridable
|
||
* Note: due to iframe sandbox rules, the parent window's location may not be accessible.
|
||
* In that case, we fall back to document.referrer, which should be reliable if the app
|
||
* within the iframe is a single page app (document.referrer changes on every page turn).
|
||
* If the app in the iframe is not a single page app, we will have to persist the
|
||
* original referrer from the first page across page turns via e.g. localStorage.
|
||
* However, this use case is not currently needed by any client.
|
||
*/
|
||
Environment.prototype.parentPageUrl = function parentPageUrl() {
|
||
var windowObject = this._window();
|
||
var parentWindow = windowObject.parent;
|
||
var parentPageUrl;
|
||
|
||
if (parentWindow !== windowObject) {
|
||
try {
|
||
parentPageUrl = parentWindow.location.href;
|
||
} catch (e) {
|
||
parentPageUrl = this._document().referrer;
|
||
}
|
||
}
|
||
|
||
return parentPageUrl;
|
||
};
|
||
|
||
/**
|
||
* Pixel multiplier factor
|
||
* @example 2
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.pixelRatio = function pixelRatio() {
|
||
return this._window().devicePixelRatio;
|
||
};
|
||
|
||
/**
|
||
* Client screen height in pixels
|
||
* @example 568
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.screenHeight = function screenHeight() {
|
||
return this._window().screen.height;
|
||
};
|
||
|
||
/**
|
||
* Client screen width in pixels
|
||
* @example 320
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.screenWidth = function screenWidth() {
|
||
return this._window().screen.width;
|
||
};
|
||
|
||
/**
|
||
* Client’s user agent string. If the "app field is not provided, "userAgent may be used to derive the value of the "app field
|
||
* @example AppStore/2.0 iOS/8.3 model/iPhone7,2 build/12F70 (6; dt:106)
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.userAgent = function userAgent() {
|
||
return this._window().navigator.userAgent;
|
||
};
|
||
|
||
/**
|
||
* App viewport height in pixels. Does not include window “chrome”, status bars, etc.
|
||
* Typically only available on desktop windowing systems.
|
||
* @example 1920
|
||
* @returns {number/undefined}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.windowInnerHeight = function windowInnerHeight() {
|
||
return this._window().innerHeight;
|
||
};
|
||
|
||
/**
|
||
* App viewport width in pixels. Does not include window “chrome”, status bars, etc.
|
||
* Typically only available on desktop windowing systems.
|
||
* @example 1080
|
||
* @returns {number/undefined}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.windowInnerWidth = function windowInnerWidth() {
|
||
return this._window().innerWidth;
|
||
};
|
||
|
||
/**
|
||
* Height in pixels of containing window, encompassing app viewport as well as window chrome, status bars, etc.
|
||
* Typically only available on desktop windowing systems.
|
||
* @example 1080
|
||
* @returns {number/undefined}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.windowOuterHeight = function windowOuterHeight() {
|
||
return this._window().outerHeight;
|
||
};
|
||
|
||
/**
|
||
* Width in pixels of containing window, encompassing app viewport as well as window chrome, status bars, etc.
|
||
* Typically only available on desktop windowing systems.
|
||
* @example 1920
|
||
* @returns {number/undefined}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.windowOuterWidth = function windowOuterWidth() {
|
||
return this._window().outerWidth;
|
||
};
|
||
|
||
/**
|
||
* The offset between W3C timing entry timestamps (which are relative to the page lifecycle) and the epoch time
|
||
* and the epoch time, in milliseconds
|
||
* @return {Number}
|
||
* @overridable
|
||
* Note: this is only currently used by PerfKit
|
||
* TODO: <rdar://problem/44976037> Refactor: Delegates: revisit HTML delegate packaging
|
||
*/
|
||
Environment.prototype.timeOriginOffset = function timeOriginOffset() {
|
||
var returnValue = null;
|
||
var performance = this._window().performance;
|
||
|
||
if (performance && performance.timing) {
|
||
returnValue = performance.timing.navigationStart;
|
||
}
|
||
|
||
return returnValue;
|
||
};
|
||
|
||
/**
|
||
* THE FOLLOWING DATA ARE UNAVAILABLE IN A PURE WEB BROWSER CONTEXT,
|
||
* BUT MAY BE IMPLEMENTED (VIA POTENTIALLY DIFFERENT APIS) IN VARIOUS HTML WEB VIEW CONTEXTS (iOS vs Desktop vs tvOS)
|
||
* THEY ARE LEFT UNIMPLEMENTED FOR CONTEXT-SPECIFIC DELEGATES TO OVERWRITE IF APPLICABLE
|
||
*/
|
||
|
||
/**
|
||
* The app identifier of the binary app
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example "com.apple.appstore" or "com.apple.gamecenter"
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.app = function app() {};
|
||
|
||
/**
|
||
* The version number of this application
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example "1.0", "5.43", etc.
|
||
* @returns {String}
|
||
* @overridable
|
||
* @defaultimpl navigator.appVersion
|
||
*/
|
||
Environment.prototype.appVersion = function appVersion() {};
|
||
|
||
/**
|
||
* The total data capacity of the system, without regard for what's already been used or not.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.capacityData = function capacityData() {};
|
||
|
||
/**
|
||
* The total available data capacity of the system.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.capacityDataAvailable = function capacityDataAvailable() {};
|
||
|
||
/**
|
||
* The total disk capacity of the system, without regard for what's already been used or not.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.capacityDisk = function capacityDisk() {};
|
||
|
||
/**
|
||
* The total system capacity, without regard for what's already been used or not.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @returns {number}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.capacitySystem = function capacitySystem() {};
|
||
|
||
/**
|
||
* The total available system capacity of the system.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @api public
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.capacitySystemAvailable = function capacitySystemAvailable() {};
|
||
|
||
/**
|
||
* Type of internet connection.
|
||
* Only applicable to devices
|
||
* Beware that users on WiFi may actually be receiving 3G speeds (i.e. if device is tethered to a portable hotspot.)
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example "WiFi, "3G, etc.
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.connectionType = function connectionType() {};
|
||
|
||
/**
|
||
* The id of this user ("directory service id").
|
||
* This id will get anonymized on the server prior to being saved.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example 659261189
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.dsId = function dsId() {};
|
||
|
||
/**
|
||
* The hardware brand of the device. Not required for Apple devices.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example "Samsung", "LG", "Google"
|
||
* @returns {String}
|
||
*/
|
||
Environment.prototype.hardwareBrand = function hardwareBrand() {};
|
||
|
||
/**
|
||
* The hardware family of the device
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example "iPhone", "Macbook Pro"
|
||
* @returns {String}
|
||
*/
|
||
Environment.prototype.hardwareFamily = function hardwareFamily() {};
|
||
|
||
/**
|
||
* The model of the device
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example "iPhone10,2", "MacbookPro11,5"
|
||
* @returns {String}
|
||
*/
|
||
Environment.prototype.hardwareModel = function hardwareModel() {};
|
||
|
||
/**
|
||
* App that is hosting the storesheet or app
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example com.rovio.AngryBirds
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.hostApp = function hostApp() {};
|
||
|
||
/**
|
||
* Version of the app that is hosting the storesheet or app
|
||
* NO DEFAULT IMPLEMENTATION... HOWEVER: this field is optional
|
||
* @example "1.0.1"
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.hostAppVersion = function hostAppVersion() {
|
||
// Optional field value
|
||
};
|
||
|
||
/**
|
||
* The name of the OS
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example "ios", "macos", "windows"
|
||
* @returns {String}
|
||
*/
|
||
Environment.prototype.os = function os() {};
|
||
|
||
/**
|
||
* The build number of the OS
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example "15D60", "17E192"
|
||
* @returns {String}
|
||
*/
|
||
Environment.prototype.osBuildNumber = function osBuildNumber() {};
|
||
|
||
/**
|
||
* A string array of language IDs, ordered in descending preference
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
|
||
* @example ["en-US", "fr-CA"]
|
||
* @returns {Array}
|
||
*/
|
||
Environment.prototype.osLanguages = function osLanguages() {};
|
||
|
||
/**
|
||
* The full OS version number
|
||
* In ITML, the value can be retrieved via Device.systemVersion
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example "8.2.1" (iOS) "10.10.3" (Desktop)
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.osVersion = function osVersion() {};
|
||
|
||
/**
|
||
* HTML resources revision number
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example 2C97 or 8.4.0.0.103
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.resourceRevNum = function resourceRevNum() {};
|
||
|
||
/**
|
||
* ISO 3166 Country Code. Apps that cannot provide a storeFrontHeader should provide a storeFrontCountryCode instead
|
||
* NO DEFAULT IMPLEMENTATION... Either this method or storeFrontHeader must be replaced.
|
||
* @example US
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.storeFrontCountryCode = function storeFrontCountryCode() {};
|
||
|
||
/**
|
||
* The value contained in the X-Apple-Store-Front header value at the time the event is being created.
|
||
* NO DEFAULT IMPLEMENTATION... Either this method or storeFrontCountryCode must be replaced.
|
||
* @example K143441-1,29 ab:rSwnYxS0
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.storeFrontHeader = function storeFrontHeader() {};
|
||
|
||
/**
|
||
* The best supported language for a storefront
|
||
* NO DEFAULT IMPLEMENTATION... HOWEVER: this field is optional
|
||
* @example en-US
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.storeFrontLanguage = function storeFrontLanguage() {};
|
||
|
||
/**
|
||
* The type of subscriber this user is.
|
||
* NO DEFAULT IMPLEMENTATION... THIS METHOD SHOULD BE REPLACED
|
||
* @example subscribed, notSubscribed, unknown, needsAuthentication
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
Environment.prototype.userType = function userType() {};
|
||
|
||
/*
|
||
* src/event_recorder
|
||
* mt-metricskit-delegates-web
|
||
*
|
||
* Copyright © 2022 Apple Inc. All rights reserved.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* A proxy EventRecorder to bridge the delegates layer to the mt-event-queue lib
|
||
* @param eventRecorder - A eventRecorder implementation from the mt-event-queue lib
|
||
* @constructor
|
||
*/
|
||
function EventRecorder(eventRecorder) {
|
||
AbstractEventRecorder.call(this);
|
||
this._proxyEventRecorder = eventRecorder;
|
||
this.SEND_METHOD = eventRecorder.SEND_METHOD;
|
||
}
|
||
|
||
EventRecorder.prototype = Object.create(AbstractEventRecorder.prototype);
|
||
EventRecorder.prototype.constructor = EventRecorder;
|
||
|
||
/**
|
||
* recordEvent implementation
|
||
* This is an implementation for "AbstractEventRecorder._recordEvent"
|
||
* @override
|
||
* @param topic
|
||
* @param eventFields
|
||
* @private
|
||
*/
|
||
EventRecorder.prototype._recordEvent = function _recordEvent(topic, eventFields) {
|
||
return this._proxyEventRecorder.recordEvent.apply(this._proxyEventRecorder, arguments);
|
||
};
|
||
|
||
/**
|
||
* This overrides the same method in AbstractEventRecorder to ignore the pending recorded event when the appExitSendMethod === 'SEND_METHOD.BEACON_SYNCHRONOUS'.
|
||
* @param {Boolean} appIsExiting - Pass true if events are being flushed due to your app exiting or page going away
|
||
* (the send method will be different in order to attempt to post events prior to actual termination)
|
||
* @param {String} appExitSendMethod (optional) the send method for how events will be flushed when the app is exiting.
|
||
* Possible options are enumerated in the `eventRecorder.SEND_METHOD` object.
|
||
* Note: This argument will be ignored if appIsExiting is false.
|
||
* @returns {Promise}
|
||
*/
|
||
EventRecorder.prototype.flushUnreportedEvents = function flushUnreportedEvents(appIsExiting, appExitSendMethod) {
|
||
var self = this;
|
||
var args = Array.prototype.slice.call(arguments);
|
||
// if this._proxyEventRecorder is an instance of QueuedEventRecorder and the callers wanted to flush events synchronously, ignore the pending events
|
||
if (
|
||
reflect.isDefinedNonNull(this._proxyEventRecorder.SEND_METHOD) &&
|
||
appExitSendMethod === this._proxyEventRecorder.SEND_METHOD.BEACON_SYNCHRONOUS
|
||
) {
|
||
return this._proxyEventRecorder.flushUnreportedEvents.apply(this._proxyEventRecorder, arguments);
|
||
} else {
|
||
return this._operationPromiseChain.then(function () {
|
||
// Reset the promise chain
|
||
self._operationPromiseChain = Promise.resolve();
|
||
return self._proxyEventRecorder.flushUnreportedEvents.apply(self._proxyEventRecorder, args);
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Sends any remaining events in the queue
|
||
* This is an implementation for "AbstractEventRecorder._flushUnreportedEvents"
|
||
* @override
|
||
*/
|
||
EventRecorder.prototype._flushUnreportedEvents = function _flushUnreportedEvents() {
|
||
return this._proxyEventRecorder.flushUnreportedEvents.apply(this._proxyEventRecorder, arguments);
|
||
};
|
||
|
||
/**
|
||
* The methodology being used to send batches of events to the server
|
||
* This field should be hardcoded in the client based on what method it is using to encode and send its events to Figaro.
|
||
* The three typical values are:
|
||
* "itms" - use this value when/if JavaScript code enqueues events for sending via the "itms.recordEvent()" method in ITML.
|
||
* "itunes" - use this value when/if JavaScript code enqueues events by calling the "iTunes.recordEvent()" method in Desktop Store apps.
|
||
* "javascript" - use this value when/if JavaScript code enqueues events for sending via the JavaScript eventQueue management. This is typically only used by older clients which don't have the built-in functionality of itms or iTunes available to them.
|
||
* DEFAULT implementation: console.debug()
|
||
* @example "itms", "itunes", "javascript"
|
||
* @returns {String}
|
||
* @overridable
|
||
*/
|
||
EventRecorder.prototype.sendMethod = function sendMethod() {
|
||
return this._proxyEventRecorder.sendMethod.apply(this._proxyEventRecorder, arguments);
|
||
};
|
||
|
||
/**
|
||
* Set event queue related properties for the giving topic
|
||
* @param {String} topic defines the Figaro "topic" that this event should be stored under
|
||
* @param {Object} properties the event queue properties for the topic
|
||
* @param {Boolean} properties.anonymous true if sending all events for the topic with credentials omitted(no cookies, no PII fields)
|
||
*/
|
||
EventRecorder.prototype.setProperties = function setProperties(topic, properties) {
|
||
return this._proxyEventRecorder.setProperties.apply(this._proxyEventRecorder, arguments);
|
||
};
|
||
|
||
/**
|
||
* clean resources of event recorder
|
||
* Subclasses implement this method to handle how to clean resources
|
||
* @returns {Promise} returns a Promise if the cleanup will asynchronously execute or undefined for synchronously executing
|
||
*/
|
||
EventRecorder.prototype.cleanup = function cleanup() {
|
||
return this._proxyEventRecorder.cleanup.apply(this._proxyEventRecorder, arguments);
|
||
};
|
||
|
||
/*
|
||
* src/web_delegate.js
|
||
* mt-metricskit-delegates-web
|
||
*
|
||
* Copyright © 2022 Apple Inc. All rights reserved.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* Delegate for providing access to the "canned" web MetricsKit delegates.
|
||
* If further modification of these delegates is required, clients may pass in delegate options to override any of the fields within any delegate.
|
||
* @constructor
|
||
* @param {String} topic - Defines the AMP Analytics "topic" for events to be stored under
|
||
* @param {Object} delegateOptions (optional) - Options that can be passed to either add additional delegates or to extend/override existing ones.
|
||
*/
|
||
var WebDelegates = function WebDelegates(topic, delegateOptions) {
|
||
var config = this.getOrCreateConfig(topic);
|
||
Delegates.call(this, topic, {
|
||
environment: new Environment(config),
|
||
eventRecorder: new EventRecorder(new EventRecorder$1(config))
|
||
});
|
||
|
||
this.immediateEventRecorder = new EventRecorder(new ImmediateEventRecorder(config));
|
||
this.network = null;
|
||
this.logger = null;
|
||
|
||
if (delegateOptions) {
|
||
this.mergeDelegates(delegateOptions);
|
||
|
||
if (delegateOptions.environment) {
|
||
this.setEnvironment(delegateOptions.environment);
|
||
}
|
||
|
||
if (delegateOptions.eventRecorder) {
|
||
this.setEventRecorder(delegateOptions.eventRecorder);
|
||
}
|
||
|
||
if (delegateOptions.network) {
|
||
this.setNetwork(delegateOptions.network);
|
||
}
|
||
|
||
if (delegateOptions.logger) {
|
||
this.setLogger(delegateOptions.logger);
|
||
}
|
||
|
||
/**
|
||
* TODO: We are temporarily setting this configUrl() delegate on the config to avoid breaking changes.
|
||
* In the next major release, we will remove this and just fetch the config from
|
||
* the delegateOptions.config.url directly instead of reading it from
|
||
* this config method (defaulting to https://xp.apple.com/config/1/report/<topic>).
|
||
*/
|
||
if (delegateOptions.config) {
|
||
if (delegateOptions.config.url) {
|
||
this.config.setDelegate({
|
||
configUrl: delegateOptions.config.url
|
||
});
|
||
}
|
||
this.setConfig(delegateOptions.config);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Inherit from the base Delegate class
|
||
*/
|
||
WebDelegates.prototype = Object.create(Delegates.prototype);
|
||
WebDelegates.prototype.constructor = WebDelegates;
|
||
|
||
/**
|
||
* Sets the environment for the web-specific event queue as well as setting it on the delegate itself.
|
||
* @param {Object} environment
|
||
* @returns {WebDelegates}
|
||
*/
|
||
WebDelegates.prototype.setEnvironment = function (environment$1) {
|
||
environment.setDelegate(environment$1);
|
||
return Delegates.prototype.setEnvironment.call(this, environment$1);
|
||
};
|
||
|
||
/**
|
||
* Sets the network for the web-specific event queue as well as setting it on the delegate itself.
|
||
* @param {Object} network
|
||
* @returns {WebDelegates}
|
||
*/
|
||
WebDelegates.prototype.setNetwork = function (network$1) {
|
||
if (network$1) {
|
||
this.network = network$1;
|
||
network.setDelegate(network$1);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the logger for the web-specific event queue as well as setting it on the delegate itself.
|
||
* @param {Object} logger
|
||
* @returns {WebDelegates}
|
||
*/
|
||
WebDelegates.prototype.setLogger = function (logger$1) {
|
||
if (logger$1) {
|
||
this.logger = logger$1;
|
||
logger.setDelegate(logger$1);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the immediate event recorder for the delegate.
|
||
* Note: Immediate event recorders are specific to web delegates.
|
||
* @param {Object} immediateEventRecorder
|
||
* @returns {WebDelegates}
|
||
*/
|
||
WebDelegates.prototype.setImmediateEventRecorder = function (immediateEventRecorder) {
|
||
if (immediateEventRecorder) {
|
||
var newImmediateEventRecorder = Object.create(this.immediateEventRecorder);
|
||
Object.assign(newImmediateEventRecorder, immediateEventRecorder);
|
||
this.immediateEventRecorder = newImmediateEventRecorder;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @returns {Object} The config sources.
|
||
*/
|
||
WebDelegates.prototype.configSources = function configSources() {
|
||
var self = this;
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
var onFetchSuccess = function onFetchSuccess(response) {
|
||
try {
|
||
var configObject = JSON.parse(response);
|
||
self.config.setCachedSource(configObject);
|
||
self.config.setServiceSource(configObject); // TODO: Deprecated
|
||
resolve(configObject);
|
||
} catch (error) {
|
||
onFetchFailure(error);
|
||
}
|
||
};
|
||
|
||
var onFetchFailure = function onFetchFailure(error) {
|
||
self.config.setCachedSource(self.config.cachedSource());
|
||
reject(error);
|
||
};
|
||
|
||
var configUrlPromise = Promise.resolve(self.config.configUrl());
|
||
|
||
configUrlPromise
|
||
.then(function (configUrl) {
|
||
backoff.exponentialBackoff(
|
||
self.config.network.makeAjaxRequest.bind(self.config.network, configUrl, 'GET', null),
|
||
onFetchSuccess,
|
||
onFetchFailure
|
||
);
|
||
})
|
||
.catch(onFetchFailure);
|
||
});
|
||
};
|
||
|
||
export { Environment, WebDelegates };
|