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,264 @@
|
|
|
1
|
+
import { isGooglePlayMultilingual, isAppStoreMultilingual, saveAsoData, downloadImage, copyLocalAssetToAso, isLocalAssetPath, resolveAppStoreImageUrl, convertToMultilingual, getAsoPullDir, getPullProductAsoDir, getScreenshotDir, getScreenshotFilePath, } from "../../packages/configs/aso-config/utils.js";
|
|
2
|
+
import { getStoreTargets } from "../../packages/configs/aso-config/store.js";
|
|
3
|
+
import { loadConfig } from "../../packages/configs/secrets-config/config.js";
|
|
4
|
+
import { updateAppSupportedLocales } from "../../packages/configs/secrets-config/registered-apps.js";
|
|
5
|
+
import { AppStoreService } from "../../core/services/app-store-service.js";
|
|
6
|
+
import { GooglePlayService } from "../../core/services/google-play-service.js";
|
|
7
|
+
import { AppResolutionService } from "../../core/services/app-resolution-service.js";
|
|
8
|
+
const appStoreService = new AppStoreService();
|
|
9
|
+
const googlePlayService = new GooglePlayService();
|
|
10
|
+
const appResolutionService = new AppResolutionService();
|
|
11
|
+
async function downloadScreenshotsToAso(slug, asoData, asoDir) {
|
|
12
|
+
const productStoreRoot = getPullProductAsoDir(slug, asoDir);
|
|
13
|
+
if (asoData.googlePlay) {
|
|
14
|
+
const googlePlayData = isGooglePlayMultilingual(asoData.googlePlay)
|
|
15
|
+
? asoData.googlePlay
|
|
16
|
+
: convertToMultilingual(asoData.googlePlay, asoData.googlePlay.defaultLanguage);
|
|
17
|
+
const languages = Object.keys(googlePlayData.locales);
|
|
18
|
+
const defaultLanguage = googlePlayData.defaultLocale;
|
|
19
|
+
const targetLanguage = (defaultLanguage && googlePlayData.locales[defaultLanguage]
|
|
20
|
+
? defaultLanguage
|
|
21
|
+
: languages[0]) || null;
|
|
22
|
+
if (targetLanguage) {
|
|
23
|
+
const localeData = googlePlayData.locales[targetLanguage];
|
|
24
|
+
const screenshotDir = getScreenshotDir(productStoreRoot, "google-play", targetLanguage);
|
|
25
|
+
if (localeData.screenshots.phone?.length > 0) {
|
|
26
|
+
console.error(`[MCP] 📥 Downloading ${localeData.screenshots.phone.length} Google Play phone screenshots...`);
|
|
27
|
+
for (let i = 0; i < localeData.screenshots.phone.length; i++) {
|
|
28
|
+
const url = localeData.screenshots.phone[i];
|
|
29
|
+
const outputPath = getScreenshotFilePath(screenshotDir, `phone-${i + 1}.png`);
|
|
30
|
+
try {
|
|
31
|
+
if (isLocalAssetPath(url)) {
|
|
32
|
+
copyLocalAssetToAso(url, outputPath);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
await downloadImage(url, outputPath);
|
|
36
|
+
}
|
|
37
|
+
console.error(`[MCP] ✅ phone-${i + 1}.png`);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(`[MCP] ❌ Failed to handle screenshot ${url}: ${error instanceof Error ? error.message : String(error)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (localeData.featureGraphic) {
|
|
45
|
+
console.error(`[MCP] 📥 Downloading Feature Graphic...`);
|
|
46
|
+
const outputPath = getScreenshotFilePath(screenshotDir, "feature-graphic.png");
|
|
47
|
+
try {
|
|
48
|
+
if (isLocalAssetPath(localeData.featureGraphic)) {
|
|
49
|
+
copyLocalAssetToAso(localeData.featureGraphic, outputPath);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await downloadImage(localeData.featureGraphic, outputPath);
|
|
53
|
+
}
|
|
54
|
+
console.error(`[MCP] ✅ feature-graphic.png`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(`[MCP] ❌ Failed to handle feature graphic ${localeData.featureGraphic}: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (asoData.appStore) {
|
|
63
|
+
const appStoreData = isAppStoreMultilingual(asoData.appStore)
|
|
64
|
+
? asoData.appStore
|
|
65
|
+
: convertToMultilingual(asoData.appStore, asoData.appStore.locale);
|
|
66
|
+
const locales = Object.keys(appStoreData.locales);
|
|
67
|
+
const defaultLocale = appStoreData.defaultLocale;
|
|
68
|
+
const targetLocale = (defaultLocale && appStoreData.locales[defaultLocale]
|
|
69
|
+
? defaultLocale
|
|
70
|
+
: locales[0]) || null;
|
|
71
|
+
if (targetLocale) {
|
|
72
|
+
const localeData = appStoreData.locales[targetLocale];
|
|
73
|
+
const screenshotDir = getScreenshotDir(productStoreRoot, "app-store", targetLocale);
|
|
74
|
+
const screenshotTypes = ["iphone65", "iphone61", "ipadPro129"];
|
|
75
|
+
for (const type of screenshotTypes) {
|
|
76
|
+
const screenshots = localeData.screenshots[type];
|
|
77
|
+
if (screenshots && screenshots.length > 0) {
|
|
78
|
+
console.error(`[MCP] 📥 Downloading ${screenshots.length} App Store ${type} screenshots...`);
|
|
79
|
+
for (let i = 0; i < screenshots.length; i++) {
|
|
80
|
+
let url = screenshots[i];
|
|
81
|
+
const outputPath = getScreenshotFilePath(screenshotDir, `${type}-${i + 1}.png`);
|
|
82
|
+
if (isLocalAssetPath(url)) {
|
|
83
|
+
copyLocalAssetToAso(url, outputPath);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
if (url.includes("{w}") || url.includes("{h}")) {
|
|
87
|
+
url = resolveAppStoreImageUrl(url);
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
await downloadImage(url, outputPath);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error(`[MCP] ❌ Failed to handle screenshot ${url}: ${error instanceof Error ? error.message : String(error)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
console.error(`[MCP] ✅ ${type}-${i + 1}.png`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export async function handleAsoPull(options) {
|
|
104
|
+
const { app, store, dryRun = false } = options;
|
|
105
|
+
let { packageName, bundleId } = options;
|
|
106
|
+
const { store: targetStore, includeAppStore, includeGooglePlay, } = getStoreTargets(store);
|
|
107
|
+
const resolved = appResolutionService.resolve({
|
|
108
|
+
slug: app,
|
|
109
|
+
packageName,
|
|
110
|
+
bundleId,
|
|
111
|
+
});
|
|
112
|
+
if (!resolved.success) {
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: "text",
|
|
117
|
+
text: resolved.error.message,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const { slug, bundleId: resolvedBundleId, packageName: resolvedPackageName, hasAppStore, hasGooglePlay, } = resolved.data;
|
|
123
|
+
bundleId = resolvedBundleId;
|
|
124
|
+
packageName = resolvedPackageName;
|
|
125
|
+
console.error(`[MCP] 📥 Pulling ASO data`);
|
|
126
|
+
console.error(`[MCP] Store: ${targetStore}`);
|
|
127
|
+
console.error(`[MCP] App: ${slug}`);
|
|
128
|
+
if (packageName)
|
|
129
|
+
console.error(`[MCP] Package Name: ${packageName}`);
|
|
130
|
+
if (bundleId)
|
|
131
|
+
console.error(`[MCP] Bundle ID: ${bundleId}`);
|
|
132
|
+
console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual fetch"}`);
|
|
133
|
+
let config;
|
|
134
|
+
try {
|
|
135
|
+
config = loadConfig();
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{ type: "text", text: `❌ Failed to load config: ${message}` },
|
|
142
|
+
],
|
|
143
|
+
isError: true,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const syncedData = {};
|
|
147
|
+
const pullDir = getAsoPullDir();
|
|
148
|
+
if (includeGooglePlay) {
|
|
149
|
+
if (!hasGooglePlay) {
|
|
150
|
+
console.error(`[MCP] ⏭️ Skipping Google Play (not registered for Google Play)`);
|
|
151
|
+
}
|
|
152
|
+
else if (!config.playStore) {
|
|
153
|
+
console.error(`[MCP] ⏭️ Skipping Google Play (not configured in ~/.config/pabal-mcp/config.json)`);
|
|
154
|
+
}
|
|
155
|
+
else if (!packageName) {
|
|
156
|
+
console.error(`[MCP] ⏭️ Skipping Google Play (no packageName provided)`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
const clientResult = googlePlayService.createClient(packageName);
|
|
160
|
+
if (!clientResult.success) {
|
|
161
|
+
console.error(`[MCP] ❌ Failed to create Google Play client: ${clientResult.error.message}`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
try {
|
|
165
|
+
console.error(`[MCP] 📥 Fetching from Google Play...`);
|
|
166
|
+
const data = await clientResult.data.pullAllLanguagesAsoData();
|
|
167
|
+
syncedData.googlePlay = data;
|
|
168
|
+
console.error(`[MCP] ✅ Google Play data fetched`);
|
|
169
|
+
// Update registered-apps.json with pulled locales
|
|
170
|
+
if (data.locales && Object.keys(data.locales).length > 0) {
|
|
171
|
+
const locales = Object.keys(data.locales);
|
|
172
|
+
try {
|
|
173
|
+
const updated = updateAppSupportedLocales({
|
|
174
|
+
identifier: packageName,
|
|
175
|
+
store: "googlePlay",
|
|
176
|
+
locales,
|
|
177
|
+
});
|
|
178
|
+
if (updated) {
|
|
179
|
+
console.error(`[MCP] ✅ Updated registered-apps.json with ${locales.length} Google Play locales`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (updateError) {
|
|
183
|
+
console.error(`[MCP] ⚠️ Failed to update registered-apps.json: ${updateError instanceof Error
|
|
184
|
+
? updateError.message
|
|
185
|
+
: String(updateError)}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
console.error(`[MCP] ❌ Google Play fetch failed:`, error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (includeAppStore) {
|
|
196
|
+
if (!hasAppStore) {
|
|
197
|
+
console.error(`[MCP] ⏭️ Skipping App Store (not registered for App Store)`);
|
|
198
|
+
}
|
|
199
|
+
else if (!config.appStore) {
|
|
200
|
+
console.error(`[MCP] ⏭️ Skipping App Store (not configured in ~/.config/pabal-mcp/config.json)`);
|
|
201
|
+
}
|
|
202
|
+
else if (!bundleId) {
|
|
203
|
+
console.error(`[MCP] ⏭️ Skipping App Store (no bundleId provided)`);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const clientResult = appStoreService.createClient(bundleId);
|
|
207
|
+
if (!clientResult.success) {
|
|
208
|
+
console.error(`[MCP] ❌ Failed to create App Store client: ${clientResult.error.message}`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
try {
|
|
212
|
+
console.error(`[MCP] 📥 Fetching from App Store...`);
|
|
213
|
+
const data = await clientResult.data.pullAllLocalesAsoData();
|
|
214
|
+
syncedData.appStore = data;
|
|
215
|
+
console.error(`[MCP] ✅ App Store data fetched`);
|
|
216
|
+
// Update registered-apps.json with pulled locales
|
|
217
|
+
if (data.locales && Object.keys(data.locales).length > 0) {
|
|
218
|
+
const locales = Object.keys(data.locales);
|
|
219
|
+
try {
|
|
220
|
+
const updated = updateAppSupportedLocales({
|
|
221
|
+
identifier: bundleId,
|
|
222
|
+
store: "appStore",
|
|
223
|
+
locales,
|
|
224
|
+
});
|
|
225
|
+
if (updated) {
|
|
226
|
+
console.error(`[MCP] ✅ Updated registered-apps.json with ${locales.length} App Store locales`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (updateError) {
|
|
230
|
+
console.error(`[MCP] ⚠️ Failed to update registered-apps.json: ${updateError instanceof Error
|
|
231
|
+
? updateError.message
|
|
232
|
+
: String(updateError)}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.error(`[MCP] ❌ App Store fetch failed:`, error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (dryRun) {
|
|
243
|
+
return {
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: "text",
|
|
247
|
+
text: `📋 Dry run - Data that would be saved:\n${JSON.stringify(syncedData, null, 2)}`,
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
saveAsoData(slug, syncedData, { asoDir: pullDir });
|
|
253
|
+
await downloadScreenshotsToAso(slug, syncedData, pullDir);
|
|
254
|
+
return {
|
|
255
|
+
content: [
|
|
256
|
+
{
|
|
257
|
+
type: "text",
|
|
258
|
+
text: `✅ ASO data pulled\n` +
|
|
259
|
+
` Google Play: ${syncedData.googlePlay ? "✓" : "✗"}\n` +
|
|
260
|
+
` App Store: ${syncedData.appStore ? "✓" : "✗"}`,
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StoreType } from "../../packages/configs/aso-config/types.js";
|
|
2
|
+
interface AsoPushOptions {
|
|
3
|
+
app?: string;
|
|
4
|
+
packageName?: string;
|
|
5
|
+
bundleId?: string;
|
|
6
|
+
store?: StoreType;
|
|
7
|
+
uploadImages?: boolean;
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function handleAsoPush(options: AsoPushOptions): Promise<{
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
isError?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { isGooglePlayMultilingual, isAppStoreMultilingual, loadAsoData, saveAsoData, prepareAsoDataForPush, getAsoDir, getAsoDataPaths, getAsoPushDir, } from "../../packages/configs/aso-config/utils.js";
|
|
2
|
+
import { loadConfig } from "../../packages/configs/secrets-config/config.js";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { AppResolutionService } from "../../core/services/app-resolution-service.js";
|
|
5
|
+
import { AppStoreService } from "../../core/services/app-store-service.js";
|
|
6
|
+
import { GooglePlayService } from "../../core/services/google-play-service.js";
|
|
7
|
+
import { formatPushResult } from "../../core/helpers/formatters.js";
|
|
8
|
+
const appResolutionService = new AppResolutionService();
|
|
9
|
+
const appStoreService = new AppStoreService();
|
|
10
|
+
const googlePlayService = new GooglePlayService();
|
|
11
|
+
export async function handleAsoPush(options) {
|
|
12
|
+
const { store = "both", uploadImages = false, dryRun = false } = options;
|
|
13
|
+
const resolved = appResolutionService.resolve({
|
|
14
|
+
slug: options.app,
|
|
15
|
+
packageName: options.packageName,
|
|
16
|
+
bundleId: options.bundleId,
|
|
17
|
+
});
|
|
18
|
+
if (!resolved.success) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: "text",
|
|
23
|
+
text: resolved.error.message,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const { slug, packageName, bundleId, hasAppStore, hasGooglePlay } = resolved.data;
|
|
29
|
+
console.error(`[MCP] 📤 Pushing ASO data`);
|
|
30
|
+
console.error(`[MCP] Store: ${store}`);
|
|
31
|
+
console.error(`[MCP] App: ${slug}`);
|
|
32
|
+
if (packageName)
|
|
33
|
+
console.error(`[MCP] Package Name: ${packageName}`);
|
|
34
|
+
if (bundleId)
|
|
35
|
+
console.error(`[MCP] Bundle ID: ${bundleId}`);
|
|
36
|
+
console.error(`[MCP] Upload Images: ${uploadImages ? "Yes" : "No"}`);
|
|
37
|
+
console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual push"}`);
|
|
38
|
+
let config;
|
|
39
|
+
try {
|
|
40
|
+
config = loadConfig();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{ type: "text", text: `❌ Failed to load config: ${message}` },
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Load local data from ASO directory
|
|
52
|
+
const asoDir = getAsoPushDir();
|
|
53
|
+
const { googlePlay: googlePlayDataPath, appStore: appStoreDataPath } = getAsoDataPaths(slug, asoDir);
|
|
54
|
+
console.error(`[MCP] 📁 ASO Directory: ${asoDir}`);
|
|
55
|
+
console.error(`[MCP] 📁 Base ASO Dir: ${getAsoDir()}`);
|
|
56
|
+
console.error(`[MCP] 🔍 Checking data files...`);
|
|
57
|
+
console.error(`[MCP] Google Play: ${googlePlayDataPath}`);
|
|
58
|
+
console.error(`[MCP] Exists: ${existsSync(googlePlayDataPath) ? "✅ Yes" : "❌ No"}`);
|
|
59
|
+
console.error(`[MCP] App Store: ${appStoreDataPath}`);
|
|
60
|
+
console.error(`[MCP] Exists: ${existsSync(appStoreDataPath) ? "✅ Yes" : "❌ No"}`);
|
|
61
|
+
let configData;
|
|
62
|
+
try {
|
|
63
|
+
configData = loadAsoData(slug, { asoDir });
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `❌ Failed to load ASO data: ${message}`,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
console.error(`[MCP] 📊 Loaded data status:`);
|
|
78
|
+
console.error(`[MCP] Google Play: ${configData.googlePlay ? "✅ Loaded" : "❌ Not found"}`);
|
|
79
|
+
if (configData.googlePlay) {
|
|
80
|
+
const gpData = configData.googlePlay;
|
|
81
|
+
if (isGooglePlayMultilingual(gpData)) {
|
|
82
|
+
const locales = Object.keys(gpData.locales);
|
|
83
|
+
console.error(`[MCP] Locales: ${locales.join(", ")} (${locales.length} total)`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.error(`[MCP] Language: ${gpData.defaultLanguage || "unknown"}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.error(`[MCP] App Store: ${configData.appStore ? "✅ Loaded" : "❌ Not found"}`);
|
|
90
|
+
if (configData.appStore) {
|
|
91
|
+
const asData = configData.appStore;
|
|
92
|
+
if (isAppStoreMultilingual(asData)) {
|
|
93
|
+
const locales = Object.keys(asData.locales);
|
|
94
|
+
console.error(`[MCP] Locales: ${locales.join(", ")} (${locales.length} total)`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.error(`[MCP] Locale: ${asData.locale || "unknown"}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!configData.googlePlay && !configData.appStore) {
|
|
101
|
+
const errorDetails = `❌ No ASO data found for ${slug}.
|
|
102
|
+
|
|
103
|
+
📁 Expected paths:
|
|
104
|
+
Google Play: ${googlePlayDataPath}
|
|
105
|
+
App Store: ${appStoreDataPath}
|
|
106
|
+
|
|
107
|
+
💡 To fix this:
|
|
108
|
+
1. Run \`aso-pull\` to fetch data from stores
|
|
109
|
+
2. Or ensure data exists at the paths above
|
|
110
|
+
3. Check that data directory is set correctly (current: ${getAsoDir()})`;
|
|
111
|
+
console.error(`[MCP] ${errorDetails}`);
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: "text", text: errorDetails }],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Prepare data for push
|
|
117
|
+
console.error(`[MCP] 🔄 Preparing data for push...`);
|
|
118
|
+
const localAsoData = prepareAsoDataForPush(slug, configData);
|
|
119
|
+
console.error(`[MCP] 📊 Prepared data status:`);
|
|
120
|
+
console.error(`[MCP] Google Play: ${localAsoData.googlePlay ? "✅ Ready" : "❌ Not available"}`);
|
|
121
|
+
if (localAsoData.googlePlay) {
|
|
122
|
+
const gpData = localAsoData.googlePlay;
|
|
123
|
+
if (isGooglePlayMultilingual(gpData)) {
|
|
124
|
+
const locales = Object.keys(gpData.locales);
|
|
125
|
+
console.error(`[MCP] Locales to push: ${locales.join(", ")} (${locales.length} total)`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
console.error(`[MCP] App Store: ${localAsoData.appStore ? "✅ Ready" : "❌ Not available"}`);
|
|
129
|
+
if (localAsoData.appStore) {
|
|
130
|
+
const asData = localAsoData.appStore;
|
|
131
|
+
if (isAppStoreMultilingual(asData)) {
|
|
132
|
+
const locales = Object.keys(asData.locales);
|
|
133
|
+
console.error(`[MCP] Locales to push: ${locales.join(", ")} (${locales.length} total)`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (dryRun) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
text: `📋 Dry run - Data that would be pushed:\n${JSON.stringify(localAsoData, null, 2)}`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// Save to ASO directory before pushing
|
|
147
|
+
if (localAsoData.googlePlay || localAsoData.appStore) {
|
|
148
|
+
saveAsoData(slug, localAsoData, { asoDir });
|
|
149
|
+
}
|
|
150
|
+
const results = [];
|
|
151
|
+
// Push to Google Play
|
|
152
|
+
if (store === "googlePlay" || store === "both") {
|
|
153
|
+
if (!hasGooglePlay) {
|
|
154
|
+
results.push(`⏭️ Skipping Google Play (not registered for Google Play)`);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const result = await googlePlayService.pushAsoData({
|
|
158
|
+
config,
|
|
159
|
+
packageName,
|
|
160
|
+
localAsoData,
|
|
161
|
+
googlePlayDataPath,
|
|
162
|
+
});
|
|
163
|
+
results.push(formatPushResult("Google Play", result));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Push to App Store
|
|
167
|
+
if (store === "appStore" || store === "both") {
|
|
168
|
+
if (!hasAppStore) {
|
|
169
|
+
results.push(`⏭️ Skipping App Store (not registered for App Store)`);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const appStoreResult = await appStoreService.pushAsoData({
|
|
173
|
+
config,
|
|
174
|
+
bundleId,
|
|
175
|
+
localAsoData,
|
|
176
|
+
appStoreDataPath,
|
|
177
|
+
});
|
|
178
|
+
results.push(formatPushResult("App Store", appStoreResult));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: "text",
|
|
185
|
+
text: `📤 ASO Push Results:\n${results.join("\n")}`,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AppStoreService } from "../../core/services/app-store-service.js";
|
|
2
|
+
const appStoreService = new AppStoreService();
|
|
3
|
+
/**
|
|
4
|
+
* App Store authentication status check tool
|
|
5
|
+
*/
|
|
6
|
+
export async function handleAuthAppStore() {
|
|
7
|
+
const result = await appStoreService.verifyAuth(300);
|
|
8
|
+
const success = Boolean(result.success && result.data);
|
|
9
|
+
if (success) {
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify({
|
|
15
|
+
ok: true,
|
|
16
|
+
header: result.data.header,
|
|
17
|
+
payload: result.data.payload,
|
|
18
|
+
}, null, 2),
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const errorMessage = result.error?.message ||
|
|
24
|
+
"App Store authentication not configured or failed.";
|
|
25
|
+
// Keep failure response as plain text for tests that expect a string with keywords.
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: "text",
|
|
30
|
+
text: `App Store auth failed: ${errorMessage}`,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auth-check: Check App Store / Google Play authentication status
|
|
3
|
+
*/
|
|
4
|
+
import { type StoreType } from "../../packages/configs/aso-config/types.js";
|
|
5
|
+
interface AuthCheckOptions {
|
|
6
|
+
store?: StoreType;
|
|
7
|
+
}
|
|
8
|
+
export declare function handleAuthCheck(options: AuthCheckOptions): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auth-check: Check App Store / Google Play authentication status
|
|
3
|
+
*/
|
|
4
|
+
import { getStoreTargets } from "../../packages/configs/aso-config/store.js";
|
|
5
|
+
import { AppStoreService } from "../../core/services/app-store-service.js";
|
|
6
|
+
import { GooglePlayService } from "../../core/services/google-play-service.js";
|
|
7
|
+
const appStoreService = new AppStoreService();
|
|
8
|
+
const googlePlayService = new GooglePlayService();
|
|
9
|
+
export async function handleAuthCheck(options) {
|
|
10
|
+
const { store } = options;
|
|
11
|
+
const { store: targetStore, includeAppStore, includeGooglePlay, } = getStoreTargets(store);
|
|
12
|
+
const results = [];
|
|
13
|
+
console.error(`[MCP] 🔐 Checking authentication (store: ${targetStore})`);
|
|
14
|
+
if (includeAppStore) {
|
|
15
|
+
console.error(`[MCP] Checking App Store Connect...`);
|
|
16
|
+
const appStoreResult = await appStoreService.verifyAuth(300);
|
|
17
|
+
if (appStoreResult.success && appStoreResult.data) {
|
|
18
|
+
results.push(`✅ **App Store Connect**`);
|
|
19
|
+
results.push(` Issuer ID: ${appStoreResult.data.payload.iss}`);
|
|
20
|
+
results.push(` Key ID: ${appStoreResult.data.header.kid}`);
|
|
21
|
+
results.push(` JWT created successfully`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
results.push(`❌ **App Store Connect**`);
|
|
25
|
+
results.push(` ${appStoreResult.error?.message || "Authentication failed"}`);
|
|
26
|
+
}
|
|
27
|
+
results.push("");
|
|
28
|
+
}
|
|
29
|
+
if (includeGooglePlay) {
|
|
30
|
+
console.error(`[MCP] Checking Google Play Console...`);
|
|
31
|
+
const playStoreResult = await googlePlayService.verifyAuth();
|
|
32
|
+
if (playStoreResult.success && playStoreResult.data) {
|
|
33
|
+
results.push(`✅ **Google Play Console**`);
|
|
34
|
+
results.push(` Project: ${playStoreResult.data.project_id}`);
|
|
35
|
+
results.push(` Service Account: ${playStoreResult.data.client_email}`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
results.push(`❌ **Google Play Console**`);
|
|
39
|
+
results.push(` ${playStoreResult.error?.message || "Authentication failed"}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: `🔐 **Authentication Status**\n\n${results.join("\n")}`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GooglePlayService } from "../../core/services/google-play-service.js";
|
|
2
|
+
const googlePlayService = new GooglePlayService();
|
|
3
|
+
/**
|
|
4
|
+
* Google Play authentication status check tool
|
|
5
|
+
*/
|
|
6
|
+
export async function handleAuthPlayStore() {
|
|
7
|
+
const result = await googlePlayService.verifyAuth();
|
|
8
|
+
if (result.success && result.data) {
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: JSON.stringify({
|
|
14
|
+
ok: true,
|
|
15
|
+
client_email: result.data.client_email,
|
|
16
|
+
project_id: result.data.project_id,
|
|
17
|
+
}, null, 2),
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{
|
|
25
|
+
type: "text",
|
|
26
|
+
text: result.error || "An unknown error occurred.",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type StoreType } from "../../packages/configs/aso-config/types.js";
|
|
2
|
+
interface CheckVersionsOptions {
|
|
3
|
+
app?: string;
|
|
4
|
+
packageName?: string;
|
|
5
|
+
bundleId?: string;
|
|
6
|
+
store?: StoreType;
|
|
7
|
+
}
|
|
8
|
+
export declare function handleCheckLatestVersions(options: CheckVersionsOptions): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
export {};
|