summaryrefslogtreecommitdiff
path: root/node_modules/@jet-app/app-store/tmp/src/common/ads
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@jet-app/app-store/tmp/src/common/ads')
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/common/ads/ad-common.js433
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/common/ads/ad-incident-recorder.js116
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/common/ads/ad-stitcher.js73
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-fetch.js286
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-stitch.js98
5 files changed, 1006 insertions, 0 deletions
diff --git a/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-common.js b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-common.js
new file mode 100644
index 0000000..6216dba
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-common.js
@@ -0,0 +1,433 @@
+/**
+ * Common utilities for dealing with Ads.
+ */
+import { isNothing, isSome } from "@jet/environment";
+import { Lockup, TodayCard, TodayCardMediaMediumLockupWithAlignedRegion, TodayCardMediaMediumLockupWithScreenshots, TodayCardMediaSingleLockup, } from "../../api/models";
+import { isDefinedNonNull, isDefinedNonNullNonEmpty, isNull, isNullOrEmpty, } from "../../foundation/json-parsing/server-data";
+import { attributeAsString } from "../../foundation/media/attributes";
+import { IAdSearchInformation } from "../metrics/helpers/models";
+import { platformSupportsAdverts } from "../search/search-ads";
+import { shouldTodayAdBeCondensed } from "../../foundation/experimentation/today-ad-experiments";
+import { getTemplateTypeForMediumAdFromLockupWithCustomCreative, getTemplateTypeForMediumAdFromLockupWithScreenshots, searchAdMissedOpportunityFromId, } from "../lockups/ad-lockups";
+import { contentAttributeAsString } from "../content/attributes";
+import { currentLocation, currentPosition } from "../metrics/helpers/location";
+// region placement logic
+/**
+ * A helper function to check if the given AdPlacement is enabled.
+ * @param objectGraph The object graph.
+ * @param adPlacementKey The ad placement to check. Matches values sent in the bag.
+ * @returns A boolean indicating if the provided AdPlacement is enabled.
+ */
+export function isAdPlacementEnabled(objectGraph, placementType) {
+ if (!platformSupportsAdverts(objectGraph)) {
+ return false;
+ }
+ switch (placementType) {
+ case "searchLanding":
+ // In transitioning from the legacy bag key `isSearchLandingAdsEnabled` to the new key `enabledAdPlacements`,
+ // we will enable SLP ads if either of the keys indicates ads are enabled for SLP.
+ const slpPlacementBagValue = adPlacementBagValueForAdPlacementType(placementType);
+ if (isSome(slpPlacementBagValue)) {
+ return (objectGraph.bag.isSearchLandingAdsEnabled ||
+ objectGraph.bag.enabledAdPlacements.includes(slpPlacementBagValue));
+ }
+ else {
+ return objectGraph.bag.isSearchLandingAdsEnabled;
+ }
+ case "searchResults":
+ return true; // Legacy
+ case "today":
+ const todayBagValue = adPlacementBagValueForAdPlacementType(placementType);
+ if (isNull(todayBagValue)) {
+ return false;
+ }
+ return objectGraph.bag.enabledAdPlacements.includes(todayBagValue) && isSome(todayAdStyle(objectGraph));
+ case "productPageYMAL":
+ case "productPageYMALDuringDownload":
+ const placementBagValue = adPlacementBagValueForAdPlacementType(placementType);
+ if (isNull(placementBagValue)) {
+ return false;
+ }
+ return objectGraph.bag.enabledAdPlacements.includes(placementBagValue);
+ default:
+ return false;
+ }
+}
+/**
+ * Get the style to use for the Today ad.
+ * A return type of `undefined` indicates the ad style is unsupported on the client.
+ * @param objectGraph The Object Graph.
+ * @returns A style, or undefined if it's unsupported.
+ */
+export function todayAdStyle(objectGraph) {
+ if (objectGraph.bag.todayAdMediumLockupScreenshotEnabled) {
+ return "mediumLockup";
+ }
+ if (objectGraph.bag.todayAdCondensedEnabled) {
+ // Only supported on iPhone.
+ if (!objectGraph.client.isPhone) {
+ return undefined;
+ }
+ return "singleLockup";
+ }
+ if (shouldTodayAdBeCondensed(objectGraph)) {
+ return "singleLockup";
+ }
+ else {
+ return undefined;
+ }
+}
+/**
+ * Get the timeout of the ad fetch for a given placement from the bag values.
+ * @param objectGraph The object graph.
+ * @param placementType The ad placement.
+ * @param isDeltaTimeout Whether the timeout we're looking for is a delta timeout between parallel organic and ad requests completing.
+ * See `Ads.setTimeoutForCurrentOnDeviceAdFetch` for more details on how this is used.
+ * @returns The timeout.
+ */
+export function adFetchTimeoutForPlacement(objectGraph, placementType, isDeltaTimeout) {
+ var _a, _b, _c, _d, _e;
+ const timeouts = objectGraph.bag.adPlacementTimeouts;
+ const defaultTimeout = 0.3;
+ switch (placementType) {
+ case "searchResults":
+ return isDeltaTimeout ? null : (_a = timeouts === null || timeouts === void 0 ? void 0 : timeouts["search-results-in-seconds"]) !== null && _a !== void 0 ? _a : defaultTimeout;
+ case "searchLanding":
+ return isDeltaTimeout ? null : (_b = objectGraph.bag.searchLandingAdFetchTimeout) !== null && _b !== void 0 ? _b : defaultTimeout; // Legacy value.
+ case "today":
+ // Today uses its timeout value as a delta after the organic request finishes.
+ return isDeltaTimeout ? (_c = timeouts === null || timeouts === void 0 ? void 0 : timeouts["today-in-seconds"]) !== null && _c !== void 0 ? _c : defaultTimeout : null;
+ case "productPageYMAL":
+ return isDeltaTimeout ? null : (_d = timeouts === null || timeouts === void 0 ? void 0 : timeouts["product-page-ymal-in-seconds"]) !== null && _d !== void 0 ? _d : defaultTimeout;
+ case "productPageYMALDuringDownload":
+ return isDeltaTimeout ? null : (_e = timeouts === null || timeouts === void 0 ? void 0 : timeouts["product-page-ymal-during-download-in-seconds"]) !== null && _e !== void 0 ? _e : defaultTimeout;
+ default:
+ return defaultTimeout;
+ }
+}
+/**
+ * Convert the value describing an ad placement from the App Store representation to the bag representation.
+ * @param placementType The bag value for different ad placements
+ * @returns The equivalent bag placement value as a string.
+ */
+function adPlacementBagValueForAdPlacementType(placementType) {
+ switch (placementType) {
+ case "searchResults":
+ return "search-results";
+ case "searchLanding":
+ return "search-landing";
+ case "today":
+ return "today";
+ case "productPageYMAL":
+ return "product-page-ymal";
+ case "productPageYMALDuringDownload":
+ return "product-page-ymal-during-download";
+ default:
+ return undefined;
+ }
+}
+/**
+ * The minimum number of landscape media items for a Today ad placement.
+ * The app must satisfy this or `todayAdPlacementMinimumPortraitMedia` to be shown.
+ */
+export const todayAdPlacementMinimumLandscapeMedia = 5;
+/**
+ * The minimum portrait media for a Today ad placement.
+ * The app must satisfy this or `todayAdPlacementMinimumLandscapeMedia` to be shown.
+ */
+export const todayAdPlacementMinimumPortraitMedia = 4;
+/**
+ * Get a count of the media in each orientation specifically for a Today ad placement.
+ * This is specific to Today because the placement only supports one video.
+ * @param trailers A set of trailers for an app.
+ * @param screenshots A set of screenshots for an app.
+ * @returns A count of media in each orientation, respecting the placement's rules.
+ */
+export function getMediaOrientationCountsForTodayPlacement(trailers, screenshots) {
+ var _a, _b, _c, _d;
+ // Grab the first array of platform screenshots and trailers - the ones the ad will display.
+ const platformScreenshotsArtwork = (_b = (_a = screenshots[0]) === null || _a === void 0 ? void 0 : _a.artwork) !== null && _b !== void 0 ? _b : [];
+ const platformTrailersVideos = (_d = (_c = trailers[0]) === null || _c === void 0 ? void 0 : _c.videos) !== null && _d !== void 0 ? _d : [];
+ // Split media into orientations.
+ const portraitScreenshots = platformScreenshotsArtwork.filter((artwork) => artwork.isPortrait());
+ const landscapeScreenshots = platformScreenshotsArtwork.filter((artwork) => artwork.isLandscape());
+ // Take a maximum of one video of each orientation.
+ const portraitVideos = platformTrailersVideos.filter((video) => video.preview.isPortrait()).slice(0, 1);
+ const landscapeVideos = platformTrailersVideos.filter((video) => video.preview.isLandscape()).slice(0, 1);
+ const portraitCount = portraitScreenshots.length + portraitVideos.length;
+ const landscapeCount = landscapeScreenshots.length + landscapeVideos.length;
+ return {
+ landscape: landscapeCount,
+ portrait: portraitCount,
+ };
+}
+/**
+ * A convenience method to determine if a position is ad eligible.
+ * @param placementType The type of placement for an ad.
+ * @param locationTracker The location tracker being used to build the items. Used to determine the current shelf and position within the shelf.
+ * @returns A boolean indicating if the current position is considered ad eligible.
+ */
+export function isAdEligible(placementType, locationTracker) {
+ var _a;
+ if (isNothing(locationTracker) || isNothing(placementType)) {
+ return false;
+ }
+ const shelfId = (_a = currentLocation(locationTracker)) === null || _a === void 0 ? void 0 : _a.id;
+ if (isNothing(shelfId)) {
+ return false;
+ }
+ const eligibleIndex = adEligibleIndexForType(placementType, shelfId);
+ if (isNothing(eligibleIndex)) {
+ return false;
+ }
+ const index = currentPosition(locationTracker);
+ return index === eligibleIndex;
+}
+/**
+ * Inserts a missed opportunity on the correct slot in the page if an ad isn't already present. This looks for
+ * types conforming to SearchAdOpportunityProviding and handles all of the construction for the metadata associated
+ * with a SearchAdOpportunity.
+ * @param objectGraph The object graph.
+ * @param shelves Completed shelves that are constructed for the page.
+ * @param placementType The location where the ad will be shown.
+ * @param shelfIdentifier The specific shelf identifier we should be evaluating against. This is not inferred to support things like Today Page that can use a shelf-per-item.
+ * @param pageInformation Metrics information for the page.
+ */
+export function applySearchAdMissedOpportunityToShelvesIfNeeded(objectGraph, shelves, placementType, shelfIdentifier, pageInformation) {
+ var _a, _b, _c;
+ if (!platformSupportsAdverts(objectGraph) || isNull(pageInformation.iAdInfo)) {
+ return;
+ }
+ const adEligibleIndex = adEligibleIndexForType(placementType, shelfIdentifier);
+ if (isNothing(adEligibleIndex)) {
+ return;
+ }
+ // Opportunities aren't present when we've recorded certain missed opportunities
+ let missedOpportunityReason = null;
+ if (typeof pageInformation.iAdInfo.pageFields.iAdMissedOpportunityReason === "string") {
+ missedOpportunityReason = pageInformation.iAdInfo.pageFields.iAdMissedOpportunityReason;
+ }
+ if (isNothing(missedOpportunityReason) ||
+ missedOpportunityReason.length === 0 ||
+ missedOpportunityReason === "EDITORIALTAKEOVER" ||
+ missedOpportunityReason === "SLPLOAD") {
+ return;
+ }
+ const allShelfItems = [];
+ for (const shelf of shelves) {
+ // searchResult is handled in a separate non-shelf workflow
+ const isValidContentType = shelf.contentType === "smallLockup" || shelf.contentType === "todayCard";
+ if (!isValidContentType) {
+ continue;
+ }
+ const nextShelfItems = shelf.items;
+ if (isDefinedNonNull(nextShelfItems) && nextShelfItems.length > 0) {
+ allShelfItems.push(...nextShelfItems);
+ }
+ }
+ if (allShelfItems.length <= adEligibleIndex) {
+ return;
+ }
+ const adEligibleShelfItem = allShelfItems[adEligibleIndex];
+ const isTodayCard = adEligibleShelfItem instanceof TodayCard;
+ const isSmallLockup = adEligibleShelfItem instanceof Lockup;
+ const shelfItemMedia = isTodayCard ? adEligibleShelfItem.media : null;
+ const lockupTypeIsMediumScreenshotFormat = isDefinedNonNull(shelfItemMedia) && shelfItemMedia instanceof TodayCardMediaMediumLockupWithScreenshots;
+ const lockupTypeIsMediumCreativeFormat = isDefinedNonNull(shelfItemMedia) && shelfItemMedia instanceof TodayCardMediaMediumLockupWithAlignedRegion;
+ const lockupHasPlacedCondensedTodayAd = isDefinedNonNull(shelfItemMedia) &&
+ shelfItemMedia instanceof TodayCardMediaSingleLockup &&
+ isDefinedNonNull(shelfItemMedia.condensedAdLockupWithIconBackground.lockup.searchAdOpportunity);
+ const lockupHasPlacedMediumAdScreenshots = lockupTypeIsMediumScreenshotFormat &&
+ isDefinedNonNull(shelfItemMedia.mediumAdLockupWithScreenshotsBackground.lockup.searchAdOpportunity);
+ const lockupHasPlacedMediumAdCreative = lockupTypeIsMediumCreativeFormat &&
+ isDefinedNonNull(shelfItemMedia.mediumAdLockupWithAlignedRegionBackground.lockup.searchAdOpportunity);
+ const lockupHasPlacedSmallLockup = isSmallLockup && isDefinedNonNull(adEligibleShelfItem.searchAdOpportunity);
+ // If we've already processed the ad data and placed it, we don't want to indicate that there's a missed opportunity
+ if (lockupHasPlacedCondensedTodayAd ||
+ lockupHasPlacedMediumAdScreenshots ||
+ lockupHasPlacedMediumAdCreative ||
+ lockupHasPlacedSmallLockup) {
+ return;
+ }
+ adEligibleShelfItem.searchAdOpportunity = searchAdMissedOpportunityFromId(objectGraph, pageInformation);
+ (_a = adEligibleShelfItem.searchAdOpportunity) === null || _a === void 0 ? void 0 : _a.setMissedOpportunityReason(missedOpportunityReason !== null && missedOpportunityReason !== void 0 ? missedOpportunityReason : "NOAD");
+ if (lockupTypeIsMediumScreenshotFormat) {
+ (_b = adEligibleShelfItem.searchAdOpportunity) === null || _b === void 0 ? void 0 : _b.setTemplateType(getTemplateTypeForMediumAdFromLockupWithScreenshots(shelfItemMedia.mediumAdLockupWithScreenshotsBackground.screenshots[0]));
+ }
+ else if (lockupTypeIsMediumCreativeFormat) {
+ adEligibleShelfItem.searchAdOpportunity.setTemplateType(getTemplateTypeForMediumAdFromLockupWithCustomCreative());
+ }
+ else {
+ (_c = adEligibleShelfItem.searchAdOpportunity) === null || _c === void 0 ? void 0 : _c.setTemplateType("APPLOCKUP");
+ }
+}
+/**
+ * This is a bit of a workaround for `isAdEligible` function in this file. Ideally this is bag-driven, but I need to figure out
+ * how to make it work. `shelfIdentifier` doesn't seem to work correctly, except for the YMAL ad on PP
+ * @param placementType The ad placement type to evaluate for ad eligibility
+ * @param shelfIdentifier The identifier for the shelf to evaluate for ad eligibility
+ * @returns The equivalent bag placement value as a string.
+ */
+function adEligibleIndexForType(placementType, shelfIdentifier) {
+ var _a;
+ const adEligibleBagRepresentation = {
+ today: [
+ {
+ shelfIdentifier: "today",
+ adEligibleIndex: 1,
+ },
+ ],
+ productPageYMAL: [
+ {
+ shelfIdentifier: "customers-also-bought-apps",
+ adEligibleIndex: 0,
+ },
+ ],
+ searchLanding: [
+ {
+ shelfIdentifier: "R8802",
+ adEligibleIndex: 0,
+ },
+ ],
+ searchResults: [
+ {
+ shelfIdentifier: "search-results",
+ adEligibleIndex: 0,
+ },
+ ],
+ };
+ const matchingSlot = ((_a = adEligibleBagRepresentation[placementType]) !== null && _a !== void 0 ? _a : []).find((element) => {
+ return element.shelfIdentifier === shelfIdentifier;
+ });
+ if (isDefinedNonNullNonEmpty(matchingSlot) && isDefinedNonNull(matchingSlot.adEligibleIndex)) {
+ return matchingSlot.adEligibleIndex;
+ }
+ else {
+ return undefined;
+ }
+}
+// endregion
+// region iad data
+export function iadInfoFromOnDeviceAdResponse(objectGraph, placementType, adResponse, flattenedTodayFeed = null) {
+ var _a, _b;
+ if (!platformSupportsAdverts(objectGraph) || isNull(adResponse)) {
+ return null;
+ }
+ return new IAdSearchInformation(objectGraph, placementType, IAdSearchInformation.createInitialSlotInfos(objectGraph, placementType, (_a = adResponse === null || adResponse === void 0 ? void 0 : adResponse.onDeviceAd) === null || _a === void 0 ? void 0 : _a.positionInfo, flattenedTodayFeed), adResponse.iAdId, adResponse.clientRequestId, undefined, (_b = adResponse.onDeviceAd) === null || _b === void 0 ? void 0 : _b.positionInfo);
+}
+/**
+ * Key added to `Data`'s `attributes` field so downstream builders can use this field.
+ * This is currently generated by JS when we create `SponsoredSearchAdverts`
+ */
+export const instanceIdAttributeKey = "jet_native_advert_instanceid";
+/**
+ * Returns the native advert id if one was annotated during `applyNativeAdvertData`
+ */
+export function advertInstanceIdForData(objectGraph, data) {
+ return attributeAsString(data, instanceIdAttributeKey);
+}
+/**
+ * Decorates `instanceId` that identifies an ad to given `Data` for consumption in builders.
+ */
+export function decorateAdInstanceIdOnData(objectGraph, data, instanceId) {
+ if (isDefinedNonNullNonEmpty(data === null || data === void 0 ? void 0 : data.attributes)) {
+ data.attributes[instanceIdAttributeKey] = instanceId;
+ }
+}
+// endregion
+// region ad localization
+/**
+ * Whether the available localization data in an ad is valid for the defined `adsOverrideLanguage`, if any.
+ * If no `adsOverrideLanguage` is set, `true` is returned.
+ * The logic for a valid set of data differs based on the passed in placement and if an ad display style
+ * is defined (for SRP only).
+ * @param objectGraph The Object Graph.
+ * @param data The app data.
+ * @param onDeviceAd Optionally, an `OnDeviceAdvert` - this is only used as a fallback for SLP ads,
+ * where the meta resource object is attached to the original ad request, but not to the subsequent
+ * hydration request. For this case only, we must use a combination of these two requests to identify
+ * whether the localization is valid.
+ * @param adDisplayStyle: Optionally, an ad display style - this is used for SRP ads, where the data used
+ * in the ad UI depends on which ad display style is being used.
+ * @returns A boolean indicating if the available localization data is valid.
+ */
+export function isAdLocalizationValid(objectGraph, data, onDeviceAd, adDisplayStyle) {
+ var _a, _b, _c, _d, _e;
+ const adsOverrideLanguage = objectGraph.bag.adsOverrideLanguage;
+ // No localization requirements if there is no adsOverrideLanguage.
+ if (isNullOrEmpty(adsOverrideLanguage) || isNullOrEmpty(data)) {
+ return true;
+ }
+ let metaResource = (_a = data.meta) === null || _a === void 0 ? void 0 : _a.resource;
+ // If the `metaResource in `data` is missing, attempt to fall back to the `onDeviceAd` values
+ // which are provided for SLP.
+ if (isNullOrEmpty(metaResource) && isDefinedNonNullNonEmpty(onDeviceAd)) {
+ metaResource = (_e = (_d = (_c = (_b = onDeviceAd === null || onDeviceAd === void 0 ? void 0 : onDeviceAd.appMetadata) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.meta) === null || _e === void 0 ? void 0 : _e.resource;
+ }
+ // If `metaResource` still don't exist, we can't validate localization.
+ if (isNullOrEmpty(metaResource)) {
+ // The meta resource attributes object is missing, assume we don't have the correct localizations.
+ return false;
+ }
+ // Title
+ // Title is always used. Check it's localized.
+ const titleLocale = attributeAsString(metaResource, "name.locale");
+ if (titleLocale !== adsOverrideLanguage) {
+ return false;
+ }
+ // Subtitle
+ // Subtitle is constructed using either the subtitle field, or falling back to the category.
+ // If the subtitle text is present, we need to validate the locale. If not, we don't.
+ const subtitle = contentAttributeAsString(objectGraph, data, "subtitle");
+ const subtitleLocale = contentAttributeAsString(objectGraph, metaResource, "subtitle.locale");
+ if (isDefinedNonNullNonEmpty(subtitle) && subtitleLocale !== adsOverrideLanguage) {
+ return false;
+ }
+ // SRP advertising text
+ // SRP ads can optionally provide a 3rd set of text, `advertisingText`.
+ // It's only used when the `adDisplayStyle` is `TEXT`.
+ if (adDisplayStyle === "TEXT" /* SearchAdDisplayStyle.TEXT */) {
+ // The text used can be defined by the ad payload inside the `data`. We need to use that path
+ // to get both the text and the locale for that text.
+ const iAdTextKey = attributeAsString(data, "iad.format.text");
+ if (isSome(iAdTextKey) && iAdTextKey !== "none") {
+ let attributePath;
+ const attributePathLocale = iAdTextKey;
+ // In the case where the path is "description", we need to use different paths for the text and the locale.
+ // This is due to a Media API limitation where the locale for "description" is just under that key, rather
+ // than "description.standard", which is the actual path for the text content.
+ if (iAdTextKey === "description") {
+ attributePath = "description.standard";
+ }
+ else {
+ attributePath = iAdTextKey;
+ }
+ const advertisingText = contentAttributeAsString(objectGraph, data, attributePath);
+ const advertisingTextLocale = contentAttributeAsString(objectGraph, metaResource, attributePathLocale.concat(".locale"));
+ if (isDefinedNonNullNonEmpty(advertisingText) && advertisingTextLocale !== adsOverrideLanguage) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+// endregion
+// region metrics
+/**
+ * Retrieve the eligible slot positions for a given ad placement type.
+ * @param objectGraph The Object Graph.
+ * @param placementType The placement the ad is for.
+ * @returns An array of eligible slot positions for the provided placement.
+ */
+export function eligibleSlotPositionsForAdPlacement(objectGraph, placementType) {
+ if (isNothing(placementType)) {
+ return undefined;
+ }
+ const placementTypeBagValue = adPlacementBagValueForAdPlacementType(placementType);
+ if (isNothing(placementTypeBagValue)) {
+ return undefined;
+ }
+ return objectGraph.bag.adPlacementEligibleSlotPositions[placementTypeBagValue];
+}
+// endregion
+//# sourceMappingURL=ad-common.js.map \ No newline at end of file
diff --git a/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-incident-recorder.js b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-incident-recorder.js
new file mode 100644
index 0000000..6dac34a
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-incident-recorder.js
@@ -0,0 +1,116 @@
+/**
+ * Ad Incident Recorder manages the Journey and Figaro events when rendering a page.
+ * This exists so managing journey and figaro metrics is a bit more sane.
+ */
+"use strict";
+import { isNothing } from "@jet/environment";
+import { DiscardAdIncident } from "../../api/models";
+import { isDefinedNonNull, isNull, isNullOrEmpty } from "../../foundation/json-parsing/server-data";
+import { advertInstanceIdForData } from "./ad-common";
+/**
+ * Create a new ad incident recorder
+ */
+export function newRecorder(objectGraph, iAdInfo) {
+ return {
+ incidents: [],
+ iAdInfo: iAdInfo,
+ };
+}
+/**
+ * Get recorded incidents from recorder
+ */
+export function recordedIncidents(objectGraph, recorder) {
+ if (isNull(recorder) || isNullOrEmpty(recorder.incidents)) {
+ return null;
+ }
+ return recorder.incidents;
+}
+/**
+ * Record that building a lockup from data failed.
+ */
+export function recordLockupFromDataFailed(objectGraph, recorder, lockupData) {
+ var _a, _b;
+ const instanceId = advertInstanceIdForData(objectGraph, lockupData);
+ if (isNothing(instanceId)) {
+ return;
+ }
+ const incident = objectGraph.props.enabled("advertSlotReporting")
+ ? null
+ : new DiscardAdIncident(instanceId, "advertDataMalformed");
+ addIncident(recorder, incident);
+ (_a = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _a === void 0 ? void 0 : _a.setMissedOpportunity(objectGraph, "METADATA", (_b = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _b === void 0 ? void 0 : _b.placementType);
+}
+/**
+ * Record events that may occur when we try to fetch an on-device ad + data
+ */
+export function recordAdResponseEventsIfNeeded(objectGraph, recorder, response) {
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
+ if (isNullOrEmpty(response === null || response === void 0 ? void 0 : response.failureReason)) {
+ return; // No failure to report
+ }
+ const instanceId = (_a = response === null || response === void 0 ? void 0 : response.onDeviceAd) === null || _a === void 0 ? void 0 : _a.instanceId;
+ const placementType = (_b = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _b === void 0 ? void 0 : _b.placementType;
+ switch (response === null || response === void 0 ? void 0 : response.failureReason) {
+ case "mapiFetchFail":
+ if (isDefinedNonNull(instanceId)) {
+ const incident = objectGraph.props.enabled("advertSlotReporting")
+ ? null
+ : new DiscardAdIncident(instanceId, "advertDataMalformed");
+ addIncident(recorder, incident);
+ }
+ (_c = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _c === void 0 ? void 0 : _c.setMissedOpportunity(objectGraph, "METADATA", placementType);
+ break;
+ case "cppAssetsMissing":
+ if (isDefinedNonNull(instanceId)) {
+ const incident = objectGraph.props.enabled("advertSlotReporting")
+ ? null
+ : new DiscardAdIncident(instanceId, "cppAssetsMissing");
+ addIncident(recorder, incident);
+ }
+ (_d = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _d === void 0 ? void 0 : _d.setMissedOpportunity(objectGraph, "METADATA", placementType);
+ break;
+ case "insufficientAssets":
+ if (isDefinedNonNull(instanceId)) {
+ const incident = objectGraph.props.enabled("advertSlotReporting")
+ ? null
+ : new DiscardAdIncident(instanceId, "insufficientAssets");
+ addIncident(recorder, incident);
+ }
+ (_e = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _e === void 0 ? void 0 : _e.setMissedOpportunity(objectGraph, "METADATA", placementType);
+ break;
+ case "noAdAvailable":
+ // no journey metric
+ (_f = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _f === void 0 ? void 0 : _f.setMissedOpportunity(objectGraph, "NOAD", placementType);
+ break;
+ case "timeout":
+ // no journey metric
+ (_g = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _g === void 0 ? void 0 : _g.setMissedOpportunity(objectGraph, "APSLA", placementType);
+ break;
+ case "localizationNotAvailable":
+ if (isDefinedNonNull(instanceId)) {
+ const incident = objectGraph.props.enabled("advertSlotReporting")
+ ? null
+ : new DiscardAdIncident(instanceId, "localizationNotAvailable");
+ addIncident(recorder, incident);
+ }
+ (_h = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _h === void 0 ? void 0 : _h.setMissedOpportunity(objectGraph, "NOLOC", placementType);
+ break;
+ case "policyAdDrop":
+ // no journey metric
+ (_j = recorder === null || recorder === void 0 ? void 0 : recorder.iAdInfo) === null || _j === void 0 ? void 0 : _j.setMissedOpportunity(objectGraph, "ODP_NOAD", placementType);
+ break;
+ default:
+ break;
+ }
+}
+// region Internals
+/**
+ * Add incident on `AdIncidentRecorder`
+ */
+function addIncident(recorder, incident) {
+ if (isNull(recorder) || isNull(incident)) {
+ return;
+ }
+ recorder.incidents.push(incident);
+}
+//# sourceMappingURL=ad-incident-recorder.js.map \ No newline at end of file
diff --git a/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-stitcher.js b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-stitcher.js
new file mode 100644
index 0000000..c9fc6b9
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/common/ads/ad-stitcher.js
@@ -0,0 +1,73 @@
+/**
+ * Handles stitching ads into pages.
+ *
+ * At a high level:
+ * 1. Setup `AdStitcher` w/ content to stitch.
+ * 2. Pass to builder
+ * 3. Destructively consume tasks during building.
+ */
+"use strict";
+import { isNull } from "../../foundation/json-parsing/server-data";
+/**
+ * Creates a string identifier representing the position information for an ad stitch task.
+ * @param positionInfo The position information object to create an identifier for.
+ * @returns The string identifier.
+ */
+function stringIdentifierForPositionInfo(positionInfo) {
+ return `${positionInfo.shelfIdentifier}.${positionInfo.slot}`;
+}
+// region exports
+/**
+ * Create a new ad stitcher
+ */
+export function newAdStitcher() {
+ return {
+ tasks: {},
+ };
+}
+/// Add task
+export function addTask(stitcher, task) {
+ if (isNull(stitcher)) {
+ return;
+ }
+ const positionIdentifier = stringIdentifierForPositionInfo(task.positionInfo);
+ stitcher.tasks[positionIdentifier] = task;
+}
+/**
+ * Consume a single task, if available, for a given position information.
+ * @param stitcher The relevant ad stitcher.
+ * @param positionInfo The position information to check for an available task.
+ * @returns A task for the position, or null if unavailable.
+ */
+export function consumeTask(stitcher, positionInfo) {
+ if (isNull(stitcher)) {
+ return null;
+ }
+ const positionIdentifier = stringIdentifierForPositionInfo(positionInfo);
+ const task = stitcher.tasks[positionIdentifier];
+ if (isNull(task)) {
+ return null;
+ }
+ delete stitcher.tasks[positionIdentifier];
+ return task;
+}
+/**
+ * Consume all tasks for a given shelf identifier. Useful where ad data is being stitched in prior to view models being built.
+ * @param stitcher The relevant ad stitcher.
+ * @param shelfIdentifier The identifier for the shelf to get all available tasks for.
+ * @returns An array of relevant tasks for the shelf.
+ */
+export function consumeTasksForShelfIdentifier(stitcher, shelfIdentifier) {
+ if (isNull(stitcher)) {
+ return [];
+ }
+ const tasksForShelf = [];
+ Object.entries(stitcher.tasks).forEach(([key, value]) => {
+ if (key.startsWith(shelfIdentifier)) {
+ tasksForShelf.push(value);
+ delete stitcher.tasks[key];
+ }
+ });
+ return tasksForShelf;
+}
+//# sourceMappingURL=ad-stitcher.js.map \ No newline at end of file
diff --git a/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-fetch.js b/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-fetch.js
new file mode 100644
index 0000000..04f3e01
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-fetch.js
@@ -0,0 +1,286 @@
+/**
+ * Handles fetching Ads for all on-device ad placements
+ * This is currently SLP, Today, Product Page.
+ *
+ * # Ad fetching for on-device placements
+ * On-Device placements are unpersonalized and rely on CDN caching. To show ads, we:
+ * 1. Fetch from an on-device cache of ads (managed by PromotedContent framework) for the specific placement
+ * 2. Fetching ad data from MAPI
+ * 2. Stitch ad onto page data...
+ */
+import * as serverData from "../../foundation/json-parsing/server-data";
+import { Request } from "../../foundation/media/data-fetching";
+import { dataFromDataContainer } from "../../foundation/media/data-structure";
+import { fetchData } from "../../foundation/media/network";
+import { buildURLFromRequest } from "../../foundation/media/url-builder";
+import { Parameters } from "../../foundation/network/url-constants";
+import { offerDataFromData } from "../offers/offers";
+import { productVariantDataForData, shouldFetchCustomAttributes } from "../product-page/product-page-variants";
+import { todayTabODPTimeoutUseCase } from "../personalization/on-device-recommendations-today";
+import { setTimeoutForRequestKey } from "../util/timeout-manager-util";
+import { adLogger } from "../search/search-ads";
+import * as adCommon from "./ad-common";
+import { getSelectedCustomCreativeId } from "../search/custom-creative";
+import { isSome } from "@jet/environment";
+// region exports
+/**
+ * Fetch ads for the given placement type leveraging on-device ads cache.
+ * @param objectGraph the object graph.
+ * @param placementType the placement type to fetch the ad for.
+ * @param adamId the adamId of the app for which the product page is being viewed, to provide a relevant ad. Only required for product page placements.
+ * @returns a promise containing an ad.
+ */
+export async function fetchAds(objectGraph, placementType, adamId) {
+ const timeout = adCommon.adFetchTimeoutForPlacement(objectGraph, placementType, false);
+ const request = new Request(objectGraph);
+ switch (placementType) {
+ case "today":
+ request.usingCustomAttributes(shouldFetchCustomAttributes(objectGraph));
+ switch (adCommon.todayAdStyle(objectGraph)) {
+ case "mediumLockup":
+ if (preprocessor.CARRY_BUILD || preprocessor.DEBUG_BUILD) {
+ if (objectGraph.featureFlags.isEnabled("aligned_region_artwork_2025A")) {
+ request.includingAttributes(["customScreenshotsByTypeForAd", "adCreativeArtwork"]);
+ }
+ else {
+ request.includingAttributes(["customScreenshotsByTypeForAd"]);
+ }
+ }
+ else {
+ request.includingAttributes(["customScreenshotsByTypeForAd"]);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case "productPageYMAL":
+ case "productPageYMALDuringDownload":
+ request.usingCustomAttributes(shouldFetchCustomAttributes(objectGraph));
+ break;
+ default:
+ break;
+ }
+ /**
+ * Ad not available content filtering
+ */
+ const adsOverrideLanguage = objectGraph.bag.adsOverrideLanguage;
+ if (serverData.isDefinedNonNullNonEmpty(adsOverrideLanguage)) {
+ request.enablingFeature("adsLocaleMetadata").addingQuery("l", adsOverrideLanguage);
+ }
+ const requestMetaFields = buildURLFromRequest(objectGraph, request).query;
+ try {
+ const onDeviceResponse = await objectGraph.ads.fetchOnDeviceAdPlacement(placementType, timeout, requestMetaFields, adamId);
+ return await handleAdResponse(objectGraph, onDeviceResponse, placementType);
+ }
+ catch {
+ return null;
+ }
+}
+/**
+ * Handle the response from an on device ad request.
+ * @param objectGraph The App Store Object Graph.
+ * @param onDeviceResponse The response from the on device ad fetcher.
+ * @param placementType The placement this request was for.
+ * @returns A promise containing an ad.
+ */
+async function handleAdResponse(objectGraph, onDeviceResponse, placementType) {
+ var _a, _b, _c, _d, _e, _f;
+ if (serverData.isNullOrEmpty(onDeviceResponse.clientRequestId)) {
+ onDeviceResponse.clientRequestId = objectGraph.random.nextUUID();
+ adLogger(objectGraph, `clientRequestId was nil. Assigned ${onDeviceResponse.clientRequestId}`);
+ }
+ const aggregateResponse = {
+ clientRequestId: onDeviceResponse.clientRequestId,
+ iAdId: onDeviceResponse.iAdId,
+ placementType: (_b = (_a = onDeviceResponse === null || onDeviceResponse === void 0 ? void 0 : onDeviceResponse.ad) === null || _a === void 0 ? void 0 : _a.placementType) !== null && _b !== void 0 ? _b : placementType,
+ };
+ // Failed w/o Ad from device.
+ if (onDeviceResponse.failureReason) {
+ aggregateResponse.failureReason = onDeviceResponse.failureReason;
+ return aggregateResponse;
+ }
+ // Set the basic ad info received on the response.
+ aggregateResponse.onDeviceAd = onDeviceResponse.ad;
+ // Ad requests should return with at least some basic app metadata.
+ // Note: On pre-SydneyC builds, this is expected to be null for the SLP placement.
+ let mediaResponse = (_c = onDeviceResponse.ad) === null || _c === void 0 ? void 0 : _c.appMetadata;
+ // Get the currently available app data from the data container.
+ const appData = dataFromDataContainer(objectGraph, mediaResponse);
+ // We should only attempt to fetch the full app data if the app data provided to us via
+ // Promoted Content is incomplete. This should only be the case for SLP ads - Chainlink
+ // placements should arrive with complete app data.
+ // We check a couple of attributes here as a way to be sure it's hydrated. Sometimes
+ // a single attribute can be misleading.
+ if (serverData.isNullOrEmpty((_d = appData === null || appData === void 0 ? void 0 : appData.attributes) === null || _d === void 0 ? void 0 : _d.name) ||
+ serverData.isNullOrEmpty((_e = appData === null || appData === void 0 ? void 0 : appData.attributes) === null || _e === void 0 ? void 0 : _e.platformAttributes) ||
+ serverData.isNullOrEmpty(offerDataFromData(objectGraph, appData))) {
+ try {
+ const adRequest = createRequestForOnDeviceAd(objectGraph, onDeviceResponse.ad);
+ mediaResponse = await fetchData(objectGraph, adRequest);
+ }
+ catch (e) {
+ adLogger(objectGraph, `fetchAds request failed - ${e}`);
+ aggregateResponse.failureReason = "mapiFetchFail";
+ }
+ }
+ // The app data should now be complete, set it on the response.
+ if (serverData.isDefinedNonNullNonEmpty((_f = dataFromDataContainer(objectGraph, mediaResponse)) === null || _f === void 0 ? void 0 : _f.attributes)) {
+ aggregateResponse.mediaResponse = decorateiAdAttributeFromOnDeviceAdResponse(objectGraph, mediaResponse, onDeviceResponse);
+ // Check the localization is valid for the ad.
+ if (!adCommon.isAdLocalizationValid(objectGraph, dataFromDataContainer(objectGraph, mediaResponse), aggregateResponse.onDeviceAd)) {
+ adLogger(objectGraph, `fetchAds request failed - localization not available`);
+ aggregateResponse.failureReason = "localizationNotAvailable";
+ }
+ const metadataFailReason = checkAppMetadataIsValidForPlacement(objectGraph, aggregateResponse, placementType);
+ if (serverData.isDefinedNonNull(metadataFailReason)) {
+ adLogger(objectGraph, `fetchAds request failed - ${metadataFailReason}`);
+ aggregateResponse.failureReason = metadataFailReason;
+ }
+ }
+ return aggregateResponse;
+}
+/**
+ * Indicates that an organic request kicked off parallel to an ad fetch has completed.
+ * This gives us an opportunity to enforce a timeout on the ad request for the time beyond the organic request.
+ * @param objectGraph The object graph.
+ * @param placementType The placement for which the parallel organic request finished.
+ */
+export function parallelOrganicRequestDidFinish(objectGraph, placementType) {
+ const timeout = adCommon.adFetchTimeoutForPlacement(objectGraph, placementType, true);
+ if (serverData.isNull(timeout)) {
+ return;
+ }
+ objectGraph.ads.setTimeoutForCurrentOnDeviceAdFetch(placementType, timeout);
+ setTimeoutForRequestKey(objectGraph, timeout, todayTabODPTimeoutUseCase);
+}
+// endregion
+// region internals
+/**
+ * Create an request for on-device adverts
+ * @param ad The on device ad to fetch MAPI data for.
+ */
+function createRequestForOnDeviceAd(objectGraph, ad) {
+ const request = new Request(objectGraph)
+ .withIdOfType(ad.adamId, "apps")
+ .usingCustomAttributes(shouldFetchCustomAttributes(objectGraph))
+ .includingAttributes(["customScreenshotsByTypeForAd"]);
+ if (serverData.isDefinedNonNullNonEmpty(ad.cppIds)) {
+ request.addingQuery(Parameters.productVariantID, ad.cppIds[0]);
+ }
+ // If there is an `adsOverrideLanguage`, attach it to this request too.
+ const adsOverrideLanguage = objectGraph.bag.adsOverrideLanguage;
+ if (serverData.isDefinedNonNullNonEmpty(adsOverrideLanguage)) {
+ request.addingQuery("l", adsOverrideLanguage);
+ }
+ return request;
+}
+/**
+ * Decorate `iad` attribute with contents of `OnDeviceAdvert`.
+ *
+ * @param mediaResponse The data from of MAPI request
+ * @param ad Ad data that was fetched independent of response.
+ */
+function decorateiAdAttributeFromOnDeviceAdResponse(objectGraph, mediaResponse, adResponse) {
+ const adData = dataFromDataContainer(objectGraph, mediaResponse);
+ if (serverData.isNullOrEmpty(adData) || serverData.isNull(adData.attributes)) {
+ adLogger(objectGraph, "decorateiAdAttributeFromOnDeviceAd cannot decorate for malformed response");
+ return null; // The data is incompatible with `iad` decoration. Return `null` to let builder report error.
+ }
+ const onDeviceAd = adResponse.ad;
+ const lineItem = `${onDeviceAd.adamId}|${onDeviceAd.metadata}`;
+ // Create `IAdAttributes` and stitch onto `mediaResponse`
+ const iadAttributes = {
+ clientRequestId: adResponse.clientRequestId,
+ impressionId: onDeviceAd.impressionId,
+ metadata: onDeviceAd.metadata,
+ privacy: onDeviceAd.privacy,
+ lineItem: lineItem,
+ };
+ const metaContainer = dataFromDataContainer(objectGraph, onDeviceAd.appMetadata);
+ if (serverData.isDefinedNonNullNonEmpty(adData.meta) &&
+ serverData.isDefinedNonNullNonEmpty(metaContainer) &&
+ serverData.isDefinedNonNullNonEmpty(metaContainer.meta)) {
+ adData.meta.passthroughAdInfo = metaContainer.meta.passthroughAdInfo;
+ if (isSome(onDeviceAd === null || onDeviceAd === void 0 ? void 0 : onDeviceAd.alignedRegionDetails)) {
+ adData.meta.alignedRegionDetails = onDeviceAd === null || onDeviceAd === void 0 ? void 0 : onDeviceAd.alignedRegionDetails[0];
+ }
+ }
+ switch (onDeviceAd.placementType) {
+ case "today":
+ // Enable images for specific placements.
+ const imagesEnabled = adCommon.todayAdStyle(objectGraph) === "mediumLockup";
+ iadAttributes.format = {
+ images: imagesEnabled,
+ text: "",
+ userRating: false,
+ };
+ break;
+ case "searchLanding":
+ iadAttributes.format = {
+ images: true,
+ text: "",
+ userRating: false,
+ };
+ break;
+ default:
+ break;
+ }
+ adData.attributes["iad"] = iadAttributes;
+ adCommon.decorateAdInstanceIdOnData(objectGraph, adData, onDeviceAd.instanceId);
+ return mediaResponse;
+}
+/**
+ * Checks whether the metadata returned for the app is considered valid for the given placement.
+ * Some ad placements have special rules to be shown. These rules are validated here.
+ * @param objectGraph The App Store object graph.
+ * @param adResponse The ad response.
+ * @param placementType The placement the given ad data is to be placed in.
+ * @returns A fail reason if there is one. Otherwise null.
+ */
+function checkAppMetadataIsValidForPlacement(objectGraph, adResponse, placementType) {
+ switch (placementType) {
+ case "today":
+ return checkAppMetadataIsValidForToday(objectGraph, adResponse);
+ default:
+ return null;
+ }
+}
+/**
+ * Checks the metadata returned for the app is considered valid **specifically** for the Today placement.
+ *
+ * Today ad placements must:
+ * - Include a valid cppId in the `meta` field of the data that matches the cppId in the ad result, and
+ * - Have enough assets to fulfill the template requirement:
+ * - Portrait: at least 4 assets, one of which can be a video.
+ * - Landscape: at least 5 assets, one of which can be a video.
+ *
+ * @param objectGraph The App Store object graph.
+ * @param adResponse The ad response.
+ * @returns A fail reason if there is one. Otherwise null.
+ */
+function checkAppMetadataIsValidForToday(objectGraph, adResponse) {
+ var _a, _b, _c;
+ const adData = dataFromDataContainer(objectGraph, adResponse.mediaResponse);
+ const productVariantData = productVariantDataForData(objectGraph, adData);
+ const hasCPP = (_b = (_a = adResponse.onDeviceAd) === null || _a === void 0 ? void 0 : _a.cppIds) === null || _b === void 0 ? void 0 : _b.includes(productVariantData.productPageId);
+ if (preprocessor.CARRY_BUILD || preprocessor.DEBUG_BUILD) {
+ const alignedRegionDetails = (_c = adResponse.onDeviceAd) === null || _c === void 0 ? void 0 : _c.alignedRegionDetails;
+ const creativeID = serverData.asString(alignedRegionDetails === null || alignedRegionDetails === void 0 ? void 0 : alignedRegionDetails[0], "apAssetId");
+ const selectedCustomCreativeId = getSelectedCustomCreativeId(adData);
+ const hasCreative = creativeID === selectedCustomCreativeId;
+ // First check there is a cppId for the ad that matches the `meta`.
+ if (!hasCPP && !hasCreative) {
+ // Then check if there is appMetadata for the custom creative ad.
+ return "cppAssetsMissing";
+ }
+ }
+ else {
+ if (!hasCPP) {
+ return "cppAssetsMissing";
+ }
+ }
+ return null;
+}
+// endregion
+//# sourceMappingURL=on-device-ad-fetch.js.map \ No newline at end of file
diff --git a/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-stitch.js b/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-stitch.js
new file mode 100644
index 0000000..4cded1e
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/common/ads/on-device-ad-stitch.js
@@ -0,0 +1,98 @@
+/**
+ * Performs ad stitching for Search Landing page using `AdStitcher`
+ */
+"use strict";
+import { isNothing, isSome } from "@jet/environment";
+import { dataFromDataContainer } from "../../foundation/media/data-structure";
+import * as adStitch from "./ad-stitcher";
+// region Constants
+export const searchLandingPagePositionInfo = {
+ shelfIdentifier: "first",
+ slot: 0,
+};
+/// shelf identifier for ad stitcher position info
+export const searchLandingPageAdShelfIdentifier = "SLPPage";
+// region Setup
+/**
+ * Get a positionInfo from a locationTracker and index.
+ * @param locationTracker A location tracker to indicate the current parsing position.
+ * @param index The index of the current position.
+ * @returns A constructed `AdStitcherPositionInfo`.
+ */
+export function todayPositionInfoForLocationTrackerAndIndex(locationTracker, index) {
+ return {
+ shelfIdentifier: locationTracker.rootPosition.toString(),
+ slot: index,
+ };
+}
+/**
+ * Creates an Ad stitcher for on device adverts *specifically for the product page YMAL shelf*
+ * This is specific to this position as it hardcodes a shelf identifier.
+ * @param adResponse Ad response to configure stitcher with.
+ */
+export function adStitcherForOnDeviceProductPageYMALAdvertData(objectGraph, adResponse) {
+ var _a;
+ const rawPositionInfo = (_a = adResponse === null || adResponse === void 0 ? void 0 : adResponse.onDeviceAd) === null || _a === void 0 ? void 0 : _a.positionInfo;
+ if (isNothing(rawPositionInfo) || isNothing(adResponse)) {
+ return null;
+ }
+ let shelfIdentifier;
+ switch (adResponse.placementType) {
+ case "productPageYMAL":
+ shelfIdentifier = "customers-also-bought-apps";
+ break;
+ case "productPageYMALDuringDownload":
+ shelfIdentifier = "customers-also-bought-apps-download";
+ break;
+ default:
+ break;
+ }
+ if (isNothing(shelfIdentifier)) {
+ return null;
+ }
+ // The slot as provided by ad platforms is one-based - adjust it so we're working with zero-based numbers.
+ const adjustedRawSlot = rawPositionInfo.slot - 1;
+ const positionInfo = {
+ shelfIdentifier: shelfIdentifier,
+ slot: adjustedRawSlot,
+ };
+ return adStitcherForOnDeviceAdvertDataAndPositionInfo(objectGraph, adResponse, positionInfo);
+}
+/**
+ * Creates an Ad stitcher for on device adverts *specifically for search landing page*
+ * This is specific to SLP because we have a hardcoded position.
+ * @param adResponse Ad response to configure stitchcher with.
+ * @param landingPageResponse Search page response to configure the positionInfo.
+ */
+export function adStitcherForOnDeviceSLPAdvertData(objectGraph, adResponse, landingPageResponse) {
+ var _a;
+ const adMeta = (landingPageResponse === null || landingPageResponse === void 0 ? void 0 : landingPageResponse.meta) || null;
+ const slot = (_a = adMeta === null || adMeta === void 0 ? void 0 : adMeta.adDisplayStyle) === null || _a === void 0 ? void 0 : _a.slot;
+ if (isSome(slot)) {
+ return adStitcherForOnDeviceAdvertDataAndPositionInfo(objectGraph, adResponse, {
+ shelfIdentifier: searchLandingPageAdShelfIdentifier,
+ slot: slot,
+ });
+ }
+ else {
+ return adStitcherForOnDeviceAdvertDataAndPositionInfo(objectGraph, adResponse, searchLandingPagePositionInfo);
+ }
+}
+function adStitcherForOnDeviceAdvertDataAndPositionInfo(objectGraph, adResponse, positionInfo) {
+ const mediaResponse = adResponse === null || adResponse === void 0 ? void 0 : adResponse.mediaResponse;
+ if (isNothing(mediaResponse) || isSome(adResponse === null || adResponse === void 0 ? void 0 : adResponse.failureReason)) {
+ return null;
+ }
+ const stitcher = adStitch.newAdStitcher();
+ /**
+ * Stitch ad data to first lockup
+ */
+ const firstAdData = dataFromDataContainer(objectGraph, mediaResponse);
+ const firstLockupAdTask = {
+ data: firstAdData,
+ positionInfo: positionInfo,
+ };
+ adStitch.addTask(stitcher, firstLockupAdTask);
+ return stitcher;
+}
+//# sourceMappingURL=on-device-ad-stitch.js.map \ No newline at end of file