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.
- package/dist/bin/mcp-server.js +93 -17
- package/dist/chunk-AM6RGDD4.js +1001 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bin/mcp-server.js
CHANGED
|
@@ -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-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
754
|
-
const raw =
|
|
829
|
+
if (fs5.existsSync(configPath)) {
|
|
830
|
+
const raw = fs5.readFileSync(configPath, "utf-8");
|
|
755
831
|
config = JSON.parse(raw);
|
|
756
832
|
}
|
|
757
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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
|
|
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 (!
|
|
1715
|
-
return
|
|
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 (
|
|
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