pabal-store-api-mcp 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/bin/pabal-mcp.js +6 -0
- package/dist/src/core/clients/app-store-factory.d.ts +29 -0
- package/dist/src/core/clients/app-store-factory.js +72 -0
- package/dist/src/core/clients/client-factory-helpers.d.ts +7 -0
- package/dist/src/core/clients/client-factory-helpers.js +10 -0
- package/dist/src/core/clients/google-play-factory.d.ts +29 -0
- package/dist/src/core/clients/google-play-factory.js +72 -0
- package/dist/src/core/clients/types.d.ts +8 -0
- package/dist/src/core/clients/types.js +1 -0
- package/dist/src/core/helpers/formatters.d.ts +3 -0
- package/dist/src/core/helpers/formatters.js +38 -0
- package/dist/src/core/helpers/registration.d.ts +21 -0
- package/dist/src/core/helpers/registration.js +21 -0
- package/dist/src/core/helpers/translate-release-notes.d.ts +46 -0
- package/dist/src/core/helpers/translate-release-notes.js +87 -0
- package/dist/src/core/services/app-resolution-service.d.ts +14 -0
- package/dist/src/core/services/app-resolution-service.js +35 -0
- package/dist/src/core/services/app-store-service.d.ts +41 -0
- package/dist/src/core/services/app-store-service.js +266 -0
- package/dist/src/core/services/google-play-service.d.ts +36 -0
- package/dist/src/core/services/google-play-service.js +203 -0
- package/dist/src/core/services/service-helpers.d.ts +15 -0
- package/dist/src/core/services/service-helpers.js +31 -0
- package/dist/src/core/services/types.d.ts +81 -0
- package/dist/src/core/services/types.js +1 -0
- package/dist/src/core/workflows/version-info.d.ts +29 -0
- package/dist/src/core/workflows/version-info.js +100 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +279 -0
- package/dist/src/packages/common/errors/app-error.d.ts +39 -0
- package/dist/src/packages/common/errors/app-error.js +134 -0
- package/dist/src/packages/common/errors/error-codes.d.ts +63 -0
- package/dist/src/packages/common/errors/error-codes.js +71 -0
- package/dist/src/packages/common/errors/status-codes.d.ts +10 -0
- package/dist/src/packages/common/errors/status-codes.js +9 -0
- package/dist/src/packages/configs/aso-config/constants.d.ts +14 -0
- package/dist/src/packages/configs/aso-config/constants.js +102 -0
- package/dist/src/packages/configs/aso-config/locale-guards.d.ts +3 -0
- package/dist/src/packages/configs/aso-config/locale-guards.js +7 -0
- package/dist/src/packages/configs/aso-config/store.d.ts +11 -0
- package/dist/src/packages/configs/aso-config/store.js +11 -0
- package/dist/src/packages/configs/aso-config/types.d.ts +98 -0
- package/dist/src/packages/configs/aso-config/types.js +2 -0
- package/dist/src/packages/configs/aso-config/utils.d.ts +43 -0
- package/dist/src/packages/configs/aso-config/utils.js +223 -0
- package/dist/src/packages/configs/secrets-config/config.d.ts +12 -0
- package/dist/src/packages/configs/secrets-config/config.js +187 -0
- package/dist/src/packages/configs/secrets-config/constants.d.ts +1 -0
- package/dist/src/packages/configs/secrets-config/constants.js +1 -0
- package/dist/src/packages/configs/secrets-config/errors.d.ts +9 -0
- package/dist/src/packages/configs/secrets-config/errors.js +15 -0
- package/dist/src/packages/configs/secrets-config/registered-apps.d.ts +52 -0
- package/dist/src/packages/configs/secrets-config/registered-apps.js +108 -0
- package/dist/src/packages/configs/secrets-config/schemas.d.ts +21 -0
- package/dist/src/packages/configs/secrets-config/schemas.js +9 -0
- package/dist/src/packages/configs/secrets-config/types.d.ts +8 -0
- package/dist/src/packages/configs/secrets-config/types.js +1 -0
- package/dist/src/packages/stores/app-store/api-converters.d.ts +26 -0
- package/dist/src/packages/stores/app-store/api-converters.js +131 -0
- package/dist/src/packages/stores/app-store/api-endpoints.d.ts +33 -0
- package/dist/src/packages/stores/app-store/api-endpoints.js +157 -0
- package/dist/src/packages/stores/app-store/auth.d.ts +12 -0
- package/dist/src/packages/stores/app-store/auth.js +36 -0
- package/dist/src/packages/stores/app-store/client.d.ts +78 -0
- package/dist/src/packages/stores/app-store/client.js +637 -0
- package/dist/src/packages/stores/app-store/constants.d.ts +11 -0
- package/dist/src/packages/stores/app-store/constants.js +38 -0
- package/dist/src/packages/stores/app-store/generated-types.d.ts +118537 -0
- package/dist/src/packages/stores/app-store/generated-types.js +5 -0
- package/dist/src/packages/stores/app-store/types.d.ts +39 -0
- package/dist/src/packages/stores/app-store/types.js +9 -0
- package/dist/src/packages/stores/app-store/verify-auth.d.ts +16 -0
- package/dist/src/packages/stores/app-store/verify-auth.js +34 -0
- package/dist/src/packages/stores/play-store/api-converters.d.ts +58 -0
- package/dist/src/packages/stores/play-store/api-converters.js +209 -0
- package/dist/src/packages/stores/play-store/api-endpoints.d.ts +68 -0
- package/dist/src/packages/stores/play-store/api-endpoints.js +145 -0
- package/dist/src/packages/stores/play-store/client.d.ts +55 -0
- package/dist/src/packages/stores/play-store/client.js +628 -0
- package/dist/src/packages/stores/play-store/constants.d.ts +10 -0
- package/dist/src/packages/stores/play-store/constants.js +17 -0
- package/dist/src/packages/stores/play-store/types.d.ts +146 -0
- package/dist/src/packages/stores/play-store/types.js +9 -0
- package/dist/src/packages/stores/play-store/verify-auth.d.ts +13 -0
- package/dist/src/packages/stores/play-store/verify-auth.js +31 -0
- package/dist/src/tools/apps/add.d.ts +28 -0
- package/dist/src/tools/apps/add.js +307 -0
- package/dist/src/tools/apps/init.d.ts +58 -0
- package/dist/src/tools/apps/init.js +390 -0
- package/dist/src/tools/apps/search.d.ts +33 -0
- package/dist/src/tools/apps/search.js +147 -0
- package/dist/src/tools/aso/pull.d.ts +22 -0
- package/dist/src/tools/aso/pull.js +264 -0
- package/dist/src/tools/aso/push.d.ts +23 -0
- package/dist/src/tools/aso/push.js +189 -0
- package/dist/src/tools/auth/app-store.d.ts +9 -0
- package/dist/src/tools/auth/app-store.js +34 -0
- package/dist/src/tools/auth/check.d.ts +14 -0
- package/dist/src/tools/auth/check.js +50 -0
- package/dist/src/tools/auth/play-store.d.ts +9 -0
- package/dist/src/tools/auth/play-store.js +30 -0
- package/dist/src/tools/release/check-versions.d.ts +14 -0
- package/dist/src/tools/release/check-versions.js +65 -0
- package/dist/src/tools/release/create.d.ts +23 -0
- package/dist/src/tools/release/create.js +128 -0
- package/dist/src/tools/release/pull-notes.d.ts +22 -0
- package/dist/src/tools/release/pull-notes.js +151 -0
- package/dist/src/tools/release/update-notes.d.ts +110 -0
- package/dist/src/tools/release/update-notes.js +537 -0
- package/package.json +71 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Store Connect API Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for App Store Connect operations.
|
|
5
|
+
* Response types are from OpenAPI, Request attribute types are extracted.
|
|
6
|
+
*
|
|
7
|
+
* @see https://developer.apple.com/documentation/appstoreconnectapi
|
|
8
|
+
*/
|
|
9
|
+
import type { App as AppModel, AppInfo as AppInfoModel, AppInfoLocalization as AppInfoLocalizationModel, AppScreenshot as AppScreenshotModel, AppScreenshotSet as AppScreenshotSetModel, AppStoreVersion as AppStoreVersionModel, AppStoreVersionLocalization as AppStoreVersionLocalizationModel, AppStoreVersionLocalizationUpdateRequestDataAttributes, AppInfoLocalizationUpdateRequestDataAttributes } from "appstore-connect-sdk/openapi";
|
|
10
|
+
export interface AppStoreClientConfig {
|
|
11
|
+
issuerId: string;
|
|
12
|
+
keyId: string;
|
|
13
|
+
privateKey: string;
|
|
14
|
+
bundleId: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ApiResponse<T> {
|
|
17
|
+
data: T;
|
|
18
|
+
links?: {
|
|
19
|
+
self?: string;
|
|
20
|
+
next?: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export type AppStoreApp = AppModel;
|
|
24
|
+
export type AppInfo = AppInfoModel;
|
|
25
|
+
export type AppInfoLocalization = AppInfoLocalizationModel;
|
|
26
|
+
export type AppStoreVersion = AppStoreVersionModel;
|
|
27
|
+
export type AppStoreLocalization = AppStoreVersionLocalizationModel;
|
|
28
|
+
export type AppStoreScreenshotSet = AppScreenshotSetModel;
|
|
29
|
+
export type AppStoreScreenshot = AppScreenshotModel;
|
|
30
|
+
/**
|
|
31
|
+
* App Info Localization Update Request Attributes
|
|
32
|
+
* @see https://developer.apple.com/documentation/appstoreconnectapi/appinfolocalizationupdaterequest/data/attributes
|
|
33
|
+
*/
|
|
34
|
+
export type AppInfoLocalizationUpdateAttributes = AppInfoLocalizationUpdateRequestDataAttributes;
|
|
35
|
+
/**
|
|
36
|
+
* App Store Version Localization Update Request Attributes
|
|
37
|
+
* @see https://developer.apple.com/documentation/appstoreconnectapi/appstoreversionlocalizationupdaterequest/data/attributes
|
|
38
|
+
*/
|
|
39
|
+
export type AppStoreVersionLocalizationUpdateAttributes = AppStoreVersionLocalizationUpdateRequestDataAttributes;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface VerifyAppStoreAuthResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
error?: string;
|
|
4
|
+
data?: {
|
|
5
|
+
header: Record<string, unknown>;
|
|
6
|
+
payload: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Verify App Store Connect authentication configuration and generate JWT token for validation.
|
|
11
|
+
* @param expirationSeconds JWT token expiration time (seconds). Default: 300 seconds
|
|
12
|
+
* @returns Authentication verification result
|
|
13
|
+
*/
|
|
14
|
+
export declare function verifyAppStoreAuth({ expirationSeconds, }?: {
|
|
15
|
+
expirationSeconds?: number;
|
|
16
|
+
}): Promise<VerifyAppStoreAuthResult>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { loadConfig } from "../../../packages/configs/secrets-config/config.js";
|
|
2
|
+
import { createAppStoreJWT, decodeJwt } from "../../../packages/stores/app-store/auth.js";
|
|
3
|
+
/**
|
|
4
|
+
* Verify App Store Connect authentication configuration and generate JWT token for validation.
|
|
5
|
+
* @param expirationSeconds JWT token expiration time (seconds). Default: 300 seconds
|
|
6
|
+
* @returns Authentication verification result
|
|
7
|
+
*/
|
|
8
|
+
export async function verifyAppStoreAuth({ expirationSeconds = 300, } = {}) {
|
|
9
|
+
try {
|
|
10
|
+
const cfg = loadConfig().appStore;
|
|
11
|
+
if (!cfg) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
error: "App Store configuration not found in ~/.config/pabal-mcp/config.json file.",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const token = await createAppStoreJWT(cfg, { expirationSeconds });
|
|
18
|
+
const decoded = decodeJwt(token);
|
|
19
|
+
return {
|
|
20
|
+
success: true,
|
|
21
|
+
data: {
|
|
22
|
+
header: decoded.header,
|
|
23
|
+
payload: decoded.payload,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: `App Store authentication verification failed: ${message}`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Play Console API Data Converters
|
|
3
|
+
*
|
|
4
|
+
* Data transformation logic between API responses and internal types
|
|
5
|
+
*/
|
|
6
|
+
import type { GooglePlayAsoData, GooglePlayMultilingualAsoData, GooglePlayReleaseNote } from "../../../packages/configs/aso-config/types.js";
|
|
7
|
+
import type { ScreenshotUrls, ListingUpdateAttributes, AppDetailsUpdateAttributes, LatestReleaseInfo, ImageType } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Convert API image responses to screenshot URLs structure
|
|
10
|
+
*/
|
|
11
|
+
export declare function fetchScreenshotsAndFeatureGraphic(fetchImagesFunc: (imageType: ImageType) => Promise<any>, language: string): Promise<{
|
|
12
|
+
screenshots: ScreenshotUrls;
|
|
13
|
+
featureGraphic: string | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Convert API listing response to GooglePlayAsoData
|
|
17
|
+
*/
|
|
18
|
+
export declare function convertToAsoData(listingData: any, appDetailsData: any, screenshots: ScreenshotUrls, featureGraphic: string | undefined, packageName: string, defaultLanguage: string): GooglePlayAsoData;
|
|
19
|
+
/**
|
|
20
|
+
* Convert API listing to locale-specific ASO data
|
|
21
|
+
*/
|
|
22
|
+
export declare function convertToLocaleAsoData(listingData: any, appDetailsData: any, screenshots: ScreenshotUrls, featureGraphic: string | undefined, packageName: string, language: string): GooglePlayAsoData;
|
|
23
|
+
/**
|
|
24
|
+
* Convert multiple locales data to multilingual ASO data structure
|
|
25
|
+
*/
|
|
26
|
+
export declare function convertToMultilingualAsoData(locales: Record<string, GooglePlayAsoData>, defaultLocale?: string): GooglePlayMultilingualAsoData;
|
|
27
|
+
/**
|
|
28
|
+
* Build request body for listing update (only defined values)
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildListingRequestBody(data: {
|
|
31
|
+
title?: string;
|
|
32
|
+
shortDescription?: string;
|
|
33
|
+
fullDescription?: string;
|
|
34
|
+
}): ListingUpdateAttributes;
|
|
35
|
+
/**
|
|
36
|
+
* Build request body for app details update (only defined values)
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildDetailsRequestBody(data: {
|
|
39
|
+
contactEmail?: string;
|
|
40
|
+
contactPhone?: string;
|
|
41
|
+
contactWebsite?: string;
|
|
42
|
+
defaultLanguage?: string;
|
|
43
|
+
}): AppDetailsUpdateAttributes;
|
|
44
|
+
/**
|
|
45
|
+
* Convert track release data to GooglePlayReleaseNote
|
|
46
|
+
*/
|
|
47
|
+
export declare function convertToReleaseNote(release: any, versionCode: string | number, trackName: string): GooglePlayReleaseNote | null;
|
|
48
|
+
/**
|
|
49
|
+
* Convert release notes map to API format
|
|
50
|
+
*/
|
|
51
|
+
export declare function convertReleaseNotesToApiFormat(releaseNotes: Record<string, string>): Array<{
|
|
52
|
+
language: string;
|
|
53
|
+
text: string;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Extract latest release from track releases
|
|
57
|
+
*/
|
|
58
|
+
export declare function extractLatestRelease(releases: any[]): LatestReleaseInfo | null;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Play Console API Data Converters
|
|
3
|
+
*
|
|
4
|
+
* Data transformation logic between API responses and internal types
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_LOCALE } from "../../../packages/configs/aso-config/constants.js";
|
|
7
|
+
import { IMAGE_TYPES } from "./constants.js";
|
|
8
|
+
/**
|
|
9
|
+
* Convert API image responses to screenshot URLs structure
|
|
10
|
+
*/
|
|
11
|
+
export async function fetchScreenshotsAndFeatureGraphic(fetchImagesFunc, language) {
|
|
12
|
+
const screenshots = {
|
|
13
|
+
phone: [],
|
|
14
|
+
tablet7: [],
|
|
15
|
+
tablet10: [],
|
|
16
|
+
tv: [],
|
|
17
|
+
wear: [],
|
|
18
|
+
};
|
|
19
|
+
let featureGraphic;
|
|
20
|
+
for (const imageType of IMAGE_TYPES) {
|
|
21
|
+
try {
|
|
22
|
+
const imagesResponse = await fetchImagesFunc(imageType);
|
|
23
|
+
const images = imagesResponse.data.images || [];
|
|
24
|
+
if (imageType === "featureGraphic") {
|
|
25
|
+
featureGraphic = images[0]?.url;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const urls = images
|
|
29
|
+
.map((img) => img.url)
|
|
30
|
+
.filter(Boolean);
|
|
31
|
+
if (imageType === "phoneScreenshots") {
|
|
32
|
+
screenshots.phone.push(...urls);
|
|
33
|
+
}
|
|
34
|
+
else if (imageType === "sevenInchScreenshots") {
|
|
35
|
+
screenshots.tablet7.push(...urls);
|
|
36
|
+
}
|
|
37
|
+
else if (imageType === "tenInchScreenshots") {
|
|
38
|
+
screenshots.tablet10.push(...urls);
|
|
39
|
+
}
|
|
40
|
+
else if (imageType === "tvScreenshots") {
|
|
41
|
+
screenshots.tv.push(...urls);
|
|
42
|
+
}
|
|
43
|
+
else if (imageType === "wearScreenshots") {
|
|
44
|
+
screenshots.wear.push(...urls);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const err = error;
|
|
50
|
+
if (err.code !== 404) {
|
|
51
|
+
console.warn(`⚠️ Failed to fetch ${imageType} images for ${language}:`, err.message);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { screenshots, featureGraphic };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert API listing response to GooglePlayAsoData
|
|
59
|
+
*/
|
|
60
|
+
export function convertToAsoData(listingData, appDetailsData, screenshots, featureGraphic, packageName, defaultLanguage) {
|
|
61
|
+
return {
|
|
62
|
+
title: listingData.title || "",
|
|
63
|
+
shortDescription: listingData.shortDescription || "",
|
|
64
|
+
fullDescription: listingData.fullDescription || "",
|
|
65
|
+
screenshots,
|
|
66
|
+
featureGraphic,
|
|
67
|
+
category: appDetailsData.category || "",
|
|
68
|
+
packageName,
|
|
69
|
+
defaultLanguage,
|
|
70
|
+
contactEmail: appDetailsData.contactEmail ?? undefined,
|
|
71
|
+
contactPhone: appDetailsData.contactPhone ?? undefined,
|
|
72
|
+
contactWebsite: appDetailsData.contactWebsite ?? undefined,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convert API listing to locale-specific ASO data
|
|
77
|
+
*/
|
|
78
|
+
export function convertToLocaleAsoData(listingData, appDetailsData, screenshots, featureGraphic, packageName, language) {
|
|
79
|
+
return {
|
|
80
|
+
title: listingData.title || "",
|
|
81
|
+
shortDescription: listingData.shortDescription || "",
|
|
82
|
+
fullDescription: listingData.fullDescription || "",
|
|
83
|
+
screenshots,
|
|
84
|
+
featureGraphic,
|
|
85
|
+
category: appDetailsData.category || "",
|
|
86
|
+
packageName,
|
|
87
|
+
defaultLanguage: language,
|
|
88
|
+
contactEmail: appDetailsData.contactEmail ?? undefined,
|
|
89
|
+
contactPhone: appDetailsData.contactPhone ?? undefined,
|
|
90
|
+
contactWebsite: appDetailsData.contactWebsite ?? undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convert multiple locales data to multilingual ASO data structure
|
|
95
|
+
*/
|
|
96
|
+
export function convertToMultilingualAsoData(locales, defaultLocale) {
|
|
97
|
+
let finalDefaultLocale = defaultLocale;
|
|
98
|
+
if (!finalDefaultLocale && Object.keys(locales).length > 0) {
|
|
99
|
+
// Try to find DEFAULT_LOCALE
|
|
100
|
+
if (locales[DEFAULT_LOCALE]) {
|
|
101
|
+
finalDefaultLocale = DEFAULT_LOCALE;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Use first available locale
|
|
105
|
+
finalDefaultLocale = Object.keys(locales)[0];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
locales,
|
|
110
|
+
defaultLocale: finalDefaultLocale || DEFAULT_LOCALE,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build request body for listing update (only defined values)
|
|
115
|
+
*/
|
|
116
|
+
export function buildListingRequestBody(data) {
|
|
117
|
+
const body = {};
|
|
118
|
+
if (data.title)
|
|
119
|
+
body.title = data.title;
|
|
120
|
+
if (data.shortDescription)
|
|
121
|
+
body.shortDescription = data.shortDescription;
|
|
122
|
+
if (data.fullDescription)
|
|
123
|
+
body.fullDescription = data.fullDescription;
|
|
124
|
+
return body;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build request body for app details update (only defined values)
|
|
128
|
+
*/
|
|
129
|
+
export function buildDetailsRequestBody(data) {
|
|
130
|
+
const body = {};
|
|
131
|
+
if (data.defaultLanguage)
|
|
132
|
+
body.defaultLanguage = data.defaultLanguage;
|
|
133
|
+
if (data.contactEmail)
|
|
134
|
+
body.contactEmail = data.contactEmail;
|
|
135
|
+
if (data.contactPhone)
|
|
136
|
+
body.contactPhone = data.contactPhone;
|
|
137
|
+
if (data.contactWebsite)
|
|
138
|
+
body.contactWebsite = data.contactWebsite;
|
|
139
|
+
return body;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Convert track release data to GooglePlayReleaseNote
|
|
143
|
+
*/
|
|
144
|
+
export function convertToReleaseNote(release, versionCode, trackName) {
|
|
145
|
+
const releaseNotesMap = {};
|
|
146
|
+
if (release.releaseNotes) {
|
|
147
|
+
for (const rn of release.releaseNotes) {
|
|
148
|
+
if (rn.language && rn.text) {
|
|
149
|
+
releaseNotesMap[rn.language] = rn.text;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (Object.keys(releaseNotesMap).length === 0) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
const releaseDate = release.releaseDate?.seconds
|
|
157
|
+
? new Date(Number(release.releaseDate.seconds) * 1000).toISOString()
|
|
158
|
+
: undefined;
|
|
159
|
+
return {
|
|
160
|
+
versionCode: Number(versionCode),
|
|
161
|
+
versionName: versionCode.toString(),
|
|
162
|
+
releaseNotes: releaseNotesMap,
|
|
163
|
+
track: trackName,
|
|
164
|
+
status: release.status || "draft",
|
|
165
|
+
releaseDate,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Convert release notes map to API format
|
|
170
|
+
*/
|
|
171
|
+
export function convertReleaseNotesToApiFormat(releaseNotes) {
|
|
172
|
+
return Object.entries(releaseNotes).map(([language, text]) => ({
|
|
173
|
+
language,
|
|
174
|
+
text,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Extract latest release from track releases
|
|
179
|
+
*/
|
|
180
|
+
export function extractLatestRelease(releases) {
|
|
181
|
+
if (releases.length === 0) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
let latestRelease = null;
|
|
185
|
+
let latestVersionCode = 0;
|
|
186
|
+
for (const release of releases) {
|
|
187
|
+
const versionCodes = (release.versionCodes || []).map((code) => Number(code));
|
|
188
|
+
const maxVersionCode = versionCodes.reduce((max, code) => Math.max(max, code), 0);
|
|
189
|
+
if (!latestRelease || maxVersionCode > latestVersionCode) {
|
|
190
|
+
latestRelease = release;
|
|
191
|
+
latestVersionCode = maxVersionCode;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!latestRelease) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const releaseDate = latestRelease.releaseDate?.seconds
|
|
198
|
+
? new Date(Number(latestRelease.releaseDate.seconds) * 1000).toISOString()
|
|
199
|
+
: undefined;
|
|
200
|
+
return {
|
|
201
|
+
versionCodes: (latestRelease.versionCodes || []).map((code) => Number(code)),
|
|
202
|
+
status: latestRelease.status
|
|
203
|
+
? latestRelease.status
|
|
204
|
+
: undefined,
|
|
205
|
+
versionName: latestRelease.name ? String(latestRelease.name) : undefined,
|
|
206
|
+
releaseName: latestRelease.name ? String(latestRelease.name) : undefined,
|
|
207
|
+
releaseDate,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Play Console API Endpoints
|
|
3
|
+
*
|
|
4
|
+
* Centralized API endpoint management for androidpublisher v3 API
|
|
5
|
+
*/
|
|
6
|
+
import type { androidpublisher_v3 } from "googleapis";
|
|
7
|
+
import type { EditSession, ListingUpdateAttributes, AppDetailsUpdateAttributes, TrackUpdateAttributes, ImageType, AppEdit, AppDetails, Listing, Image, Track, ListingsListResponse, ImagesListResponse, TracksListResponse } from "./types.js";
|
|
8
|
+
export declare class GooglePlayApiEndpoints {
|
|
9
|
+
private androidPublisher;
|
|
10
|
+
constructor(androidPublisher: androidpublisher_v3.Androidpublisher);
|
|
11
|
+
/**
|
|
12
|
+
* Edit Operations
|
|
13
|
+
*/
|
|
14
|
+
createEdit(auth: EditSession["auth"], packageName: string): Promise<{
|
|
15
|
+
data: AppEdit;
|
|
16
|
+
}>;
|
|
17
|
+
deleteEdit(session: EditSession): Promise<{
|
|
18
|
+
data: void;
|
|
19
|
+
}>;
|
|
20
|
+
commitEdit(session: EditSession): Promise<{
|
|
21
|
+
data: AppEdit;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* App Details Operations
|
|
25
|
+
*/
|
|
26
|
+
getAppDetails(session: EditSession): Promise<{
|
|
27
|
+
data: AppDetails;
|
|
28
|
+
}>;
|
|
29
|
+
updateAppDetails(session: EditSession, requestBody: AppDetailsUpdateAttributes): Promise<{
|
|
30
|
+
data: AppDetails;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Listing Operations
|
|
34
|
+
*/
|
|
35
|
+
listListings(session: EditSession): Promise<{
|
|
36
|
+
data: ListingsListResponse;
|
|
37
|
+
}>;
|
|
38
|
+
getListing(session: EditSession, language: string): Promise<{
|
|
39
|
+
data: Listing;
|
|
40
|
+
}>;
|
|
41
|
+
updateListing(session: EditSession, language: string, requestBody: ListingUpdateAttributes): Promise<{
|
|
42
|
+
data: Listing;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Image Operations
|
|
46
|
+
*/
|
|
47
|
+
listImages(session: EditSession, language: string, imageType: ImageType): Promise<{
|
|
48
|
+
data: ImagesListResponse;
|
|
49
|
+
}>;
|
|
50
|
+
uploadImage(session: EditSession, language: string, imageType: ImageType, media: {
|
|
51
|
+
mimeType: string;
|
|
52
|
+
body: Buffer;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
data: Image;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Track Operations
|
|
58
|
+
*/
|
|
59
|
+
getTrack(session: EditSession, track: string): Promise<{
|
|
60
|
+
data: Track;
|
|
61
|
+
}>;
|
|
62
|
+
updateTrack(session: EditSession, track: string, requestBody: TrackUpdateAttributes): Promise<{
|
|
63
|
+
data: Track;
|
|
64
|
+
}>;
|
|
65
|
+
listTracks(session: EditSession): Promise<{
|
|
66
|
+
data: TracksListResponse;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Play Console API Endpoints
|
|
3
|
+
*
|
|
4
|
+
* Centralized API endpoint management for androidpublisher v3 API
|
|
5
|
+
*/
|
|
6
|
+
export class GooglePlayApiEndpoints {
|
|
7
|
+
androidPublisher;
|
|
8
|
+
constructor(androidPublisher) {
|
|
9
|
+
this.androidPublisher = androidPublisher;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Edit Operations
|
|
13
|
+
*/
|
|
14
|
+
async createEdit(auth, packageName) {
|
|
15
|
+
const response = await this.androidPublisher.edits.insert({
|
|
16
|
+
auth,
|
|
17
|
+
packageName,
|
|
18
|
+
});
|
|
19
|
+
return { data: response.data };
|
|
20
|
+
}
|
|
21
|
+
async deleteEdit(session) {
|
|
22
|
+
await this.androidPublisher.edits.delete({
|
|
23
|
+
auth: session.auth,
|
|
24
|
+
packageName: session.packageName,
|
|
25
|
+
editId: session.editId,
|
|
26
|
+
});
|
|
27
|
+
return { data: undefined };
|
|
28
|
+
}
|
|
29
|
+
async commitEdit(session) {
|
|
30
|
+
const response = await this.androidPublisher.edits.commit({
|
|
31
|
+
auth: session.auth,
|
|
32
|
+
packageName: session.packageName,
|
|
33
|
+
editId: session.editId,
|
|
34
|
+
});
|
|
35
|
+
return { data: response.data };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* App Details Operations
|
|
39
|
+
*/
|
|
40
|
+
async getAppDetails(session) {
|
|
41
|
+
const response = await this.androidPublisher.edits.details.get({
|
|
42
|
+
auth: session.auth,
|
|
43
|
+
packageName: session.packageName,
|
|
44
|
+
editId: session.editId,
|
|
45
|
+
});
|
|
46
|
+
return { data: response.data };
|
|
47
|
+
}
|
|
48
|
+
async updateAppDetails(session, requestBody) {
|
|
49
|
+
const response = await this.androidPublisher.edits.details.update({
|
|
50
|
+
auth: session.auth,
|
|
51
|
+
packageName: session.packageName,
|
|
52
|
+
editId: session.editId,
|
|
53
|
+
requestBody,
|
|
54
|
+
});
|
|
55
|
+
return { data: response.data };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Listing Operations
|
|
59
|
+
*/
|
|
60
|
+
async listListings(session) {
|
|
61
|
+
const response = await this.androidPublisher.edits.listings.list({
|
|
62
|
+
auth: session.auth,
|
|
63
|
+
packageName: session.packageName,
|
|
64
|
+
editId: session.editId,
|
|
65
|
+
});
|
|
66
|
+
return { data: response.data };
|
|
67
|
+
}
|
|
68
|
+
async getListing(session, language) {
|
|
69
|
+
const response = await this.androidPublisher.edits.listings.get({
|
|
70
|
+
auth: session.auth,
|
|
71
|
+
packageName: session.packageName,
|
|
72
|
+
editId: session.editId,
|
|
73
|
+
language,
|
|
74
|
+
});
|
|
75
|
+
return { data: response.data };
|
|
76
|
+
}
|
|
77
|
+
async updateListing(session, language, requestBody) {
|
|
78
|
+
const response = await this.androidPublisher.edits.listings.update({
|
|
79
|
+
auth: session.auth,
|
|
80
|
+
packageName: session.packageName,
|
|
81
|
+
editId: session.editId,
|
|
82
|
+
language,
|
|
83
|
+
requestBody,
|
|
84
|
+
});
|
|
85
|
+
return { data: response.data };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Image Operations
|
|
89
|
+
*/
|
|
90
|
+
async listImages(session, language, imageType) {
|
|
91
|
+
const response = await this.androidPublisher.edits.images.list({
|
|
92
|
+
auth: session.auth,
|
|
93
|
+
packageName: session.packageName,
|
|
94
|
+
editId: session.editId,
|
|
95
|
+
language,
|
|
96
|
+
imageType,
|
|
97
|
+
});
|
|
98
|
+
return { data: response.data };
|
|
99
|
+
}
|
|
100
|
+
async uploadImage(session, language, imageType, media) {
|
|
101
|
+
const response = await this.androidPublisher.edits.images.upload({
|
|
102
|
+
auth: session.auth,
|
|
103
|
+
packageName: session.packageName,
|
|
104
|
+
editId: session.editId,
|
|
105
|
+
language,
|
|
106
|
+
imageType,
|
|
107
|
+
media,
|
|
108
|
+
});
|
|
109
|
+
const uploadData = response.data;
|
|
110
|
+
if (!uploadData?.image) {
|
|
111
|
+
throw new Error("Image upload failed: no image data returned");
|
|
112
|
+
}
|
|
113
|
+
return { data: uploadData.image };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Track Operations
|
|
117
|
+
*/
|
|
118
|
+
async getTrack(session, track) {
|
|
119
|
+
const response = await this.androidPublisher.edits.tracks.get({
|
|
120
|
+
auth: session.auth,
|
|
121
|
+
packageName: session.packageName,
|
|
122
|
+
editId: session.editId,
|
|
123
|
+
track,
|
|
124
|
+
});
|
|
125
|
+
return { data: response.data };
|
|
126
|
+
}
|
|
127
|
+
async updateTrack(session, track, requestBody) {
|
|
128
|
+
const response = await this.androidPublisher.edits.tracks.update({
|
|
129
|
+
auth: session.auth,
|
|
130
|
+
packageName: session.packageName,
|
|
131
|
+
editId: session.editId,
|
|
132
|
+
track,
|
|
133
|
+
requestBody,
|
|
134
|
+
});
|
|
135
|
+
return { data: response.data };
|
|
136
|
+
}
|
|
137
|
+
async listTracks(session) {
|
|
138
|
+
const response = await this.androidPublisher.edits.tracks.list({
|
|
139
|
+
auth: session.auth,
|
|
140
|
+
packageName: session.packageName,
|
|
141
|
+
editId: session.editId,
|
|
142
|
+
});
|
|
143
|
+
return { data: response.data };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Play Console API Client
|
|
3
|
+
*
|
|
4
|
+
* Authentication: Service account JSON key file required
|
|
5
|
+
* API Documentation: https://developers.google.com/android-publisher
|
|
6
|
+
*/
|
|
7
|
+
import type { GooglePlayAsoData, GooglePlayMultilingualAsoData, GooglePlayReleaseNote } from "../../../packages/configs/aso-config/types.js";
|
|
8
|
+
import type { GooglePlayClientConfig, AppAccessInfo, LatestReleaseInfo, ReleaseUpdateResult, CreateReleaseOptions, UploadScreenshotOptions, UpdateReleaseNotesOptions, AppDetailsData } from "./types.js";
|
|
9
|
+
export declare class GooglePlayClient {
|
|
10
|
+
private auth;
|
|
11
|
+
private androidPublisher;
|
|
12
|
+
private packageName;
|
|
13
|
+
constructor(config: GooglePlayClientConfig);
|
|
14
|
+
/**
|
|
15
|
+
* Verify app access (returns app information)
|
|
16
|
+
* Google Play API does not support listing apps, so only verifies access by package name
|
|
17
|
+
*/
|
|
18
|
+
verifyAppAccess(): Promise<AppAccessInfo>;
|
|
19
|
+
pullAllLanguagesAsoData(): Promise<GooglePlayMultilingualAsoData>;
|
|
20
|
+
pullAsoData(): Promise<GooglePlayAsoData>;
|
|
21
|
+
pushAsoData(data: Partial<GooglePlayAsoData>): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Push multilingual ASO data in a single edit session
|
|
24
|
+
* This prevents backendError from rapid successive commits
|
|
25
|
+
*/
|
|
26
|
+
pushMultilingualAsoData(data: GooglePlayMultilingualAsoData): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Push app details (contactEmail, contactPhone, contactWebsite) in a separate edit session
|
|
29
|
+
* This must be called separately from pushMultilingualAsoData due to Google Play API limitations
|
|
30
|
+
* NOTE: defaultLanguage is required - it will be fetched from current app details if not provided
|
|
31
|
+
*/
|
|
32
|
+
pushAppDetails(details: AppDetailsData): Promise<void>;
|
|
33
|
+
uploadScreenshot(options: UploadScreenshotOptions): Promise<void>;
|
|
34
|
+
getLatestProductionRelease(): Promise<LatestReleaseInfo | null>;
|
|
35
|
+
createProductionRelease(options: CreateReleaseOptions): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Update release notes for production track
|
|
38
|
+
*/
|
|
39
|
+
updateReleaseNotes(options: UpdateReleaseNotesOptions): Promise<ReleaseUpdateResult>;
|
|
40
|
+
pullReleaseNotes(): Promise<GooglePlayReleaseNote[]>;
|
|
41
|
+
pullProductionReleaseNotes(): Promise<GooglePlayReleaseNote[]>;
|
|
42
|
+
private createEdit;
|
|
43
|
+
private deleteEdit;
|
|
44
|
+
private commitEdit;
|
|
45
|
+
private getAppDetails;
|
|
46
|
+
private updateAppDetails;
|
|
47
|
+
private listListings;
|
|
48
|
+
private getListing;
|
|
49
|
+
private updateListing;
|
|
50
|
+
private listImages;
|
|
51
|
+
private uploadImage;
|
|
52
|
+
private getTrack;
|
|
53
|
+
private updateTrack;
|
|
54
|
+
private listTracks;
|
|
55
|
+
}
|