import TitlesRoute from "../routes/TitlesRoute"; import Requests from "../util/Requests"; import Response from "../util/Response"; import { AxiosPromise } from "axios"; export type GameReviewRecommendation = 'recommended' | 'not_recommended' | 'neutral'; export type GameReviewSentiment = 'positive' | 'mixed' | 'negative'; export type GameReviewVoteType = 'helpful' | 'funny' | 'detailed' | 'not_helpful'; export type GameReviewReportReason = 'abuse' | 'spam' | 'off_topic' | 'manipulation' | 'hate' | 'personal_info' | 'other'; export type TitleTokenPurpose = 'install' | 'deploy' | 'hosting'; export type TitleTokenAbility = | 'deployments:*' | 'deployments:create' | 'deployments:read' | 'deployments:activate' | 'hosting:*' | 'hosting:read' | 'hosting:deploy' | 'hosting:promote'; export interface CreateTitleTokenRequest { expires_at?: string; name?: string; purpose?: TitleTokenPurpose; abilities?: TitleTokenAbility[]; } export interface TitleToken { id: string; title_id: string; name?: string | null; purpose: TitleTokenPurpose; token_prefix: string; abilities: TitleTokenAbility[]; expires_at?: string | null; revoked: boolean; last_used_at?: string | null; created_at?: string; } export interface CreatedTitleToken { /** Full secret value. Returned once and never retrievable again. */ full_token: string; token: TitleToken; } export interface GameReviewRatings { gameplay?: GameReviewSentiment; performance?: GameReviewSentiment; value?: GameReviewSentiment; content?: GameReviewSentiment; multiplayer?: GameReviewSentiment; monetization?: GameReviewSentiment; stability?: GameReviewSentiment; localization?: GameReviewSentiment; accessibility?: GameReviewSentiment; } export interface CreateGameReviewRequest { recommendation: GameReviewRecommendation; title: string; body: string; review_type?: 'first_impression' | 'full_review' | 'bug_performance_warning' | 'early_access_feedback' | 'multiplayer_community_feedback' | 'monetization_pricing_feedback' | 'changed_opinion_after_update'; liked?: string; needs_work?: string; audience?: string; language?: string; game_version?: string; platform?: string; acquisition_type?: 'purchased' | 'free_to_play' | 'free_copy' | 'promotional_key' | 'beta_key' | 'demo' | 'external_verified'; received_for_free?: boolean; early_access?: boolean; current_version_review?: boolean; main_negative_reason?: 'bugs_crashes' | 'bad_performance' | 'not_enough_content' | 'misleading_marketing' | 'price_value' | 'monetization' | 'community_toxicity' | 'developer_business_decision' | 'localization' | 'server_network' | 'gameplay_design' | 'not_my_type' | 'other'; change_reason?: string; ratings?: GameReviewRatings; } export type UpdateGameReviewRequest = Partial; class Titles { /** * List all the Titles. * * @see https://api.glitch.fun/api/documentation#/Titles/edab2e3b061347b06c82258622d239e2 * * @returns promise */ public static list(params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.list, undefined, undefined, params); } /** * Create a new title. * * @see https://api.glitch.fun/api/documentation#/Titles/storeTitle * * @param data The data to be passed when creating a title. * * @returns Promise */ public static create(data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.create, data, undefined, params); } /** * Update a title. * * @see https://api.glitch.fun/api/documentation#/Titles/updateTitle * * @param title_id The id of the title to update. * @param data The data to update. * * @returns promise */ public static update(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.update, data, { title_id: title_id }, params); } /** * Retrieve the information for a single title. * * @see https://api.glitch.fun/api/documentation#/Titles/getTitleByUUID * * @param title_id The id fo the title to retrieve. * * @returns promise */ public static view(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.view, {}, { title_id: title_id }, params); } /** * Deletes a title. * * @see https://api.glitch.fun/api/documentation#/Titles/deleteTitle * * @param title_id The id of the title to delete. * @returns promise */ public static delete(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.delete, {}, { title_id: title_id }, params); } /** * Approve a title * * @see https://api.glitch.fun/api/documentation#/Titles/approveTitle * * @param data The data to be passed when creating a title. * * @returns Promise */ public static approve(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.approve, data, { title_id: title_id }, params); } /** * Reject a title * * @see https://api.glitch.fun/api/documentation#/Titles/rejectTitle * * @param data The data to be passed when creating a title. * * @returns Promise */ public static reject(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reject, data, { title_id: title_id }, params); } /** * Add a user as an administrator to a title * * @see https://api.glitch.fun/api/documentation#/Titles/addTitleAdministrator * * @param data The data to be passed when creating a title. * * @returns Promise */ public static addAdministrator(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.addAdministrator, data, { title_id: title_id }, params); } /** * Remove a user as an administrator toa tile * * @see https://api.glitch.fun/api/documentation#/Titles/removeTitleAdministrator * * @param data The data to be passed when creating a title. * * @returns Promise */ public static removeAdministrator(title_id: string, user_id: string, data?: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.removeAdministrator, data, { title_id: title_id, user_id: user_id }, params); } /** * Updates the main image for the title using a File object. * * @see https://api.glitch.fun/api/documentation#/Titles/uploadTitleMainImage * * @param file The file object to upload. * @param data Any additional data to pass along to the upload. * * @returns promise */ public static uploadMainImageFile(title_id: string, file: File, data?: object, params?: Record): AxiosPromise> { let url = TitlesRoute.routes.uploadMainImage.url.replace('{title_id}', title_id); return Requests.uploadFile(url, 'image', file, data); } /** * Updates the main image for the title using a Blob. * * @see https://api.glitch.fun/api/documentation#/Titles/uploadTitleMainImage * * @param blob The blob to upload. * @param data Any additional data to pass along to the upload * * @returns promise */ public static uploadMainImageBlob(title_id: string, blob: Blob, data?: object, params?: Record): AxiosPromise> { let url = TitlesRoute.routes.uploadMainImage.url.replace('{title_id}', title_id); return Requests.uploadBlob(url, 'image', blob, data); } /** * Updates the banner image for the title using a File object. * * @see https://api.glitch.fun/api/documentation#/Titles/uploadTitleBannerImage * * @param file The file object to upload. * @param data Any additional data to pass along to the upload. * * @returns promise */ public static uploadBannerImageFile(title_id: string, file: File, data?: object, params?: Record): AxiosPromise> { let url = TitlesRoute.routes.uploadBannerImage.url.replace('{title_id}', title_id); return Requests.uploadFile(url, 'image', file, data); } /** * Updates the banner image for the title using a Blob. * * @see https://api.glitch.fun/api/documentation#/Titles/uploadTitleBannerImage * * @param blob The blob to upload. * @param data Any additional data to pass along to the upload * * @returns promise */ public static uploadBannerImageBlob(title_id: string, blob: Blob, data?: object, params?: Record): AxiosPromise> { let url = TitlesRoute.routes.uploadBannerImage.url.replace('{title_id}', title_id); return Requests.uploadBlob(url, 'image', blob, data); } /** * Add media to a title. */ public static addMedia(title_id: string, data?: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.addMedia, data, { title_id: title_id }, params); } /** * Remove media from a title. */ public static removeMedia(title_id: string, media_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.removeMedia, {}, { title_id: title_id, media_id: media_id }, params); } /** * Update the ordering of media items (images, videos, etc.) for a title. * * @see https://api.glitch.fun/api/documentation#/Titles/updateMediaOrder * * @param title_id The ID of the title to update * @param media_order An array of objects, each containing: * - media_id: string (the UUID of the media) * - order: number (the new order/index) * @returns Promise containing the server response */ public static updateMediaOrder(title_id: string, media_order: { media_id: string, order: number }[]): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.updateMediaOrder, { media_order }, { title_id: title_id } ); } /** * Upload a CSV/Excel file containing wishlist data for a title. * * @param title_id The UUID of the title * @param file The CSV or Excel file * @param data Any additional form data, e.g. platform * @returns AxiosPromise */ public static importWishlist( title_id: string, file: File | Blob, data?: Record, params?: Record ): AxiosPromise> { let url = TitlesRoute.routes.importWishlist.url.replace('{title_id}', title_id); return Requests.uploadFile(url, 'file', file, data, params); } /** * Retrieve the wishlist data for a specific title. * * @param title_id The UUID of the title * @param params Optional query params, e.g. { platform: 'steam', start_date: '2025-01-01', end_date: '2025-01-31'} * @returns AxiosPromise */ public static getWishlist( title_id: string, params?: Record ): AxiosPromise> { let url = TitlesRoute.routes.getWishlist.url.replace('{title_id}', title_id); return Requests.processRoute(TitlesRoute.routes.getWishlist, {}, { title_id }, params); } /** * Create a new API token for a title. * Returns { full_token: string, token: TitleToken }. */ public static createTitleToken( title_id: string, data?: CreateTitleTokenRequest ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.createToken, data, { title_id } ); } /** * List all tokens for a title. */ public static listTitleTokens( title_id: string ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.listTokens, {}, { title_id } ); } /** * Revoke a specific token by ID. */ public static revokeTitleToken( title_id: string, token_id: string ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.revokeToken, {}, { title_id, token_id } ); } /** * Search for Titles using Meilisearch or fallback based on the query and filters. * * @see https://api.glitch.fun/api/documentation#/Titles/searchTitles * * @param params Object of query params: * - q?: string, filters?: string, * - sort_by?: string, sort_order?: 'asc'|'desc', * - page?: number, per_page?: number */ public static search(params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.search, {}, undefined, params); } /** * List game installs for a specific title. */ public static listInstalls(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listInstalls, {}, { title_id: title_id }, params); } /** * View a single game install record. */ public static viewInstall(title_id: string, install_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.viewInstall, {}, { title_id: title_id, install_id: install_id }, params); } /** * Create or update a game install record. * * `user_install_id` is required. `game_build_id` is optional: send the * exact Glitch build UUID returned as `build_id` by a play session when it * is available, and omit it for external/legacy/unknown builds. Do not * guess a build id. `game_version`, `build_type`, `device_id`, platform, * device type, and operating system may be sent independently. */ public static createInstall(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.createInstall, data, { title_id: title_id }, params); } /** * List retention events for a specific title. */ public static listRetentions(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listRetentions, {}, { title_id: title_id }, params); } /** * Get a summary report of retention events for a specific title. */ public static retentionSummary(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.retentionSummary, {}, { title_id: title_id }, params); } /** Filter/group by platform, device_type, operating_system, game_version, optional game_build_id, or optional device_id. */ public static activeRetentions(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.activeRetentions, {}, { title_id }, params); } public static retentionAnalysis(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.retentionAnalysis, {}, { title_id }, params); } /** Returns string dimensions plus labeled `builds` and `devices` options for report filters. */ public static distinctDimensions(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.distinctDimensions, {}, { title_id }, params); } /** * List sessions for a specific title, with optional filters and pagination. * Returns a paginated list of sessions with start/end times, session_length, * build/version/device snapshots, and user info. `game_build_id` and * `device_id` filters are optional; unattributed/unknown options are exposed * by distinctDimensions. */ public static listSessions( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.listSessions, {}, { title_id }, params ); } /** * Get aggregated average session length data (daily/weekly/monthly) for a title. * Optionally filter/group by platform, device type, OS, version, exact * build id, or device id. */ public static sessionsAverage( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.sessionsAverage, {}, { title_id }, params ); } public static sessionsHistogram( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.sessionsHistogram, {}, { title_id }, params ); } /** * Upload a CSV/Excel file containing daily UTM analytics for a specific title. * * @param title_id The UUID of the title * @param file The CSV or Excel file * @param data Optional form fields (if needed) * @param params Optional query parameters * @returns AxiosPromise */ public static importUtmAnalytics( title_id: string, file: File | Blob, data?: Record, params?: Record ): AxiosPromise> { const url = TitlesRoute.routes.importUtmAnalytics.url.replace("{title_id}", title_id); return Requests.uploadFile(url, "file", file, data, params); } /** * Retrieve the UTM analytics data for a title (paginated, filterable, sortable). * * GET /titles/{title_id}/utm * * @param title_id The UUID of the title * @param params Optional query params: start_date, end_date, source, device_type, sort_by, etc. * @returns AxiosPromise */ public static getUtmAnalytics( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.getUtmAnalytics, {}, { title_id }, params ); } /** * Get the web tracking token used for websites. * * GET /titles/{title_id}/webTrackingToken * * @param title_id The UUID of the title * @param params Optional query params: * @returns AxiosPromise */ public static getWebTrackingToken( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.getWebTrackingToken, {}, { title_id }, params ); } /** * Analyze UTM data with optional group_by (source, campaign, medium, device_type, etc.) * * GET /titles/{title_id}/utm/analysis * * @param title_id The UUID of the title * @param params e.g. ?group_by=source&start_date=YYYY-MM-DD * @returns AxiosPromise */ public static analyzeUtmAnalytics( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.analyzeUtmAnalytics, {}, { title_id }, params ); } /** * List all chat sessions for a title. */ public static chatListSessions( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.chatListSessions, {}, { title_id }, params ); } /** * Get a specific chat session and its messages. */ public static chatShowSession( title_id: string, session_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.chatShowSession, {}, { title_id, session_id }, params ); } /** * Search messages across all sessions of a title. */ public static chatListMessages( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.chatListMessages, {}, { title_id }, params ); } /** * Update a specific chat message. */ public static chatUpdateMessage( title_id: string, message_id: string, data: object ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.chatUpdateMessage, data, { title_id, message_id } ); } /** * List all purchase events for a specific title. * Matches GET /titles/{title_id}/purchases */ public static listPurchases( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesList, {}, { title_id }, params ); } /** * Retrieve a single purchase record by ID. * Matches GET /titles/{title_id}/purchases/{purchase_id} */ public static viewPurchase( title_id: string, purchase_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesShow, {}, { title_id, purchase_id }, params ); } /** * Create a new purchase record. * Matches POST /titles/{title_id}/purchases */ public static createPurchase( title_id: string, data: object, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesCreate, data, { title_id }, params ); } /** * Get a summary of total revenue, grouped by day or purchase_type. * Matches GET /titles/{title_id}/purchases/summary */ public static purchaseSummary( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesSummary, {}, { title_id }, params ); } /** * Revenue by time (daily, weekly, or monthly). * Matches GET /titles/{title_id}/purchases/reports/time */ public static purchaseRevenueByTime( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesTimeReport, {}, { title_id }, params ); } /** * 30-day LTV (Lifetime Value) per install. * Matches GET /titles/{title_id}/purchases/reports/ltv30 */ public static purchaseLtv30( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesLtv30Report, {}, { title_id }, params ); } /** * Show breakdown of revenue per currency, with optional USD conversion. * Matches GET /titles/{title_id}/purchases/reports/currency */ public static purchaseCurrencyBreakdown( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesCurrencyBreakdown, {}, { title_id }, params ); } /** * Distribution of installs by total revenue, plus a histogram array. * Matches GET /titles/{title_id}/purchases/reports/install-distribution */ public static installRevenueDistribution( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesInstallDistribution, {}, { title_id }, params ); } /** * Stats by item SKU, purchase type, and repeat purchase analysis. * Matches GET /titles/{title_id}/purchases/reports/item-type-stats */ public static itemAndPurchaseTypeStats( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.purchasesItemTypeStats, {}, { title_id }, params ); } /** * Bulk import access keys for a title from a CSV or Excel file. * The file must contain 'platform' and 'code' columns. * * @see https://api.glitch.fun/api/documentation#/Titles/importTitleKeys * * @param title_id The UUID of the title. * @param file The CSV or Excel file to upload. * @param data Optional additional form data. * @param params Optional query parameters. * @returns AxiosPromise */ public static importKeys( title_id: string, file: File | Blob, data?: Record, params?: Record ): AxiosPromise> { const url = TitlesRoute.routes.importKeys.url.replace("{title_id}", title_id); return Requests.uploadFile(url, "file", file, data, params); } /** * Update administrator email preferences for a title. * * @see https://api.glitch.fun/api/documentation#/Titles/updateTitleAdministrator * * @param title_id The id of the title. * @param user_id The id of the user/administrator. * @param data The preference data to update (notify_promotion_schedule_reminder_email, notify_weekly_promotion_performance_email). * * @returns Promise */ public static updateAdministrator(title_id: string, user_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.updateAdministrator, data, { title_id: title_id, user_id: user_id }, params); } /** * List ad conversion events for a title with filtering */ public static listAdConversionEvents( title_id: string, params?: Record ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.listAdConversionEvents, {}, { title_id }, params ); } /** * Retry a failed or pending ad conversion event */ public static retryAdConversionEvent( title_id: string, event_id: string ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.retryAdConversionEvent, {}, { title_id, event_id } ); } /** * List all landing pages for a specific title. * @param title_id The UUID of the title. * @param params Optional query parameters for pagination. */ public static listLandingPages(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listLandingPages, {}, { title_id }, params); } /** * Create a new landing page for a title. * @param title_id The UUID of the title. * @param data The data for the new landing page. */ public static createLandingPage(title_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.createLandingPage, data, { title_id }, params); } /** * View a specific landing page by its ID. * @param landing_page_id The UUID of the landing page. */ public static viewLandingPage(landing_page_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.viewLandingPage, {}, { landing_page_id }, params); } /** * Update an existing landing page. * @param landing_page_id The UUID of the landing page to update. * @param data The new data for the landing page. */ public static updateLandingPage(landing_page_id: string, data: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.updateLandingPage, data, { landing_page_id }, params); } /** * Delete a landing page. * @param landing_page_id The UUID of the landing page to delete. */ public static deleteLandingPage(landing_page_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.deleteLandingPage, {}, { landing_page_id }, params); } /** * Trigger an AI translation for a landing page. * @param landing_page_id The UUID of the landing page. * @param data An object containing the target language code, e.g., { language_code: 'es' }. */ public static translateLandingPage(landing_page_id: string, data: { language_code: string }, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.translateLandingPage, data, { landing_page_id }, params); } /** * Generate or regenerate AI-powered HTML content for a landing page. * @param landing_page_id The UUID of the landing page. * @param data An object containing the prompt, language_code, and privacy_mode. */ public static generateLandingPageAiContent(landing_page_id: string, data: { prompt: string, language_code: string, privacy_mode: string }, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.generateLandingPageAiContent, data, { landing_page_id }, params); } /** * Create or update a specific translation for a landing page. * @param landing_page_id The UUID of the landing page. * @param translationData The full translation object to be saved. */ public static saveLandingPageTranslation(landing_page_id: string, translationData: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.saveLandingPageTranslation, translationData, { landing_page_id }, params); } public static cohorts(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.cohorts, {}, { title_id }, params); } /** * Get an aggregated report of ad conversion events for charting. */ public static getAdConversionEventsReport( title_id: string, params: { start_date: string; end_date: string; group_by: 'platform' | 'status' | 'event_type'; unique_clicks?: boolean; } ): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.getAdConversionEventsReport, {}, { title_id }, params ); } /** * Get a geographical distribution report for installs. * @param params e.g., { group_by: 'country_code', start_date: '2025-01-01' } */ public static geoReport(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.geoReport, {}, { title_id }, params); } /** * List and filter raw game events (telemetry). */ public static listEvents(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listEvents, {}, { title_id }, params); } /** * Record a single in-game action. * * Keep step_key and action_key stable. Optional step_label, * step_description, event_label, and event_description fields are * canonical display text for those keys within the title. */ public static createEvent(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.createEvent, data, { title_id }); } /** * Record multiple events in one request (Batching). * @param data { events: Array<{game_install_id, step_key, step_label?, step_description?, action_key, event_label?, event_description?, previous_step_key?, metadata?, event_timestamp?}> } */ public static bulkCreateEvents(title_id: string, data: { events: object[] }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.bulkCreateEvents, data, { title_id }); } /** * Get a summary of actions per step. */ public static eventSummary(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.eventSummary, {}, { title_id }, params); } /** * Get all unique step and action keys used in this title. */ public static eventDistinctKeys(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.eventDistinctKeys, {}, { title_id }); } /** * List all saved behavioral funnel definitions. */ public static listBehavioralFunnels(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listBehavioralFunnels, {}, { title_id }); } /** * Create and save a new behavioral funnel definition. * @param data { name: string, description?: string, steps: string[] } */ public static createBehavioralFunnel(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.createBehavioralFunnel, data, { title_id }); } /** * Generate the drop-off report for a specific behavioral funnel. * @param params { start_date?: string, end_date?: string } */ public static behavioralFunnelReport(title_id: string, funnel_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.behavioralFunnelReport, {}, { title_id, funnel_id }, params); } /** * Delete a saved behavioral funnel definition. */ public static deleteBehavioralFunnel(title_id: string, funnel_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.deleteBehavioralFunnel, {}, { title_id, funnel_id }); } /** * Generates a presigned S3 URL for uploading a game build ZIP. */ public static getDeploymentUploadUrl(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.getDeploymentUploadUrl, {}, { title_id }); } /** * Confirms the upload and starts the automated deployment/extraction process. * @param data { file_path: string, version_string: string, entry_point?: string } */ public static confirmDeployment(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.confirmDeployment, data, { title_id }); } /** * Initializes a play session. Handles age-gating and license verification. * Returns the CDN URL for WASM/iFrame or Signaling URL for Pixel Streaming. */ public static getPlaySession(title_id: string, data?: object, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.getPlaySession, data, { title_id }, params); } /** * List all developer payouts for a title. */ public static listDeveloperPayouts(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listDeveloperPayouts, undefined, { title_id }, params); } /** * View a specific payout record. */ public static viewDeveloperPayout(title_id: string, payout_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.viewDeveloperPayout, {}, { title_id, payout_id }); } /** * Get the total earnings and playtime summary for a title. */ public static getDeveloperPayoutSummary(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.developerPayoutSummary, {}, { title_id }, params); } /** * The Aegis Handshake: Verify if a player is allowed to play. * * This is used by the game engine (Unity/Unreal) to confirm that the * current session is valid and the user has a proper license. * * @see https://api.glitch.fun/api/documentation#/Aegis%20Security/validateGameSession * * @param title_id The UUID of the game title. * @param install_id The UUID of the specific install/session. * @returns AxiosPromise containing { valid: boolean, user_name: string, license_type: string } */ public static validateInstall(title_id: string, install_id: string): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.validateInstall, {}, { title_id: title_id, install_id: install_id } ); } /** * List all builds/deployments for a specific title. * @param title_id The UUID of the title. */ public static listBuilds(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listBuilds, {}, { title_id }, params); } /** * List all cloud save slots for the player associated with this install. */ public static listSaves(title_id: string, install_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.listSaves, {}, { title_id, install_id }); } /** * Upload game progress. The user is identified by the install_id. */ public static storeSave(title_id: string, install_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.storeSave, data, { title_id, install_id }); } /** * Resolve a conflict. */ public static resolveSaveConflict(title_id: string, install_id: string, save_id: string, conflict_id: string, choice: 'keep_server' | 'use_client'): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.resolveSaveConflict, { conflict_id, choice }, { title_id, install_id, save_id }); } /** * Toggle a game on the current user's wishlist. * If the game is not wishlisted, it will be added. If it is, it will be removed. * * @param title_id The UUID of the title. * @param data Optional context: { fingerprint_id?: string, short_link_click_id?: string } */ public static wishlistToggle(title_id: string, data?: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistToggle, data, { title_id }); } /** * Record a self-assigned excitement score (1-5) for a wishlisted game. * * @param title_id The UUID of the title. * @param data { score: number } - Must be between 1 and 5. */ public static wishlistUpdateScore(title_id: string, data: { score: number }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistUpdateScore, data, { title_id }); } /** * Retrieve the current user's personal wishlist collection. * * @param params Optional pagination parameters (?page=1&per_page=25) */ public static myWishlists(params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.myWishlists, undefined, undefined, params); } /** Look up the current user's wishlist rows for up to 100 title UUIDs. */ public static lookupMyWishlists(title_ids: string[]): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.lookupMyWishlists, { title_ids }); } /** * Get Wishlist Intelligence statistics for a title. * Includes funnel data and predictive revenue forecasting. * Note: Requires Title Administrator permissions. * * @param title_id The UUID of the title. */ public static wishlistStats(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistStats, undefined, { title_id }); } /** * Get the current user's specific wishlist for a title. * @param title_id The UUID of the title. */ public static wishlistMe(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistMe, undefined, { title_id }); } /** * Get the consolidated attribution funnel report. * @param title_id The UUID of the title. */ public static attributionFunnel(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.attributionFunnel, undefined, { title_id }, params); } /** * Update the status of a specific deployment build. * @param title_id The UUID of the title. * @param build_id The UUID of the build. * @param status The new status ('ready', 'inactive', or 'failed'). */ public static updateBuildStatus(title_id: string, build_id: string, status: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.updateBuildStatus, { status }, { title_id, build_id }); } /** * Proxies a request through the backend to the matchmaker. * This avoids HTTPS -> HTTP mixed content blocks. * * @param title_id The UUID of the game title. * @returns AxiosPromise containing { signallingServer: string } */ public static getMatchmakerServer(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.getMatchmakerServer, {}, { title_id }, params // ← passes as ?sessionId=xxx via Requests.get() ); } /** * Send a session heartbeat to keep the dedicated instance claimed. * Called every 30s during active gameplay. */ public static matchmakerSessionHeartbeat(title_id: string, data: { sessionId: string }): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.matchmakerSessionHeartbeat, data, { title_id } ); } /** * Release the session (starts reclaim countdown). * Called on beforeunload or explicit navigation away. */ public static matchmakerSessionRelease(title_id: string, data: { sessionId: string }): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.matchmakerSessionRelease, data, { title_id } ); } /** * Initiates a resumable S3 multipart upload for large files. */ public static initiateMultipartUpload(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.initiateMultipartUpload, data, { title_id }); } /** * Get presigned URLs for specific chunk parts. */ public static getMultipartUrls(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.getMultipartUrls, data, { title_id }); } /** * Stitch together all uploaded chunks to complete the file in S3. */ public static completeMultipartUpload(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.completeMultipartUpload, data, { title_id }); } // --- Developer Definition Methods --- public static listProgressionStats(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionStatsList, undefined, { title_id }); } public static createProgressionStat(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionStatsStore, data, { title_id }); } public static deleteProgressionStat(title_id: string, id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionStatsDelete, undefined, { title_id, id }); } public static listProgressionAchievements(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionAchievementsList, undefined, { title_id }); } public static createProgressionAchievement(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionAchievementsStore, data, { title_id }); } public static listProgressionLeaderboards(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionLeaderboardsList, undefined, { title_id }); } public static createProgressionLeaderboard(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionLeaderboardsStore, data, { title_id }); } public static listProgressionSeasons(title_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionSeasonsList, undefined, { title_id }); } public static createProgressionSeason(title_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionSeasonsStore, data, { title_id }); } /** * Submit a gameplay run. Updates stats and scores using the install_id for privacy. * @param data { idempotency_key: string, payload: { stats: {}, scores: {} } } */ public static submitProgressionRun(title_id: string, install_id: string, data: object): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionSubmit, data, { title_id, install_id }); } public static getProgressionPlayerStats(title_id: string, install_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionPlayerStats, undefined, { title_id, install_id }); } public static getProgressionPlayerAchievements(title_id: string, install_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionPlayerAchievements, undefined, { title_id, install_id }); } /** Compatibility alias matching the list-style naming used by the frontend. */ public static listProgressionPlayerAchievements(title_id: string, install_id: string): AxiosPromise> { return this.getProgressionPlayerAchievements(title_id, install_id); } /** * View leaderboard rankings. * @param params Optional filters like { around_me: true, install_id: 'uuid', season_id: 'uuid' } */ public static getProgressionLeaderboard(title_id: string, api_key: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.progressionLeaderboardView, undefined, { title_id, api_key }, params); } public static getTechnicalEventSummary(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.getTechnicalEventSummary, {}, { title_id }, params); } /** * Get games ranked by community activity (active players). * * @param params * - window: number (hours, default 24) * - limit: number (default 10) * - is_nsfw: 1 for adult titles only, 0 for safe titles only */ public static getCommunityActivity(params?: { window?: number, limit?: number, is_nsfw?: number | boolean }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.communityActivity, {}, {}, params); } /** * Get games trending on social media. * * @param params * - type: 'influencer' (campaigns) or 'organic' (non-paid) * - window: number (hours, default 168) * - limit: number (default 10) * - is_nsfw: 1 for adult titles only, 0 for safe titles only */ public static getSocialTrending(params: { type: 'influencer' | 'organic', window?: number, limit?: number, is_nsfw?: number | boolean }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.socialTrending, {}, {}, params); } /** * Get a personalized discovery queue of games. * * @param params * - limit: number (default 12) * - device_id: string (highly recommended for guest tracking) * - is_nsfw: 1 for adult titles only, 0 for safe titles only */ public static getDiscoveryQueue(params?: { limit?: number, device_id?: string, is_nsfw?: number | boolean }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.discoveryQueue, {}, {}, params); } /** * Get a curated, playable feed for the Swipe interface. * This route ensures games have builds and images, and supports seeded randomization. * * @see https://api.glitch.fun/api/documentation#/Discovery/getSwipeFeed * * @param params Object of query params: * - seed?: number (For consistent randomization) * - genres?: string[] (Filter by genre names) * - models?: string[] (premium, rental, subscription, free) * - is_nsfw?: 1 | 0 (1 for adult titles only, 0 for safe titles only) * - excluded_ids?: string[] (UUIDs to skip) * - page?: number * - per_page?: number */ public static swipeFeed(params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.swipeFeed, {}, undefined, params); } /** * Get a consolidated report of all earnings for a title, including * playtime payouts, direct premium purchases, and rentals (minus refunds). * * @param title_id The UUID of the title. * @returns AxiosPromise containing the consolidated financial data. */ public static getDeveloperPayoutConsolidatedSummary(title_id: string): AxiosPromise> { return Requests.processRoute( TitlesRoute.routes.developerPayoutConsolidatedSummary, {}, { title_id } ); } public static wishlistHistory(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistHistory, undefined, { title_id }, params); } public static wishlistInfluencers(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistInfluencers, undefined, { title_id }, params); } public static wishlistAds(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistAds, undefined, { title_id }, params); } public static wishlistUtms(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistUtms, undefined, { title_id }, params); } public static wishlistConversions(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistConversions, undefined, { title_id }, params); } public static wishlistGeo(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistGeo, undefined, { title_id }, params); } public static wishlistDevices(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.wishlistDevices, undefined, { title_id }, params); } /** * List public reviews for a title. * * @param title_id The UUID of the title. * @param params Optional filters: recommendation, language, current_version_only, * verified_only, platform, acquisition_type, complaint, playtime, sort, per_page. */ public static listReviews(title_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsList, {}, { title_id }, params); } /** * Get aggregate review scores and structured praise/complaint summaries. */ public static reviewSummary(title_id: string, params?: { language?: string }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsSummary, {}, { title_id }, params); } /** * Create the current user's review for a title. The backend verifies play/purchase eligibility. */ public static createReview(title_id: string, data: CreateGameReviewRequest): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsCreate, data, { title_id }); } /** * View a single review, including revision history when the backend includes it. */ public static viewReview(review_id: string, params?: Record): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsShow, {}, { review_id }, params); } /** * Update the current user's review and preserve a backend revision trail. */ public static updateReview(review_id: string, data: UpdateGameReviewRequest): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsUpdate, data, { review_id }); } /** * Delete the current user's review, or a title admin's moderated review. */ public static deleteReview(review_id: string): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsDelete, {}, { review_id }); } /** * Vote on a review as helpful, funny, detailed, or not helpful. */ public static voteReview(review_id: string, vote_type: GameReviewVoteType): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsVote, { vote_type }, { review_id }); } /** * Report a review for moderation. */ public static reportReview(review_id: string, data: { reason: GameReviewReportReason; notes?: string }): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsReport, data, { review_id }); } /** * Create or update the title developer's official response to a review. */ public static respondToReview( review_id: string, data: { body: string; linked_patch_note_id?: string; issue_marked_fixed?: boolean } ): AxiosPromise> { return Requests.processRoute(TitlesRoute.routes.reviewsDeveloperResponse, data, { review_id }); } } export default Titles;