pabal-store-api-mcp 1.3.9 → 1.3.11
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/dist/src/core/services/app-store-service.d.ts +7 -1
- package/dist/src/core/services/app-store-service.js +26 -5
- package/dist/src/core/services/google-play-service.d.ts +7 -1
- package/dist/src/core/services/google-play-service.js +49 -14
- package/dist/src/index.js +10 -0
- package/dist/src/packages/common/errors/error-codes.d.ts +2 -0
- package/dist/src/packages/common/errors/error-codes.js +2 -0
- package/dist/src/packages/stores/app-store/client.d.ts +2 -0
- package/dist/src/packages/stores/app-store/client.js +10 -5
- package/dist/src/packages/stores/play-store/client.d.ts +1 -0
- package/dist/src/packages/stores/play-store/client.js +18 -45
- package/dist/src/packages/stores/play-store/types.d.ts +1 -0
- package/dist/src/tools/aso/push.d.ts +2 -0
- package/dist/src/tools/aso/push.js +10 -1
- package/package.json +1 -1
|
@@ -7,6 +7,10 @@ interface AppStoreAppInfo {
|
|
|
7
7
|
name?: string;
|
|
8
8
|
supportedLocales?: string[];
|
|
9
9
|
}
|
|
10
|
+
export declare function resolveAppStoreLocales(allLocales: string[], requestedLocales?: string[]): {
|
|
11
|
+
localesToPush: string[];
|
|
12
|
+
missingLocales: string[];
|
|
13
|
+
};
|
|
10
14
|
/**
|
|
11
15
|
* App Store-facing service layer that wraps client creation and common operations.
|
|
12
16
|
* Keeps MCP tools independent from client factories and SDK details.
|
|
@@ -26,12 +30,14 @@ export declare class AppStoreService {
|
|
|
26
30
|
updateReleaseNotes(bundleId: string, releaseNotes: Record<string, string>, versionId?: string, supportedLocales?: string[]): Promise<ServiceResult<UpdatedReleaseNotesResult>>;
|
|
27
31
|
pullReleaseNotes(bundleId: string): Promise<ServiceResult<AppStoreReleaseNote[]>>;
|
|
28
32
|
createVersion(bundleId: string, versionString: string, autoIncrement?: boolean): Promise<ServiceResult<CreatedAppStoreVersion>>;
|
|
29
|
-
pushAsoData({ config, bundleId, localAsoData, appStoreDataPath, uploadImages, slug, }: {
|
|
33
|
+
pushAsoData({ config, bundleId, localAsoData, appStoreDataPath, uploadImages, locales, imageUploadTimeoutMs, slug, }: {
|
|
30
34
|
config: EnvConfig;
|
|
31
35
|
bundleId?: string;
|
|
32
36
|
localAsoData: AsoData;
|
|
33
37
|
appStoreDataPath: string;
|
|
34
38
|
uploadImages?: boolean;
|
|
39
|
+
locales?: string[];
|
|
40
|
+
imageUploadTimeoutMs?: number;
|
|
35
41
|
slug?: string;
|
|
36
42
|
}): Promise<PushAsoResult>;
|
|
37
43
|
verifyAuth(expirationSeconds?: number): Promise<VerifyAuthResult<{
|
|
@@ -6,6 +6,16 @@ import { verifyAppStoreAuth } from "../../packages/stores/app-store/verify-auth.
|
|
|
6
6
|
import { createAppStoreClient } from "../../core/clients/app-store-factory.js";
|
|
7
7
|
import { parseAppStoreScreenshots, hasScreenshots, APP_STORE_DEVICE_TYPES, } from "../../core/helpers/screenshot-helpers.js";
|
|
8
8
|
import { checkPushPrerequisites, serviceFailure, toServiceResult, updateRegisteredLocales, } from "./service-helpers.js";
|
|
9
|
+
export function resolveAppStoreLocales(allLocales, requestedLocales) {
|
|
10
|
+
if (!requestedLocales?.length) {
|
|
11
|
+
return { localesToPush: allLocales, missingLocales: [] };
|
|
12
|
+
}
|
|
13
|
+
const requested = new Set(requestedLocales);
|
|
14
|
+
return {
|
|
15
|
+
localesToPush: allLocales.filter((locale) => requested.has(locale)),
|
|
16
|
+
missingLocales: requestedLocales.filter((locale) => !allLocales.includes(locale)),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
9
19
|
/**
|
|
10
20
|
* App Store-facing service layer that wraps client creation and common operations.
|
|
11
21
|
* Keeps MCP tools independent from client factories and SDK details.
|
|
@@ -163,7 +173,7 @@ export class AppStoreService {
|
|
|
163
173
|
return serviceFailure(AppError.wrap(error, HTTP_STATUS.INTERNAL_SERVER_ERROR, ERROR_CODES.APP_STORE_CREATE_VERSION_FAILED, "Failed to create App Store version"));
|
|
164
174
|
}
|
|
165
175
|
}
|
|
166
|
-
async pushAsoData({ config, bundleId, localAsoData, appStoreDataPath, uploadImages = false, slug, }) {
|
|
176
|
+
async pushAsoData({ config, bundleId, localAsoData, appStoreDataPath, uploadImages = false, locales, imageUploadTimeoutMs, slug, }) {
|
|
167
177
|
const skip = checkPushPrerequisites({
|
|
168
178
|
storeLabel: "App Store",
|
|
169
179
|
configured: Boolean(config.appStore),
|
|
@@ -181,9 +191,20 @@ export class AppStoreService {
|
|
|
181
191
|
console.error(`[MCP] Bundle ID: ${bundleId}`);
|
|
182
192
|
try {
|
|
183
193
|
// Push locale data (supportUrl/marketingUrl already set by prepareAsoDataForPush)
|
|
184
|
-
const
|
|
194
|
+
const allLocales = Object.keys(appStoreData.locales);
|
|
195
|
+
const { localesToPush, missingLocales } = resolveAppStoreLocales(allLocales, locales);
|
|
196
|
+
if (missingLocales.length) {
|
|
197
|
+
console.error(`[AppStore] ⚠️ Requested locale(s) not found in local ASO data: ${missingLocales.join(", ")}`);
|
|
198
|
+
}
|
|
199
|
+
if (localesToPush.length === 0) {
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
error: AppError.validation(ERROR_CODES.APP_STORE_ASO_DATA_EMPTY, "No matching App Store locales found to push"),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
185
205
|
const failedFieldsList = [];
|
|
186
|
-
for (const
|
|
206
|
+
for (const locale of localesToPush) {
|
|
207
|
+
const localeData = appStoreData.locales[locale];
|
|
187
208
|
console.error(`[AppStore] 📤 Pushing ${locale}...`);
|
|
188
209
|
const localeResult = await client.pushAsoData(localeData);
|
|
189
210
|
if (localeResult.failedFields && localeResult.failedFields.length > 0) {
|
|
@@ -279,6 +300,7 @@ export class AppStoreService {
|
|
|
279
300
|
const uploadResult = await client.uploadScreenshotsForLocale({
|
|
280
301
|
locale,
|
|
281
302
|
screenshots: screenshotsToUpload,
|
|
303
|
+
imageUploadTimeoutMs,
|
|
282
304
|
});
|
|
283
305
|
if (uploadResult.failed > 0) {
|
|
284
306
|
throw new Error(`Screenshot upload reported ${uploadResult.failed} failed files`);
|
|
@@ -335,7 +357,6 @@ export class AppStoreService {
|
|
|
335
357
|
const version = await client.createNewVersionWithAutoIncrement();
|
|
336
358
|
const versionId = version.id;
|
|
337
359
|
const versionString = version.attributes?.versionString ?? "";
|
|
338
|
-
const locales = Object.keys(appStoreData.locales);
|
|
339
360
|
console.error(`[AppStore] ✅ New version ${versionString} created.`);
|
|
340
361
|
return {
|
|
341
362
|
success: false,
|
|
@@ -344,7 +365,7 @@ export class AppStoreService {
|
|
|
344
365
|
versionInfo: {
|
|
345
366
|
versionId,
|
|
346
367
|
versionString,
|
|
347
|
-
locales,
|
|
368
|
+
locales: Object.keys(appStoreData.locales),
|
|
348
369
|
},
|
|
349
370
|
};
|
|
350
371
|
}
|
|
@@ -6,6 +6,10 @@ interface GooglePlayAppInfo {
|
|
|
6
6
|
name?: string;
|
|
7
7
|
supportedLocales?: string[];
|
|
8
8
|
}
|
|
9
|
+
export declare function resolveGooglePlayLocales(allLocales: string[], requestedLocales?: string[]): {
|
|
10
|
+
localesToPush: string[];
|
|
11
|
+
missingLocales: string[];
|
|
12
|
+
};
|
|
9
13
|
/**
|
|
10
14
|
* Google Play-facing service layer that wraps client creation and common operations.
|
|
11
15
|
* Keeps MCP tools independent from client factories and SDK details.
|
|
@@ -21,12 +25,14 @@ export declare class GooglePlayService {
|
|
|
21
25
|
updateReleaseNotes(packageName: string, releaseNotes: Record<string, string>, track?: string, supportedLocales?: string[]): Promise<ServiceResult<UpdatedReleaseNotesResult>>;
|
|
22
26
|
pullReleaseNotes(packageName: string): Promise<ServiceResult<GooglePlayReleaseNote[]>>;
|
|
23
27
|
createVersion(packageName: string, versionString: string, versionCodes: number[]): Promise<ServiceResult<CreatedGooglePlayVersion>>;
|
|
24
|
-
pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages, slug, }: {
|
|
28
|
+
pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages, locales, imageUploadTimeoutMs, slug, }: {
|
|
25
29
|
config: EnvConfig;
|
|
26
30
|
packageName?: string;
|
|
27
31
|
localAsoData: AsoData;
|
|
28
32
|
googlePlayDataPath: string;
|
|
29
33
|
uploadImages?: boolean;
|
|
34
|
+
locales?: string[];
|
|
35
|
+
imageUploadTimeoutMs?: number;
|
|
30
36
|
slug?: string;
|
|
31
37
|
}): Promise<PushAsoResult>;
|
|
32
38
|
verifyAuth(): Promise<VerifyAuthResult<{
|
|
@@ -6,6 +6,16 @@ import { verifyPlayStoreAuth } from "../../packages/stores/play-store/verify-aut
|
|
|
6
6
|
import { createGooglePlayClient } from "../../core/clients/google-play-factory.js";
|
|
7
7
|
import { parseGooglePlayScreenshots, hasScreenshots, } from "../../core/helpers/screenshot-helpers.js";
|
|
8
8
|
import { checkPushPrerequisites, serviceFailure, toServiceResult, updateRegisteredLocales, } from "./service-helpers.js";
|
|
9
|
+
export function resolveGooglePlayLocales(allLocales, requestedLocales) {
|
|
10
|
+
if (!requestedLocales?.length) {
|
|
11
|
+
return { localesToPush: allLocales, missingLocales: [] };
|
|
12
|
+
}
|
|
13
|
+
const requested = new Set(requestedLocales);
|
|
14
|
+
return {
|
|
15
|
+
localesToPush: allLocales.filter((locale) => requested.has(locale)),
|
|
16
|
+
missingLocales: requestedLocales.filter((locale) => !allLocales.includes(locale)),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
9
19
|
/**
|
|
10
20
|
* Google Play-facing service layer that wraps client creation and common operations.
|
|
11
21
|
* Keeps MCP tools independent from client factories and SDK details.
|
|
@@ -148,7 +158,7 @@ export class GooglePlayService {
|
|
|
148
158
|
return serviceFailure(AppError.wrap(error, HTTP_STATUS.INTERNAL_SERVER_ERROR, ERROR_CODES.GOOGLE_PLAY_CREATE_VERSION_FAILED, "Failed to create Google Play version"));
|
|
149
159
|
}
|
|
150
160
|
}
|
|
151
|
-
async pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages = false, slug, }) {
|
|
161
|
+
async pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages = false, locales, imageUploadTimeoutMs, slug, }) {
|
|
152
162
|
const skip = checkPushPrerequisites({
|
|
153
163
|
storeLabel: "Google Play",
|
|
154
164
|
configured: Boolean(config.playStore),
|
|
@@ -165,12 +175,28 @@ export class GooglePlayService {
|
|
|
165
175
|
console.error(`[MCP] 📤 Pushing to Google Play...`);
|
|
166
176
|
console.error(`[MCP] Package: ${packageName}`);
|
|
167
177
|
try {
|
|
168
|
-
const
|
|
178
|
+
const allLocales = Object.keys(googlePlayData.locales);
|
|
179
|
+
const { localesToPush, missingLocales } = resolveGooglePlayLocales(allLocales, locales);
|
|
180
|
+
if (missingLocales.length) {
|
|
181
|
+
console.error(`[GooglePlay] ⚠️ Requested locale(s) not found in local ASO data: ${missingLocales.join(", ")}`);
|
|
182
|
+
}
|
|
183
|
+
if (localesToPush.length === 0) {
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
error: AppError.validation(ERROR_CODES.GOOGLE_PLAY_ASO_DATA_EMPTY, "No matching Google Play locales found to push"),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
169
189
|
for (const locale of localesToPush) {
|
|
170
190
|
console.error(`[GooglePlay] 📤 Preparing locale: ${locale}`);
|
|
171
191
|
}
|
|
172
192
|
// Push locale data as-is from aso-data.json
|
|
173
|
-
await client.pushMultilingualAsoData(
|
|
193
|
+
await client.pushMultilingualAsoData({
|
|
194
|
+
...googlePlayData,
|
|
195
|
+
locales: Object.fromEntries(localesToPush.map((locale) => [
|
|
196
|
+
locale,
|
|
197
|
+
googlePlayData.locales[locale],
|
|
198
|
+
])),
|
|
199
|
+
});
|
|
174
200
|
// Push app-level contact information
|
|
175
201
|
if (googlePlayData.contactEmail || googlePlayData.contactWebsite) {
|
|
176
202
|
console.error(`[GooglePlay] 📤 Pushing app details...`);
|
|
@@ -191,14 +217,15 @@ export class GooglePlayService {
|
|
|
191
217
|
for (const locale of localesToPush) {
|
|
192
218
|
try {
|
|
193
219
|
const localeData = googlePlayData.locales[locale];
|
|
194
|
-
// Check if
|
|
195
|
-
const
|
|
196
|
-
(
|
|
197
|
-
localeData.screenshots.phone
|
|
198
|
-
|
|
199
|
-
localeData.screenshots.tablet
|
|
220
|
+
// Check if images are defined in aso-data.json
|
|
221
|
+
const hasImagesInJson = Boolean(localeData?.featureGraphic) ||
|
|
222
|
+
Boolean(localeData?.screenshots &&
|
|
223
|
+
((localeData.screenshots.phone &&
|
|
224
|
+
localeData.screenshots.phone.length > 0) ||
|
|
225
|
+
(localeData.screenshots.tablet &&
|
|
226
|
+
localeData.screenshots.tablet.length > 0)));
|
|
200
227
|
let screenshots;
|
|
201
|
-
if (
|
|
228
|
+
if (hasImagesInJson) {
|
|
202
229
|
// Use screenshots from aso-data.json (relative paths)
|
|
203
230
|
console.error(`[GooglePlay] 📋 Using screenshots from aso-data.json for ${locale}`);
|
|
204
231
|
const relativePaths = localeData.screenshots;
|
|
@@ -230,10 +257,17 @@ export class GooglePlayService {
|
|
|
230
257
|
featureGraphic: fsScreenshots.featureGraphic,
|
|
231
258
|
};
|
|
232
259
|
}
|
|
233
|
-
// Google Play requires minimum 2 phone screenshots
|
|
260
|
+
// Google Play requires minimum 2 phone screenshots for that image type.
|
|
234
261
|
const phoneCount = screenshots.phone.length;
|
|
235
|
-
if (phoneCount < 2) {
|
|
236
|
-
console.error(`[GooglePlay] ⚠️ Skipping ${locale} - needs at least 2
|
|
262
|
+
if (phoneCount > 0 && phoneCount < 2) {
|
|
263
|
+
console.error(`[GooglePlay] ⚠️ Skipping phone screenshots for ${locale} - needs at least 2 (found ${phoneCount})`);
|
|
264
|
+
screenshots.phone = [];
|
|
265
|
+
}
|
|
266
|
+
const hasImagesToUpload = screenshots.phone.length > 0 ||
|
|
267
|
+
screenshots.tablet.length > 0 ||
|
|
268
|
+
Boolean(screenshots.featureGraphic);
|
|
269
|
+
if (!hasImagesToUpload) {
|
|
270
|
+
console.error(`[GooglePlay] ⏭️ Skipping ${locale} - no uploadable images found`);
|
|
237
271
|
skippedLocales.push(locale);
|
|
238
272
|
continue;
|
|
239
273
|
}
|
|
@@ -247,8 +281,9 @@ export class GooglePlayService {
|
|
|
247
281
|
sevenInchScreenshots: screenshots.phone,
|
|
248
282
|
tenInchScreenshots: screenshots.tablet,
|
|
249
283
|
featureGraphic: screenshots.featureGraphic || undefined,
|
|
284
|
+
imageUploadTimeoutMs,
|
|
250
285
|
});
|
|
251
|
-
console.error(`[GooglePlay] ✅
|
|
286
|
+
console.error(`[GooglePlay] ✅ Images uploaded for ${locale}: ${uploadResult.uploaded.phoneScreenshots} phone, ${uploadResult.uploaded.sevenInchScreenshots} 7-inch, ${uploadResult.uploaded.tenInchScreenshots} 10-inch, feature graphic ${uploadResult.uploaded.featureGraphic ? "yes" : "no"}`);
|
|
252
287
|
uploadedLocales.push(locale);
|
|
253
288
|
}
|
|
254
289
|
catch (error) {
|
package/dist/src/index.js
CHANGED
|
@@ -195,6 +195,16 @@ registerToolWithInfo("aso-push", {
|
|
|
195
195
|
.boolean()
|
|
196
196
|
.optional()
|
|
197
197
|
.describe("Whether to upload images as well"),
|
|
198
|
+
locales: z
|
|
199
|
+
.array(z.string())
|
|
200
|
+
.optional()
|
|
201
|
+
.describe("Optional locale allowlist to push (e.g. ['en-US', 'ko-KR'])"),
|
|
202
|
+
imageUploadTimeoutMs: z
|
|
203
|
+
.number()
|
|
204
|
+
.int()
|
|
205
|
+
.positive()
|
|
206
|
+
.optional()
|
|
207
|
+
.describe("Per-image upload timeout in milliseconds"),
|
|
198
208
|
dryRun: z
|
|
199
209
|
.boolean()
|
|
200
210
|
.optional()
|
|
@@ -42,6 +42,7 @@ export declare const ERROR_CODES: {
|
|
|
42
42
|
readonly APP_STORE_PULL_RELEASE_NOTES_FAILED: "APP_STORE_PULL_RELEASE_NOTES_FAILED";
|
|
43
43
|
readonly APP_STORE_CREATE_VERSION_FAILED: "APP_STORE_CREATE_VERSION_FAILED";
|
|
44
44
|
readonly APP_STORE_PUSH_FAILED: "APP_STORE_PUSH_FAILED";
|
|
45
|
+
readonly APP_STORE_ASO_DATA_EMPTY: "APP_STORE_ASO_DATA_EMPTY";
|
|
45
46
|
readonly APP_STORE_STATE_ERROR: "APP_STORE_STATE_ERROR";
|
|
46
47
|
readonly APP_STORE_CREATE_VERSION_FOR_STATE_ERROR_FAILED: "APP_STORE_CREATE_VERSION_FOR_STATE_ERROR_FAILED";
|
|
47
48
|
readonly APP_STORE_VERIFY_AUTH_FAILED: "APP_STORE_VERIFY_AUTH_FAILED";
|
|
@@ -53,6 +54,7 @@ export declare const ERROR_CODES: {
|
|
|
53
54
|
readonly GOOGLE_PLAY_PULL_RELEASE_NOTES_FAILED: "GOOGLE_PLAY_PULL_RELEASE_NOTES_FAILED";
|
|
54
55
|
readonly GOOGLE_PLAY_CREATE_VERSION_FAILED: "GOOGLE_PLAY_CREATE_VERSION_FAILED";
|
|
55
56
|
readonly GOOGLE_PLAY_PUSH_FAILED: "GOOGLE_PLAY_PUSH_FAILED";
|
|
57
|
+
readonly GOOGLE_PLAY_ASO_DATA_EMPTY: "GOOGLE_PLAY_ASO_DATA_EMPTY";
|
|
56
58
|
readonly GOOGLE_PLAY_VERIFY_AUTH_FAILED: "GOOGLE_PLAY_VERIFY_AUTH_FAILED";
|
|
57
59
|
readonly ASO_GOOGLE_PLAY_DATA_PARSE_FAILED: "ASO_GOOGLE_PLAY_DATA_PARSE_FAILED";
|
|
58
60
|
readonly ASO_APP_STORE_DATA_PARSE_FAILED: "ASO_APP_STORE_DATA_PARSE_FAILED";
|
|
@@ -49,6 +49,7 @@ export const ERROR_CODES = {
|
|
|
49
49
|
APP_STORE_PULL_RELEASE_NOTES_FAILED: "APP_STORE_PULL_RELEASE_NOTES_FAILED",
|
|
50
50
|
APP_STORE_CREATE_VERSION_FAILED: "APP_STORE_CREATE_VERSION_FAILED",
|
|
51
51
|
APP_STORE_PUSH_FAILED: "APP_STORE_PUSH_FAILED",
|
|
52
|
+
APP_STORE_ASO_DATA_EMPTY: "APP_STORE_ASO_DATA_EMPTY",
|
|
52
53
|
APP_STORE_STATE_ERROR: "APP_STORE_STATE_ERROR",
|
|
53
54
|
APP_STORE_CREATE_VERSION_FOR_STATE_ERROR_FAILED: "APP_STORE_CREATE_VERSION_FOR_STATE_ERROR_FAILED",
|
|
54
55
|
APP_STORE_VERIFY_AUTH_FAILED: "APP_STORE_VERIFY_AUTH_FAILED",
|
|
@@ -61,6 +62,7 @@ export const ERROR_CODES = {
|
|
|
61
62
|
GOOGLE_PLAY_PULL_RELEASE_NOTES_FAILED: "GOOGLE_PLAY_PULL_RELEASE_NOTES_FAILED",
|
|
62
63
|
GOOGLE_PLAY_CREATE_VERSION_FAILED: "GOOGLE_PLAY_CREATE_VERSION_FAILED",
|
|
63
64
|
GOOGLE_PLAY_PUSH_FAILED: "GOOGLE_PLAY_PUSH_FAILED",
|
|
65
|
+
GOOGLE_PLAY_ASO_DATA_EMPTY: "GOOGLE_PLAY_ASO_DATA_EMPTY",
|
|
64
66
|
GOOGLE_PLAY_VERIFY_AUTH_FAILED: "GOOGLE_PLAY_VERIFY_AUTH_FAILED",
|
|
65
67
|
// ASO data/files
|
|
66
68
|
ASO_GOOGLE_PLAY_DATA_PARSE_FAILED: "ASO_GOOGLE_PLAY_DATA_PARSE_FAILED",
|
|
@@ -82,6 +82,7 @@ export declare class AppStoreClient {
|
|
|
82
82
|
imagePath: string;
|
|
83
83
|
screenshotDisplayType: string;
|
|
84
84
|
locale: string;
|
|
85
|
+
imageUploadTimeoutMs?: number;
|
|
85
86
|
}): Promise<void>;
|
|
86
87
|
/**
|
|
87
88
|
* Find or create Screenshot Set for a specific display type
|
|
@@ -124,6 +125,7 @@ export declare class AppStoreClient {
|
|
|
124
125
|
displayType: string;
|
|
125
126
|
filename: string;
|
|
126
127
|
}>;
|
|
128
|
+
imageUploadTimeoutMs?: number;
|
|
127
129
|
}): Promise<{
|
|
128
130
|
uploaded: number;
|
|
129
131
|
deleted: number;
|
|
@@ -577,7 +577,7 @@ export class AppStoreClient {
|
|
|
577
577
|
* 4. Commit upload operation
|
|
578
578
|
*/
|
|
579
579
|
async uploadScreenshot(options) {
|
|
580
|
-
const { imagePath, screenshotDisplayType, locale } = options;
|
|
580
|
+
const { imagePath, screenshotDisplayType, locale, imageUploadTimeoutMs } = options;
|
|
581
581
|
try {
|
|
582
582
|
// Get app and version info
|
|
583
583
|
const appId = await this.findAppId();
|
|
@@ -611,7 +611,7 @@ export class AppStoreClient {
|
|
|
611
611
|
if (screenshot.uploadOperations &&
|
|
612
612
|
screenshot.uploadOperations.length > 0) {
|
|
613
613
|
const uploadOp = screenshot.uploadOperations[0];
|
|
614
|
-
await this.uploadFileToUrl(uploadOp.url, fileBuffer, uploadOp.method);
|
|
614
|
+
await this.uploadFileToUrl(uploadOp.url, fileBuffer, uploadOp.method, imageUploadTimeoutMs);
|
|
615
615
|
}
|
|
616
616
|
// Step 4: Commit screenshot
|
|
617
617
|
await this.commitAppScreenshot(screenshot.id);
|
|
@@ -703,7 +703,7 @@ export class AppStoreClient {
|
|
|
703
703
|
/**
|
|
704
704
|
* Upload file to reserved URL
|
|
705
705
|
*/
|
|
706
|
-
async uploadFileToUrl(url, fileBuffer, method = "PUT") {
|
|
706
|
+
async uploadFileToUrl(url, fileBuffer, method = "PUT", timeoutMs) {
|
|
707
707
|
const https = await import("node:https");
|
|
708
708
|
const { URL } = await import("node:url");
|
|
709
709
|
return new Promise((resolve, reject) => {
|
|
@@ -727,6 +727,11 @@ export class AppStoreClient {
|
|
|
727
727
|
}
|
|
728
728
|
});
|
|
729
729
|
req.on("error", reject);
|
|
730
|
+
if (timeoutMs) {
|
|
731
|
+
req.setTimeout(timeoutMs, () => {
|
|
732
|
+
req.destroy(new Error(`Upload timed out after ${timeoutMs}ms`));
|
|
733
|
+
});
|
|
734
|
+
}
|
|
730
735
|
req.write(fileBuffer);
|
|
731
736
|
req.end();
|
|
732
737
|
});
|
|
@@ -853,7 +858,7 @@ export class AppStoreClient {
|
|
|
853
858
|
* 3. Upload new screenshots in order
|
|
854
859
|
*/
|
|
855
860
|
async uploadScreenshotsForLocale(options) {
|
|
856
|
-
const { locale, screenshots } = options;
|
|
861
|
+
const { locale, screenshots, imageUploadTimeoutMs } = options;
|
|
857
862
|
const result = { uploaded: 0, deleted: 0, failed: 0 };
|
|
858
863
|
if (screenshots.length === 0) {
|
|
859
864
|
return result;
|
|
@@ -914,7 +919,7 @@ export class AppStoreClient {
|
|
|
914
919
|
if (screenshotData.uploadOperations &&
|
|
915
920
|
screenshotData.uploadOperations.length > 0) {
|
|
916
921
|
const uploadOp = screenshotData.uploadOperations[0];
|
|
917
|
-
await this.uploadFileToUrl(uploadOp.url, fileBuffer, uploadOp.method);
|
|
922
|
+
await this.uploadFileToUrl(uploadOp.url, fileBuffer, uploadOp.method, imageUploadTimeoutMs);
|
|
918
923
|
}
|
|
919
924
|
// Commit screenshot
|
|
920
925
|
await this.commitAppScreenshot(screenshotData.id);
|
|
@@ -55,6 +55,7 @@ export declare class GooglePlayClient {
|
|
|
55
55
|
* Deletes existing screenshots before uploading new ones
|
|
56
56
|
*/
|
|
57
57
|
uploadScreenshotsForLocale(options: BatchUploadScreenshotsOptions): Promise<BatchUploadScreenshotsResult>;
|
|
58
|
+
private uploadImageWithOptionalTimeout;
|
|
58
59
|
private getTrack;
|
|
59
60
|
private updateTrack;
|
|
60
61
|
private listTracks;
|
|
@@ -620,7 +620,7 @@ export class GooglePlayClient {
|
|
|
620
620
|
* Deletes existing screenshots before uploading new ones
|
|
621
621
|
*/
|
|
622
622
|
async uploadScreenshotsForLocale(options) {
|
|
623
|
-
const { language, phoneScreenshots = [], sevenInchScreenshots = [], tenInchScreenshots = [], featureGraphic, } = options;
|
|
623
|
+
const { language, phoneScreenshots = [], sevenInchScreenshots = [], tenInchScreenshots = [], featureGraphic, imageUploadTimeoutMs, } = options;
|
|
624
624
|
const authClient = await this.auth.getClient();
|
|
625
625
|
const editResponse = await this.createEdit(authClient, this.packageName);
|
|
626
626
|
const editId = editResponse.data.id;
|
|
@@ -694,17 +694,7 @@ export class GooglePlayClient {
|
|
|
694
694
|
}
|
|
695
695
|
const imageBuffer = readFileSync(imagePath);
|
|
696
696
|
const fileName = imagePath.split("/").pop() || `phone-${i + 1}.png`;
|
|
697
|
-
await this.
|
|
698
|
-
auth: session.auth,
|
|
699
|
-
packageName: session.packageName,
|
|
700
|
-
editId: session.editId,
|
|
701
|
-
language,
|
|
702
|
-
imageType: "phoneScreenshots",
|
|
703
|
-
media: {
|
|
704
|
-
mimeType: "image/png",
|
|
705
|
-
body: imageBuffer,
|
|
706
|
-
},
|
|
707
|
-
});
|
|
697
|
+
await this.uploadImageWithOptionalTimeout(session, language, "phoneScreenshots", imageBuffer, imageUploadTimeoutMs);
|
|
708
698
|
console.error(`[GooglePlayClient] ✅ Uploaded ${fileName}`);
|
|
709
699
|
result.uploaded.phoneScreenshots++;
|
|
710
700
|
}
|
|
@@ -717,17 +707,7 @@ export class GooglePlayClient {
|
|
|
717
707
|
}
|
|
718
708
|
const imageBuffer = readFileSync(imagePath);
|
|
719
709
|
const fileName = imagePath.split("/").pop() || `tablet7-${i + 1}.png`;
|
|
720
|
-
await this.
|
|
721
|
-
auth: session.auth,
|
|
722
|
-
packageName: session.packageName,
|
|
723
|
-
editId: session.editId,
|
|
724
|
-
language,
|
|
725
|
-
imageType: "sevenInchScreenshots",
|
|
726
|
-
media: {
|
|
727
|
-
mimeType: "image/png",
|
|
728
|
-
body: imageBuffer,
|
|
729
|
-
},
|
|
730
|
-
});
|
|
710
|
+
await this.uploadImageWithOptionalTimeout(session, language, "sevenInchScreenshots", imageBuffer, imageUploadTimeoutMs);
|
|
731
711
|
console.error(`[GooglePlayClient] ✅ Uploaded ${fileName}`);
|
|
732
712
|
result.uploaded.sevenInchScreenshots++;
|
|
733
713
|
}
|
|
@@ -740,34 +720,14 @@ export class GooglePlayClient {
|
|
|
740
720
|
}
|
|
741
721
|
const imageBuffer = readFileSync(imagePath);
|
|
742
722
|
const fileName = imagePath.split("/").pop() || `tablet10-${i + 1}.png`;
|
|
743
|
-
await this.
|
|
744
|
-
auth: session.auth,
|
|
745
|
-
packageName: session.packageName,
|
|
746
|
-
editId: session.editId,
|
|
747
|
-
language,
|
|
748
|
-
imageType: "tenInchScreenshots",
|
|
749
|
-
media: {
|
|
750
|
-
mimeType: "image/png",
|
|
751
|
-
body: imageBuffer,
|
|
752
|
-
},
|
|
753
|
-
});
|
|
723
|
+
await this.uploadImageWithOptionalTimeout(session, language, "tenInchScreenshots", imageBuffer, imageUploadTimeoutMs);
|
|
754
724
|
console.error(`[GooglePlayClient] ✅ Uploaded ${fileName}`);
|
|
755
725
|
result.uploaded.tenInchScreenshots++;
|
|
756
726
|
}
|
|
757
727
|
// Upload feature graphic
|
|
758
728
|
if (featureGraphic && existsSync(featureGraphic)) {
|
|
759
729
|
const imageBuffer = readFileSync(featureGraphic);
|
|
760
|
-
await this.
|
|
761
|
-
auth: session.auth,
|
|
762
|
-
packageName: session.packageName,
|
|
763
|
-
editId: session.editId,
|
|
764
|
-
language,
|
|
765
|
-
imageType: "featureGraphic",
|
|
766
|
-
media: {
|
|
767
|
-
mimeType: "image/png",
|
|
768
|
-
body: imageBuffer,
|
|
769
|
-
},
|
|
770
|
-
});
|
|
730
|
+
await this.uploadImageWithOptionalTimeout(session, language, "featureGraphic", imageBuffer, imageUploadTimeoutMs);
|
|
771
731
|
console.error(`[GooglePlayClient] ✅ Uploaded feature-graphic.png`);
|
|
772
732
|
result.uploaded.featureGraphic = true;
|
|
773
733
|
}
|
|
@@ -788,6 +748,19 @@ export class GooglePlayClient {
|
|
|
788
748
|
throw error;
|
|
789
749
|
}
|
|
790
750
|
}
|
|
751
|
+
async uploadImageWithOptionalTimeout(session, language, imageType, imageBuffer, timeoutMs) {
|
|
752
|
+
await this.androidPublisher.edits.images.upload({
|
|
753
|
+
auth: session.auth,
|
|
754
|
+
packageName: session.packageName,
|
|
755
|
+
editId: session.editId,
|
|
756
|
+
language,
|
|
757
|
+
imageType,
|
|
758
|
+
media: {
|
|
759
|
+
mimeType: "image/png",
|
|
760
|
+
body: imageBuffer,
|
|
761
|
+
},
|
|
762
|
+
}, timeoutMs ? { timeout: timeoutMs } : undefined);
|
|
763
|
+
}
|
|
791
764
|
async getTrack(session, track) {
|
|
792
765
|
const response = await this.androidPublisher.edits.tracks.get({
|
|
793
766
|
auth: session.auth,
|
|
@@ -9,7 +9,7 @@ const appResolutionService = new AppResolutionService();
|
|
|
9
9
|
const appStoreService = new AppStoreService();
|
|
10
10
|
const googlePlayService = new GooglePlayService();
|
|
11
11
|
export async function handleAsoPush(options) {
|
|
12
|
-
const { store = "both", uploadImages = false, dryRun = false } = options;
|
|
12
|
+
const { store = "both", uploadImages = false, locales, imageUploadTimeoutMs, dryRun = false, } = options;
|
|
13
13
|
const resolved = appResolutionService.resolve({
|
|
14
14
|
slug: options.app,
|
|
15
15
|
packageName: options.packageName,
|
|
@@ -34,6 +34,11 @@ export async function handleAsoPush(options) {
|
|
|
34
34
|
if (bundleId)
|
|
35
35
|
console.error(`[MCP] Bundle ID: ${bundleId}`);
|
|
36
36
|
console.error(`[MCP] Upload Images: ${uploadImages ? "Yes" : "No"}`);
|
|
37
|
+
if (locales?.length)
|
|
38
|
+
console.error(`[MCP] Locales: ${locales.join(", ")}`);
|
|
39
|
+
if (imageUploadTimeoutMs) {
|
|
40
|
+
console.error(`[MCP] Image Upload Timeout: ${imageUploadTimeoutMs}ms`);
|
|
41
|
+
}
|
|
37
42
|
console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual push"}`);
|
|
38
43
|
let config;
|
|
39
44
|
try {
|
|
@@ -136,6 +141,8 @@ export async function handleAsoPush(options) {
|
|
|
136
141
|
localAsoData: configData,
|
|
137
142
|
googlePlayDataPath,
|
|
138
143
|
uploadImages,
|
|
144
|
+
locales,
|
|
145
|
+
imageUploadTimeoutMs,
|
|
139
146
|
slug,
|
|
140
147
|
});
|
|
141
148
|
results.push(formatPushResult("Google Play", result));
|
|
@@ -153,6 +160,8 @@ export async function handleAsoPush(options) {
|
|
|
153
160
|
localAsoData: configData,
|
|
154
161
|
appStoreDataPath,
|
|
155
162
|
uploadImages,
|
|
163
|
+
locales,
|
|
164
|
+
imageUploadTimeoutMs,
|
|
156
165
|
slug,
|
|
157
166
|
});
|
|
158
167
|
results.push(formatPushResult("App Store", appStoreResult));
|