import { isSome } from "@jet/environment"; import { isNothing } from "@jet/environment/types/optional"; import { AppStoreMetricsData, } from "../../api/models/metrics/metrics"; import * as serverData from "../../foundation/json-parsing/server-data"; import * as client from "../../foundation/wrappers/client"; import { EventLinter } from "./event-linter"; import { optOutOfLegacyMetricsIdFieldsProvider } from "./helpers/legacy-metrics-identifier-fields-opt-out"; export function createMetricsClickData(objectGraph, targetId, targetType, eventFields, additionalIncludingFields, isDefaultBrowser) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "click"; fields["targetType"] = targetType; fields["targetId"] = targetId; const include = ["impressionsSnapshot", "pageFields"]; if (!preprocessor.GAMES_TARGET) { include.push("contentRestrictionReasons"); } if (additionalIncludingFields) { include.push(...additionalIncludingFields); } addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, [], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields, null, isDefaultBrowser))); } export function createMetricsBackClickData(objectGraph, eventFields) { const fields = {}; Object.assign(fields, eventFields); fields["actionType"] = "back"; const clickData = createMetricsClickData(objectGraph, "back", "button", fields); return clickData; } export function createMetricsPageData(objectGraph, isReferralEligible, isCrossfireReferralCandidate, timingMetrics, eventFields, isDefaultBrowser) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "page"; if (timingMetrics) { fields["clientCorrelationKey"] = timingMetrics.clientCorrelationKey; fields["requestStartTime"] = timingMetrics.requestStartTime; fields["responseStartTime"] = timingMetrics.responseStartTime; fields["responseEndTime"] = timingMetrics.responseEndTime; } const include = ["pageFields", "pageReferrer"]; if (!preprocessor.GAMES_TARGET) { include.push("userContentRestriction"); } if (isReferralEligible) { include.push("crossfireReferral"); } else if (isCrossfireReferralCandidate) { include.push("crossfireReferralCandidate"); // Only possible when not crossfire eligible. } addAltAb2DataToEventFields(objectGraph, fields); addWebClientEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, [], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields, null, isDefaultBrowser))); } export function createMetricsSearchData(objectGraph, term, target, actionType, actionUrl, eventFields, additionalIncludingFields) { const fields = {}; Object.assign(fields, eventFields); fields["term"] = term; fields["targetType"] = target; fields["actionType"] = actionType; if (actionUrl) { fields["actionUrl"] = actionUrl; // actionUrl is defined for `hints` but not for searches fired from elsewhere. } fields["eventType"] = "search"; const include = ["pageReferrer"]; if (additionalIncludingFields) { include.push(...additionalIncludingFields); } addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, [], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields))); } export function createMetricsPageRenderFields(objectGraph, timingMetrics, eventFields) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "pageRender"; if (timingMetrics) { if (!fields["pageUrl"]) { fields["pageUrl"] = timingMetrics.pageURL; } fields["clientCorrelationKey"] = timingMetrics.clientCorrelationKey; fields["platformRequestStartTime"] = timingMetrics.requestStartTime; fields["platformResponseStartTime"] = timingMetrics.responseStartTime; fields["platformResponseEndTime"] = timingMetrics.responseEndTime; fields["platformResponseWasCached"] = timingMetrics.responseWasCached; fields["platformJsonParseStartTime"] = timingMetrics.parseStartTime; fields["platformJsonParseEndTime"] = timingMetrics.parseEndTime; } addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return fields; } /** * Create a metrics data for regular impressions. * @param objectGraph The dependency graph for the App Store. * @param eventFields Base fields to build off on. * @param shouldIncludeAdFieldsForPad Whether or not metrics data should include iPad related fields for adverts. * @param includeAdRotationFields Whether or not metrics data should include advert related fields. * @param hasImpressionsAppendix Whether condensed format search results should track appendix data. */ export function createMetricsImpressionsData(objectGraph, eventFields, shouldIncludeAdFieldsForPad, includeAdRotationFields, hasImpressionsAppendix) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "impressions"; fields["impressionQueue"] = "data-metrics"; fields["eventVersion"] = 4; const include = ["impressions", "pageFields", "pageReferrer"]; if (!preprocessor.GAMES_TARGET) { include.push("contentRestrictionReasons"); } if (shouldIncludeAdFieldsForPad) { include.push("advertDeviceWindow"); } if (includeAdRotationFields) { include.push("advertRotation"); } if (hasImpressionsAppendix) { include.push("impressionsAppendix"); } addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, ["eventVersion"], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields))); } /** * Create a metrics data for fast impressions, a special type for SearchAds on Search Page. * Included fields assume fields are for search page w/ Ads. * @param baseFields Base fields to build off on. */ export function createMetricsFastImpressionsData(objectGraph, baseFields, pageInformation) { var _a, _b; const shouldIncludeAdFieldsForPad = serverData.isDefinedNonNull(pageInformation.iAdInfo) && objectGraph.client.isPad && (isNothing(pageInformation.iAdInfo.missedOpportunityReason) || pageInformation.iAdInfo.missedOpportunityReason.length === 0); const shouldIncludeAdRotationFields = (_b = (_a = pageInformation.iAdInfo) === null || _a === void 0 ? void 0 : _a.shouldIncludeAdRotationFields) !== null && _b !== void 0 ? _b : false; const exclude = []; const fields = createMetricsImpressionsData(objectGraph, baseFields, shouldIncludeAdFieldsForPad, shouldIncludeAdRotationFields, false).fields; fields["impressionQueue"] = "data-metrics-impressions-low-latency"; if (pageInformation !== null && serverData.isDefinedNonNull(pageInformation.iAdInfo)) { const eventVersion = pageInformation.iAdInfo.fastImpressionsEventVersion; fields["eventVersion"] = eventVersion; exclude.push("eventVersion"); // Make some manual adjustments to events for v5. if (eventVersion === 5) { // Indicates the viewable area where elements can be impressed excludes the tab bar fields["viewableArea"] = "excludingTabBar"; // Remove the `iAdPlacementId` for v5. It's added for compatibility with v4 impressions. delete fields["iAdPlacementId"]; } } const include = ["fastImpressions", "pageFields", "pageReferrer"]; if (shouldIncludeAdFieldsForPad) { include.push("advertDeviceWindow"); } if (shouldIncludeAdRotationFields) { include.push("advertRotation"); } return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, exclude, topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields, pageInformation))); } export function createMetricsMediaData(objectGraph, eventFields) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "media"; addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, [], [], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields))); } export function createMetricsMediaClickData(objectGraph, targetId, targetType, eventFields) { const fields = {}; Object.assign(fields, eventFields); fields["eventType"] = "click"; fields["targetType"] = targetType; fields["targetId"] = targetId; const include = ["pageFields"]; addWebClientEventFields(objectGraph, fields); addAltAb2DataToEventFields(objectGraph, fields); return optOutOfLegacyMetricsIdFieldsProvider(objectGraph, new AppStoreMetricsData(fields, include, [], topicFromEventFields(objectGraph, fields), shouldFlushFromEventFields(objectGraph, fields))); } function shouldFlushFromEventFields(objectGraph, eventFields, pageInformation = null, isDefaultBrowser) { var _a, _b; const eventType = eventFields["eventType"]; let shouldFlush = false; if (!serverData.isDefinedNonNullNonEmpty(eventType)) { return shouldFlush; } const isDefaultBrowserContext = isDefaultBrowser !== null && isDefaultBrowser !== void 0 ? isDefaultBrowser : false; switch (eventType) { case "click": shouldFlush = serverData.asBooleanOrFalse(eventFields, EventLinter.hasIAdData) || isDefaultBrowserContext; break; case "exit": shouldFlush = true; break; case "impressions": shouldFlush = serverData.asBooleanOrFalse(eventFields, EventLinter.hasIAdData); // Not my best work here. // For most ad placements on a page, it's fine to check the `hasIAdData` as an indicator for whether we should flush after a given event. // The challenge for the product page placements is that they're fetched asynchronously, and we don't create an entirely new impressions // event when that happens (we just update fields within the event via the `pageChange` mechanism). To ensure that fast impression events on // the product page are actually fast, we have to force the events to flush if they meet the below conditions that effectively guarantee // we will be impressing something on the low latency queue. if (eventFields["impressionQueue"] === "data-metrics-impressions-low-latency" && (((_a = pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo) === null || _a === void 0 ? void 0 : _a.placementType) === "productPageYMAL" || ((_b = pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo) === null || _b === void 0 ? void 0 : _b.placementType) === "productPageYMALDuringDownload")) { shouldFlush = true; } break; case "page": // rdar://98487650 (CL seed: Product Page observed lower % of events coming in <2 mins ( page change + page events )) // In order to resolve issues with flushing timeliness in the PPE: rdar://93127678 ([Metrics] Dismissing store sheet does not fire clickstream events) // we allow page events with ad data in them to cause a flush on product pages in the PPE. // We also pre-emptively flush for page events where it's the default browser flow in order to "prewarm" the metrics pipeline, ensuring flushes can occur // if and when the user taps "Open" on an installed app. const isProductPageExtension = objectGraph.host.clientIdentifier === client.productPageExtensionIdentifier; shouldFlush = isProductPageExtension && (serverData.asBooleanOrFalse(eventFields, EventLinter.hasIAdData) || isDefaultBrowserContext); break; default: break; } const isSubscribePageExtensionEnterExitEventsEnabled = objectGraph.host.isiOS; if (objectGraph.host.clientIdentifier === client.subscribePageExtensionIdentifier && !isSubscribePageExtensionEnterExitEventsEnabled) { // Metrics: missing metrics events for arcade upsell from springboard app open on unsubscribed user // Until a native fix is in to address enter/exit events in SPE (subscribePageExtensionEnterExitEvents), we // need to force events in the SubscribePageExtension to trigger a flush. shouldFlush = true; } return shouldFlush; } function topicFromEventFields(objectGraph, eventFields) { const topic = eventFields["topic"] || objectGraph.bag.metricsTopic; return topic; } function addAltAb2DataToEventFields(objectGraph, eventFields) { if (objectGraph.bag.isMetricsAb2DataFallbackEnabled && isSome(objectGraph.experimentCache)) { eventFields["alt_ab2_data"] = JSON.stringify(objectGraph.experimentCache.createAb2Data()); } } /** * Attach expected metrics fields specific to the "web" client, if necessary */ function addWebClientEventFields(objectGraph, eventFields) { var _a; if (!objectGraph.client.isWeb) { return; } // The `platformContext` field is expected to reflect the "platform" that the user is browsing // at the time of the event eventFields["platformContext"] = (_a = objectGraph.activeIntent) === null || _a === void 0 ? void 0 : _a.previewPlatform; } //# sourceMappingURL=builder.js.map