pabal-store-api-mcp 1.3.18 → 1.3.19

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 CHANGED
@@ -38,6 +38,14 @@ chmod 700 ~/.config/pabal-mcp
38
38
 
39
39
  <br>
40
40
 
41
+ ### Registered Apps
42
+
43
+ Registered apps are stored locally in `~/.config/pabal-mcp/registered-apps.json`.
44
+ It is usually created and updated by `apps-init` or `apps-add`, then used by tools such as `apps-search`, `aso-pull`, and release-note workflows.
45
+ See the app management docs for the detailed format: [English](docs/en-US/apps.md) / [한국어](docs/ko-KR/apps.md).
46
+
47
+ <br>
48
+
41
49
  ## Features
42
50
 
43
51
  - ✅ **ASO Data Sync**: Pull/push metadata from App Store and Google Play
@@ -13,6 +13,7 @@ export declare const APP_STORE_DEVICE_TYPES: {
13
13
  readonly iphone55: "APP_IPHONE_55";
14
14
  readonly iphone47: "APP_IPHONE_47";
15
15
  readonly iphone40: "APP_IPHONE_40";
16
+ readonly ipad13: "APP_IPAD_PRO_3GEN_129";
16
17
  readonly ipadPro129: "APP_IPAD_PRO_3GEN_129";
17
18
  readonly ipadPro11: "APP_IPAD_PRO_11";
18
19
  readonly ipad105: "APP_IPAD_105";
@@ -14,6 +14,7 @@ export const APP_STORE_DEVICE_TYPES = {
14
14
  iphone55: "APP_IPHONE_55",
15
15
  iphone47: "APP_IPHONE_47",
16
16
  iphone40: "APP_IPHONE_40",
17
+ ipad13: "APP_IPAD_PRO_3GEN_129",
17
18
  ipadPro129: "APP_IPAD_PRO_3GEN_129",
18
19
  ipadPro11: "APP_IPAD_PRO_11",
19
20
  ipad105: "APP_IPAD_105",
@@ -253,6 +253,8 @@ export class AppStoreService {
253
253
  const hasScreenshotsInJson = localeData?.screenshots &&
254
254
  ((localeData.screenshots.iphone65 &&
255
255
  localeData.screenshots.iphone65.length > 0) ||
256
+ (localeData.screenshots.ipad13 &&
257
+ localeData.screenshots.ipad13.length > 0) ||
256
258
  (localeData.screenshots.ipadPro129 &&
257
259
  localeData.screenshots.ipadPro129.length > 0));
258
260
  let screenshotsToUpload = [];
@@ -270,13 +272,13 @@ export class AppStoreService {
270
272
  });
271
273
  }
272
274
  }
273
- // Map ipadPro129 screenshots
274
- if (relativePaths.ipadPro129 &&
275
- relativePaths.ipadPro129.length > 0) {
276
- for (const relPath of relativePaths.ipadPro129) {
275
+ // Map 13" iPad screenshots. ipadPro129 is kept as a legacy alias.
276
+ const ipad13Paths = relativePaths.ipad13 ?? relativePaths.ipadPro129 ?? [];
277
+ if (ipad13Paths.length > 0) {
278
+ for (const relPath of ipad13Paths) {
277
279
  screenshotsToUpload.push({
278
280
  path: `${screenshotsBaseDir}/${relPath}`,
279
- displayType: APP_STORE_DEVICE_TYPES.ipadPro129,
281
+ displayType: APP_STORE_DEVICE_TYPES.ipad13,
280
282
  filename: relPath.split("/").pop() || relPath,
281
283
  });
282
284
  }
@@ -49,6 +49,7 @@ export interface AppStoreScreenshots {
49
49
  iphone55?: string[];
50
50
  iphone47?: string[];
51
51
  iphone40?: string[];
52
+ ipad13?: string[];
52
53
  ipadPro129?: string[];
53
54
  ipadPro11?: string[];
54
55
  ipad105?: string[];
@@ -803,19 +803,29 @@ export class AppStoreClient {
803
803
  }
804
804
  const screenshotsResponse = await this.listScreenshots(screenshotSetId);
805
805
  const existingScreenshots = (screenshotsResponse.data || []).filter((screenshot) => screenshot.type === "appScreenshots");
806
+ const incompleteScreenshots = existingScreenshots.filter((screenshot) => {
807
+ const deliveryState = screenshot.attributes?.assetDeliveryState;
808
+ return deliveryState?.state && deliveryState.state !== "COMPLETE";
809
+ });
810
+ const completeScreenshots = existingScreenshots.filter((screenshot) => !incompleteScreenshots.includes(screenshot));
806
811
  const nonScreenshotCount = (screenshotsResponse.data || []).length - existingScreenshots.length;
807
812
  if (nonScreenshotCount > 0) {
808
813
  console.error(`[AppStore] Ignoring ${nonScreenshotCount} non-screenshot asset(s) in screenshot set`);
809
814
  }
810
- const slotsToFree = Math.max(0, existingScreenshots.length +
815
+ const deletedIncomplete = await this.deleteScreenshots(incompleteScreenshots);
816
+ if (deletedIncomplete > 0) {
817
+ console.error(`[AppStore] Deleted ${deletedIncomplete} incomplete screenshot upload(s)`);
818
+ }
819
+ const slotsToFree = Math.max(0, completeScreenshots.length +
811
820
  incomingCount -
812
821
  APP_STORE_SCREENSHOT_SET_MAX_COUNT);
813
822
  // Preserve the first screenshots as long as possible. If the upload fails
814
823
  // after freeing slots, users are more likely to still see the primary
815
824
  // screenshots rather than the tail of the old set.
816
- const screenshotsToDeleteBeforeUpload = slotsToFree > 0 ? existingScreenshots.slice(-slotsToFree) : [];
817
- const screenshotsToDeleteAfterUpload = existingScreenshots.slice(0, existingScreenshots.length - slotsToFree);
818
- const deletedBeforeUpload = await this.deleteScreenshots(screenshotsToDeleteBeforeUpload);
825
+ const screenshotsToDeleteBeforeUpload = slotsToFree > 0 ? completeScreenshots.slice(-slotsToFree) : [];
826
+ const screenshotsToDeleteAfterUpload = completeScreenshots.slice(0, completeScreenshots.length - slotsToFree);
827
+ const deletedBeforeUpload = deletedIncomplete +
828
+ (await this.deleteScreenshots(screenshotsToDeleteBeforeUpload));
819
829
  if (deletedBeforeUpload > 0) {
820
830
  console.error(`[AppStore] Deleted ${deletedBeforeUpload} existing screenshots to free upload slots`);
821
831
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-store-api-mcp",
3
- "version": "1.3.18",
3
+ "version": "1.3.19",
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",