pabal-store-api-mcp 1.3.14 → 1.3.16

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.
@@ -6,6 +6,29 @@ 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
+ const APP_STORE_RELEASE_NOTES_UPDATE_CONCURRENCY = 5;
10
+ const updateReleaseNotesWithConcurrency = async (options) => {
11
+ const { locales, concurrency, update } = options;
12
+ const results = new Array(locales.length);
13
+ let nextIndex = 0;
14
+ const workerCount = Math.min(concurrency, locales.length);
15
+ await Promise.all(Array.from({ length: workerCount }, async () => {
16
+ while (nextIndex < locales.length) {
17
+ const currentIndex = nextIndex;
18
+ nextIndex += 1;
19
+ const locale = locales[currentIndex];
20
+ try {
21
+ await update(locale);
22
+ results[currentIndex] = { locale };
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ results[currentIndex] = { locale, error: message };
27
+ }
28
+ }
29
+ }));
30
+ return results;
31
+ };
9
32
  export function resolveAppStoreLocales(allLocales, requestedLocales) {
10
33
  if (!requestedLocales?.length) {
11
34
  return { localesToPush: allLocales, missingLocales: [] };
@@ -111,22 +134,19 @@ export class AppStoreService {
111
134
  const localesToUpdate = supportedLocales
112
135
  ? Object.keys(releaseNotes).filter((locale) => supportedLocales.includes(locale))
113
136
  : Object.keys(releaseNotes);
114
- const updated = [];
115
- const failed = [];
116
- for (const locale of localesToUpdate) {
117
- try {
118
- await client.updateWhatsNew({
119
- versionId: targetVersionId,
120
- locale,
121
- whatsNew: releaseNotes[locale],
122
- });
123
- updated.push(locale);
124
- }
125
- catch (error) {
126
- const msg = error instanceof Error ? error.message : String(error);
127
- failed.push({ locale, error: msg });
128
- }
129
- }
137
+ const updateResults = await updateReleaseNotesWithConcurrency({
138
+ locales: localesToUpdate,
139
+ concurrency: APP_STORE_RELEASE_NOTES_UPDATE_CONCURRENCY,
140
+ update: (locale) => client.updateWhatsNew({
141
+ versionId: targetVersionId,
142
+ locale,
143
+ whatsNew: releaseNotes[locale],
144
+ }),
145
+ });
146
+ const updated = updateResults
147
+ .filter((result) => !result.error)
148
+ .map((result) => result.locale);
149
+ const failed = updateResults.flatMap((result) => result.error ? [{ locale: result.locale, error: result.error }] : []);
130
150
  const success = failed.length === 0;
131
151
  const partialError = !success
132
152
  ? AppError.wrap(failed[0]?.error ?? "Failed to update some release notes", HTTP_STATUS.INTERNAL_SERVER_ERROR, ERROR_CODES.APP_STORE_UPDATE_RELEASE_NOTES_PARTIAL)
@@ -6,6 +6,7 @@ interface GooglePlayAppInfo {
6
6
  name?: string;
7
7
  supportedLocales?: string[];
8
8
  }
9
+ type GooglePlayScreenshotUploadOption = Parameters<GooglePlayClient["uploadScreenshotsForLocales"]>[0][number];
9
10
  export declare function resolveGooglePlayLocales(allLocales: string[], requestedLocales?: string[]): {
10
11
  localesToPush: string[];
11
12
  missingLocales: string[];
@@ -14,6 +15,7 @@ export declare function shouldPushGooglePlayAppDetails({ hasContactDetails, requ
14
15
  hasContactDetails: boolean;
15
16
  requestedLocales?: string[];
16
17
  }): boolean;
18
+ export declare function createGooglePlayScreenshotUploadBatches(options: GooglePlayScreenshotUploadOption[], batchSize?: number): GooglePlayScreenshotUploadOption[][];
17
19
  /**
18
20
  * Google Play-facing service layer that wraps client creation and common operations.
19
21
  * Keeps MCP tools independent from client factories and SDK details.
@@ -29,7 +31,7 @@ export declare class GooglePlayService {
29
31
  updateReleaseNotes(packageName: string, releaseNotes: Record<string, string>, track?: string, supportedLocales?: string[]): Promise<ServiceResult<UpdatedReleaseNotesResult>>;
30
32
  pullReleaseNotes(packageName: string): Promise<ServiceResult<GooglePlayReleaseNote[]>>;
31
33
  createVersion(packageName: string, versionString: string, versionCodes: number[]): Promise<ServiceResult<CreatedGooglePlayVersion>>;
32
- pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages, locales, imageUploadTimeoutMs, slug, }: {
34
+ pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages, locales, imageUploadTimeoutMs, imageLocaleBatchSize, slug, }: {
33
35
  config: EnvConfig;
34
36
  packageName?: string;
35
37
  localAsoData: AsoData;
@@ -37,6 +39,7 @@ export declare class GooglePlayService {
37
39
  uploadImages?: boolean;
38
40
  locales?: string[];
39
41
  imageUploadTimeoutMs?: number;
42
+ imageLocaleBatchSize?: number;
40
43
  slug?: string;
41
44
  }): Promise<PushAsoResult>;
42
45
  verifyAuth(): Promise<VerifyAuthResult<{
@@ -6,7 +6,6 @@ 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
- const GOOGLE_PLAY_SCREENSHOT_LOCALE_BATCH_SIZE = 5;
10
9
  export function resolveGooglePlayLocales(allLocales, requestedLocales) {
11
10
  if (!requestedLocales?.length) {
12
11
  return { localesToPush: allLocales, missingLocales: [] };
@@ -20,6 +19,15 @@ export function resolveGooglePlayLocales(allLocales, requestedLocales) {
20
19
  export function shouldPushGooglePlayAppDetails({ hasContactDetails, requestedLocales, }) {
21
20
  return hasContactDetails && !requestedLocales?.length;
22
21
  }
22
+ export function createGooglePlayScreenshotUploadBatches(options, batchSize) {
23
+ if (!batchSize)
24
+ return options.length > 0 ? [options] : [];
25
+ const batches = [];
26
+ for (let offset = 0; offset < options.length; offset += batchSize) {
27
+ batches.push(options.slice(offset, offset + batchSize));
28
+ }
29
+ return batches;
30
+ }
23
31
  /**
24
32
  * Google Play-facing service layer that wraps client creation and common operations.
25
33
  * Keeps MCP tools independent from client factories and SDK details.
@@ -162,7 +170,7 @@ export class GooglePlayService {
162
170
  return serviceFailure(AppError.wrap(error, HTTP_STATUS.INTERNAL_SERVER_ERROR, ERROR_CODES.GOOGLE_PLAY_CREATE_VERSION_FAILED, "Failed to create Google Play version"));
163
171
  }
164
172
  }
165
- async pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages = false, locales, imageUploadTimeoutMs, slug, }) {
173
+ async pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, uploadImages = false, locales, imageUploadTimeoutMs, imageLocaleBatchSize, slug, }) {
166
174
  const skip = checkPushPrerequisites({
167
175
  storeLabel: "Google Play",
168
176
  configured: Boolean(config.playStore),
@@ -302,8 +310,8 @@ export class GooglePlayService {
302
310
  failedLocales.push(locale);
303
311
  }
304
312
  }
305
- for (let offset = 0; offset < screenshotUploadOptions.length; offset += GOOGLE_PLAY_SCREENSHOT_LOCALE_BATCH_SIZE) {
306
- const batch = screenshotUploadOptions.slice(offset, offset + GOOGLE_PLAY_SCREENSHOT_LOCALE_BATCH_SIZE);
313
+ const screenshotBatches = createGooglePlayScreenshotUploadBatches(screenshotUploadOptions, imageLocaleBatchSize);
314
+ for (const batch of screenshotBatches) {
307
315
  try {
308
316
  console.error(`[GooglePlay] 📤 Uploading screenshots for ${batch.length} locale(s) in one edit...`);
309
317
  const uploadResults = await client.uploadScreenshotsForLocales(batch);
package/dist/src/index.js CHANGED
@@ -205,6 +205,12 @@ registerToolWithInfo("aso-push", {
205
205
  .positive()
206
206
  .optional()
207
207
  .describe("Per-image upload timeout in milliseconds (default: 600000 when uploadImages=true)"),
208
+ imageLocaleBatchSize: z
209
+ .number()
210
+ .int()
211
+ .positive()
212
+ .optional()
213
+ .describe("Google Play image locale batch size. Omit to upload all target locales in one edit commit"),
208
214
  dryRun: z
209
215
  .boolean()
210
216
  .optional()
@@ -7,6 +7,7 @@ interface AsoPushOptions {
7
7
  uploadImages?: boolean;
8
8
  locales?: string[];
9
9
  imageUploadTimeoutMs?: number;
10
+ imageLocaleBatchSize?: number;
10
11
  dryRun?: boolean;
11
12
  }
12
13
  export declare function handleAsoPush(options: AsoPushOptions): Promise<{
@@ -42,6 +42,9 @@ export async function handleAsoPush(options) {
42
42
  if (imageUploadTimeoutMs) {
43
43
  console.error(`[MCP] Image Upload Timeout: ${imageUploadTimeoutMs}ms`);
44
44
  }
45
+ if (options.imageLocaleBatchSize) {
46
+ console.error(`[MCP] Image Locale Batch Size: ${options.imageLocaleBatchSize}`);
47
+ }
45
48
  console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual push"}`);
46
49
  let config;
47
50
  try {
@@ -146,6 +149,7 @@ export async function handleAsoPush(options) {
146
149
  uploadImages,
147
150
  locales,
148
151
  imageUploadTimeoutMs,
152
+ imageLocaleBatchSize: options.imageLocaleBatchSize,
149
153
  slug,
150
154
  });
151
155
  results.push(formatPushResult("Google Play", result));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-store-api-mcp",
3
- "version": "1.3.14",
3
+ "version": "1.3.16",
4
4
  "description": "MCP server for App Store / Play Store ASO workflows",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",