pabal-web-mcp 0.1.1 → 0.1.2

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.
@@ -7,13 +7,15 @@ import {
7
7
  getPullDataDir,
8
8
  getPushDataDir,
9
9
  googlePlayToUnified,
10
+ isAppStoreLocale,
10
11
  isAppStoreMultilingual,
12
+ isGooglePlayLocale,
11
13
  isGooglePlayMultilingual,
12
14
  loadAsoFromConfig,
13
15
  saveAsoToAsoDir,
14
16
  unifiedToAppStore,
15
17
  unifiedToGooglePlay
16
- } from "../chunk-MWXNTV3M.js";
18
+ } from "../chunk-AM6RGDD4.js";
17
19
 
18
20
  // src/bin/mcp-server.ts
19
21
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -506,6 +508,7 @@ function convertToMultilingual(data, locale) {
506
508
  }
507
509
 
508
510
  // src/tools/public-to-aso.ts
511
+ import fs4 from "fs";
509
512
  var FIELD_LIMITS_DOC_PATH = "docs/aso/ASO_FIELD_LIMITS.md";
510
513
  var toJsonSchema2 = zodToJsonSchema2;
511
514
  var publicToAsoInputSchema = z2.object({
@@ -520,12 +523,7 @@ var jsonSchema2 = toJsonSchema2(publicToAsoInputSchema, {
520
523
  var inputSchema2 = jsonSchema2.definitions?.PublicToAsoInput || jsonSchema2;
521
524
  async function downloadScreenshotsToAsoDir(slug, asoData, options) {
522
525
  const rootDir = options?.rootDir ?? getPushDataDir();
523
- const productStoreRoot = path4.join(
524
- rootDir,
525
- "products",
526
- slug,
527
- "store"
528
- );
526
+ const productStoreRoot = path4.join(rootDir, "products", slug, "store");
529
527
  if (asoData.googlePlay) {
530
528
  let googlePlayData = asoData.googlePlay;
531
529
  if (!isGooglePlayMultilingual(googlePlayData)) {
@@ -675,7 +673,85 @@ async function handlePublicToAso(input) {
675
673
  const { slug, dryRun } = input;
676
674
  const configData = loadAsoFromConfig(slug);
677
675
  if (!configData.googlePlay && !configData.appStore) {
678
- throw new Error(`No ASO data found in config.json + locales/ for ${slug}`);
676
+ const productsDir = getProductsDir();
677
+ const configPath = path4.join(productsDir, slug, "config.json");
678
+ const localesDir = path4.join(productsDir, slug, "locales");
679
+ const errors = [];
680
+ if (!fs4.existsSync(configPath)) {
681
+ errors.push(`- config.json not found at ${configPath}`);
682
+ } else {
683
+ try {
684
+ const config = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
685
+ if (!config.packageName && !config.bundleId) {
686
+ errors.push(
687
+ `- config.json exists but missing both packageName and bundleId`
688
+ );
689
+ } else {
690
+ if (config.packageName) {
691
+ errors.push(`- packageName found: ${config.packageName}`);
692
+ }
693
+ if (config.bundleId) {
694
+ errors.push(`- bundleId found: ${config.bundleId}`);
695
+ }
696
+ }
697
+ } catch (e) {
698
+ errors.push(
699
+ `- Failed to parse config.json: ${e instanceof Error ? e.message : String(e)}`
700
+ );
701
+ }
702
+ }
703
+ if (!fs4.existsSync(localesDir)) {
704
+ errors.push(`- locales directory not found at ${localesDir}`);
705
+ } else {
706
+ try {
707
+ const localeFiles = fs4.readdirSync(localesDir).filter((f) => f.endsWith(".json"));
708
+ if (localeFiles.length === 0) {
709
+ errors.push(`- locales directory exists but no .json files found`);
710
+ } else {
711
+ errors.push(
712
+ `- Found ${localeFiles.length} locale file(s): ${localeFiles.join(
713
+ ", "
714
+ )}`
715
+ );
716
+ const validLocales = [];
717
+ const invalidLocales = [];
718
+ for (const file of localeFiles) {
719
+ const localeCode = file.replace(".json", "");
720
+ if (isGooglePlayLocale(localeCode) || isAppStoreLocale(localeCode)) {
721
+ validLocales.push(localeCode);
722
+ } else {
723
+ invalidLocales.push(localeCode);
724
+ }
725
+ }
726
+ if (validLocales.length > 0) {
727
+ errors.push(`- Valid locales: ${validLocales.join(", ")}`);
728
+ }
729
+ if (invalidLocales.length > 0) {
730
+ errors.push(
731
+ `- Invalid locales (not supported by Google Play or App Store): ${invalidLocales.join(
732
+ ", "
733
+ )}`
734
+ );
735
+ }
736
+ }
737
+ } catch (e) {
738
+ errors.push(
739
+ `- Failed to read locales directory: ${e instanceof Error ? e.message : String(e)}`
740
+ );
741
+ }
742
+ }
743
+ throw new Error(
744
+ `No ASO data found in config.json + locales/ for ${slug}
745
+
746
+ Diagnostics:
747
+ ${errors.join("\n")}
748
+
749
+ Possible causes:
750
+ 1. config.json is missing packageName (for Google Play) or bundleId (for App Store)
751
+ 2. locales/ directory is missing or empty
752
+ 3. Locale files exist but don't match supported Google Play/App Store locales
753
+ 4. Locale files don't contain valid ASO data`
754
+ );
679
755
  }
680
756
  const storeData = prepareAsoDataForPush(slug, configData);
681
757
  const pushDataRoot = getPushDataDir();
@@ -742,7 +818,7 @@ import { z as z3 } from "zod";
742
818
  import { zodToJsonSchema as zodToJsonSchema3 } from "zod-to-json-schema";
743
819
 
744
820
  // src/tools/utils/improve-public/load-product-locales.util.ts
745
- import fs4 from "fs";
821
+ import fs5 from "fs";
746
822
  import path5 from "path";
747
823
  function loadProductLocales(slug) {
748
824
  const productsDir = getProductsDir();
@@ -750,22 +826,22 @@ function loadProductLocales(slug) {
750
826
  const configPath = path5.join(productDir, "config.json");
751
827
  const localesDir = path5.join(productDir, "locales");
752
828
  let config = null;
753
- if (fs4.existsSync(configPath)) {
754
- const raw = fs4.readFileSync(configPath, "utf-8");
829
+ if (fs5.existsSync(configPath)) {
830
+ const raw = fs5.readFileSync(configPath, "utf-8");
755
831
  config = JSON.parse(raw);
756
832
  }
757
- if (!fs4.existsSync(localesDir)) {
833
+ if (!fs5.existsSync(localesDir)) {
758
834
  throw new Error(`No locales directory found for ${slug}`);
759
835
  }
760
836
  const locales = {};
761
- const localeFiles = fs4.readdirSync(localesDir).filter((file) => file.endsWith(".json"));
837
+ const localeFiles = fs5.readdirSync(localesDir).filter((file) => file.endsWith(".json"));
762
838
  if (localeFiles.length === 0) {
763
839
  throw new Error(`No locale files found for ${slug}`);
764
840
  }
765
841
  for (const file of localeFiles) {
766
842
  const localeCode = file.replace(".json", "");
767
843
  const localePath = path5.join(localesDir, file);
768
- const content = fs4.readFileSync(localePath, "utf-8");
844
+ const content = fs5.readFileSync(localePath, "utf-8");
769
845
  locales[localeCode] = JSON.parse(content);
770
846
  }
771
847
  return { config, locales };
@@ -1706,13 +1782,13 @@ async function handleImprovePublic(input) {
1706
1782
  }
1707
1783
 
1708
1784
  // src/tools/init-project.ts
1709
- import fs5 from "fs";
1785
+ import fs6 from "fs";
1710
1786
  import path6 from "path";
1711
1787
  import { z as z4 } from "zod";
1712
1788
  import { zodToJsonSchema as zodToJsonSchema4 } from "zod-to-json-schema";
1713
1789
  var listSlugDirs = (dir) => {
1714
- if (!fs5.existsSync(dir)) return [];
1715
- return fs5.readdirSync(dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1790
+ if (!fs6.existsSync(dir)) return [];
1791
+ return fs6.readdirSync(dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1716
1792
  };
1717
1793
  var initProjectInputSchema = z4.object({
1718
1794
  slug: z4.string().trim().optional().describe(
@@ -0,0 +1,1001 @@
1
+ // src/constants/unified-locales.ts
2
+ var UNIFIED_LOCALES = [
3
+ "af",
4
+ // Afrikaans - Google Play only
5
+ "am",
6
+ // Amharic - Google Play only
7
+ "ar",
8
+ // Arabic
9
+ "az-AZ",
10
+ // Azerbaijani - Google Play only
11
+ "be",
12
+ // Belarusian - Google Play only
13
+ "bg-BG",
14
+ // Bulgarian - Google Play only
15
+ "bn-BD",
16
+ // Bengali - Google Play only
17
+ "ca-ES",
18
+ // Catalan
19
+ "cs-CZ",
20
+ // Czech
21
+ "da-DK",
22
+ // Danish
23
+ "de-DE",
24
+ // German
25
+ "el-GR",
26
+ // Greek
27
+ "en-AU",
28
+ // English (Australia)
29
+ "en-CA",
30
+ // English (Canada)
31
+ "en-GB",
32
+ // English (United Kingdom)
33
+ "en-IN",
34
+ // English (India) - Google Play only
35
+ "en-SG",
36
+ // English (Singapore) - Google Play only
37
+ "en-US",
38
+ // English (United States)
39
+ "en-ZA",
40
+ // English (South Africa) - Google Play only
41
+ "es-419",
42
+ // Spanish (Latin America)
43
+ "es-ES",
44
+ // Spanish (Spain)
45
+ "es-US",
46
+ // Spanish (United States)
47
+ "et-EE",
48
+ // Estonian - Google Play only
49
+ "eu-ES",
50
+ // Basque - Google Play only
51
+ "fa",
52
+ // Persian - Google Play only
53
+ "fa-AE",
54
+ // Persian (UAE) - Google Play only
55
+ "fa-AF",
56
+ // Persian (Afghanistan) - Google Play only
57
+ "fa-IR",
58
+ // Persian (Iran) - Google Play only
59
+ "fi-FI",
60
+ // Finnish
61
+ "fil",
62
+ // Filipino - Google Play only
63
+ "fr-CA",
64
+ // French (Canada)
65
+ "fr-FR",
66
+ // French (France)
67
+ "gl-ES",
68
+ // Galician - Google Play only
69
+ "gu",
70
+ // Gujarati - Google Play only
71
+ "he-IL",
72
+ // Hebrew
73
+ "hi-IN",
74
+ // Hindi
75
+ "hr-HR",
76
+ // Croatian - Google Play only
77
+ "hu-HU",
78
+ // Hungarian
79
+ "hy-AM",
80
+ // Armenian - Google Play only
81
+ "id-ID",
82
+ // Indonesian
83
+ "is-IS",
84
+ // Icelandic - Google Play only
85
+ "it-IT",
86
+ // Italian
87
+ "ja-JP",
88
+ // Japanese
89
+ "ka-GE",
90
+ // Georgian - Google Play only
91
+ "kk",
92
+ // Kazakh - Google Play only
93
+ "km-KH",
94
+ // Khmer - Google Play only
95
+ "kn-IN",
96
+ // Kannada - Google Play only
97
+ "ko-KR",
98
+ // Korean
99
+ "ky-KG",
100
+ // Kyrgyz - Google Play only
101
+ "lo-LA",
102
+ // Lao - Google Play only
103
+ "lt-LT",
104
+ // Lithuanian - Google Play only
105
+ "lv-LV",
106
+ // Latvian - Google Play only
107
+ "mk-MK",
108
+ // Macedonian - Google Play only
109
+ "ml-IN",
110
+ // Malayalam - Google Play only
111
+ "mn-MN",
112
+ // Mongolian - Google Play only
113
+ "mr-IN",
114
+ // Marathi - Google Play only
115
+ "ms",
116
+ // Malay - Google Play only
117
+ "ms-MY",
118
+ // Malay (Malaysia)
119
+ "my-MM",
120
+ // Burmese - Google Play only
121
+ "ne-NP",
122
+ // Nepali - Google Play only
123
+ "nl-NL",
124
+ // Dutch
125
+ "no-NO",
126
+ // Norwegian
127
+ "pa",
128
+ // Punjabi - Google Play only
129
+ "pl-PL",
130
+ // Polish
131
+ "pt-BR",
132
+ // Portuguese (Brazil)
133
+ "pt-PT",
134
+ // Portuguese (Portugal)
135
+ "rm",
136
+ // Romansh - Google Play only
137
+ "ro-RO",
138
+ // Romanian
139
+ "ru-RU",
140
+ // Russian
141
+ "si-LK",
142
+ // Sinhala - Google Play only
143
+ "sk-SK",
144
+ // Slovak
145
+ "sl-SI",
146
+ // Slovenian - Google Play only
147
+ "sq",
148
+ // Albanian - Google Play only
149
+ "sr-RS",
150
+ // Serbian - Google Play only
151
+ "sv-SE",
152
+ // Swedish
153
+ "sw",
154
+ // Swahili - Google Play only
155
+ "ta-IN",
156
+ // Tamil - Google Play only
157
+ "te-IN",
158
+ // Telugu - Google Play only
159
+ "th-TH",
160
+ // Thai
161
+ "tr-TR",
162
+ // Turkish
163
+ "uk-UA",
164
+ // Ukrainian
165
+ "ur",
166
+ // Urdu - Google Play only
167
+ "vi-VN",
168
+ // Vietnamese
169
+ "zh-HK",
170
+ // Chinese (Hong Kong)
171
+ "zh-Hans",
172
+ // Chinese (Simplified)
173
+ "zh-Hant",
174
+ // Chinese (Traditional)
175
+ "zu"
176
+ // Zulu - Google Play only
177
+ ];
178
+ var DEFAULT_LOCALE = "en-US";
179
+ var UNIFIED_TO_APP_STORE = {
180
+ af: null,
181
+ // Not supported by App Store
182
+ am: null,
183
+ // Not supported by App Store
184
+ ar: "ar-SA",
185
+ "az-AZ": null,
186
+ // Not supported by App Store
187
+ be: null,
188
+ // Not supported by App Store
189
+ "bg-BG": null,
190
+ // Not supported by App Store
191
+ "bn-BD": null,
192
+ // Not supported by App Store
193
+ "ca-ES": "ca",
194
+ "cs-CZ": "cs",
195
+ "da-DK": "da",
196
+ "de-DE": "de-DE",
197
+ "el-GR": "el",
198
+ "en-AU": "en-AU",
199
+ "en-CA": "en-CA",
200
+ "en-GB": "en-GB",
201
+ "en-IN": null,
202
+ // Not supported by App Store
203
+ "en-SG": null,
204
+ // Not supported by App Store
205
+ "en-US": "en-US",
206
+ "en-ZA": null,
207
+ // Not supported by App Store
208
+ "es-419": "es-MX",
209
+ // Latin America → Mexico for App Store
210
+ "es-ES": "es-ES",
211
+ "es-US": null,
212
+ // Not supported by App Store
213
+ "et-EE": null,
214
+ // Not supported by App Store
215
+ "eu-ES": null,
216
+ // Not supported by App Store
217
+ fa: null,
218
+ // Not supported by App Store
219
+ "fa-AE": null,
220
+ // Not supported by App Store
221
+ "fa-AF": null,
222
+ // Not supported by App Store
223
+ "fa-IR": null,
224
+ // Not supported by App Store
225
+ "fi-FI": "fi",
226
+ fil: null,
227
+ // Not supported by App Store
228
+ "fr-CA": "fr-CA",
229
+ "fr-FR": "fr-FR",
230
+ "gl-ES": null,
231
+ // Not supported by App Store
232
+ gu: null,
233
+ // Not supported by App Store
234
+ "he-IL": "he",
235
+ "hi-IN": "hi",
236
+ "hr-HR": "hr",
237
+ "hu-HU": "hu",
238
+ "hy-AM": null,
239
+ // Not supported by App Store
240
+ "id-ID": "id",
241
+ "is-IS": null,
242
+ // Not supported by App Store
243
+ "it-IT": "it",
244
+ "ja-JP": "ja",
245
+ "ka-GE": null,
246
+ // Not supported by App Store
247
+ kk: null,
248
+ // Not supported by App Store
249
+ "km-KH": null,
250
+ // Not supported by App Store
251
+ "kn-IN": null,
252
+ // Not supported by App Store
253
+ "ko-KR": "ko",
254
+ "ky-KG": null,
255
+ // Not supported by App Store
256
+ "lo-LA": null,
257
+ // Not supported by App Store
258
+ "lt-LT": null,
259
+ // Not supported by App Store
260
+ "lv-LV": null,
261
+ // Not supported by App Store
262
+ "mk-MK": null,
263
+ // Not supported by App Store
264
+ "ml-IN": null,
265
+ // Not supported by App Store
266
+ "mn-MN": null,
267
+ // Not supported by App Store
268
+ "mr-IN": null,
269
+ // Not supported by App Store
270
+ ms: null,
271
+ // Use ms-MY for App Store Malay coverage
272
+ "ms-MY": "ms",
273
+ "my-MM": null,
274
+ // Not supported by App Store
275
+ "ne-NP": null,
276
+ // Not supported by App Store
277
+ "nl-NL": "nl-NL",
278
+ "no-NO": "no",
279
+ pa: null,
280
+ // Not supported by App Store
281
+ "pl-PL": "pl",
282
+ "pt-BR": "pt-BR",
283
+ "pt-PT": "pt-PT",
284
+ rm: null,
285
+ // Not supported by App Store
286
+ "ro-RO": "ro",
287
+ "ru-RU": "ru",
288
+ "si-LK": null,
289
+ // Not supported by App Store
290
+ "sk-SK": "sk",
291
+ "sl-SI": null,
292
+ // Not supported by App Store
293
+ sq: null,
294
+ // Not supported by App Store
295
+ "sr-RS": null,
296
+ // Not supported by App Store
297
+ "sv-SE": "sv",
298
+ sw: null,
299
+ // Not supported by App Store
300
+ "ta-IN": null,
301
+ // Not supported by App Store
302
+ "te-IN": null,
303
+ // Not supported by App Store
304
+ "th-TH": "th",
305
+ "tr-TR": "tr",
306
+ "uk-UA": "uk",
307
+ ur: null,
308
+ // Not supported by App Store
309
+ "vi-VN": "vi",
310
+ "zh-HK": null,
311
+ // Not supported by App Store
312
+ "zh-Hans": "zh-Hans",
313
+ "zh-Hant": "zh-Hant",
314
+ zu: null
315
+ // Not supported by App Store
316
+ };
317
+ var UNIFIED_TO_GOOGLE_PLAY = {
318
+ af: "af",
319
+ am: "am",
320
+ ar: "ar",
321
+ "az-AZ": "az-AZ",
322
+ be: "be",
323
+ "bg-BG": "bg",
324
+ "bn-BD": "bn-BD",
325
+ "ca-ES": "ca",
326
+ "cs-CZ": "cs-CZ",
327
+ "da-DK": "da-DK",
328
+ "de-DE": "de-DE",
329
+ "el-GR": "el-GR",
330
+ "en-AU": "en-AU",
331
+ "en-CA": "en-CA",
332
+ "en-GB": "en-GB",
333
+ "en-IN": "en-IN",
334
+ "en-SG": "en-SG",
335
+ "en-US": "en-US",
336
+ "en-ZA": "en-ZA",
337
+ "es-419": "es-419",
338
+ "es-ES": "es-ES",
339
+ "es-US": "es-US",
340
+ "et-EE": "et",
341
+ "eu-ES": "eu-ES",
342
+ fa: "fa",
343
+ "fa-AE": "fa-AE",
344
+ "fa-AF": "fa-AF",
345
+ "fa-IR": "fa-IR",
346
+ "fi-FI": "fi-FI",
347
+ fil: "fil",
348
+ "fr-CA": "fr-CA",
349
+ "fr-FR": "fr-FR",
350
+ "gl-ES": "gl-ES",
351
+ gu: "gu",
352
+ "he-IL": "iw-IL",
353
+ "hi-IN": "hi-IN",
354
+ "hr-HR": "hr",
355
+ "hu-HU": "hu-HU",
356
+ "hy-AM": "hy-AM",
357
+ "id-ID": "id",
358
+ // Google Play also accepts "in"
359
+ "is-IS": "is-IS",
360
+ "it-IT": "it-IT",
361
+ "ja-JP": "ja-JP",
362
+ "ka-GE": "ka-GE",
363
+ kk: "kk",
364
+ "km-KH": "km-KH",
365
+ "kn-IN": "kn-IN",
366
+ "ko-KR": "ko-KR",
367
+ "ky-KG": "ky-KG",
368
+ "lo-LA": "lo-LA",
369
+ "lt-LT": "lt",
370
+ "lv-LV": "lv",
371
+ "mk-MK": "mk-MK",
372
+ "ml-IN": "ml-IN",
373
+ "mn-MN": "mn-MN",
374
+ "mr-IN": "mr-IN",
375
+ ms: "ms",
376
+ "ms-MY": "ms-MY",
377
+ "my-MM": "my-MM",
378
+ "ne-NP": "ne-NP",
379
+ "nl-NL": "nl-NL",
380
+ "no-NO": "no-NO",
381
+ pa: "pa",
382
+ "pl-PL": "pl-PL",
383
+ "pt-BR": "pt-BR",
384
+ "pt-PT": "pt-PT",
385
+ rm: "rm",
386
+ "ro-RO": "ro",
387
+ "ru-RU": "ru-RU",
388
+ "si-LK": "si-LK",
389
+ "sk-SK": "sk",
390
+ "sl-SI": "sl",
391
+ sq: "sq",
392
+ "sr-RS": "sr",
393
+ "sv-SE": "sv-SE",
394
+ sw: "sw",
395
+ "ta-IN": "ta-IN",
396
+ "te-IN": "te-IN",
397
+ "th-TH": "th",
398
+ "tr-TR": "tr-TR",
399
+ "uk-UA": "uk",
400
+ ur: "ur",
401
+ "vi-VN": "vi",
402
+ "zh-HK": "zh-HK",
403
+ "zh-Hans": "zh-CN",
404
+ // Simplified Chinese → China for Google Play
405
+ "zh-Hant": "zh-TW",
406
+ // Traditional Chinese → Taiwan for Google Play
407
+ zu: "zu"
408
+ };
409
+ var APP_STORE_TO_UNIFIED = {
410
+ "en-US": "en-US",
411
+ "en-AU": "en-AU",
412
+ "en-CA": "en-CA",
413
+ "en-GB": "en-GB",
414
+ ko: "ko-KR",
415
+ ja: "ja-JP",
416
+ "zh-Hans": "zh-Hans",
417
+ "zh-Hant": "zh-Hant",
418
+ "fr-FR": "fr-FR",
419
+ "fr-CA": "fr-CA",
420
+ "de-DE": "de-DE",
421
+ it: "it-IT",
422
+ "es-ES": "es-ES",
423
+ "es-MX": "es-419",
424
+ // Mexico → Latin America in unified system
425
+ "pt-BR": "pt-BR",
426
+ "pt-PT": "pt-PT",
427
+ ru: "ru-RU",
428
+ "ar-SA": "ar",
429
+ // Saudi Arabia → Generic Arabic in unified system
430
+ "nl-NL": "nl-NL",
431
+ sv: "sv-SE",
432
+ da: "da-DK",
433
+ no: "no-NO",
434
+ fi: "fi-FI",
435
+ pl: "pl-PL",
436
+ tr: "tr-TR",
437
+ vi: "vi-VN",
438
+ th: "th-TH",
439
+ id: "id-ID",
440
+ ms: "ms-MY",
441
+ hi: "hi-IN",
442
+ cs: "cs-CZ",
443
+ sk: "sk-SK",
444
+ hu: "hu-HU",
445
+ ro: "ro-RO",
446
+ uk: "uk-UA",
447
+ he: "he-IL",
448
+ el: "el-GR",
449
+ ca: "ca-ES",
450
+ hr: "hr-HR"
451
+ };
452
+ var GOOGLE_PLAY_TO_UNIFIED = {
453
+ af: "af",
454
+ am: "am",
455
+ ar: "ar",
456
+ "az-AZ": "az-AZ",
457
+ be: "be",
458
+ bg: "bg-BG",
459
+ "bn-BD": "bn-BD",
460
+ ca: "ca-ES",
461
+ "cs-CZ": "cs-CZ",
462
+ cs: "cs-CZ",
463
+ "da-DK": "da-DK",
464
+ da: "da-DK",
465
+ "de-DE": "de-DE",
466
+ de: "de-DE",
467
+ "el-GR": "el-GR",
468
+ el: "el-GR",
469
+ "en-AU": "en-AU",
470
+ "en-CA": "en-CA",
471
+ "en-GB": "en-GB",
472
+ "en-IN": "en-IN",
473
+ "en-SG": "en-SG",
474
+ "en-US": "en-US",
475
+ "en-ZA": "en-ZA",
476
+ "es-419": "es-419",
477
+ "es-ES": "es-ES",
478
+ es: "es-ES",
479
+ "es-US": "es-US",
480
+ et: "et-EE",
481
+ "et-EE": "et-EE",
482
+ "eu-ES": "eu-ES",
483
+ fa: "fa",
484
+ "fa-AE": "fa-AE",
485
+ "fa-AF": "fa-AF",
486
+ "fa-IR": "fa-IR",
487
+ "fi-FI": "fi-FI",
488
+ fi: "fi-FI",
489
+ fil: "fil",
490
+ "fr-FR": "fr-FR",
491
+ fr: "fr-FR",
492
+ "fr-CA": "fr-CA",
493
+ "gl-ES": "gl-ES",
494
+ gu: "gu",
495
+ "iw-IL": "he-IL",
496
+ "he-IL": "he-IL",
497
+ he: "he-IL",
498
+ "hi-IN": "hi-IN",
499
+ hi: "hi-IN",
500
+ hr: "hr-HR",
501
+ "hu-HU": "hu-HU",
502
+ hu: "hu-HU",
503
+ "hy-AM": "hy-AM",
504
+ id: "id-ID",
505
+ // Google Play "id" or "in" maps to unified "id-ID"
506
+ in: "id-ID",
507
+ // Alternative Indonesian code
508
+ "is-IS": "is-IS",
509
+ "it-IT": "it-IT",
510
+ it: "it-IT",
511
+ "ja-JP": "ja-JP",
512
+ ja: "ja-JP",
513
+ "ka-GE": "ka-GE",
514
+ kk: "kk",
515
+ "km-KH": "km-KH",
516
+ "kn-IN": "kn-IN",
517
+ "ko-KR": "ko-KR",
518
+ ko: "ko-KR",
519
+ "ky-KG": "ky-KG",
520
+ "lo-LA": "lo-LA",
521
+ lt: "lt-LT",
522
+ "lt-LT": "lt-LT",
523
+ lv: "lv-LV",
524
+ "lv-LV": "lv-LV",
525
+ "mk-MK": "mk-MK",
526
+ "ml-IN": "ml-IN",
527
+ "mn-MN": "mn-MN",
528
+ "mr-IN": "mr-IN",
529
+ ms: "ms",
530
+ "ms-MY": "ms-MY",
531
+ "my-MM": "my-MM",
532
+ "ne-NP": "ne-NP",
533
+ "nl-NL": "nl-NL",
534
+ nl: "nl-NL",
535
+ "no-NO": "no-NO",
536
+ no: "no-NO",
537
+ pa: "pa",
538
+ "pl-PL": "pl-PL",
539
+ pl: "pl-PL",
540
+ "pt-BR": "pt-BR",
541
+ "pt-PT": "pt-PT",
542
+ rm: "rm",
543
+ ro: "ro-RO",
544
+ "ru-RU": "ru-RU",
545
+ ru: "ru-RU",
546
+ "si-LK": "si-LK",
547
+ sk: "sk-SK",
548
+ "sl-SI": "sl-SI",
549
+ sl: "sl-SI",
550
+ sq: "sq",
551
+ sr: "sr-RS",
552
+ "sv-SE": "sv-SE",
553
+ sv: "sv-SE",
554
+ sw: "sw",
555
+ "ta-IN": "ta-IN",
556
+ "te-IN": "te-IN",
557
+ th: "th-TH",
558
+ "tr-TR": "tr-TR",
559
+ tr: "tr-TR",
560
+ uk: "uk-UA",
561
+ ur: "ur",
562
+ vi: "vi-VN",
563
+ "zh-HK": "zh-HK",
564
+ "zh-CN": "zh-Hans",
565
+ // China → Simplified Chinese in unified system
566
+ "zh-TW": "zh-Hant",
567
+ // Taiwan → Traditional Chinese in unified system
568
+ zu: "zu"
569
+ };
570
+ var APP_STORE_SUPPORTED_LOCALES = UNIFIED_LOCALES.filter(
571
+ (locale) => UNIFIED_TO_APP_STORE[locale] !== null
572
+ );
573
+ var GOOGLE_PLAY_SUPPORTED_LOCALES = UNIFIED_LOCALES.filter(
574
+ (locale) => UNIFIED_TO_GOOGLE_PLAY[locale] !== null
575
+ );
576
+ var COMMON_SUPPORTED_LOCALES = UNIFIED_LOCALES.filter(
577
+ (locale) => UNIFIED_TO_APP_STORE[locale] !== null && UNIFIED_TO_GOOGLE_PLAY[locale] !== null
578
+ );
579
+ function appStoreToUnified(appStoreLocale) {
580
+ const unified = APP_STORE_TO_UNIFIED[appStoreLocale];
581
+ if (!unified) {
582
+ throw new Error(`Unknown App Store locale: ${appStoreLocale}`);
583
+ }
584
+ return unified;
585
+ }
586
+ function googlePlayToUnified(googlePlayLocale) {
587
+ const unified = GOOGLE_PLAY_TO_UNIFIED[googlePlayLocale];
588
+ if (!unified) {
589
+ throw new Error(`Unknown Google Play locale: ${googlePlayLocale}`);
590
+ }
591
+ return unified;
592
+ }
593
+
594
+ // src/types/aso/aso.types.ts
595
+ function isSupportedLocale(locale) {
596
+ return UNIFIED_LOCALES.includes(locale);
597
+ }
598
+ function isAppStoreLocale(locale) {
599
+ return APP_STORE_SUPPORTED_LOCALES.includes(locale);
600
+ }
601
+ function isGooglePlayLocale(locale) {
602
+ return GOOGLE_PLAY_SUPPORTED_LOCALES.includes(locale);
603
+ }
604
+ function isGooglePlayMultilingual(data) {
605
+ return data !== void 0 && "locales" in data;
606
+ }
607
+ function isAppStoreMultilingual(data) {
608
+ return data !== void 0 && "locales" in data;
609
+ }
610
+
611
+ // src/utils/locale-converter.ts
612
+ function unifiedToAppStore(locale) {
613
+ return UNIFIED_TO_APP_STORE[locale];
614
+ }
615
+ function unifiedToGooglePlay(locale) {
616
+ return UNIFIED_TO_GOOGLE_PLAY[locale];
617
+ }
618
+ function unifiedToBothPlatforms(locale) {
619
+ return {
620
+ appStore: unifiedToAppStore(locale),
621
+ googlePlay: unifiedToGooglePlay(locale)
622
+ };
623
+ }
624
+ function appStoreToUnified2(locale) {
625
+ return APP_STORE_TO_UNIFIED[locale] ?? DEFAULT_LOCALE;
626
+ }
627
+ function googlePlayToUnified2(locale) {
628
+ return GOOGLE_PLAY_TO_UNIFIED[locale] ?? DEFAULT_LOCALE;
629
+ }
630
+ function unifiedToAppStoreBatch(locales) {
631
+ return locales.map((locale) => unifiedToAppStore(locale)).filter((locale) => locale !== null);
632
+ }
633
+ function unifiedToGooglePlayBatch(locales) {
634
+ return locales.map((locale) => unifiedToGooglePlay(locale)).filter((locale) => locale !== null);
635
+ }
636
+ function appStoreToUnifiedBatch(locales) {
637
+ return locales.map((locale) => appStoreToUnified2(locale));
638
+ }
639
+ function googlePlayToUnifiedBatch(locales) {
640
+ return locales.map((locale) => googlePlayToUnified2(locale));
641
+ }
642
+ function appStoreToGooglePlay(locale) {
643
+ const unified = appStoreToUnified2(locale);
644
+ return unifiedToGooglePlay(unified);
645
+ }
646
+ function googlePlayToAppStore(locale) {
647
+ const unified = googlePlayToUnified2(locale);
648
+ return unifiedToAppStore(unified);
649
+ }
650
+ function convertObjectToAppStore(data) {
651
+ const result = {};
652
+ for (const [locale, value] of Object.entries(data)) {
653
+ const appStoreLocale = unifiedToAppStore(locale);
654
+ if (appStoreLocale !== null) {
655
+ result[appStoreLocale] = value;
656
+ }
657
+ }
658
+ return result;
659
+ }
660
+ function convertObjectToGooglePlay(data) {
661
+ const result = {};
662
+ for (const [locale, value] of Object.entries(data)) {
663
+ const googlePlayLocale = unifiedToGooglePlay(locale);
664
+ if (googlePlayLocale !== null) {
665
+ result[googlePlayLocale] = value;
666
+ }
667
+ }
668
+ return result;
669
+ }
670
+ function convertObjectFromAppStore(data) {
671
+ const result = {};
672
+ for (const [locale, value] of Object.entries(data)) {
673
+ const unifiedLocale = appStoreToUnified2(locale);
674
+ result[unifiedLocale] = value;
675
+ }
676
+ return result;
677
+ }
678
+ function convertObjectFromGooglePlay(data) {
679
+ const result = {};
680
+ for (const [locale, value] of Object.entries(data)) {
681
+ const unifiedLocale = googlePlayToUnified2(locale);
682
+ result[unifiedLocale] = value;
683
+ }
684
+ return result;
685
+ }
686
+
687
+ // src/utils/config.util.ts
688
+ import fs from "fs";
689
+ import path from "path";
690
+ import os from "os";
691
+ function getAsoDataDir() {
692
+ const configPath = path.join(
693
+ os.homedir(),
694
+ ".config",
695
+ "pabal-mcp",
696
+ "config.json"
697
+ );
698
+ if (!fs.existsSync(configPath)) {
699
+ throw new Error(
700
+ `Config file not found at ${configPath}. Please create the config file and set the 'dataDir' property to specify the ASO data directory.`
701
+ );
702
+ }
703
+ try {
704
+ const configContent = fs.readFileSync(configPath, "utf-8");
705
+ const config = JSON.parse(configContent);
706
+ if (!config.dataDir) {
707
+ throw new Error(
708
+ `'dataDir' property is not set in ${configPath}. Please set 'dataDir' to specify the ASO data directory.`
709
+ );
710
+ }
711
+ if (path.isAbsolute(config.dataDir)) {
712
+ return config.dataDir;
713
+ }
714
+ return path.resolve(os.homedir(), config.dataDir);
715
+ } catch (error) {
716
+ if (error instanceof Error && error.message.includes("dataDir")) {
717
+ throw error;
718
+ }
719
+ throw new Error(
720
+ `Failed to read config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`
721
+ );
722
+ }
723
+ }
724
+ function getPullDataDir() {
725
+ return path.join(getAsoDataDir(), "pullData");
726
+ }
727
+ function getPushDataDir() {
728
+ return path.join(getAsoDataDir(), "pushData");
729
+ }
730
+ function getPublicDir() {
731
+ return path.join(getAsoDataDir(), "public");
732
+ }
733
+ function getProductsDir() {
734
+ return path.join(getPublicDir(), "products");
735
+ }
736
+
737
+ // src/utils/aso-converter.ts
738
+ import fs2 from "fs";
739
+ import path2 from "path";
740
+ function generateFullDescription(localeData, metadata = {}) {
741
+ const { aso, landing } = localeData;
742
+ const template = aso?.template;
743
+ if (!template) {
744
+ return "";
745
+ }
746
+ const landingFeatures = landing?.features?.items || [];
747
+ const landingScreenshots = landing?.screenshots?.images || [];
748
+ const keyHeading = template.keyFeaturesHeading || "Key Features";
749
+ const featuresHeading = template.featuresHeading || "Additional Features";
750
+ const parts = [template.intro];
751
+ if (landingFeatures.length > 0) {
752
+ parts.push(
753
+ "",
754
+ keyHeading,
755
+ "",
756
+ ...landingFeatures.map(
757
+ (feature) => [feature.title, feature.body || ""].filter(Boolean).join("\n")
758
+ )
759
+ );
760
+ }
761
+ if (landingScreenshots.length > 0) {
762
+ parts.push("", featuresHeading, "");
763
+ parts.push(
764
+ ...landingScreenshots.map(
765
+ (screenshot) => [screenshot.title, screenshot.description || ""].filter(Boolean).join("\n")
766
+ )
767
+ );
768
+ }
769
+ parts.push("", template.outro);
770
+ const includeSupport = template.includeSupportLinks ?? true;
771
+ if (includeSupport) {
772
+ const contactLines = [
773
+ metadata.instagram ? `Instagram: ${metadata.instagram}` : null,
774
+ metadata.contactEmail ? `Email: ${metadata.contactEmail}` : null,
775
+ metadata.termsUrl ? `- Terms of Use: ${metadata.termsUrl}` : null,
776
+ metadata.privacyUrl ? `- Privacy Policy: ${metadata.privacyUrl}` : null
777
+ ].filter((line) => line !== null);
778
+ if (contactLines.length > 0) {
779
+ parts.push("", "[Contact & Support]", "", ...contactLines);
780
+ }
781
+ }
782
+ return parts.join("\n");
783
+ }
784
+ function loadAsoFromConfig(slug) {
785
+ const productsDir = getProductsDir();
786
+ const configPath = path2.join(
787
+ productsDir,
788
+ slug,
789
+ "config.json"
790
+ );
791
+ if (!fs2.existsSync(configPath)) {
792
+ return {};
793
+ }
794
+ try {
795
+ const configContent = fs2.readFileSync(configPath, "utf-8");
796
+ const config = JSON.parse(configContent);
797
+ const localesDir = path2.join(
798
+ productsDir,
799
+ slug,
800
+ "locales"
801
+ );
802
+ if (!fs2.existsSync(localesDir)) {
803
+ return {};
804
+ }
805
+ const localeFiles = fs2.readdirSync(localesDir).filter((f) => f.endsWith(".json"));
806
+ const locales = {};
807
+ for (const file of localeFiles) {
808
+ const localeCode = file.replace(".json", "");
809
+ const localePath = path2.join(localesDir, file);
810
+ const localeContent = fs2.readFileSync(localePath, "utf-8");
811
+ locales[localeCode] = JSON.parse(localeContent);
812
+ }
813
+ const defaultLocale = config.content?.defaultLocale || DEFAULT_LOCALE;
814
+ const asoData = {};
815
+ if (config.packageName) {
816
+ const googlePlayLocales = {};
817
+ const metadata = config.metadata || {};
818
+ const screenshots = metadata.screenshots || {};
819
+ for (const [locale, localeData] of Object.entries(locales)) {
820
+ if (!isGooglePlayLocale(locale)) {
821
+ continue;
822
+ }
823
+ const aso = localeData.aso || {};
824
+ const localeScreenshots = {
825
+ phone: screenshots.phone?.map((p) => p.replace("/screenshots/", `/screenshots/${locale}/`)),
826
+ tablet: screenshots.tablet?.map((p) => p.replace("/screenshots/", `/screenshots/${locale}/`))
827
+ };
828
+ googlePlayLocales[locale] = {
829
+ title: aso.title || "",
830
+ shortDescription: aso.shortDescription || "",
831
+ fullDescription: generateFullDescription(localeData, metadata),
832
+ packageName: config.packageName,
833
+ defaultLanguage: locale,
834
+ screenshots: {
835
+ phone: localeScreenshots.phone || [],
836
+ tablet: localeScreenshots.tablet
837
+ },
838
+ contactEmail: metadata.contactEmail
839
+ };
840
+ }
841
+ const googleLocaleKeys = Object.keys(googlePlayLocales);
842
+ if (googleLocaleKeys.length > 0) {
843
+ const hasConfigDefault = isGooglePlayLocale(defaultLocale) && Boolean(googlePlayLocales[defaultLocale]);
844
+ const resolvedDefault = hasConfigDefault ? defaultLocale : googlePlayLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : googleLocaleKeys[0];
845
+ asoData.googlePlay = {
846
+ locales: googlePlayLocales,
847
+ defaultLocale: resolvedDefault
848
+ };
849
+ }
850
+ }
851
+ if (config.bundleId) {
852
+ const appStoreLocales = {};
853
+ const metadata = config.metadata || {};
854
+ const screenshots = metadata.screenshots || {};
855
+ for (const [locale, localeData] of Object.entries(locales)) {
856
+ if (!isAppStoreLocale(locale)) {
857
+ continue;
858
+ }
859
+ const aso = localeData.aso || {};
860
+ const localeScreenshots = {
861
+ phone: screenshots.phone?.map((p) => p.replace("/screenshots/", `/screenshots/${locale}/`)),
862
+ tablet: screenshots.tablet?.map((p) => p.replace("/screenshots/", `/screenshots/${locale}/`))
863
+ };
864
+ appStoreLocales[locale] = {
865
+ name: aso.title || "",
866
+ subtitle: aso.subtitle,
867
+ description: generateFullDescription(localeData, metadata),
868
+ keywords: Array.isArray(aso.keywords) ? aso.keywords.join(", ") : aso.keywords,
869
+ promotionalText: void 0,
870
+ bundleId: config.bundleId,
871
+ locale,
872
+ supportUrl: metadata.supportUrl,
873
+ marketingUrl: metadata.marketingUrl,
874
+ privacyPolicyUrl: metadata.privacyUrl,
875
+ screenshots: {
876
+ // 폰 스크린샷을 iphone65로 매핑
877
+ iphone65: localeScreenshots.phone || [],
878
+ // 태블릿 스크린샷을 ipadPro129로 매핑
879
+ ipadPro129: localeScreenshots.tablet
880
+ }
881
+ };
882
+ }
883
+ const appStoreLocaleKeys = Object.keys(appStoreLocales);
884
+ if (appStoreLocaleKeys.length > 0) {
885
+ const hasConfigDefault = isAppStoreLocale(defaultLocale) && Boolean(appStoreLocales[defaultLocale]);
886
+ const resolvedDefault = hasConfigDefault ? defaultLocale : appStoreLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : appStoreLocaleKeys[0];
887
+ asoData.appStore = {
888
+ locales: appStoreLocales,
889
+ defaultLocale: resolvedDefault
890
+ };
891
+ }
892
+ }
893
+ return asoData;
894
+ } catch (error) {
895
+ console.error(`Failed to load ASO data from config for ${slug}:`, error);
896
+ return {};
897
+ }
898
+ }
899
+ function saveAsoToConfig(slug, config) {
900
+ const productsDir = getProductsDir();
901
+ const configPath = path2.join(
902
+ productsDir,
903
+ slug,
904
+ "config.json"
905
+ );
906
+ fs2.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
907
+ }
908
+ function saveAsoToAsoDir(slug, asoData, options) {
909
+ const rootDir = options?.rootDir ?? getPushDataDir();
910
+ if (asoData.googlePlay) {
911
+ const asoPath = path2.join(
912
+ rootDir,
913
+ "products",
914
+ slug,
915
+ "store",
916
+ "google-play",
917
+ "aso-data.json"
918
+ );
919
+ const dir = path2.dirname(asoPath);
920
+ if (!fs2.existsSync(dir)) {
921
+ fs2.mkdirSync(dir, { recursive: true });
922
+ }
923
+ const googlePlayData = asoData.googlePlay;
924
+ const multilingualData = "locales" in googlePlayData ? googlePlayData : {
925
+ locales: {
926
+ [googlePlayData.defaultLanguage || DEFAULT_LOCALE]: googlePlayData
927
+ },
928
+ defaultLocale: googlePlayData.defaultLanguage || DEFAULT_LOCALE
929
+ };
930
+ fs2.writeFileSync(
931
+ asoPath,
932
+ JSON.stringify({ googlePlay: multilingualData }, null, 2) + "\n",
933
+ "utf-8"
934
+ );
935
+ }
936
+ if (asoData.appStore) {
937
+ const asoPath = path2.join(
938
+ rootDir,
939
+ "products",
940
+ slug,
941
+ "store",
942
+ "app-store",
943
+ "aso-data.json"
944
+ );
945
+ const dir = path2.dirname(asoPath);
946
+ if (!fs2.existsSync(dir)) {
947
+ fs2.mkdirSync(dir, { recursive: true });
948
+ }
949
+ const appStoreData = asoData.appStore;
950
+ const multilingualData = "locales" in appStoreData ? appStoreData : {
951
+ locales: {
952
+ [appStoreData.locale || DEFAULT_LOCALE]: appStoreData
953
+ },
954
+ defaultLocale: appStoreData.locale || DEFAULT_LOCALE
955
+ };
956
+ fs2.writeFileSync(
957
+ asoPath,
958
+ JSON.stringify({ appStore: multilingualData }, null, 2) + "\n",
959
+ "utf-8"
960
+ );
961
+ }
962
+ }
963
+
964
+ export {
965
+ UNIFIED_LOCALES,
966
+ DEFAULT_LOCALE,
967
+ UNIFIED_TO_APP_STORE,
968
+ UNIFIED_TO_GOOGLE_PLAY,
969
+ APP_STORE_TO_UNIFIED,
970
+ GOOGLE_PLAY_TO_UNIFIED,
971
+ appStoreToUnified,
972
+ googlePlayToUnified,
973
+ isSupportedLocale,
974
+ isAppStoreLocale,
975
+ isGooglePlayLocale,
976
+ isGooglePlayMultilingual,
977
+ isAppStoreMultilingual,
978
+ unifiedToAppStore,
979
+ unifiedToGooglePlay,
980
+ unifiedToBothPlatforms,
981
+ appStoreToUnified2,
982
+ googlePlayToUnified2,
983
+ unifiedToAppStoreBatch,
984
+ unifiedToGooglePlayBatch,
985
+ appStoreToUnifiedBatch,
986
+ googlePlayToUnifiedBatch,
987
+ appStoreToGooglePlay,
988
+ googlePlayToAppStore,
989
+ convertObjectToAppStore,
990
+ convertObjectToGooglePlay,
991
+ convertObjectFromAppStore,
992
+ convertObjectFromGooglePlay,
993
+ getAsoDataDir,
994
+ getPullDataDir,
995
+ getPushDataDir,
996
+ getPublicDir,
997
+ getProductsDir,
998
+ loadAsoFromConfig,
999
+ saveAsoToConfig,
1000
+ saveAsoToAsoDir
1001
+ };
package/dist/index.d.ts CHANGED
@@ -603,11 +603,11 @@ declare function getPullDataDir(): string;
603
603
  */
604
604
  declare function getPushDataDir(): string;
605
605
  /**
606
- * Get the public directory path (always relative to process.cwd())
606
+ * Get the public directory path (dataDir/public)
607
607
  */
608
608
  declare function getPublicDir(): string;
609
609
  /**
610
- * Get the products directory path (public/products)
610
+ * Get the products directory path (dataDir/public/products)
611
611
  */
612
612
  declare function getProductsDir(): string;
613
613
 
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ import {
33
33
  unifiedToBothPlatforms,
34
34
  unifiedToGooglePlay,
35
35
  unifiedToGooglePlayBatch
36
- } from "./chunk-MWXNTV3M.js";
36
+ } from "./chunk-AM6RGDD4.js";
37
37
  export {
38
38
  APP_STORE_TO_UNIFIED,
39
39
  DEFAULT_LOCALE,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-web-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",