pabal-resource-mcp 1.10.8 → 1.10.9

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.
@@ -14,7 +14,7 @@ import {
14
14
  getPushDataDir,
15
15
  loadAsoFromConfig,
16
16
  saveAsoToAsoDir
17
- } from "../chunk-H4MYWLFK.js";
17
+ } from "../chunk-REQG4DR7.js";
18
18
  import {
19
19
  DEFAULT_LOCALE,
20
20
  appStoreToUnified,
@@ -896,17 +896,17 @@ async function downloadScreenshotsToAsoDir(slug, asoData) {
896
896
  relativeDir,
897
897
  "iphone65"
898
898
  );
899
- const ipadPro129Paths = await downloadScreenshotArray(
900
- localeData.screenshots?.ipadPro129,
899
+ const ipad13Paths = await downloadScreenshotArray(
900
+ localeData.screenshots?.ipad13 ?? localeData.screenshots?.ipadPro129,
901
901
  asoDir,
902
902
  relativeDir,
903
- "ipadPro129"
903
+ "ipad13"
904
904
  );
905
- const hasDownloadedScreenshots = iphone65Paths.length > 0 || ipadPro129Paths.length > 0;
905
+ const hasDownloadedScreenshots = iphone65Paths.length > 0 || ipad13Paths.length > 0;
906
906
  if (hasDownloadedScreenshots) {
907
907
  localeData.screenshots = {
908
908
  iphone65: iphone65Paths,
909
- ipadPro129: ipadPro129Paths
909
+ ipad13: ipad13Paths
910
910
  };
911
911
  }
912
912
  }
package/dist/browser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as APP_STORE_TO_UNIFIED, Y as AppIconConfig, X as AppIconStyleConfig, F as AppMetaLinks, H as AppPageData, t as AppStoreAsoData, p as AppStoreInfoLocalization, d as AppStoreLocale, v as AppStoreMultilingualAsoData, o as AppStoreReleaseNote, r as AppStoreScreenshotDisplayType, s as AppStoreScreenshots, q as AppStoreVersionLocalization, w as AsoData, a1 as AsoLocaleContent, a0 as AsoTemplate, C as BlogArticle, z as BlogMeta, B as BlogMetaBlock, ac as BlogMetaOutput, E as BlogSummary, ad as CreateBlogHtmlInput, af as CreateBlogHtmlResult, D as DEFAULT_LOCALE, R as DeepPartial, M as FeatureItem, G as GOOGLE_PLAY_TO_UNIFIED, ae as GeneratedBlogFile, m as GooglePlayAsoData, j as GooglePlayImageType, h as GooglePlayListing, e as GooglePlayLocale, u as GooglePlayMultilingualAsoData, n as GooglePlayReleaseNote, k as GooglePlayScreenshotType, l as GooglePlayScreenshots, I as ImageAsset, P as LandingCta, N as LandingFeatures, J as LandingHero, Q as LandingPage, V as LandingPageLocale, O as LandingReviews, K as LandingScreenshots, L as LayoutColors, a7 as LocaleDisplayInfo, $ as ProductConfig, _ as ProductContent, a2 as ProductLocale, Z as ProductMetadata, W as ProductScreenshots, ab as ResolvedWorkData, a5 as ScreenshotGeneratorConfig, a4 as ScreenshotGeneratorSlideConfig, a3 as ScreenshotGeneratorThemeTokens, a6 as SiteConfig, a8 as SiteData, S as SupportedLocale, T as Testimonial, U as UNIFIED_LOCALES, a as UNIFIED_TO_APP_STORE, b as UNIFIED_TO_GOOGLE_PLAY, c as UnifiedLocale, a9 as WorkItem, aa as WorkLocaleData, ap as appStoreToGooglePlay, aj as appStoreToUnified, an as appStoreToUnifiedBatch, at as convertObjectFromAppStore, au as convertObjectFromGooglePlay, ar as convertObjectToAppStore, as as convertObjectToGooglePlay, aq as googlePlayToAppStore, ak as googlePlayToUnified, ao as googlePlayToUnifiedBatch, f as isAppStoreLocale, y as isAppStoreMultilingual, g as isGooglePlayLocale, x as isGooglePlayMultilingual, i as isSupportedLocale, ag as unifiedToAppStore, al as unifiedToAppStoreBatch, ai as unifiedToBothPlatforms, ah as unifiedToGooglePlay, am as unifiedToGooglePlayBatch } from './locale-converter-CTItgoKU.js';
1
+ export { A as APP_STORE_TO_UNIFIED, Y as AppIconConfig, X as AppIconStyleConfig, F as AppMetaLinks, H as AppPageData, t as AppStoreAsoData, p as AppStoreInfoLocalization, d as AppStoreLocale, v as AppStoreMultilingualAsoData, o as AppStoreReleaseNote, r as AppStoreScreenshotDisplayType, s as AppStoreScreenshots, q as AppStoreVersionLocalization, w as AsoData, a1 as AsoLocaleContent, a0 as AsoTemplate, C as BlogArticle, z as BlogMeta, B as BlogMetaBlock, ac as BlogMetaOutput, E as BlogSummary, ad as CreateBlogHtmlInput, af as CreateBlogHtmlResult, D as DEFAULT_LOCALE, R as DeepPartial, M as FeatureItem, G as GOOGLE_PLAY_TO_UNIFIED, ae as GeneratedBlogFile, m as GooglePlayAsoData, j as GooglePlayImageType, h as GooglePlayListing, e as GooglePlayLocale, u as GooglePlayMultilingualAsoData, n as GooglePlayReleaseNote, k as GooglePlayScreenshotType, l as GooglePlayScreenshots, I as ImageAsset, P as LandingCta, N as LandingFeatures, J as LandingHero, Q as LandingPage, V as LandingPageLocale, O as LandingReviews, K as LandingScreenshots, L as LayoutColors, a7 as LocaleDisplayInfo, $ as ProductConfig, _ as ProductContent, a2 as ProductLocale, Z as ProductMetadata, W as ProductScreenshots, ab as ResolvedWorkData, a5 as ScreenshotGeneratorConfig, a4 as ScreenshotGeneratorSlideConfig, a3 as ScreenshotGeneratorThemeTokens, a6 as SiteConfig, a8 as SiteData, S as SupportedLocale, T as Testimonial, U as UNIFIED_LOCALES, a as UNIFIED_TO_APP_STORE, b as UNIFIED_TO_GOOGLE_PLAY, c as UnifiedLocale, a9 as WorkItem, aa as WorkLocaleData, ap as appStoreToGooglePlay, aj as appStoreToUnified, an as appStoreToUnifiedBatch, at as convertObjectFromAppStore, au as convertObjectFromGooglePlay, ar as convertObjectToAppStore, as as convertObjectToGooglePlay, aq as googlePlayToAppStore, ak as googlePlayToUnified, ao as googlePlayToUnifiedBatch, f as isAppStoreLocale, y as isAppStoreMultilingual, g as isGooglePlayLocale, x as isGooglePlayMultilingual, i as isSupportedLocale, ag as unifiedToAppStore, al as unifiedToAppStoreBatch, ai as unifiedToBothPlatforms, ah as unifiedToGooglePlay, am as unifiedToGooglePlayBatch } from './locale-converter-CzWIV3a-.js';
2
2
  import '@googleapis/androidpublisher';
3
3
  import 'appstore-connect-sdk/openapi';
4
4
 
@@ -0,0 +1,418 @@
1
+ import {
2
+ DEFAULT_LOCALE,
3
+ isAppStoreLocale,
4
+ isGooglePlayLocale,
5
+ isSupportedLocale
6
+ } from "./chunk-BOWRBVVV.js";
7
+
8
+ // src/utils/config.util.ts
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import os from "os";
12
+ function getAsoDataDir() {
13
+ const configPath = path.join(
14
+ os.homedir(),
15
+ ".config",
16
+ "pabal-mcp",
17
+ "config.json"
18
+ );
19
+ if (!fs.existsSync(configPath)) {
20
+ throw new Error(
21
+ `Config file not found at ${configPath}. Please create the config file and set the 'dataDir' property to specify the ASO data directory.`
22
+ );
23
+ }
24
+ try {
25
+ const configContent = fs.readFileSync(configPath, "utf-8");
26
+ const config = JSON.parse(configContent);
27
+ if (!config.dataDir) {
28
+ throw new Error(
29
+ `'dataDir' property is not set in ${configPath}. Please set 'dataDir' to specify the ASO data directory.`
30
+ );
31
+ }
32
+ if (path.isAbsolute(config.dataDir)) {
33
+ return config.dataDir;
34
+ }
35
+ return path.resolve(os.homedir(), config.dataDir);
36
+ } catch (error) {
37
+ if (error instanceof Error && error.message.includes("dataDir")) {
38
+ throw error;
39
+ }
40
+ throw new Error(
41
+ `Failed to read config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`
42
+ );
43
+ }
44
+ }
45
+ function getPullDataDir() {
46
+ return path.join(getAsoDataDir(), ".aso", "pullData");
47
+ }
48
+ function getPushDataDir() {
49
+ return path.join(getAsoDataDir(), ".aso", "pushData");
50
+ }
51
+ function getPublicDir() {
52
+ return path.join(getAsoDataDir(), "public");
53
+ }
54
+ function getKeywordResearchDir() {
55
+ return path.join(getAsoDataDir(), ".aso", "keywordResearch");
56
+ }
57
+ function getProductsDir() {
58
+ return path.join(getPublicDir(), "products");
59
+ }
60
+ function loadConfig() {
61
+ const configPath = path.join(
62
+ os.homedir(),
63
+ ".config",
64
+ "pabal-mcp",
65
+ "config.json"
66
+ );
67
+ if (!fs.existsSync(configPath)) {
68
+ return {};
69
+ }
70
+ try {
71
+ const configContent = fs.readFileSync(configPath, "utf-8");
72
+ return JSON.parse(configContent);
73
+ } catch {
74
+ return {};
75
+ }
76
+ }
77
+ function getGeminiApiKey() {
78
+ const config = loadConfig();
79
+ if (config.gemini?.apiKey) {
80
+ return config.gemini.apiKey;
81
+ }
82
+ const envKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
83
+ if (envKey) {
84
+ return envKey;
85
+ }
86
+ throw new Error(
87
+ `Gemini API key not found. Set it in ~/.config/pabal-mcp/config.json under "gemini.apiKey" or use GEMINI_API_KEY environment variable.`
88
+ );
89
+ }
90
+
91
+ // src/utils/aso-converter.ts
92
+ import fs2 from "fs";
93
+ import path2 from "path";
94
+ function generateFullDescription(localeData, metadata = {}) {
95
+ const { aso, landing } = localeData;
96
+ const template = aso?.template;
97
+ if (!template) {
98
+ return "";
99
+ }
100
+ const landingFeatures = landing?.features?.items || [];
101
+ const landingScreenshots = landing?.screenshots?.images || [];
102
+ const keyHeading = template.keyFeaturesHeading || "Key Features";
103
+ const featuresHeading = template.featuresHeading || "Additional Features";
104
+ const parts = [template.intro];
105
+ if (landingFeatures.length > 0) {
106
+ parts.push(
107
+ "",
108
+ keyHeading,
109
+ "",
110
+ ...landingFeatures.map(
111
+ (feature) => [`\u25B6\uFE0E ${feature.title}`, feature.body || ""].filter(Boolean).join("\n")
112
+ )
113
+ );
114
+ }
115
+ if (landingScreenshots.length > 0) {
116
+ parts.push("", featuresHeading, "");
117
+ parts.push(
118
+ ...landingScreenshots.map(
119
+ (screenshot) => [`\u25B6\uFE0E ${screenshot.title}`, screenshot.description || ""].filter(Boolean).join("\n")
120
+ )
121
+ );
122
+ }
123
+ parts.push("", template.outro);
124
+ const includeSupport = template.includeSupportLinks ?? true;
125
+ if (includeSupport) {
126
+ const contactLines = [
127
+ metadata.instagram ? `Instagram: ${metadata.instagram}` : null,
128
+ metadata.contactEmail ? `Email: ${metadata.contactEmail}` : null,
129
+ metadata.termsUrl ? `- Terms of Use: ${metadata.termsUrl}` : null,
130
+ metadata.privacyUrl ? `- Privacy Policy: ${metadata.privacyUrl}` : null
131
+ ].filter((line) => line !== null);
132
+ if (contactLines.length > 0) {
133
+ parts.push("", "[Contact & Support]", "", ...contactLines);
134
+ }
135
+ }
136
+ return parts.join("\n");
137
+ }
138
+ function loadAsoFromConfig(slug) {
139
+ const productsDir = getProductsDir();
140
+ const configPath = path2.join(productsDir, slug, "config.json");
141
+ console.debug(`[loadAsoFromConfig] Looking for ${slug}:`);
142
+ console.debug(` - productsDir: ${productsDir}`);
143
+ console.debug(` - configPath: ${configPath}`);
144
+ console.debug(` - configPath exists: ${fs2.existsSync(configPath)}`);
145
+ if (!fs2.existsSync(configPath)) {
146
+ console.warn(`[loadAsoFromConfig] Config file not found at ${configPath}`);
147
+ return {};
148
+ }
149
+ try {
150
+ const configContent = fs2.readFileSync(configPath, "utf-8");
151
+ const config = JSON.parse(configContent);
152
+ const localesDir = path2.join(productsDir, slug, "locales");
153
+ console.debug(` - localesDir: ${localesDir}`);
154
+ console.debug(` - localesDir exists: ${fs2.existsSync(localesDir)}`);
155
+ if (!fs2.existsSync(localesDir)) {
156
+ console.warn(
157
+ `[loadAsoFromConfig] Locales directory not found at ${localesDir}`
158
+ );
159
+ return {};
160
+ }
161
+ const localeFiles = fs2.readdirSync(localesDir).filter((f) => f.endsWith(".json"));
162
+ const locales = {};
163
+ for (const file of localeFiles) {
164
+ const localeCode = file.replace(".json", "");
165
+ const localePath = path2.join(localesDir, file);
166
+ const localeContent = fs2.readFileSync(localePath, "utf-8");
167
+ locales[localeCode] = JSON.parse(localeContent);
168
+ }
169
+ console.debug(
170
+ ` - Found ${Object.keys(locales).length} locale file(s): ${Object.keys(
171
+ locales
172
+ ).join(", ")}`
173
+ );
174
+ if (Object.keys(locales).length === 0) {
175
+ console.warn(
176
+ `[loadAsoFromConfig] No locale files found in ${localesDir}`
177
+ );
178
+ }
179
+ const defaultLocale = config.content?.defaultLocale || DEFAULT_LOCALE;
180
+ const asoData = {};
181
+ if (config.packageName) {
182
+ const googlePlayLocales = {};
183
+ const metadata = config.metadata || {};
184
+ const screenshots = metadata.screenshots || {};
185
+ for (const [locale, localeData] of Object.entries(locales)) {
186
+ if (!isSupportedLocale(locale)) {
187
+ console.debug(
188
+ `Skipping locale ${locale} - not a valid unified locale`
189
+ );
190
+ continue;
191
+ }
192
+ if (!isGooglePlayLocale(locale)) {
193
+ console.debug(
194
+ `Skipping locale ${locale} - not supported by Google Play`
195
+ );
196
+ continue;
197
+ }
198
+ const aso = localeData.aso || {};
199
+ if (!aso || !aso.title && !aso.shortDescription) {
200
+ console.warn(
201
+ `Locale ${locale} has no ASO data (title or shortDescription)`
202
+ );
203
+ }
204
+ const screenshotsDir = path2.join(
205
+ productsDir,
206
+ slug,
207
+ "screenshots",
208
+ locale
209
+ );
210
+ const phoneDir = path2.join(screenshotsDir, "phone");
211
+ const tabletDir = path2.join(screenshotsDir, "tablet");
212
+ const featureGraphicPath = path2.join(
213
+ screenshotsDir,
214
+ "feature-graphic.png"
215
+ );
216
+ const hasPhoneScreenshots = fs2.existsSync(phoneDir);
217
+ const hasTabletScreenshots = fs2.existsSync(tabletDir);
218
+ const hasFeatureGraphic = fs2.existsSync(featureGraphicPath);
219
+ const localeScreenshots = {
220
+ phone: hasPhoneScreenshots ? screenshots.phone?.map(
221
+ (p) => p.replace(/\/screenshots\/[^/]+\//, `/screenshots/${locale}/`)
222
+ ) : void 0,
223
+ tablet: hasTabletScreenshots ? screenshots.tablet?.map(
224
+ (p) => p.replace(/\/screenshots\/[^/]+\//, `/screenshots/${locale}/`)
225
+ ) : void 0
226
+ };
227
+ googlePlayLocales[locale] = {
228
+ title: aso.title || "",
229
+ shortDescription: aso.shortDescription || "",
230
+ fullDescription: generateFullDescription(localeData, metadata),
231
+ packageName: config.packageName,
232
+ defaultLanguage: locale,
233
+ screenshots: {
234
+ phone: localeScreenshots.phone || [],
235
+ tablet: localeScreenshots.tablet
236
+ },
237
+ featureGraphic: hasFeatureGraphic ? `/products/${slug}/screenshots/${locale}/feature-graphic.png` : metadata.featureGraphic
238
+ };
239
+ }
240
+ const googleLocaleKeys = Object.keys(googlePlayLocales);
241
+ if (googleLocaleKeys.length > 0) {
242
+ const hasConfigDefault = isGooglePlayLocale(defaultLocale) && Boolean(googlePlayLocales[defaultLocale]);
243
+ const resolvedDefault = hasConfigDefault ? defaultLocale : googlePlayLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : googleLocaleKeys[0];
244
+ asoData.googlePlay = {
245
+ locales: googlePlayLocales,
246
+ defaultLocale: resolvedDefault,
247
+ // App-level contact information
248
+ contactEmail: metadata.contactEmail,
249
+ contactWebsite: metadata.supportUrl,
250
+ youtubeUrl: metadata.youtubeUrl
251
+ };
252
+ }
253
+ }
254
+ if (config.bundleId) {
255
+ const appStoreLocales = {};
256
+ const metadata = config.metadata || {};
257
+ const screenshots = metadata.screenshots || {};
258
+ for (const [locale, localeData] of Object.entries(locales)) {
259
+ if (!isSupportedLocale(locale)) {
260
+ console.debug(
261
+ `Skipping locale ${locale} - not a valid unified locale`
262
+ );
263
+ continue;
264
+ }
265
+ if (!isAppStoreLocale(locale)) {
266
+ console.debug(
267
+ `Skipping locale ${locale} - not supported by App Store`
268
+ );
269
+ continue;
270
+ }
271
+ const aso = localeData.aso || {};
272
+ if (!aso || !aso.title && !aso.shortDescription) {
273
+ console.warn(
274
+ `Locale ${locale} has no ASO data (title or shortDescription)`
275
+ );
276
+ }
277
+ const screenshotsDir = path2.join(
278
+ productsDir,
279
+ slug,
280
+ "screenshots",
281
+ locale
282
+ );
283
+ const phoneDir = path2.join(screenshotsDir, "phone");
284
+ const tabletDir = path2.join(screenshotsDir, "tablet");
285
+ const hasPhoneScreenshots = fs2.existsSync(phoneDir);
286
+ const hasTabletScreenshots = fs2.existsSync(tabletDir);
287
+ const localeScreenshots = {
288
+ phone: hasPhoneScreenshots ? screenshots.phone?.map(
289
+ (p) => p.replace(/\/screenshots\/[^/]+\//, `/screenshots/${locale}/`)
290
+ ) : void 0,
291
+ tablet: hasTabletScreenshots ? screenshots.tablet?.map(
292
+ (p) => p.replace(/\/screenshots\/[^/]+\//, `/screenshots/${locale}/`)
293
+ ) : void 0
294
+ };
295
+ appStoreLocales[locale] = {
296
+ name: aso.title || "",
297
+ subtitle: aso.subtitle,
298
+ description: generateFullDescription(localeData, metadata),
299
+ keywords: Array.isArray(aso.keywords) ? aso.keywords.join(",") : aso.keywords,
300
+ promotionalText: void 0,
301
+ bundleId: config.bundleId,
302
+ locale,
303
+ screenshots: {
304
+ // Map phone screenshots to iphone65
305
+ iphone65: localeScreenshots.phone || [],
306
+ // Map tablet screenshots to iPad 13"
307
+ ipad13: localeScreenshots.tablet
308
+ }
309
+ };
310
+ }
311
+ const appStoreLocaleKeys = Object.keys(appStoreLocales);
312
+ if (appStoreLocaleKeys.length > 0) {
313
+ const hasConfigDefault = isAppStoreLocale(defaultLocale) && Boolean(appStoreLocales[defaultLocale]);
314
+ const resolvedDefault = hasConfigDefault ? defaultLocale : appStoreLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : appStoreLocaleKeys[0];
315
+ asoData.appStore = {
316
+ locales: appStoreLocales,
317
+ defaultLocale: resolvedDefault,
318
+ // App-level contact information
319
+ contactEmail: metadata.contactEmail,
320
+ supportUrl: metadata.supportUrl,
321
+ marketingUrl: metadata.marketingUrl,
322
+ privacyPolicyUrl: metadata.privacyUrl,
323
+ termsUrl: metadata.termsUrl
324
+ };
325
+ }
326
+ }
327
+ const hasGooglePlay = !!asoData.googlePlay;
328
+ const hasAppStore = !!asoData.appStore;
329
+ console.debug(`[loadAsoFromConfig] Result for ${slug}:`);
330
+ console.debug(
331
+ ` - Google Play data: ${hasGooglePlay ? "found" : "not found"}`
332
+ );
333
+ console.debug(` - App Store data: ${hasAppStore ? "found" : "not found"}`);
334
+ if (!hasGooglePlay && !hasAppStore) {
335
+ console.warn(`[loadAsoFromConfig] No ASO data generated for ${slug}`);
336
+ }
337
+ return asoData;
338
+ } catch (error) {
339
+ console.error(
340
+ `[loadAsoFromConfig] Failed to load ASO data from config for ${slug}:`,
341
+ error
342
+ );
343
+ return {};
344
+ }
345
+ }
346
+ function saveAsoToConfig(slug, config) {
347
+ const productsDir = getProductsDir();
348
+ const configPath = path2.join(productsDir, slug, "config.json");
349
+ fs2.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
350
+ }
351
+ function saveAsoToAsoDir(slug, asoData) {
352
+ const rootDir = getPushDataDir();
353
+ if (asoData.googlePlay) {
354
+ const asoPath = path2.join(
355
+ rootDir,
356
+ "products",
357
+ slug,
358
+ "store",
359
+ "google-play",
360
+ "aso-data.json"
361
+ );
362
+ const dir = path2.dirname(asoPath);
363
+ if (!fs2.existsSync(dir)) {
364
+ fs2.mkdirSync(dir, { recursive: true });
365
+ }
366
+ const googlePlayData = asoData.googlePlay;
367
+ const multilingualData = "locales" in googlePlayData ? googlePlayData : {
368
+ locales: {
369
+ [googlePlayData.defaultLanguage || DEFAULT_LOCALE]: googlePlayData
370
+ },
371
+ defaultLocale: googlePlayData.defaultLanguage || DEFAULT_LOCALE
372
+ };
373
+ fs2.writeFileSync(
374
+ asoPath,
375
+ JSON.stringify({ googlePlay: multilingualData }, null, 2) + "\n",
376
+ "utf-8"
377
+ );
378
+ }
379
+ if (asoData.appStore) {
380
+ const asoPath = path2.join(
381
+ rootDir,
382
+ "products",
383
+ slug,
384
+ "store",
385
+ "app-store",
386
+ "aso-data.json"
387
+ );
388
+ const dir = path2.dirname(asoPath);
389
+ if (!fs2.existsSync(dir)) {
390
+ fs2.mkdirSync(dir, { recursive: true });
391
+ }
392
+ const appStoreData = asoData.appStore;
393
+ const multilingualData = "locales" in appStoreData ? appStoreData : {
394
+ locales: {
395
+ [appStoreData.locale || DEFAULT_LOCALE]: appStoreData
396
+ },
397
+ defaultLocale: appStoreData.locale || DEFAULT_LOCALE
398
+ };
399
+ fs2.writeFileSync(
400
+ asoPath,
401
+ JSON.stringify({ appStore: multilingualData }, null, 2) + "\n",
402
+ "utf-8"
403
+ );
404
+ }
405
+ }
406
+
407
+ export {
408
+ getAsoDataDir,
409
+ getPullDataDir,
410
+ getPushDataDir,
411
+ getPublicDir,
412
+ getKeywordResearchDir,
413
+ getProductsDir,
414
+ getGeminiApiKey,
415
+ loadAsoFromConfig,
416
+ saveAsoToConfig,
417
+ saveAsoToAsoDir
418
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { w as AsoData, $ as ProductConfig } from './locale-converter-CTItgoKU.js';
2
- export { A as APP_STORE_TO_UNIFIED, Y as AppIconConfig, X as AppIconStyleConfig, F as AppMetaLinks, H as AppPageData, t as AppStoreAsoData, p as AppStoreInfoLocalization, d as AppStoreLocale, v as AppStoreMultilingualAsoData, o as AppStoreReleaseNote, r as AppStoreScreenshotDisplayType, s as AppStoreScreenshots, q as AppStoreVersionLocalization, a1 as AsoLocaleContent, a0 as AsoTemplate, C as BlogArticle, z as BlogMeta, B as BlogMetaBlock, ac as BlogMetaOutput, E as BlogSummary, ad as CreateBlogHtmlInput, af as CreateBlogHtmlResult, D as DEFAULT_LOCALE, R as DeepPartial, M as FeatureItem, G as GOOGLE_PLAY_TO_UNIFIED, ae as GeneratedBlogFile, m as GooglePlayAsoData, j as GooglePlayImageType, h as GooglePlayListing, e as GooglePlayLocale, u as GooglePlayMultilingualAsoData, n as GooglePlayReleaseNote, k as GooglePlayScreenshotType, l as GooglePlayScreenshots, I as ImageAsset, P as LandingCta, N as LandingFeatures, J as LandingHero, Q as LandingPage, V as LandingPageLocale, O as LandingReviews, K as LandingScreenshots, L as LayoutColors, a7 as LocaleDisplayInfo, _ as ProductContent, a2 as ProductLocale, Z as ProductMetadata, W as ProductScreenshots, ab as ResolvedWorkData, a5 as ScreenshotGeneratorConfig, a4 as ScreenshotGeneratorSlideConfig, a3 as ScreenshotGeneratorThemeTokens, a6 as SiteConfig, a8 as SiteData, S as SupportedLocale, T as Testimonial, U as UNIFIED_LOCALES, a as UNIFIED_TO_APP_STORE, b as UNIFIED_TO_GOOGLE_PLAY, c as UnifiedLocale, a9 as WorkItem, aa as WorkLocaleData, ap as appStoreToGooglePlay, aj as appStoreToUnified, an as appStoreToUnifiedBatch, at as convertObjectFromAppStore, au as convertObjectFromGooglePlay, ar as convertObjectToAppStore, as as convertObjectToGooglePlay, aq as googlePlayToAppStore, ak as googlePlayToUnified, ao as googlePlayToUnifiedBatch, f as isAppStoreLocale, y as isAppStoreMultilingual, g as isGooglePlayLocale, x as isGooglePlayMultilingual, i as isSupportedLocale, ag as unifiedToAppStore, al as unifiedToAppStoreBatch, ai as unifiedToBothPlatforms, ah as unifiedToGooglePlay, am as unifiedToGooglePlayBatch } from './locale-converter-CTItgoKU.js';
1
+ import { w as AsoData, $ as ProductConfig } from './locale-converter-CzWIV3a-.js';
2
+ export { A as APP_STORE_TO_UNIFIED, Y as AppIconConfig, X as AppIconStyleConfig, F as AppMetaLinks, H as AppPageData, t as AppStoreAsoData, p as AppStoreInfoLocalization, d as AppStoreLocale, v as AppStoreMultilingualAsoData, o as AppStoreReleaseNote, r as AppStoreScreenshotDisplayType, s as AppStoreScreenshots, q as AppStoreVersionLocalization, a1 as AsoLocaleContent, a0 as AsoTemplate, C as BlogArticle, z as BlogMeta, B as BlogMetaBlock, ac as BlogMetaOutput, E as BlogSummary, ad as CreateBlogHtmlInput, af as CreateBlogHtmlResult, D as DEFAULT_LOCALE, R as DeepPartial, M as FeatureItem, G as GOOGLE_PLAY_TO_UNIFIED, ae as GeneratedBlogFile, m as GooglePlayAsoData, j as GooglePlayImageType, h as GooglePlayListing, e as GooglePlayLocale, u as GooglePlayMultilingualAsoData, n as GooglePlayReleaseNote, k as GooglePlayScreenshotType, l as GooglePlayScreenshots, I as ImageAsset, P as LandingCta, N as LandingFeatures, J as LandingHero, Q as LandingPage, V as LandingPageLocale, O as LandingReviews, K as LandingScreenshots, L as LayoutColors, a7 as LocaleDisplayInfo, _ as ProductContent, a2 as ProductLocale, Z as ProductMetadata, W as ProductScreenshots, ab as ResolvedWorkData, a5 as ScreenshotGeneratorConfig, a4 as ScreenshotGeneratorSlideConfig, a3 as ScreenshotGeneratorThemeTokens, a6 as SiteConfig, a8 as SiteData, S as SupportedLocale, T as Testimonial, U as UNIFIED_LOCALES, a as UNIFIED_TO_APP_STORE, b as UNIFIED_TO_GOOGLE_PLAY, c as UnifiedLocale, a9 as WorkItem, aa as WorkLocaleData, ap as appStoreToGooglePlay, aj as appStoreToUnified, an as appStoreToUnifiedBatch, at as convertObjectFromAppStore, au as convertObjectFromGooglePlay, ar as convertObjectToAppStore, as as convertObjectToGooglePlay, aq as googlePlayToAppStore, ak as googlePlayToUnified, ao as googlePlayToUnifiedBatch, f as isAppStoreLocale, y as isAppStoreMultilingual, g as isGooglePlayLocale, x as isGooglePlayMultilingual, i as isSupportedLocale, ag as unifiedToAppStore, al as unifiedToAppStoreBatch, ai as unifiedToBothPlatforms, ah as unifiedToGooglePlay, am as unifiedToGooglePlayBatch } from './locale-converter-CzWIV3a-.js';
3
3
  import '@googleapis/androidpublisher';
4
4
  import 'appstore-connect-sdk/openapi';
5
5
 
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  loadAsoFromConfig,
10
10
  saveAsoToAsoDir,
11
11
  saveAsoToConfig
12
- } from "./chunk-H4MYWLFK.js";
12
+ } from "./chunk-REQG4DR7.js";
13
13
  import {
14
14
  APP_STORE_TO_UNIFIED,
15
15
  DEFAULT_LOCALE,
@@ -0,0 +1,884 @@
1
+ import { androidpublisher_v3 } from '@googleapis/androidpublisher';
2
+ import { AppStoreVersionAttributes, AppStoreVersionLocalizationAttributes, AppInfoLocalizationAttributes, ScreenshotDisplayType } from 'appstore-connect-sdk/openapi';
3
+
4
+ /**
5
+ * Unified locale system for ASO (App Store Optimization)
6
+ * Consolidates App Store Connect and Google Play Console locale codes
7
+ */
8
+ /**
9
+ * Unified locale codes used across the application
10
+ * These codes are used in /locales directory structure
11
+ */
12
+ declare const UNIFIED_LOCALES: readonly ["af", "am", "ar", "az-AZ", "be", "bg-BG", "bn-BD", "ca-ES", "cs-CZ", "da-DK", "de-DE", "el-GR", "en-AU", "en-CA", "en-GB", "en-IN", "en-SG", "en-US", "en-ZA", "es-419", "es-ES", "es-US", "et-EE", "eu-ES", "fa", "fa-AE", "fa-AF", "fa-IR", "fi-FI", "fil", "fr-CA", "fr-FR", "gl-ES", "gu", "he-IL", "hi-IN", "hr-HR", "hu-HU", "hy-AM", "id-ID", "is-IS", "it-IT", "ja-JP", "ka-GE", "kk", "km-KH", "kn-IN", "ko-KR", "ky-KG", "lo-LA", "lt-LT", "lv-LV", "mk-MK", "ml-IN", "mn-MN", "mr-IN", "ms", "ms-MY", "my-MM", "ne-NP", "nl-NL", "no-NO", "pa", "pl-PL", "pt-BR", "pt-PT", "rm", "ro-RO", "ru-RU", "si-LK", "sk-SK", "sl-SI", "sq", "sr-RS", "sv-SE", "sw", "ta-IN", "te-IN", "th-TH", "tr-TR", "uk-UA", "ur", "vi-VN", "zh-HK", "zh-Hans", "zh-Hant", "zu"];
13
+ type UnifiedLocale = (typeof UNIFIED_LOCALES)[number];
14
+ /**
15
+ * Default locale (for fallback)
16
+ */
17
+ declare const DEFAULT_LOCALE: UnifiedLocale;
18
+ /**
19
+ * Unified locale to App Store Connect locale mapping
20
+ * Maps our unified locale codes to App Store Connect API codes
21
+ */
22
+ declare const UNIFIED_TO_APP_STORE: Record<UnifiedLocale, string | null>;
23
+ /**
24
+ * Unified locale to Google Play Console locale mapping
25
+ * Maps our unified locale codes to Google Play Console API codes
26
+ */
27
+ declare const UNIFIED_TO_GOOGLE_PLAY: Record<UnifiedLocale, string | null>;
28
+ /**
29
+ * App Store Connect locale to unified locale mapping
30
+ * Reverse mapping for converting App Store codes to our unified system
31
+ */
32
+ declare const APP_STORE_TO_UNIFIED: Record<string, UnifiedLocale>;
33
+ /**
34
+ * Google Play Console locale to unified locale mapping
35
+ * Reverse mapping for converting Google Play codes to our unified system
36
+ */
37
+ declare const GOOGLE_PLAY_TO_UNIFIED: Record<string, UnifiedLocale>;
38
+ /**
39
+ * Locales supported by App Store Connect
40
+ */
41
+ declare const APP_STORE_SUPPORTED_LOCALES: ("af" | "am" | "ar" | "az-AZ" | "be" | "bg-BG" | "bn-BD" | "ca-ES" | "cs-CZ" | "da-DK" | "de-DE" | "el-GR" | "en-AU" | "en-CA" | "en-GB" | "en-IN" | "en-SG" | "en-US" | "en-ZA" | "es-419" | "es-ES" | "es-US" | "et-EE" | "eu-ES" | "fa" | "fa-AE" | "fa-AF" | "fa-IR" | "fi-FI" | "fil" | "fr-CA" | "fr-FR" | "gl-ES" | "gu" | "he-IL" | "hi-IN" | "hr-HR" | "hu-HU" | "hy-AM" | "id-ID" | "is-IS" | "it-IT" | "ja-JP" | "ka-GE" | "kk" | "km-KH" | "kn-IN" | "ko-KR" | "ky-KG" | "lo-LA" | "lt-LT" | "lv-LV" | "mk-MK" | "ml-IN" | "mn-MN" | "mr-IN" | "ms" | "ms-MY" | "my-MM" | "ne-NP" | "nl-NL" | "no-NO" | "pa" | "pl-PL" | "pt-BR" | "pt-PT" | "rm" | "ro-RO" | "ru-RU" | "si-LK" | "sk-SK" | "sl-SI" | "sq" | "sr-RS" | "sv-SE" | "sw" | "ta-IN" | "te-IN" | "th-TH" | "tr-TR" | "uk-UA" | "ur" | "vi-VN" | "zh-HK" | "zh-Hans" | "zh-Hant" | "zu")[];
42
+ /**
43
+ * Locales supported by Google Play Console
44
+ */
45
+ declare const GOOGLE_PLAY_SUPPORTED_LOCALES: ("af" | "am" | "ar" | "az-AZ" | "be" | "bg-BG" | "bn-BD" | "ca-ES" | "cs-CZ" | "da-DK" | "de-DE" | "el-GR" | "en-AU" | "en-CA" | "en-GB" | "en-IN" | "en-SG" | "en-US" | "en-ZA" | "es-419" | "es-ES" | "es-US" | "et-EE" | "eu-ES" | "fa" | "fa-AE" | "fa-AF" | "fa-IR" | "fi-FI" | "fil" | "fr-CA" | "fr-FR" | "gl-ES" | "gu" | "he-IL" | "hi-IN" | "hr-HR" | "hu-HU" | "hy-AM" | "id-ID" | "is-IS" | "it-IT" | "ja-JP" | "ka-GE" | "kk" | "km-KH" | "kn-IN" | "ko-KR" | "ky-KG" | "lo-LA" | "lt-LT" | "lv-LV" | "mk-MK" | "ml-IN" | "mn-MN" | "mr-IN" | "ms" | "ms-MY" | "my-MM" | "ne-NP" | "nl-NL" | "no-NO" | "pa" | "pl-PL" | "pt-BR" | "pt-PT" | "rm" | "ro-RO" | "ru-RU" | "si-LK" | "sk-SK" | "sl-SI" | "sq" | "sr-RS" | "sv-SE" | "sw" | "ta-IN" | "te-IN" | "th-TH" | "tr-TR" | "uk-UA" | "ur" | "vi-VN" | "zh-HK" | "zh-Hans" | "zh-Hant" | "zu")[];
46
+
47
+ /**
48
+ * ASO (App Store Optimization) data type definitions
49
+ */
50
+
51
+ /**
52
+ * Unified locale type used across the application
53
+ * This type represents the unified locale codes used in /locales directory
54
+ */
55
+ type SupportedLocale = UnifiedLocale;
56
+ /**
57
+ * App Store Connect specific locale type
58
+ */
59
+ type AppStoreLocale = (typeof APP_STORE_SUPPORTED_LOCALES)[number];
60
+ /**
61
+ * Google Play Console specific locale type
62
+ */
63
+ type GooglePlayLocale = (typeof GOOGLE_PLAY_SUPPORTED_LOCALES)[number];
64
+ /**
65
+ * Check if locale is supported by our unified system
66
+ */
67
+ declare function isSupportedLocale(locale: string): locale is SupportedLocale;
68
+ /**
69
+ * Check if locale is supported by App Store
70
+ */
71
+ declare function isAppStoreLocale(locale: string): locale is AppStoreLocale;
72
+ /**
73
+ * Check if locale is supported by Google Play
74
+ */
75
+ declare function isGooglePlayLocale(locale: string): locale is GooglePlayLocale;
76
+ /**
77
+ * Google Play Android Publisher base types
78
+ */
79
+ type GooglePlayListing = androidpublisher_v3.Schema$Listing;
80
+ type GooglePlayImageType = NonNullable<androidpublisher_v3.Params$Resource$Edits$Images$List["imageType"]>;
81
+ type GooglePlayScreenshotType = Extract<GooglePlayImageType, "phoneScreenshots" | "sevenInchScreenshots" | "tenInchScreenshots" | "tvScreenshots" | "wearScreenshots">;
82
+ /**
83
+ * Google Play screenshots keyed by Android Publisher imageType
84
+ * Includes legacy aliases for existing data structures
85
+ */
86
+ interface GooglePlayScreenshots extends Partial<Record<GooglePlayScreenshotType, string[]>> {
87
+ phone?: string[];
88
+ tablet?: string[];
89
+ tablet7?: string[];
90
+ tablet10?: string[];
91
+ tv?: string[];
92
+ wear?: string[];
93
+ }
94
+ /**
95
+ * Google Play Store ASO data
96
+ */
97
+ interface GooglePlayAsoData extends Pick<GooglePlayListing, "video" | "language"> {
98
+ title: NonNullable<GooglePlayListing["title"]>;
99
+ shortDescription: NonNullable<GooglePlayListing["shortDescription"]>;
100
+ fullDescription: NonNullable<GooglePlayListing["fullDescription"]>;
101
+ screenshots: GooglePlayScreenshots;
102
+ featureGraphic?: string;
103
+ promoGraphic?: string;
104
+ category?: string;
105
+ contentRating?: string;
106
+ keywords?: string[];
107
+ contactEmail?: string;
108
+ contactPhone?: string;
109
+ contactWebsite?: string;
110
+ packageName: string;
111
+ defaultLanguage: string;
112
+ }
113
+ /**
114
+ * Google Play release notes (per version)
115
+ */
116
+ type GooglePlayReleaseNote = androidpublisher_v3.Schema$TrackRelease;
117
+ /**
118
+ * App Store release notes (per version)
119
+ */
120
+ type AppStoreReleaseNote = Pick<AppStoreVersionAttributes, "versionString" | "platform"> & {
121
+ releaseNotes: Record<string, NonNullable<AppStoreVersionLocalizationAttributes["whatsNew"]>>;
122
+ releaseDate?: string;
123
+ };
124
+ /**
125
+ * App Store Connect base types
126
+ */
127
+ type AppStoreInfoLocalization = AppInfoLocalizationAttributes;
128
+ type AppStoreVersionLocalization = AppStoreVersionLocalizationAttributes;
129
+ type AppStoreScreenshotDisplayType = ScreenshotDisplayType;
130
+ /**
131
+ * App Store screenshots keyed by official display type
132
+ * Includes legacy aliases used in existing data structures
133
+ */
134
+ interface AppStoreScreenshots extends Partial<Record<AppStoreScreenshotDisplayType, string[]>> {
135
+ iphone65?: string[];
136
+ iphone61?: string[];
137
+ iphone58?: string[];
138
+ iphone55?: string[];
139
+ iphone47?: string[];
140
+ iphone40?: string[];
141
+ ipad13?: string[];
142
+ ipadPro129?: string[];
143
+ ipadPro11?: string[];
144
+ ipad105?: string[];
145
+ ipad97?: string[];
146
+ appleWatch?: string[];
147
+ }
148
+ /**
149
+ * App Store ASO data
150
+ */
151
+ interface AppStoreAsoData {
152
+ name: NonNullable<AppStoreInfoLocalization["name"]>;
153
+ subtitle?: AppStoreInfoLocalization["subtitle"];
154
+ description: NonNullable<AppStoreVersionLocalization["description"]>;
155
+ keywords?: AppStoreVersionLocalization["keywords"];
156
+ promotionalText?: AppStoreVersionLocalization["promotionalText"];
157
+ screenshots: AppStoreScreenshots;
158
+ appPreview?: string[];
159
+ primaryCategory?: string;
160
+ secondaryCategory?: string;
161
+ contentRightId?: string;
162
+ supportUrl?: AppStoreVersionLocalization["supportUrl"];
163
+ marketingUrl?: AppStoreVersionLocalization["marketingUrl"];
164
+ privacyPolicyUrl?: AppStoreInfoLocalization["privacyPolicyUrl"];
165
+ termsUrl?: string;
166
+ bundleId: string;
167
+ locale: NonNullable<AppStoreVersionLocalization["locale"]>;
168
+ whatsNew?: AppStoreVersionLocalization["whatsNew"];
169
+ }
170
+ /**
171
+ * Multilingual Google Play ASO data
172
+ */
173
+ interface GooglePlayMultilingualAsoData {
174
+ locales: {
175
+ [locale: string]: GooglePlayAsoData;
176
+ };
177
+ defaultLocale?: string;
178
+ contactEmail?: string;
179
+ contactWebsite?: string;
180
+ youtubeUrl?: string;
181
+ }
182
+ /**
183
+ * Multilingual App Store ASO data
184
+ */
185
+ interface AppStoreMultilingualAsoData {
186
+ locales: {
187
+ [locale: string]: AppStoreAsoData;
188
+ };
189
+ defaultLocale?: string;
190
+ contactEmail?: string;
191
+ supportUrl?: string;
192
+ marketingUrl?: string;
193
+ privacyPolicyUrl?: string;
194
+ termsUrl?: string;
195
+ }
196
+ /**
197
+ * Unified ASO data (format stored in local config.json)
198
+ * Supports single language (legacy compatible) or multilingual structure
199
+ */
200
+ interface AsoData {
201
+ googlePlay?: GooglePlayAsoData | GooglePlayMultilingualAsoData;
202
+ appStore?: AppStoreAsoData | AppStoreMultilingualAsoData;
203
+ lastSynced?: {
204
+ googlePlay?: string;
205
+ appStore?: string;
206
+ };
207
+ }
208
+ /**
209
+ * Check if Google Play data is multilingual structure
210
+ */
211
+ declare function isGooglePlayMultilingual(data: GooglePlayAsoData | GooglePlayMultilingualAsoData | undefined): data is GooglePlayMultilingualAsoData;
212
+ /**
213
+ * Check if App Store data is multilingual structure
214
+ */
215
+ declare function isAppStoreMultilingual(data: AppStoreAsoData | AppStoreMultilingualAsoData | undefined): data is AppStoreMultilingualAsoData;
216
+
217
+ /**
218
+ * Blog type definitions
219
+ * Used by both MCP tools and web application
220
+ */
221
+ /**
222
+ * Blog Meta Block (raw from HTML comment)
223
+ * All fields are optional as they may be parsed from HTML or defaults
224
+ */
225
+ interface BlogMetaBlock {
226
+ title: string;
227
+ description: string;
228
+ appSlug: string;
229
+ slug: string;
230
+ locale?: string;
231
+ coverImage?: string;
232
+ publishedAt?: string;
233
+ modifiedAt?: string;
234
+ tags?: string[];
235
+ }
236
+ /**
237
+ * Blog Meta (resolved with UnifiedLocale)
238
+ * Used by web application after normalization
239
+ */
240
+ interface BlogMeta extends BlogMetaBlock {
241
+ locale: UnifiedLocale;
242
+ coverImage?: string;
243
+ publishedAt?: string;
244
+ modifiedAt?: string;
245
+ }
246
+ /**
247
+ * Blog Article (complete parsed article with HTML content)
248
+ */
249
+ interface BlogArticle {
250
+ appSlug: string;
251
+ slug: string;
252
+ locale: UnifiedLocale;
253
+ html: string;
254
+ meta: BlogMeta;
255
+ filePath: string;
256
+ }
257
+ /**
258
+ * Blog Summary (aggregated metadata across locales)
259
+ */
260
+ interface BlogSummary {
261
+ appSlug: string;
262
+ slug: string;
263
+ title: string;
264
+ description: string;
265
+ coverImage?: string;
266
+ publishedAt?: string;
267
+ modifiedAt?: string;
268
+ locales: UnifiedLocale[];
269
+ defaultLocale: UnifiedLocale;
270
+ }
271
+
272
+ interface ImageAsset {
273
+ src: string;
274
+ alt: string;
275
+ width?: number;
276
+ height?: number;
277
+ srcDark?: string;
278
+ }
279
+ interface LandingHero {
280
+ brand?: string;
281
+ logoPath?: string;
282
+ title?: string;
283
+ titleHighlight?: string;
284
+ description: string;
285
+ }
286
+ interface LandingScreenshots {
287
+ title?: string;
288
+ images: Array<{
289
+ imageSrc: string;
290
+ width?: number;
291
+ height?: number;
292
+ title: string;
293
+ description: string;
294
+ }>;
295
+ }
296
+ interface FeatureItem {
297
+ title: string;
298
+ body: string;
299
+ iconPath?: string;
300
+ iconName?: string;
301
+ media?: ImageAsset;
302
+ badge?: string;
303
+ }
304
+ interface LandingFeatures {
305
+ title: string;
306
+ items: FeatureItem[];
307
+ }
308
+ interface Testimonial {
309
+ authorName: string;
310
+ handle?: string;
311
+ avatarPath?: string;
312
+ quote: string;
313
+ rating?: number;
314
+ }
315
+ interface LandingReviews {
316
+ title?: string;
317
+ description?: string;
318
+ testimonials: Testimonial[];
319
+ icons?: string[];
320
+ rating?: number;
321
+ }
322
+ interface LandingCta {
323
+ headline: string;
324
+ icons?: string[];
325
+ rating?: number;
326
+ description?: string;
327
+ }
328
+ interface LandingPage {
329
+ hero: LandingHero;
330
+ screenshots: LandingScreenshots;
331
+ features: LandingFeatures;
332
+ reviews: LandingReviews;
333
+ cta: LandingCta;
334
+ }
335
+ type DeepPartial<T> = T extends (infer U)[] ? Array<DeepPartial<U>> : T extends object ? {
336
+ [P in keyof T]?: DeepPartial<T[P]>;
337
+ } : T;
338
+ type LandingPageLocale = DeepPartial<LandingPage>;
339
+
340
+ /**
341
+ * Product Config JSON file type definitions
342
+ * Structure for public/products/{slug}/config.json
343
+ */
344
+ /**
345
+ * Screenshot metadata
346
+ */
347
+ interface ProductScreenshots {
348
+ /**
349
+ * When true, the first screenshot is a marketing cover.
350
+ * Detail pages may use it in the hero while excluding it from feature galleries.
351
+ */
352
+ hasCover?: boolean;
353
+ phone?: string[];
354
+ tablet?: string[];
355
+ }
356
+ /**
357
+ * App Icon style configuration
358
+ */
359
+ interface AppIconStyleConfig {
360
+ backgroundColor?: string;
361
+ alignment?: "center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
362
+ }
363
+ /**
364
+ * App Icon configuration
365
+ */
366
+ interface AppIconConfig {
367
+ /** Default background color for app icons (hex format, e.g., "#FFFFFF") */
368
+ defaultBackgroundColor?: string;
369
+ /** Default logo alignment */
370
+ defaultAlignment?: "center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
371
+ /** Style-specific configurations (e.g., christmas, halloween) */
372
+ styles?: Record<string, AppIconStyleConfig>;
373
+ }
374
+ /**
375
+ * Product Metadata (store-common metadata)
376
+ */
377
+ interface ProductMetadata {
378
+ category?: string;
379
+ contactEmail?: string;
380
+ instagram?: string;
381
+ supportUrl?: string;
382
+ marketingUrl?: string;
383
+ termsUrl?: string;
384
+ privacyUrl?: string;
385
+ youtubeUrl?: string;
386
+ screenshots?: ProductScreenshots;
387
+ featureGraphic?: string;
388
+ /** Background color for screenshot resizing (hex format, e.g., "#FFFFFF") */
389
+ screenshotBgColor?: string;
390
+ }
391
+ /**
392
+ * Product Content settings
393
+ */
394
+ interface ProductContent {
395
+ defaultLocale?: string;
396
+ }
397
+ /**
398
+ * Product Config (complete config.json structure)
399
+ *
400
+ * Based on actual config.json file structure,
401
+ * includes additional fields used by existing code.
402
+ */
403
+ interface ProductConfig {
404
+ slug: string;
405
+ order?: number;
406
+ appStoreAppId?: string;
407
+ packageName?: string;
408
+ bundleId?: string;
409
+ isHiddenAtHomepage?: boolean;
410
+ isHiddenOnHome?: boolean;
411
+ layoutColors?: LayoutColors;
412
+ metadata?: ProductMetadata;
413
+ content?: ProductContent;
414
+ appIcon?: AppIconConfig;
415
+ extraPaths?: string[];
416
+ name?: string;
417
+ tagline?: string;
418
+ webUrl?: string;
419
+ hasDetailPage?: boolean;
420
+ isDarkIcon?: boolean;
421
+ landing?: LandingPage;
422
+ }
423
+
424
+ interface LayoutColors {
425
+ bg?: string;
426
+ fg?: string;
427
+ fgMuted?: string;
428
+ muted?: string;
429
+ accentGrad?: string;
430
+ }
431
+ interface AppMetaLinks {
432
+ privacyPath: string;
433
+ termsPath: string;
434
+ backPath: string;
435
+ }
436
+ interface AppPageData {
437
+ product?: ProductConfig;
438
+ links: AppMetaLinks;
439
+ privacy: string;
440
+ terms: string;
441
+ layoutColors?: LayoutColors;
442
+ landing?: LandingPage;
443
+ }
444
+
445
+ interface AsoTemplate {
446
+ intro: string;
447
+ keyFeaturesHeading?: string;
448
+ featuresHeading?: string;
449
+ outro: string;
450
+ includeSupportLinks?: boolean;
451
+ }
452
+ interface AsoLocaleContent {
453
+ title?: string;
454
+ subtitle?: string;
455
+ shortDescription?: string;
456
+ keywords?: string[] | string;
457
+ template?: AsoTemplate;
458
+ }
459
+ interface ProductLocale {
460
+ aso?: AsoLocaleContent;
461
+ landing?: LandingPageLocale;
462
+ }
463
+
464
+ /**
465
+ * Screenshot generator configuration types
466
+ * Structure for public/products/{slug}/screenshot-generator.config.json
467
+ */
468
+ interface ScreenshotGeneratorThemeTokens {
469
+ backgroundStart: string;
470
+ backgroundEnd: string;
471
+ panel: string;
472
+ textPrimary: string;
473
+ textSecondary: string;
474
+ accent: string;
475
+ }
476
+ interface ScreenshotGeneratorSlideConfig {
477
+ fileName: string;
478
+ badge?: string;
479
+ headline?: string;
480
+ }
481
+ interface ScreenshotGeneratorConfig {
482
+ title?: string;
483
+ subtitle?: string;
484
+ statusLabel?: string;
485
+ layoutVariant?: "showcase-dark" | "clean-light";
486
+ accentGradient?: string;
487
+ theme?: Partial<ScreenshotGeneratorThemeTokens>;
488
+ slides?: ScreenshotGeneratorSlideConfig[];
489
+ }
490
+
491
+ /**
492
+ * Site data type definitions
493
+ * Structure for public/site/ directory
494
+ * - config.json: Site configuration (supported locales, default locale)
495
+ * - contacts.json: Contact information
496
+ * - locales/en-US.json: Localized content (meta, hero, developer)
497
+ */
498
+
499
+ /**
500
+ * Site configuration for locale support
501
+ * Stored in public/site/config.json
502
+ */
503
+ interface SiteConfig {
504
+ /** List of locales supported by this site */
505
+ supportedLocales: UnifiedLocale[];
506
+ /** Default locale for fallback */
507
+ defaultLocale: UnifiedLocale;
508
+ }
509
+ /**
510
+ * Locale display information for UI components
511
+ */
512
+ interface LocaleDisplayInfo {
513
+ /** Locale code (e.g., "en-US", "ko-KR") */
514
+ code: UnifiedLocale;
515
+ /** English name of the language */
516
+ name: string;
517
+ /** Native name of the language */
518
+ nativeName: string;
519
+ /** Flag emoji */
520
+ flag: string;
521
+ }
522
+ interface SiteData {
523
+ meta: {
524
+ title: string;
525
+ description: string;
526
+ };
527
+ hero: {
528
+ brand: string;
529
+ tagline: string;
530
+ subtitle: string;
531
+ };
532
+ contacts: {
533
+ id: string;
534
+ label: string;
535
+ icon: string;
536
+ value: string;
537
+ }[];
538
+ developer: {
539
+ name: string;
540
+ heading: string;
541
+ role: string;
542
+ bio: string;
543
+ principles: string[];
544
+ stack: string[];
545
+ now: string;
546
+ availability: string;
547
+ likes: string[];
548
+ location?: string;
549
+ timezone?: string;
550
+ visited: {
551
+ countries: {
552
+ code: string;
553
+ name: string;
554
+ flagEmoji: string;
555
+ cities: string[];
556
+ }[];
557
+ };
558
+ };
559
+ }
560
+
561
+ interface WorkItem {
562
+ id: string;
563
+ title: string;
564
+ summary: string;
565
+ period?: string;
566
+ screenshotUrl?: string;
567
+ techStack?: string[];
568
+ tags?: string[];
569
+ links?: string[];
570
+ order?: number;
571
+ }
572
+ interface WorkLocaleData {
573
+ items: WorkItem[];
574
+ }
575
+ interface ResolvedWorkData {
576
+ items: WorkItem[];
577
+ usedLocale: string;
578
+ }
579
+
580
+ /**
581
+ * Types for the create-blog-html MCP tool
582
+ */
583
+ /**
584
+ * BlogMetaOutput for MCP tool output
585
+ * All fields are required (resolved values)
586
+ * Note: This is separate from blog.types.ts BlogMeta which uses UnifiedLocale
587
+ */
588
+ interface BlogMetaOutput {
589
+ title: string;
590
+ description: string;
591
+ appSlug: string;
592
+ slug: string;
593
+ locale: string;
594
+ publishedAt: string;
595
+ modifiedAt: string;
596
+ coverImage: string;
597
+ tags: string[];
598
+ }
599
+ interface CreateBlogHtmlInput {
600
+ /**
601
+ * Product/app slug used for paths and CTAs.
602
+ * Defaults to "developer-journal" when not provided.
603
+ */
604
+ appSlug: string;
605
+ /**
606
+ * English title used for slug creation and H1
607
+ */
608
+ title?: string;
609
+ /**
610
+ * Topic/angle to cover inside the article body
611
+ */
612
+ topic: string;
613
+ /**
614
+ * Single locale to generate (REQUIRED). Ignored when locales[] is provided.
615
+ */
616
+ locale: string;
617
+ /**
618
+ * Optional list of locales to generate. Each gets its own HTML file.
619
+ */
620
+ locales?: string[];
621
+ /**
622
+ * HTML content for the blog body. REQUIRED. The LLM must generate this based on the topic and locale.
623
+ * Structure should follow public/en-US.html pattern.
624
+ */
625
+ content: string;
626
+ /**
627
+ * Meta description override. If absent, a locale-aware summary is generated from topic/appSlug.
628
+ */
629
+ description?: string;
630
+ /**
631
+ * Optional tags for BLOG_META. If absent, tags are derived from topic and appSlug.
632
+ */
633
+ tags?: string[];
634
+ /**
635
+ * Optional cover image. Relative paths are rewritten to /blogs/<app>/<slug>/...
636
+ */
637
+ coverImage?: string;
638
+ /**
639
+ * Include a relative image example in the body (./images/hero.png by default).
640
+ */
641
+ includeRelativeImageExample?: boolean;
642
+ /**
643
+ * Override the relative image path used when includeRelativeImageExample is true.
644
+ */
645
+ relativeImagePath?: string;
646
+ /**
647
+ * Publish date (YYYY-MM-DD). Defaults to today.
648
+ */
649
+ publishedAt?: string;
650
+ /**
651
+ * Last modified date (YYYY-MM-DD). Defaults to publishedAt.
652
+ */
653
+ modifiedAt?: string;
654
+ /**
655
+ * Overwrite existing HTML files when true (default false).
656
+ */
657
+ overwrite?: boolean;
658
+ }
659
+ interface GeneratedBlogFile {
660
+ locale: string;
661
+ path: string;
662
+ }
663
+ interface CreateBlogHtmlResult {
664
+ slug: string;
665
+ baseDir: string;
666
+ files: GeneratedBlogFile[];
667
+ coverImage: string;
668
+ metaByLocale: Record<string, BlogMetaOutput>;
669
+ }
670
+
671
+ /**
672
+ * Locale conversion utilities for ASO platforms
673
+ * Handles conversion between unified locales and platform-specific locale codes
674
+ */
675
+
676
+ /**
677
+ * Convert unified locale to App Store Connect locale
678
+ * Returns null if the locale is not supported by App Store
679
+ *
680
+ * @param locale - Unified locale code (e.g., "ar", "zh-Hans")
681
+ * @returns App Store locale code (e.g., "ar-SA", "zh-Hans") or null
682
+ *
683
+ * @example
684
+ * unifiedToAppStore("ar") // Returns "ar-SA"
685
+ * unifiedToAppStore("zh-Hans") // Returns "zh-Hans"
686
+ * unifiedToAppStore("en-IN") // Returns null (not supported)
687
+ */
688
+ declare function unifiedToAppStore(locale: UnifiedLocale): string | null;
689
+ /**
690
+ * Convert unified locale to Google Play Console locale
691
+ * Returns null if the locale is not supported by Google Play
692
+ *
693
+ * @param locale - Unified locale code (e.g., "ar", "zh-Hans")
694
+ * @returns Google Play locale code (e.g., "ar-SA", "zh-CN") or null
695
+ *
696
+ * @example
697
+ * unifiedToGooglePlay("ar") // Returns "ar-SA"
698
+ * unifiedToGooglePlay("zh-Hans") // Returns "zh-CN"
699
+ * unifiedToGooglePlay("bg-BG") // Returns "bg-BG"
700
+ */
701
+ declare function unifiedToGooglePlay(locale: UnifiedLocale): string | null;
702
+ /**
703
+ * Convert unified locale to both platforms
704
+ * Returns an object with App Store and Google Play locale codes
705
+ *
706
+ * @param locale - Unified locale code
707
+ * @returns Object with appStore and googlePlay locale codes (or null if not supported)
708
+ *
709
+ * @example
710
+ * unifiedToBothPlatforms("ar")
711
+ * // Returns { appStore: "ar-SA", googlePlay: "ar-SA" }
712
+ *
713
+ * unifiedToBothPlatforms("zh-Hans")
714
+ * // Returns { appStore: "zh-Hans", googlePlay: "zh-CN" }
715
+ */
716
+ declare function unifiedToBothPlatforms(locale: UnifiedLocale): {
717
+ appStore: string | null;
718
+ googlePlay: string | null;
719
+ };
720
+ /**
721
+ * Convert App Store Connect locale to unified locale
722
+ * Returns the default locale if the App Store locale is not recognized
723
+ *
724
+ * @param locale - App Store locale code (e.g., "ar-SA", "zh-Hans")
725
+ * @returns Unified locale code (e.g., "ar", "zh-Hans")
726
+ *
727
+ * @example
728
+ * appStoreToUnified("ar-SA") // Returns "ar"
729
+ * appStoreToUnified("zh-Hans") // Returns "zh-Hans"
730
+ * appStoreToUnified("es-MX") // Returns "es-419"
731
+ */
732
+ declare function appStoreToUnified(locale: string): UnifiedLocale;
733
+ /**
734
+ * Convert Google Play Console locale to unified locale
735
+ * Returns the default locale if the Google Play locale is not recognized
736
+ *
737
+ * @param locale - Google Play locale code (e.g., "ar-SA", "zh-CN")
738
+ * @returns Unified locale code (e.g., "ar", "zh-Hans")
739
+ *
740
+ * @example
741
+ * googlePlayToUnified("ar-SA") // Returns "ar"
742
+ * googlePlayToUnified("zh-CN") // Returns "zh-Hans"
743
+ * googlePlayToUnified("zh-TW") // Returns "zh-Hant"
744
+ */
745
+ declare function googlePlayToUnified(locale: string): UnifiedLocale;
746
+ /**
747
+ * Convert multiple unified locales to App Store locales
748
+ * Filters out locales not supported by App Store
749
+ *
750
+ * @param locales - Array of unified locale codes
751
+ * @returns Array of App Store locale codes (excluding unsupported locales)
752
+ *
753
+ * @example
754
+ * unifiedToAppStoreBatch(["ar", "zh-Hans", "en-IN"])
755
+ * // Returns ["ar-SA", "zh-Hans"] (en-IN is not supported by App Store)
756
+ */
757
+ declare function unifiedToAppStoreBatch(locales: UnifiedLocale[]): string[];
758
+ /**
759
+ * Convert multiple unified locales to Google Play locales
760
+ * Filters out locales not supported by Google Play
761
+ *
762
+ * @param locales - Array of unified locale codes
763
+ * @returns Array of Google Play locale codes (excluding unsupported locales)
764
+ *
765
+ * @example
766
+ * unifiedToGooglePlayBatch(["ar", "zh-Hans", "bg-BG"])
767
+ * // Returns ["ar-SA", "zh-CN", "bg-BG"]
768
+ */
769
+ declare function unifiedToGooglePlayBatch(locales: UnifiedLocale[]): string[];
770
+ /**
771
+ * Convert multiple App Store locales to unified locales
772
+ *
773
+ * @param locales - Array of App Store locale codes
774
+ * @returns Array of unified locale codes
775
+ *
776
+ * @example
777
+ * appStoreToUnifiedBatch(["ar-SA", "zh-Hans", "es-MX"])
778
+ * // Returns ["ar", "zh-Hans", "es-419"]
779
+ */
780
+ declare function appStoreToUnifiedBatch(locales: string[]): UnifiedLocale[];
781
+ /**
782
+ * Convert multiple Google Play locales to unified locales
783
+ *
784
+ * @param locales - Array of Google Play locale codes
785
+ * @returns Array of unified locale codes
786
+ *
787
+ * @example
788
+ * googlePlayToUnifiedBatch(["ar-SA", "zh-CN", "zh-TW"])
789
+ * // Returns ["ar", "zh-Hans", "zh-Hant"]
790
+ */
791
+ declare function googlePlayToUnifiedBatch(locales: string[]): UnifiedLocale[];
792
+ /**
793
+ * Convert App Store locale to Google Play locale
794
+ * Goes through unified locale as intermediate step
795
+ *
796
+ * @param locale - App Store locale code
797
+ * @returns Google Play locale code or null if conversion not possible
798
+ *
799
+ * @example
800
+ * appStoreToGooglePlay("ar-SA") // Returns "ar-SA"
801
+ * appStoreToGooglePlay("zh-Hans") // Returns "zh-CN"
802
+ * appStoreToGooglePlay("es-MX") // Returns "es-419"
803
+ */
804
+ declare function appStoreToGooglePlay(locale: string): string | null;
805
+ /**
806
+ * Convert Google Play locale to App Store locale
807
+ * Goes through unified locale as intermediate step
808
+ *
809
+ * @param locale - Google Play locale code
810
+ * @returns App Store locale code or null if conversion not possible
811
+ *
812
+ * @example
813
+ * googlePlayToAppStore("ar-SA") // Returns "ar-SA"
814
+ * googlePlayToAppStore("zh-CN") // Returns "zh-Hans"
815
+ * googlePlayToAppStore("zh-TW") // Returns "zh-Hant"
816
+ * googlePlayToAppStore("en-IN") // Returns null (not supported by App Store)
817
+ */
818
+ declare function googlePlayToAppStore(locale: string): string | null;
819
+ /**
820
+ * Convert an object with unified locale keys to App Store locale keys
821
+ * Useful for converting locale-based data structures
822
+ *
823
+ * @param data - Object with unified locale keys
824
+ * @returns Object with App Store locale keys (excluding unsupported locales)
825
+ *
826
+ * @example
827
+ * convertObjectToAppStore({
828
+ * "ar": "مرحبا",
829
+ * "zh-Hans": "你好",
830
+ * "en-IN": "Hello"
831
+ * })
832
+ * // Returns { "ar-SA": "مرحبا", "zh-Hans": "你好" }
833
+ */
834
+ declare function convertObjectToAppStore<T>(data: Record<UnifiedLocale, T>): Record<string, T>;
835
+ /**
836
+ * Convert an object with unified locale keys to Google Play locale keys
837
+ * Useful for converting locale-based data structures
838
+ *
839
+ * @param data - Object with unified locale keys
840
+ * @returns Object with Google Play locale keys (excluding unsupported locales)
841
+ *
842
+ * @example
843
+ * convertObjectToGooglePlay({
844
+ * "ar": "مرحبا",
845
+ * "zh-Hans": "你好",
846
+ * "zh-Hant": "你好"
847
+ * })
848
+ * // Returns { "ar-SA": "مرحبا", "zh-CN": "你好", "zh-TW": "你好" }
849
+ */
850
+ declare function convertObjectToGooglePlay<T>(data: Record<UnifiedLocale, T>): Record<string, T>;
851
+ /**
852
+ * Convert an object with App Store locale keys to unified locale keys
853
+ * Useful for converting locale-based data structures from App Store
854
+ *
855
+ * @param data - Object with App Store locale keys
856
+ * @returns Object with unified locale keys
857
+ *
858
+ * @example
859
+ * convertObjectFromAppStore({
860
+ * "ar-SA": "مرحبا",
861
+ * "zh-Hans": "你好",
862
+ * "es-MX": "Hola"
863
+ * })
864
+ * // Returns { "ar": "مرحبا", "zh-Hans": "你好", "es-419": "Hola" }
865
+ */
866
+ declare function convertObjectFromAppStore<T>(data: Record<string, T>): Record<UnifiedLocale, T>;
867
+ /**
868
+ * Convert an object with Google Play locale keys to unified locale keys
869
+ * Useful for converting locale-based data structures from Google Play
870
+ *
871
+ * @param data - Object with Google Play locale keys
872
+ * @returns Object with unified locale keys
873
+ *
874
+ * @example
875
+ * convertObjectFromGooglePlay({
876
+ * "ar-SA": "مرحبا",
877
+ * "zh-CN": "你好",
878
+ * "zh-TW": "你好"
879
+ * })
880
+ * // Returns { "ar": "مرحبا", "zh-Hans": "你好", "zh-Hant": "你好" }
881
+ */
882
+ declare function convertObjectFromGooglePlay<T>(data: Record<string, T>): Record<UnifiedLocale, T>;
883
+
884
+ export { type ProductConfig as $, APP_STORE_TO_UNIFIED as A, type BlogMetaBlock as B, type BlogArticle as C, DEFAULT_LOCALE as D, type BlogSummary as E, type AppMetaLinks as F, GOOGLE_PLAY_TO_UNIFIED as G, type AppPageData as H, type ImageAsset as I, type LandingHero as J, type LandingScreenshots as K, type LayoutColors as L, type FeatureItem as M, type LandingFeatures as N, type LandingReviews as O, type LandingCta as P, type LandingPage as Q, type DeepPartial as R, type SupportedLocale as S, type Testimonial as T, UNIFIED_LOCALES as U, type LandingPageLocale as V, type ProductScreenshots as W, type AppIconStyleConfig as X, type AppIconConfig as Y, type ProductMetadata as Z, type ProductContent as _, UNIFIED_TO_APP_STORE as a, type AsoTemplate as a0, type AsoLocaleContent as a1, type ProductLocale as a2, type ScreenshotGeneratorThemeTokens as a3, type ScreenshotGeneratorSlideConfig as a4, type ScreenshotGeneratorConfig as a5, type SiteConfig as a6, type LocaleDisplayInfo as a7, type SiteData as a8, type WorkItem as a9, type WorkLocaleData as aa, type ResolvedWorkData as ab, type BlogMetaOutput as ac, type CreateBlogHtmlInput as ad, type GeneratedBlogFile as ae, type CreateBlogHtmlResult as af, unifiedToAppStore as ag, unifiedToGooglePlay as ah, unifiedToBothPlatforms as ai, appStoreToUnified as aj, googlePlayToUnified as ak, unifiedToAppStoreBatch as al, unifiedToGooglePlayBatch as am, appStoreToUnifiedBatch as an, googlePlayToUnifiedBatch as ao, appStoreToGooglePlay as ap, googlePlayToAppStore as aq, convertObjectToAppStore as ar, convertObjectToGooglePlay as as, convertObjectFromAppStore as at, convertObjectFromGooglePlay as au, UNIFIED_TO_GOOGLE_PLAY as b, type UnifiedLocale as c, type AppStoreLocale as d, type GooglePlayLocale as e, isAppStoreLocale as f, isGooglePlayLocale as g, type GooglePlayListing as h, isSupportedLocale as i, type GooglePlayImageType as j, type GooglePlayScreenshotType as k, type GooglePlayScreenshots as l, type GooglePlayAsoData as m, type GooglePlayReleaseNote as n, type AppStoreReleaseNote as o, type AppStoreInfoLocalization as p, type AppStoreVersionLocalization as q, type AppStoreScreenshotDisplayType as r, type AppStoreScreenshots as s, type AppStoreAsoData as t, type GooglePlayMultilingualAsoData as u, type AppStoreMultilingualAsoData as v, type AsoData as w, isGooglePlayMultilingual as x, isAppStoreMultilingual as y, type BlogMeta as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-resource-mcp",
3
- "version": "1.10.8",
3
+ "version": "1.10.9",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",