pabal-web-mcp 1.2.1 → 1.2.3
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 +13 -3
- package/dist/chunk-FDI7WF45.js +1058 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +15 -3
package/dist/bin/mcp-server.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
saveAsoToAsoDir,
|
|
16
16
|
unifiedToAppStore,
|
|
17
17
|
unifiedToGooglePlay
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-FDI7WF45.js";
|
|
19
19
|
|
|
20
20
|
// src/bin/mcp-server.ts
|
|
21
21
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -2052,11 +2052,16 @@ function findExistingBlogPosts({
|
|
|
2052
2052
|
}));
|
|
2053
2053
|
}
|
|
2054
2054
|
|
|
2055
|
+
// src/constants/blog.constants.ts
|
|
2056
|
+
var DEFAULT_APP_SLUG = "developer";
|
|
2057
|
+
|
|
2055
2058
|
// src/tools/create-blog-html.ts
|
|
2056
2059
|
var toJsonSchema4 = zodToJsonSchema5;
|
|
2057
2060
|
var DATE_REGEX2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
2058
2061
|
var createBlogHtmlInputSchema = z5.object({
|
|
2059
|
-
appSlug: z5.string().trim().min(1
|
|
2062
|
+
appSlug: z5.string().trim().min(1).default(DEFAULT_APP_SLUG).describe(
|
|
2063
|
+
`Product/app slug used for paths and CTAs. Defaults to "${DEFAULT_APP_SLUG}" when not provided.`
|
|
2064
|
+
),
|
|
2060
2065
|
title: z5.string().trim().optional().describe(
|
|
2061
2066
|
"English title used for slug (kebab-case). Falls back to topic when omitted."
|
|
2062
2067
|
),
|
|
@@ -2103,10 +2108,15 @@ IMPORTANT REQUIREMENTS:
|
|
|
2103
2108
|
1. The 'locale' parameter is REQUIRED. If the user does not provide a locale, you MUST ask them to specify which language/locale they want to write the blog in (e.g., 'en-US', 'ko-KR', 'ja-JP', etc.).
|
|
2104
2109
|
2. The 'content' parameter is REQUIRED. You (the LLM) must generate the HTML content based on the 'topic' and 'locale' provided by the user. The content should be written in the language corresponding to the locale AND match the writing style of existing blog posts for that locale.
|
|
2105
2110
|
3. The 'description' parameter is REQUIRED. You (the LLM) must generate this based on the topic, locale, AND the writing style of existing blog posts.
|
|
2111
|
+
4. The 'appSlug' parameter:
|
|
2112
|
+
- If the user explicitly requests "developer category", "developer blog", "personal category", "my category", or similar, you MUST set appSlug to "developer".
|
|
2113
|
+
- If the user mentions a specific app/product, use that app's slug.
|
|
2114
|
+
- If not specified, defaults to "developer".
|
|
2106
2115
|
|
|
2107
2116
|
Slug rules:
|
|
2108
2117
|
- slug = slugify(English title, kebab-case ASCII)
|
|
2109
2118
|
- path: public/blogs/<appSlug>/<slug>/<locale>.html
|
|
2119
|
+
- appSlug: Use "developer" when user requests developer/personal category. Defaults to "developer" if not specified.
|
|
2110
2120
|
- coverImage default: /products/<appSlug>/og-image.png (relative paths are rewritten under /blogs/<app>/<slug>/)
|
|
2111
2121
|
- overwrite defaults to false (throws when file exists)
|
|
2112
2122
|
|
|
@@ -2124,7 +2134,7 @@ Supports multiple locales when locales[] is provided. Each locale gets its own H
|
|
|
2124
2134
|
async function handleCreateBlogHtml(input) {
|
|
2125
2135
|
const publicDir = getPublicDir();
|
|
2126
2136
|
const {
|
|
2127
|
-
appSlug,
|
|
2137
|
+
appSlug = DEFAULT_APP_SLUG,
|
|
2128
2138
|
topic,
|
|
2129
2139
|
title,
|
|
2130
2140
|
description,
|
|
@@ -0,0 +1,1058 @@
|
|
|
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(), ".aso", "pullData");
|
|
726
|
+
}
|
|
727
|
+
function getPushDataDir() {
|
|
728
|
+
return path.join(getAsoDataDir(), ".aso", "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) => [`\u25B6\uFE0E ${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) => [`\u25B6\uFE0E ${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(productsDir, slug, "config.json");
|
|
787
|
+
console.debug(`[loadAsoFromConfig] Looking for ${slug}:`);
|
|
788
|
+
console.debug(` - productsDir: ${productsDir}`);
|
|
789
|
+
console.debug(` - configPath: ${configPath}`);
|
|
790
|
+
console.debug(` - configPath exists: ${fs2.existsSync(configPath)}`);
|
|
791
|
+
if (!fs2.existsSync(configPath)) {
|
|
792
|
+
console.warn(`[loadAsoFromConfig] Config file not found at ${configPath}`);
|
|
793
|
+
return {};
|
|
794
|
+
}
|
|
795
|
+
try {
|
|
796
|
+
const configContent = fs2.readFileSync(configPath, "utf-8");
|
|
797
|
+
const config = JSON.parse(configContent);
|
|
798
|
+
const localesDir = path2.join(productsDir, slug, "locales");
|
|
799
|
+
console.debug(` - localesDir: ${localesDir}`);
|
|
800
|
+
console.debug(` - localesDir exists: ${fs2.existsSync(localesDir)}`);
|
|
801
|
+
if (!fs2.existsSync(localesDir)) {
|
|
802
|
+
console.warn(
|
|
803
|
+
`[loadAsoFromConfig] Locales directory not found at ${localesDir}`
|
|
804
|
+
);
|
|
805
|
+
return {};
|
|
806
|
+
}
|
|
807
|
+
const localeFiles = fs2.readdirSync(localesDir).filter((f) => f.endsWith(".json"));
|
|
808
|
+
const locales = {};
|
|
809
|
+
for (const file of localeFiles) {
|
|
810
|
+
const localeCode = file.replace(".json", "");
|
|
811
|
+
const localePath = path2.join(localesDir, file);
|
|
812
|
+
const localeContent = fs2.readFileSync(localePath, "utf-8");
|
|
813
|
+
locales[localeCode] = JSON.parse(localeContent);
|
|
814
|
+
}
|
|
815
|
+
console.debug(
|
|
816
|
+
` - Found ${Object.keys(locales).length} locale file(s): ${Object.keys(
|
|
817
|
+
locales
|
|
818
|
+
).join(", ")}`
|
|
819
|
+
);
|
|
820
|
+
if (Object.keys(locales).length === 0) {
|
|
821
|
+
console.warn(
|
|
822
|
+
`[loadAsoFromConfig] No locale files found in ${localesDir}`
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
const defaultLocale = config.content?.defaultLocale || DEFAULT_LOCALE;
|
|
826
|
+
const asoData = {};
|
|
827
|
+
if (config.packageName) {
|
|
828
|
+
const googlePlayLocales = {};
|
|
829
|
+
const metadata = config.metadata || {};
|
|
830
|
+
const screenshots = metadata.screenshots || {};
|
|
831
|
+
for (const [locale, localeData] of Object.entries(locales)) {
|
|
832
|
+
if (!isSupportedLocale(locale)) {
|
|
833
|
+
console.debug(
|
|
834
|
+
`Skipping locale ${locale} - not a valid unified locale`
|
|
835
|
+
);
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
if (!isGooglePlayLocale(locale)) {
|
|
839
|
+
console.debug(
|
|
840
|
+
`Skipping locale ${locale} - not supported by Google Play`
|
|
841
|
+
);
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
const aso = localeData.aso || {};
|
|
845
|
+
if (!aso || !aso.title && !aso.shortDescription) {
|
|
846
|
+
console.warn(
|
|
847
|
+
`Locale ${locale} has no ASO data (title or shortDescription)`
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
const localeScreenshots = {
|
|
851
|
+
phone: screenshots.phone?.map(
|
|
852
|
+
(p) => p.replace("/screenshots/", `/screenshots/${locale}/`)
|
|
853
|
+
),
|
|
854
|
+
tablet: screenshots.tablet?.map(
|
|
855
|
+
(p) => p.replace("/screenshots/", `/screenshots/${locale}/`)
|
|
856
|
+
)
|
|
857
|
+
};
|
|
858
|
+
googlePlayLocales[locale] = {
|
|
859
|
+
title: aso.title || "",
|
|
860
|
+
shortDescription: aso.shortDescription || "",
|
|
861
|
+
fullDescription: generateFullDescription(localeData, metadata),
|
|
862
|
+
packageName: config.packageName,
|
|
863
|
+
defaultLanguage: locale,
|
|
864
|
+
screenshots: {
|
|
865
|
+
phone: localeScreenshots.phone || [],
|
|
866
|
+
tablet: localeScreenshots.tablet
|
|
867
|
+
},
|
|
868
|
+
contactEmail: metadata.contactEmail
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
const googleLocaleKeys = Object.keys(googlePlayLocales);
|
|
872
|
+
if (googleLocaleKeys.length > 0) {
|
|
873
|
+
const hasConfigDefault = isGooglePlayLocale(defaultLocale) && Boolean(googlePlayLocales[defaultLocale]);
|
|
874
|
+
const resolvedDefault = hasConfigDefault ? defaultLocale : googlePlayLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : googleLocaleKeys[0];
|
|
875
|
+
asoData.googlePlay = {
|
|
876
|
+
locales: googlePlayLocales,
|
|
877
|
+
defaultLocale: resolvedDefault
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (config.bundleId) {
|
|
882
|
+
const appStoreLocales = {};
|
|
883
|
+
const metadata = config.metadata || {};
|
|
884
|
+
const screenshots = metadata.screenshots || {};
|
|
885
|
+
for (const [locale, localeData] of Object.entries(locales)) {
|
|
886
|
+
if (!isSupportedLocale(locale)) {
|
|
887
|
+
console.debug(
|
|
888
|
+
`Skipping locale ${locale} - not a valid unified locale`
|
|
889
|
+
);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (!isAppStoreLocale(locale)) {
|
|
893
|
+
console.debug(
|
|
894
|
+
`Skipping locale ${locale} - not supported by App Store`
|
|
895
|
+
);
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
const aso = localeData.aso || {};
|
|
899
|
+
if (!aso || !aso.title && !aso.shortDescription) {
|
|
900
|
+
console.warn(
|
|
901
|
+
`Locale ${locale} has no ASO data (title or shortDescription)`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
const localeScreenshots = {
|
|
905
|
+
phone: screenshots.phone?.map(
|
|
906
|
+
(p) => p.replace("/screenshots/", `/screenshots/${locale}/`)
|
|
907
|
+
),
|
|
908
|
+
tablet: screenshots.tablet?.map(
|
|
909
|
+
(p) => p.replace("/screenshots/", `/screenshots/${locale}/`)
|
|
910
|
+
)
|
|
911
|
+
};
|
|
912
|
+
appStoreLocales[locale] = {
|
|
913
|
+
name: aso.title || "",
|
|
914
|
+
subtitle: aso.subtitle,
|
|
915
|
+
description: generateFullDescription(localeData, metadata),
|
|
916
|
+
keywords: Array.isArray(aso.keywords) ? aso.keywords.join(", ") : aso.keywords,
|
|
917
|
+
promotionalText: void 0,
|
|
918
|
+
bundleId: config.bundleId,
|
|
919
|
+
locale,
|
|
920
|
+
supportUrl: metadata.supportUrl,
|
|
921
|
+
marketingUrl: metadata.marketingUrl,
|
|
922
|
+
privacyPolicyUrl: metadata.privacyUrl,
|
|
923
|
+
screenshots: {
|
|
924
|
+
// 폰 스크린샷을 iphone65로 매핑
|
|
925
|
+
iphone65: localeScreenshots.phone || [],
|
|
926
|
+
// 태블릿 스크린샷을 ipadPro129로 매핑
|
|
927
|
+
ipadPro129: localeScreenshots.tablet
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
const appStoreLocaleKeys = Object.keys(appStoreLocales);
|
|
932
|
+
if (appStoreLocaleKeys.length > 0) {
|
|
933
|
+
const hasConfigDefault = isAppStoreLocale(defaultLocale) && Boolean(appStoreLocales[defaultLocale]);
|
|
934
|
+
const resolvedDefault = hasConfigDefault ? defaultLocale : appStoreLocales[DEFAULT_LOCALE] ? DEFAULT_LOCALE : appStoreLocaleKeys[0];
|
|
935
|
+
asoData.appStore = {
|
|
936
|
+
locales: appStoreLocales,
|
|
937
|
+
defaultLocale: resolvedDefault
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
const hasGooglePlay = !!asoData.googlePlay;
|
|
942
|
+
const hasAppStore = !!asoData.appStore;
|
|
943
|
+
console.debug(`[loadAsoFromConfig] Result for ${slug}:`);
|
|
944
|
+
console.debug(
|
|
945
|
+
` - Google Play data: ${hasGooglePlay ? "found" : "not found"}`
|
|
946
|
+
);
|
|
947
|
+
console.debug(` - App Store data: ${hasAppStore ? "found" : "not found"}`);
|
|
948
|
+
if (!hasGooglePlay && !hasAppStore) {
|
|
949
|
+
console.warn(`[loadAsoFromConfig] No ASO data generated for ${slug}`);
|
|
950
|
+
}
|
|
951
|
+
return asoData;
|
|
952
|
+
} catch (error) {
|
|
953
|
+
console.error(
|
|
954
|
+
`[loadAsoFromConfig] Failed to load ASO data from config for ${slug}:`,
|
|
955
|
+
error
|
|
956
|
+
);
|
|
957
|
+
return {};
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
function saveAsoToConfig(slug, config) {
|
|
961
|
+
const productsDir = getProductsDir();
|
|
962
|
+
const configPath = path2.join(productsDir, slug, "config.json");
|
|
963
|
+
fs2.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
964
|
+
}
|
|
965
|
+
function saveAsoToAsoDir(slug, asoData) {
|
|
966
|
+
const rootDir = getPushDataDir();
|
|
967
|
+
if (asoData.googlePlay) {
|
|
968
|
+
const asoPath = path2.join(
|
|
969
|
+
rootDir,
|
|
970
|
+
"products",
|
|
971
|
+
slug,
|
|
972
|
+
"store",
|
|
973
|
+
"google-play",
|
|
974
|
+
"aso-data.json"
|
|
975
|
+
);
|
|
976
|
+
const dir = path2.dirname(asoPath);
|
|
977
|
+
if (!fs2.existsSync(dir)) {
|
|
978
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
979
|
+
}
|
|
980
|
+
const googlePlayData = asoData.googlePlay;
|
|
981
|
+
const multilingualData = "locales" in googlePlayData ? googlePlayData : {
|
|
982
|
+
locales: {
|
|
983
|
+
[googlePlayData.defaultLanguage || DEFAULT_LOCALE]: googlePlayData
|
|
984
|
+
},
|
|
985
|
+
defaultLocale: googlePlayData.defaultLanguage || DEFAULT_LOCALE
|
|
986
|
+
};
|
|
987
|
+
fs2.writeFileSync(
|
|
988
|
+
asoPath,
|
|
989
|
+
JSON.stringify({ googlePlay: multilingualData }, null, 2) + "\n",
|
|
990
|
+
"utf-8"
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
if (asoData.appStore) {
|
|
994
|
+
const asoPath = path2.join(
|
|
995
|
+
rootDir,
|
|
996
|
+
"products",
|
|
997
|
+
slug,
|
|
998
|
+
"store",
|
|
999
|
+
"app-store",
|
|
1000
|
+
"aso-data.json"
|
|
1001
|
+
);
|
|
1002
|
+
const dir = path2.dirname(asoPath);
|
|
1003
|
+
if (!fs2.existsSync(dir)) {
|
|
1004
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
1005
|
+
}
|
|
1006
|
+
const appStoreData = asoData.appStore;
|
|
1007
|
+
const multilingualData = "locales" in appStoreData ? appStoreData : {
|
|
1008
|
+
locales: {
|
|
1009
|
+
[appStoreData.locale || DEFAULT_LOCALE]: appStoreData
|
|
1010
|
+
},
|
|
1011
|
+
defaultLocale: appStoreData.locale || DEFAULT_LOCALE
|
|
1012
|
+
};
|
|
1013
|
+
fs2.writeFileSync(
|
|
1014
|
+
asoPath,
|
|
1015
|
+
JSON.stringify({ appStore: multilingualData }, null, 2) + "\n",
|
|
1016
|
+
"utf-8"
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
export {
|
|
1022
|
+
UNIFIED_LOCALES,
|
|
1023
|
+
DEFAULT_LOCALE,
|
|
1024
|
+
UNIFIED_TO_APP_STORE,
|
|
1025
|
+
UNIFIED_TO_GOOGLE_PLAY,
|
|
1026
|
+
APP_STORE_TO_UNIFIED,
|
|
1027
|
+
GOOGLE_PLAY_TO_UNIFIED,
|
|
1028
|
+
appStoreToUnified,
|
|
1029
|
+
googlePlayToUnified,
|
|
1030
|
+
isSupportedLocale,
|
|
1031
|
+
isAppStoreLocale,
|
|
1032
|
+
isGooglePlayLocale,
|
|
1033
|
+
isGooglePlayMultilingual,
|
|
1034
|
+
isAppStoreMultilingual,
|
|
1035
|
+
unifiedToAppStore,
|
|
1036
|
+
unifiedToGooglePlay,
|
|
1037
|
+
unifiedToBothPlatforms,
|
|
1038
|
+
appStoreToUnified2,
|
|
1039
|
+
googlePlayToUnified2,
|
|
1040
|
+
unifiedToAppStoreBatch,
|
|
1041
|
+
unifiedToGooglePlayBatch,
|
|
1042
|
+
appStoreToUnifiedBatch,
|
|
1043
|
+
googlePlayToUnifiedBatch,
|
|
1044
|
+
appStoreToGooglePlay,
|
|
1045
|
+
googlePlayToAppStore,
|
|
1046
|
+
convertObjectToAppStore,
|
|
1047
|
+
convertObjectToGooglePlay,
|
|
1048
|
+
convertObjectFromAppStore,
|
|
1049
|
+
convertObjectFromGooglePlay,
|
|
1050
|
+
getAsoDataDir,
|
|
1051
|
+
getPullDataDir,
|
|
1052
|
+
getPushDataDir,
|
|
1053
|
+
getPublicDir,
|
|
1054
|
+
getProductsDir,
|
|
1055
|
+
loadAsoFromConfig,
|
|
1056
|
+
saveAsoToConfig,
|
|
1057
|
+
saveAsoToAsoDir
|
|
1058
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -512,7 +512,8 @@ interface BlogMetaOutput {
|
|
|
512
512
|
}
|
|
513
513
|
interface CreateBlogHtmlInput {
|
|
514
514
|
/**
|
|
515
|
-
* Product/app slug used for paths and CTAs
|
|
515
|
+
* Product/app slug used for paths and CTAs.
|
|
516
|
+
* Defaults to "developer" when not provided.
|
|
516
517
|
*/
|
|
517
518
|
appSlug: string;
|
|
518
519
|
/**
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pabal-web-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for ASO data management with shared types and utilities",
|
|
6
6
|
"author": "skyu",
|
|
@@ -23,9 +23,21 @@
|
|
|
23
23
|
"exports": {
|
|
24
24
|
".": {
|
|
25
25
|
"types": "./dist/index.d.ts",
|
|
26
|
-
"import": "./dist/index.js"
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"require": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./server": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.js"
|
|
27
33
|
}
|
|
28
34
|
},
|
|
35
|
+
"browser": {
|
|
36
|
+
"node:fs": false,
|
|
37
|
+
"node:path": false,
|
|
38
|
+
"node:os": false
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": false,
|
|
29
41
|
"bin": {
|
|
30
42
|
"pabal-web-mcp": "./dist/bin/mcp-server.js"
|
|
31
43
|
},
|
|
@@ -33,7 +45,7 @@
|
|
|
33
45
|
"dist"
|
|
34
46
|
],
|
|
35
47
|
"scripts": {
|
|
36
|
-
"build": "tsup src/index.ts src/bin/mcp-server.ts --format esm --dts",
|
|
48
|
+
"build": "tsup src/index.ts src/bin/mcp-server.ts --format esm --dts --external node:fs --external node:path --external node:os",
|
|
37
49
|
"dev": "tsx src/bin/mcp-server.ts",
|
|
38
50
|
"typecheck": "tsc --noEmit",
|
|
39
51
|
"prepublishOnly": "npm run build"
|