pabal-store-api-mcp 1.3.17 → 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 +8 -0
- package/dist/src/core/helpers/screenshot-helpers.d.ts +1 -0
- package/dist/src/core/helpers/screenshot-helpers.js +1 -0
- package/dist/src/core/services/app-store-service.js +7 -5
- package/dist/src/index.js +1 -1
- package/dist/src/packages/configs/aso-config/types.d.ts +1 -0
- package/dist/src/packages/stores/app-store/client.js +14 -4
- package/dist/src/tools/aso/push.js +12 -4
- package/package.json +1 -1
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
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
for (const relPath of
|
|
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.
|
|
281
|
+
displayType: APP_STORE_DEVICE_TYPES.ipad13,
|
|
280
282
|
filename: relPath.split("/").pop() || relPath,
|
|
281
283
|
});
|
|
282
284
|
}
|
package/dist/src/index.js
CHANGED
|
@@ -210,7 +210,7 @@ registerToolWithInfo("aso-push", {
|
|
|
210
210
|
.int()
|
|
211
211
|
.positive()
|
|
212
212
|
.optional()
|
|
213
|
-
.describe("Google Play image locale batch size
|
|
213
|
+
.describe("Google Play image locale batch size (default: 1 when uploadImages=true, replacing screenshots per locale while preserving videos)"),
|
|
214
214
|
dryRun: z
|
|
215
215
|
.boolean()
|
|
216
216
|
.optional()
|
|
@@ -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
|
|
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 ?
|
|
817
|
-
const screenshotsToDeleteAfterUpload =
|
|
818
|
-
const deletedBeforeUpload =
|
|
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
|
}
|
|
@@ -6,6 +6,7 @@ import { AppStoreService } from "../../core/services/app-store-service.js";
|
|
|
6
6
|
import { GooglePlayService } from "../../core/services/google-play-service.js";
|
|
7
7
|
import { formatPushResult } from "../../core/helpers/formatters.js";
|
|
8
8
|
const DEFAULT_IMAGE_UPLOAD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
9
|
+
const DEFAULT_IMAGE_LOCALE_BATCH_SIZE = 1;
|
|
9
10
|
const appResolutionService = new AppResolutionService();
|
|
10
11
|
const appStoreService = new AppStoreService();
|
|
11
12
|
const googlePlayService = new GooglePlayService();
|
|
@@ -13,6 +14,8 @@ export async function handleAsoPush(options) {
|
|
|
13
14
|
const { store = "both", uploadImages = false, locales, dryRun = false, } = options;
|
|
14
15
|
const imageUploadTimeoutMs = options.imageUploadTimeoutMs ??
|
|
15
16
|
(uploadImages ? DEFAULT_IMAGE_UPLOAD_TIMEOUT_MS : undefined);
|
|
17
|
+
const imageLocaleBatchSize = options.imageLocaleBatchSize ??
|
|
18
|
+
(uploadImages ? DEFAULT_IMAGE_LOCALE_BATCH_SIZE : undefined);
|
|
16
19
|
const resolved = appResolutionService.resolve({
|
|
17
20
|
slug: options.app,
|
|
18
21
|
packageName: options.packageName,
|
|
@@ -37,13 +40,16 @@ export async function handleAsoPush(options) {
|
|
|
37
40
|
if (bundleId)
|
|
38
41
|
console.error(`[MCP] Bundle ID: ${bundleId}`);
|
|
39
42
|
console.error(`[MCP] Upload Images: ${uploadImages ? "Yes" : "No"}`);
|
|
43
|
+
if (uploadImages) {
|
|
44
|
+
console.error(`[MCP] Image Upload Mode: overwrite screenshots only (videos preserved)`);
|
|
45
|
+
}
|
|
40
46
|
if (locales?.length)
|
|
41
47
|
console.error(`[MCP] Locales: ${locales.join(", ")}`);
|
|
42
48
|
if (imageUploadTimeoutMs) {
|
|
43
49
|
console.error(`[MCP] Image Upload Timeout: ${imageUploadTimeoutMs}ms`);
|
|
44
50
|
}
|
|
45
|
-
if (
|
|
46
|
-
console.error(`[MCP] Image Locale Batch Size: ${
|
|
51
|
+
if (imageLocaleBatchSize) {
|
|
52
|
+
console.error(`[MCP] Image Locale Batch Size: ${imageLocaleBatchSize}`);
|
|
47
53
|
}
|
|
48
54
|
console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual push"}`);
|
|
49
55
|
let config;
|
|
@@ -129,7 +135,9 @@ export async function handleAsoPush(options) {
|
|
|
129
135
|
content: [
|
|
130
136
|
{
|
|
131
137
|
type: "text",
|
|
132
|
-
text: `📋 Dry run - Data that would be pushed:\n${JSON.stringify(configData, null, 2)}
|
|
138
|
+
text: `📋 Dry run - Data that would be pushed:\n${JSON.stringify(configData, null, 2)}${uploadImages
|
|
139
|
+
? "\n\nImage upload mode: overwrite screenshots only; videos/app previews are preserved."
|
|
140
|
+
: ""}`,
|
|
133
141
|
},
|
|
134
142
|
],
|
|
135
143
|
};
|
|
@@ -149,7 +157,7 @@ export async function handleAsoPush(options) {
|
|
|
149
157
|
uploadImages,
|
|
150
158
|
locales,
|
|
151
159
|
imageUploadTimeoutMs,
|
|
152
|
-
imageLocaleBatchSize
|
|
160
|
+
imageLocaleBatchSize,
|
|
153
161
|
slug,
|
|
154
162
|
});
|
|
155
163
|
results.push(formatPushResult("Google Play", result));
|