Skip to main content
Glama
api-converters.ts5.78 kB
/** * App Store Connect API Data Converters * * Data transformation logic between API responses and internal types */ import type { AppStoreAsoData, AppStoreMultilingualAsoData, AppStoreReleaseNote, AppStoreScreenshots, } from "@/packages/configs/aso-config/types"; import { DEFAULT_LOCALE } from "@/packages/configs/aso-config/constants"; import { SCREENSHOT_TYPE_MAP } from "./constants"; import type { ApiResponse, AppInfoLocalization, AppStoreApp, AppStoreLocalization, AppStoreScreenshot, AppStoreScreenshotSet, AppStoreVersion, } from "./types"; export function sortVersions(versions: AppStoreVersion[]): AppStoreVersion[] { return versions.sort((a, b) => { const vA = (a.attributes?.versionString ?? "0").split(".").map(Number); const vB = (b.attributes?.versionString ?? "0").split(".").map(Number); for (let i = 0; i < Math.max(vA.length, vB.length); i++) { const diff = (vB[i] || 0) - (vA[i] || 0); if (diff !== 0) return diff; } return 0; }); } export function selectEnglishAppName( localizations: AppInfoLocalization[] ): string | null { const enUS = localizations.find((l) => l.attributes?.locale === "en-US"); if (enUS?.attributes?.name) return enUS.attributes.name; const enGB = localizations.find((l) => l.attributes?.locale === "en-GB"); if (enGB?.attributes?.name) return enGB.attributes.name; const enAny = localizations.find((l) => l.attributes?.locale?.startsWith("en") ); if (enAny?.attributes?.name) return enAny.attributes.name; return null; } export function mapLocalizationsByLocale< T extends { attributes?: { locale?: string } }, >(localizations: T[]): Record<string, T> { return localizations.reduce<Record<string, T>>((acc, loc) => { const locale = loc.attributes?.locale; if (locale) acc[locale] = loc; return acc; }, {}); } export async function fetchScreenshotsForLocalization( localizationId: string | undefined, listScreenshotSets: ( localizationId: string ) => Promise<ApiResponse<AppStoreScreenshotSet[]>>, listScreenshots: ( screenshotSetId: string ) => Promise<ApiResponse<AppStoreScreenshot[]>> ): Promise<AppStoreScreenshots> { const screenshots: AppStoreScreenshots = {}; if (!localizationId) return screenshots; const setsResponse = await listScreenshotSets(localizationId); for (const set of setsResponse.data || []) { const screenshotsResponse = await listScreenshots(set.id); const urls = (screenshotsResponse.data || []) .map((s) => s.attributes?.imageAsset?.templateUrl) .filter(Boolean) as string[]; if (urls.length > 0) { const displayType = set.attributes?.screenshotDisplayType; if (displayType) { const mappedType = SCREENSHOT_TYPE_MAP[displayType]; if (mappedType) screenshots[mappedType] = urls; } } } return screenshots; } export function convertToAsoData(params: { app: AppStoreApp; appInfoLocalization?: AppInfoLocalization | null; localization?: AppStoreLocalization | null; screenshots: AppStoreScreenshots; locale: string; bundleId: string; }): AppStoreAsoData { const { app, appInfoLocalization, localization, screenshots, locale, bundleId, } = params; return { name: appInfoLocalization?.attributes?.name || app.attributes?.name || "Unknown", subtitle: appInfoLocalization?.attributes?.subtitle, description: localization?.attributes?.description || "", keywords: localization?.attributes?.keywords, promotionalText: localization?.attributes?.promotionalText, screenshots, bundleId, locale, supportUrl: localization?.attributes?.supportUrl, marketingUrl: localization?.attributes?.marketingUrl, whatsNew: localization?.attributes?.whatsNew, }; } export function convertToMultilingualAsoData( locales: Record<string, AppStoreAsoData>, defaultLocale?: string ): AppStoreMultilingualAsoData { let finalDefaultLocale = defaultLocale; if (!finalDefaultLocale && Object.keys(locales).length > 0) { if (locales[DEFAULT_LOCALE]) { finalDefaultLocale = DEFAULT_LOCALE; } else { finalDefaultLocale = Object.keys(locales)[0]; } } return { locales, defaultLocale: finalDefaultLocale || DEFAULT_LOCALE, }; } export function convertToReleaseNote( version: AppStoreVersion, localizations: AppStoreLocalization[] ): AppStoreReleaseNote | null { const releaseNotesMap: Record<string, string> = {}; for (const localization of localizations) { const locale = localization.attributes?.locale; const whatsNew = localization.attributes?.whatsNew; if (locale && whatsNew) { releaseNotesMap[locale] = whatsNew; } } if (Object.keys(releaseNotesMap).length === 0) { return null; } const versionString = version.attributes?.versionString; const platform = version.attributes?.platform; if (!versionString || !platform) { return null; } return { versionString, releaseNotes: releaseNotesMap, platform, }; } export function sortReleaseNotes( releaseNotes: AppStoreReleaseNote[] ): AppStoreReleaseNote[] { const versionMap = new Map( releaseNotes.map((note) => [note.versionString, note]) ); const sortedVersions = sortVersions( releaseNotes.map((note) => ({ type: "appStoreVersions" as const, id: note.versionString, attributes: { versionString: note.versionString, platform: note.platform as "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS", }, })) ); return sortedVersions .map((version) => versionMap.get(version.attributes?.versionString ?? "")) .filter( (note): note is AppStoreReleaseNote => !!note && !!note.versionString ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quartz-labs-dev/pabal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server