From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Tue, 4 Nov 2025 05:03:50 +0800 Subject: init commit --- .../tmp/src/common/builders/url-mapping.js | 627 +++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 node_modules/@jet-app/app-store/tmp/src/common/builders/url-mapping.js (limited to 'node_modules/@jet-app/app-store/tmp/src/common/builders/url-mapping.js') diff --git a/node_modules/@jet-app/app-store/tmp/src/common/builders/url-mapping.js b/node_modules/@jet-app/app-store/tmp/src/common/builders/url-mapping.js new file mode 100644 index 0000000..fdaa85b --- /dev/null +++ b/node_modules/@jet-app/app-store/tmp/src/common/builders/url-mapping.js @@ -0,0 +1,627 @@ +import { isNothing, isSome } from "@jet/environment/types/optional"; +import * as mediaAPI from "@apple-media-services/media-api"; +import * as serverData from "../../foundation/json-parsing/server-data"; +import * as mediaDataFetching from "../../foundation/media/data-fetching"; +import * as urlBuilder from "../../foundation/media/url-builder"; +import { Host, Parameters, Path, previewHosts, ProductPageParameters } from "../../foundation/network/url-constants"; +import { configureMediaRequestForGameRecommendations } from "../../gameservicesui/src/foundation/media-api/requests/game-recommendations"; +import * as client from "../../foundation/wrappers/client"; +import { isAdPlacementEnabled } from "../ads/ad-common"; +import * as appPromotionsCommon from "../app-promotions/app-promotions-common"; +import * as privacySuppression from "../privacy/privacy-suppression"; +import * as productPageVariants from "../product-page/product-page-variants"; +import * as mediaRequestUtils from "./url-mapping-utils"; +import { addDeveloperRequestProperties, makeDeveloperRequest } from "../developer/developer-request"; +import { isReviewSummaryEnabled } from "../product-page/reviews"; +import { isProductAccessibilityLabelsEnabled, shouldSuppressAccessibilityLabelsForAdamId, shouldSuppressAccessibilityLabelsForBundleId, } from "../accessibility/accessibility-common"; +import { buildArticlePageRequest } from "../today/article-request"; +import { makeRoutableArticlePageIntent } from "../../api/intents/routable-article-page-intent"; +import { getLocale } from "../locale"; +import { shouldUsePrerenderedIconArtwork } from "../content/content"; +import { AppEventsAttributes } from "../../gameservicesui/src/foundation/media-api/requests/recommendation-request-types"; +import { MediaApiConfiguration } from "../../gameservicesui/src/foundation/media-api/media-api-configuration"; +const appsResourceAttributes = [ + "description", + "fileSizeByDevice", + "messagesScreenshots", + "minimumOSVersion", + "privacyPolicyUrl", + "promotionalText", + "screenshotsByType", + "supportsFunCamera", + "supportURLForLanguage", + "versionHistory", + "videoPreviewsByType", + "websiteUrl", + "expectedReleaseDateDisplayFormat", + "requirementsByDeviceFamily", + "remoteControllerRequirement", + "backgroundAssetsInfo", + "backgroundAssetsInfoWithOptional", + "supportsSharePlay", + "installSizeByDeviceInBytes", + "miniGamesDeepLink", + "gameDisplayName", +]; +// exporting this will be bad in the long run +// adding for Catagories: Games results in cannot connect to app store. +// should be removed when we stop handling media api urls in the router +export function isMediaUrl(objectGraph, url) { + const host = url.host; + if (serverData.isNull(host)) { + return false; + } + const mediaApiHosts = [ + objectGraph.bag.mediaHost, + objectGraph.bag.mediaEdgeHost(objectGraph), + objectGraph.bag.mediaEdgeSearchHost, + ]; + for (const mediaApiHost of mediaApiHosts) { + if (serverData.isNull(mediaApiHost)) { + continue; + } + if (host.indexOf(mediaApiHost) !== -1) { + return true; + } + } + return false; +} +export function hrefToRoutableUrl(objectGraph, href, additionalQueryParams) { + if (isNothing(href)) { + return undefined; + } + if (preprocessor.GAMES_TARGET) { + const request = new mediaAPI.Request(objectGraph, href); + if (isSome(additionalQueryParams)) { + for (const [key, value] of Object.entries(additionalQueryParams)) { + request.addingQuery(key, value); + } + } + return mediaAPI.buildURLFromRequest(new MediaApiConfiguration(objectGraph), request).toString(); + } + else { + const request = new mediaDataFetching.Request(objectGraph, href).addingQueryValues(additionalQueryParams); + return urlBuilder.buildURLFromRequest(objectGraph, request).toString(); + } +} +// region Grouping +export function mediaApiGroupingURLFromHref(objectGraph, href) { + const attributes = [ + "editorialArtwork", + "editorialVideo", + "isAppleWatchSupported", + "requiredCapabilities", + "minimumOSVersion", + "expectedReleaseDateDisplayFormat", + ]; + if (objectGraph.appleSilicon.isSupportEnabled) { + attributes.push("macRequiredCapabilities"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + if (objectGraph.bag.enableUpdatedAgeRatings) { + attributes.push("ageRating"); + } + if (shouldUsePrerenderedIconArtwork(objectGraph)) { + attributes.push("iconArtwork"); + } + // Catalyst apps have clickable 'get' button on 10.14. + // - minimumOSVersion required to filter catalyst apps from groupings. + const mediaApiRequest = new mediaDataFetching.Request(objectGraph, href) + .includingAttributes(attributes) + .includingAgeRestrictions() + .includingMacOSCompatibleIOSAppsWhenSupported(); + if (appPromotionsCommon.appEventsAreEnabled(objectGraph)) { + mediaApiRequest.enablingFeature("appEvents"); + mediaApiRequest.includingScopedAttributes("app-events", AppEventsAttributes); + mediaApiRequest.includingScopedRelationships("app-events", ["app"]); + mediaApiRequest.includingScopedRelationships("editorial-item-shelves", ["app-events"]); + } + const context = mediaDataFetching.defaultGroupingContextForClient(objectGraph); + if (serverData.isDefinedNonNull(context)) { + mediaApiRequest.addingQuery("contexts", context); + } + return mediaApiRequest; +} +// endregion +// region Editorial Stories +export function mappedMediaApiEditorialItemURL(objectGraph, url, isIncomingURL) { + const pathComponents = url.pathComponents(); + if (pathComponents.indexOf("story") < 0 && + pathComponents.indexOf("editorialItem") < 0 && + pathComponents.indexOf("viewEditorialItem") < 0 && + url.host !== Host.spamBlockingExtensions && + url.host !== Host.sharePlayApps && + url.host !== Host.buddyOnboarding) { + throw new Error(`Unable to map ${url.build()} to a media api url`); + } + let editorialItemId; + if (url.host === Host.spamBlockingExtensions) { + // Populate editorial item ID for spam blocking extensions. + editorialItemId = objectGraph.props.asString("spamBlockingExtensionsEditorialItemID"); + } + else if (url.host === Host.sharePlayApps) { + editorialItemId = objectGraph.bag.sharePlayAppsEditorialItemId; + } + else if (url.host === Host.buddyOnboarding) { + editorialItemId = objectGraph.bag.buddyOnboardingEditorialItemId; + } + else { + // Otherwise extract the ID from the URL. + editorialItemId = extractedIdFromURL(url); + } + if (!serverData.isNumber(editorialItemId)) { + throw new Error(`Unable to map ${url.build()} to a media api url`); + } + if (!serverData.isNumber(editorialItemId)) { + throw new Error(`Unable to map ${url} to a media api url`); + } + const mediaApiRequest = buildArticlePageRequest(objectGraph, makeRoutableArticlePageIntent({ + ...getLocale(objectGraph), + id: editorialItemId, + }), isIncomingURL); + const editorialCardId = url.query[Parameters.editorialCardId]; + if (serverData.isDefinedNonNullNonEmpty(editorialCardId)) { + mediaApiRequest.withFilter("canvas:cardId", editorialCardId); + } + const previewParam = url.query[Parameters.preview]; + if (previewHosts.has(url.host) && (previewParam === null || previewParam === void 0 ? void 0 : previewParam.length) > 0) { + mediaApiRequest.addingQuery("preview", previewParam); + mediaApiRequest.isStorePreviewRequest = true; + } + return mediaApiRequest.attributingTo(url.build()); +} +// endregion +// region Product +const entityIdRegex = /id([0-9]+)\/?$/i; +export function extractedIdFromURL(url) { + // 1. Look at the query parameter for the id + let extractedId = url.query["id"]; + // 2. Consider the last path component /id + const pathName = url.pathname; + if (serverData.isNull(extractedId) && (pathName === null || pathName === void 0 ? void 0 : pathName.length) > 0) { + const match = entityIdRegex.exec(pathName); + if (match && match.length > 1) { + extractedId = match[1]; + } + } + // 3. At this point, if the ID is not found, try looking for / instead, since this is what the last path + // component looks like in QA now. + if (!serverData.isNumber(extractedId)) { + const pathComponents = url.pathComponents(); + if (serverData.isDefinedNonNullNonEmpty(pathComponents)) { + extractedId = pathComponents[pathComponents.length - 1]; + } + } + return extractedId; +} +const productRedirectionTable = { + "915249334": "1462947752", // rdar://49929244 (SAD: Redirect from the old 2nd party Shortcuts product page to the new 1st party page on iOS 13) +}; +export function mappedMediaApiProductURL(objectGraph, url, includeUnlistedApps = false) { + var _a, _b; + let productId = extractedIdFromURL(url); + if (!serverData.isNumber(productId)) { + throw new Error(`Unable to map ${url.build()} to a media api url`); + } + // Redirect to a different product if needed + if (productId in productRedirectionTable) { + productId = productRedirectionTable[productId]; + } + let resourceType = "apps"; + let attributes = appsResourceAttributes; + let relationships = []; + if (preprocessor.GAMES_TARGET) { + relationships = ["alternate-apps"]; + } + else { + relationships = [ + "customers-also-bought-apps", + "reviews", + "app-bundles", + "top-in-apps", + "related-editorial-items", + "alternate-apps", + ]; + } + const pathComponents = (_a = url.pathname) === null || _a === void 0 ? void 0 : _a.split("/"); + const isBundle = isSome(pathComponents) && pathComponents.includes(Path.productBundle); + if (isBundle) { + resourceType = "app-bundles"; + attributes = [ + "screenshotsByType", + "videoPreviewsByType", + "minimumOSVersion", + "requirementsByDeviceFamily", + "remoteControllerRequirement", + ]; + relationships = ["apps", "reviews", "related-editorial-items"]; + } + if (!preprocessor.GAMES_TARGET) { + relationships.push("developer-other-apps"); + } + if (objectGraph.bag.enablePrivacyNutritionLabels && + !privacySuppression.shouldSuppressPrivacyInformationForAdamId(objectGraph, productId)) { + attributes.push("privacy"); + } + if (isProductAccessibilityLabelsEnabled(objectGraph) && + !shouldSuppressAccessibilityLabelsForAdamId(objectGraph, productId)) { + attributes.push("accessibility"); + } + if (objectGraph.appleSilicon.isSupportEnabled) { + attributes.push("macRequiredCapabilities"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + if (objectGraph.bag.enableUpdatedAgeRatings) { + attributes.push("ageRating"); + } + if (shouldUsePrerenderedIconArtwork(objectGraph)) { + attributes.push("iconArtwork"); + } + if (objectGraph.bag.enableLicenses) { + attributes.push("licenses"); + } + // TODO Product Page should not request developer information if supportsArcade is false + // We need to pipe the supportsArcade information from the sidepack, through the lockup, to the productPage action URL + // until then, isArcade will always be null. + // If no arcade affiliation is specified, or the product definitely isArcade, fetch the developer genre. + const isArcade = serverData.asBoolean(url.query[Parameters.isArcade]); + if (isArcade === null || isArcade) { + attributes.push("minPlayers", "maxPlayers", "editorialVideo"); + relationships.push("developer"); + } + if (objectGraph.client.isVision) { + attributes.push("compatibilityControllerRequirement"); + attributes.push("isHighMotion"); + if (objectGraph.featureFlags.isEnabled("spatial_controllers_2025A")) { + attributes.push("spatialControllerRequirement"); + } + } + if (objectGraph.bag.enableSellerInfo) { + attributes.push("sellerInfo"); + } + // Extends the API to include Internet Content Provider Info + if (objectGraph.bag.enableSellerICPAnnotation) { + attributes.push("internetContentProviderInfo"); + } + // Extends the API to include supported Game Center features. + if (objectGraph.bag.gameCenterExtendSupportedFeatures) { + attributes.push("supportedGameCenterFeatures"); + } + // Extends the API to include Review Summary + if (isReviewSummaryEnabled(objectGraph)) { + relationships.push("review-summary"); + } + if (preprocessor.GAMES_TARGET) { + attributes.push("gamesUrl"); + attributes.push("isEligibleForGamesApp"); + } + const mediaApiRequest = new mediaDataFetching.Request(objectGraph) + .withIdOfType(productId, resourceType) + .includingAdditionalPlatforms(mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph)) + .includingAgeRestrictions() + .includingRelationships(relationships) + .includingAttributes(attributes) + .includingMacOSCompatibleIOSAppsWhenSupported(true) + .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph)) + .includingViews(["categorizations"]); + if (!preprocessor.GAMES_TARGET) { + mediaApiRequest.addingRelationshipLimit("reviews", mediaDataFetching.defaultProductPageReviewsLimitForClient(objectGraph)); + } + if (preprocessor.GAMES_TARGET) { + mediaApiRequest.includingScopedRelationships("apps", ["activities", "challenges"]); + mediaApiRequest.includingViews(["customers-also-bought-games", "developer-other-games"]); + mediaApiRequest.enablingFeature("unlistedApps"); + if (objectGraph.debugSettings.enableHighlightsFromProductPageResponse) { + configureMediaRequestForGameRecommendations(mediaApiRequest); + } + } + if (((_b = url.query[Parameters.productVariantID]) === null || _b === void 0 ? void 0 : _b.length) > 0) { + mediaApiRequest.addingQuery(Parameters.productVariantID, url.query[Parameters.productVariantID]); + } + // If a `minExternalVersionId` is specified, pass this through to the MAPI request + const minExternalVersionId = url.query[ProductPageParameters.minExternalVersionId]; + if (serverData.isDefinedNonNull(minExternalVersionId)) { + mediaApiRequest.addingQuery(ProductPageParameters.minExternalVersionId, minExternalVersionId); + } + // Disabling for bundles due to rdar://78542145 ([REG] Pre-Prod JS: SkySeed: App bundle product page does not load) + if (appPromotionsCommon.appEventsAreEnabled(objectGraph) && !isBundle) { + if (!appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaApiRequest.includingScopedRelationships("apps", ["app-events"]); + } + mediaApiRequest.includingScopedAttributes("app-events", AppEventsAttributes); + mediaApiRequest.includingScopedAvailableIn("app-events", ["future"]); + } + if (appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureContingentItemsForMediaRequest(mediaApiRequest); + } + if (appPromotionsCommon.appOfferItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureOfferItemsForMediaRequest(mediaApiRequest); + } + if (isAdPlacementEnabled(objectGraph, "productPageYMAL")) { + mediaApiRequest.enablingFeature("cabAdSupport"); + } + if (includeUnlistedApps) { + mediaApiRequest.enablingFeature("unlistedApps"); + } + if (!appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaApiRequest.includingRelationships(["merchandised-in-apps"]); + } + return mediaApiRequest.attributingTo(url.build()); +} +// endregion +// region Developer +export function mediaApiDeveloperURLFromHref(objectGraph, href) { + const mediaApiRequest = new mediaDataFetching.Request(objectGraph, href); + return addDeveloperRequestProperties(objectGraph, mediaApiRequest); +} +export function mappedMediaApiDeveloperURL(objectGraph, url) { + const developerId = extractedIdFromURL(url); + if (!serverData.isNumber(developerId)) { + throw new Error(`Unable to map ${url.build()} to a media api url`); + } + return makeDeveloperRequest(objectGraph, developerId); +} +// endregion +// region Charts +/** + * Creates a Media API request for one or more charts using provided critera. + * @param objectGraph The App Store object graph. + * @param genreId The genre for the chart request. + * @param charts The list of charts for the request. + * @param ageBandId The age band to include in the request. + * @param clientIdentifier The identifier of the current client. + * @returns A Media API request for one or more charts using provided critera. + */ +export function mediaApiChartRequestForGenre(objectGraph, genreId, charts, ageBandId = null, clientIdentifier = objectGraph.host.clientIdentifier) { + const attributes = ["isAppleWatchSupported", "requiredCapabilities", "minimumOSVersion"]; + if (objectGraph.appleSilicon.isSupportEnabled) { + attributes.push("macRequiredCapabilities"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + const mediaApiRequest = new mediaDataFetching.Request(objectGraph) + .forType("charts") + .addingQuery("genre", genreId) + .includingAttributes(attributes) + .addingQuery("types", "apps") + .includingMacOSCompatibleIOSAppsWhenSupported(true) + .includingAdditionalPlatforms(mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph)) + .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph)); + if (serverData.isDefinedNonNullNonEmpty(charts)) { + mediaApiRequest.addingQuery(Parameters.charts, charts); + } + if (clientIdentifier === client.watchIdentifier) { + mediaApiRequest.addingContext("watch"); + } + else if (clientIdentifier === client.messagesIdentifier) { + mediaApiRequest.addingContext("messages"); + } + if (objectGraph.appleSilicon.isSupportEnabled) { + mediaApiRequest.includingAdditionalPlatforms(["iphone", "ipad"]); + } + if (isSome(ageBandId)) { + mediaApiRequest.addingQuery(Parameters.ages, ageBandId); + } + return mediaApiRequest; +} +export function mediaApiChartsRequest(objectGraph, genreId, ageBandId = null) { + let request = new mediaDataFetching.Request(objectGraph) + .forType("charts") + .addingQuery("types", "apps") + .addingQuery("genre", genreId) + .includingMacOSCompatibleIOSAppsWhenSupported(true); + if (ageBandId) { + request = request.addingQuery("ages", ageBandId); + } + if (objectGraph.appleSilicon.isSupportEnabled) { + request = request.includingAdditionalPlatforms(["iphone", "ipad"]); + } + return request; +} +// endregion +// region Lookups +export function lookupURLForProductId(objectGraph, productId, isPurchasesProduct, productVariantID, isBundle, includeUnlistedApps) { + const attributes = appsResourceAttributes; + if (objectGraph.bag.enablePrivacyNutritionLabels && + !privacySuppression.shouldSuppressPrivacyInformationForAdamId(objectGraph, productId)) { + attributes.push("privacy"); + // The "web" client needs the full privacy information in the initial page load; + // unlike other platforms, it does not load the full details on a separate page + if (objectGraph.client.isWeb) { + attributes.push("privacyDetails"); + } + } + if (isProductAccessibilityLabelsEnabled(objectGraph) && + !shouldSuppressAccessibilityLabelsForAdamId(objectGraph, productId)) { + attributes.push("accessibility"); + // The web client requires complete accessibility information on initial page load. + // Unlike other platforms that load full details on separate pages, + // the web client displays this information in a modal overlay. + if (objectGraph.client.isWeb) { + attributes.push("accessibilityDetails"); + } + } + if (objectGraph.appleSilicon.isSupportEnabled) { + attributes.push("macRequiredCapabilities"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + if (objectGraph.client.isVision) { + attributes.push("compatibilityControllerRequirement"); + attributes.push("isHighMotion"); + if (objectGraph.featureFlags.isEnabled("spatial_controllers_2025A")) { + attributes.push("spatialControllerRequirement"); + } + } + if (objectGraph.bag.enableUpdatedAgeRatings) { + attributes.push("ageRating"); + } + if (shouldUsePrerenderedIconArtwork(objectGraph)) { + attributes.push("iconArtwork"); + } + if (objectGraph.bag.enableLicenses) { + attributes.push("licenses"); + } + // Extends the API to include supported Game Center features. + if (objectGraph.bag.gameCenterExtendSupportedFeatures) { + attributes.push("supportedGameCenterFeatures"); + } + const mediaApiRequest = new mediaDataFetching.Request(objectGraph) + .withIdOfType(productId, "apps") + .includingAdditionalPlatforms(mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph)) + .includingAttributes(attributes) + .includingRelationships([ + "developer", + "customers-also-bought-apps", + "developer-other-apps", + "reviews", + "app-bundles", + "top-in-apps", + "related-editorial-items", + "alternate-apps", + ]) + .addingRelationshipLimit("reviews", mediaDataFetching.defaultProductPageReviewsLimitForClient(objectGraph)) + .includingMacOSCompatibleIOSAppsWhenSupported(true) + .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph)); + if (objectGraph.client.isWeb) { + // Ensure that the "web" client fully hydrates all PDP shelves + mediaApiRequest + .includingScopedSparseLimit("apps:customers-also-bought-apps", 40) + .includingScopedSparseLimit("apps:developer-other-apps", 40) + .includingScopedSparseLimit("apps:related-editorial-items", 40); + // Ensures web can render the DSA information in the annotation shelf + if (objectGraph.bag.enableSellerInfo) { + attributes.push("sellerInfo"); + } + } + if (isPurchasesProduct) { + mediaApiRequest.addingQuery("availability", "redownload"); + } + if (isSome(productVariantID)) { + mediaApiRequest.addingQuery(Parameters.productVariantID, productVariantID); + } + if (includeUnlistedApps) { + mediaApiRequest.enablingFeature("unlistedApps"); + } + // Disabling for bundles due to rdar://78542145 ([REG] Pre-Prod JS: SkySeed: App bundle product page does not load) + if (appPromotionsCommon.appEventsAreEnabled(objectGraph) && !isBundle) { + if (!appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaApiRequest.includingScopedRelationships("apps", ["app-events"]); + } + mediaApiRequest.includingScopedAttributes("app-events", AppEventsAttributes); + mediaApiRequest.includingScopedAvailableIn("app-events", ["future"]); + } + if (appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureContingentItemsForMediaRequest(mediaApiRequest); + } + if (appPromotionsCommon.appOfferItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureOfferItemsForMediaRequest(mediaApiRequest); + } + if (!appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaApiRequest.includingRelationships(["merchandised-in-apps"]); + } + // Extends the API to include Review Summary + if (isReviewSummaryEnabled(objectGraph)) { + mediaApiRequest.includingRelationships(["review-summary"]); + } + if (isAdPlacementEnabled(objectGraph, "productPageYMAL")) { + mediaApiRequest.enablingFeature("cabAdSupport"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + return mediaApiRequest; +} +export function lookupURLForBundleId(objectGraph, bundleId, productVariantID, includeUnlistedApps) { + const attributes = appsResourceAttributes; + if (objectGraph.bag.enablePrivacyNutritionLabels && + !privacySuppression.shouldSuppressPrivacyInformationForBundleId(objectGraph, bundleId)) { + attributes.push("privacy"); + } + if (isProductAccessibilityLabelsEnabled(objectGraph) && + !shouldSuppressAccessibilityLabelsForBundleId(objectGraph, bundleId)) { + attributes.push("accessibility"); + } + if (objectGraph.appleSilicon.isSupportEnabled) { + attributes.push("macRequiredCapabilities"); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + if (objectGraph.client.isVision) { + attributes.push("compatibilityControllerRequirement"); + attributes.push("isHighMotion"); + if (objectGraph.featureFlags.isEnabled("spatial_controllers_2025A")) { + attributes.push("spatialControllerRequirement"); + } + } + if (objectGraph.bag.enableUpdatedAgeRatings) { + attributes.push("ageRating"); + } + if (shouldUsePrerenderedIconArtwork(objectGraph)) { + attributes.push("iconArtwork"); + } + if (objectGraph.bag.enableLicenses) { + attributes.push("licenses"); + } + const mediaApiRequest = new mediaDataFetching.Request(objectGraph) + .forType("apps") + .withFilter("bundleId", bundleId) + .includingAdditionalPlatforms(mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph)) + .includingRelationships([ + "developer", + "customers-also-bought-apps", + "developer-other-apps", + "reviews", + "app-bundles", + "top-in-apps", + "related-editorial-items", + "alternate-apps", + ]) + .includingAttributes(attributes) + .addingRelationshipLimit("reviews", mediaDataFetching.defaultProductPageReviewsLimitForClient(objectGraph)) + .includingMacOSCompatibleIOSAppsWhenSupported(true) + .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph)); + if (isSome(productVariantID)) { + mediaApiRequest.addingQuery(Parameters.productVariantID, productVariantID); + } + if (isAdPlacementEnabled(objectGraph, "productPageYMAL")) { + mediaApiRequest.enablingFeature("cabAdSupport"); + } + if (includeUnlistedApps) { + mediaApiRequest.enablingFeature("unlistedApps"); + } + if (appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaApiRequest.includingViews(["standalone-merchandised-in-apps"]); + } + else { + mediaApiRequest.includingRelationships(["merchandised-in-apps"]); + } + if (objectGraph.client.isMac) { + attributes.push("hasMacIPAPackage"); + } + return mediaApiRequest; +} +export function mediaApiProductSeeAllRequest(objectGraph, productId, relationship) { + const mediaApiRequest = new mediaDataFetching.Request(objectGraph) + .withIdOfType(productId, "apps") + .includingAdditionalPlatforms(mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph)) + .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph)) + .includingRelationships([relationship, "apps", "developer"]) + .includingScopedSparseLimit(`apps:${relationship}`, 20); + if (appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureContingentItemsForMediaRequest(mediaApiRequest); + } + if (appPromotionsCommon.appOfferItemsAreEnabled(objectGraph)) { + mediaRequestUtils.configureOfferItemsForMediaRequest(mediaApiRequest); + } + return mediaApiRequest; +} +// endregion +//# sourceMappingURL=url-mapping.js.map \ No newline at end of file -- cgit v1.2.3