pabal-web-mcp 1.4.4 → 1.4.5

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.
@@ -530,6 +530,7 @@ var GOOGLE_PLAY_LIMITS = {
530
530
  shortDescription: 80,
531
531
  fullDescription: 4e3
532
532
  };
533
+ var INVALID_CHAR_REGEX = /[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F\uFEFF\u200B-\u200F\u202A-\u202E\u2060\uFE00-\uFE0F]/g;
533
534
  var toJsonSchema2 = zodToJsonSchema2;
534
535
  var publicToAsoInputSchema = z2.object({
535
536
  slug: z2.string().describe("Product slug"),
@@ -540,6 +541,76 @@ var jsonSchema2 = toJsonSchema2(publicToAsoInputSchema, {
540
541
  $refStrategy: "none"
541
542
  });
542
543
  var inputSchema2 = jsonSchema2.definitions?.PublicToAsoInput || jsonSchema2;
544
+ function sanitizeText(value, fieldPath, warnings) {
545
+ if (typeof value !== "string") {
546
+ return value;
547
+ }
548
+ const cleaned = value.replace(INVALID_CHAR_REGEX, "");
549
+ if (cleaned !== value) {
550
+ warnings.push(`Removed invalid characters from ${fieldPath}`);
551
+ }
552
+ return cleaned;
553
+ }
554
+ function sanitizeAsoData(configData) {
555
+ const sanitizedData = JSON.parse(JSON.stringify(configData));
556
+ const warnings = [];
557
+ if (sanitizedData.appStore) {
558
+ const appStoreData = sanitizedData.appStore;
559
+ const locales = isAppStoreMultilingual(appStoreData) ? appStoreData.locales : { [appStoreData.locale || DEFAULT_LOCALE]: appStoreData };
560
+ for (const [locale, data] of Object.entries(locales)) {
561
+ data.name = sanitizeText(data.name, `App Store [${locale}].name`, warnings);
562
+ data.subtitle = sanitizeText(
563
+ data.subtitle,
564
+ `App Store [${locale}].subtitle`,
565
+ warnings
566
+ );
567
+ data.keywords = sanitizeText(
568
+ data.keywords,
569
+ `App Store [${locale}].keywords`,
570
+ warnings
571
+ );
572
+ data.promotionalText = sanitizeText(
573
+ data.promotionalText,
574
+ `App Store [${locale}].promotionalText`,
575
+ warnings
576
+ );
577
+ data.description = sanitizeText(
578
+ data.description,
579
+ `App Store [${locale}].description`,
580
+ warnings
581
+ );
582
+ data.whatsNew = sanitizeText(
583
+ data.whatsNew,
584
+ `App Store [${locale}].whatsNew`,
585
+ warnings
586
+ );
587
+ }
588
+ }
589
+ if (sanitizedData.googlePlay) {
590
+ const googlePlayData = sanitizedData.googlePlay;
591
+ const locales = isGooglePlayMultilingual(googlePlayData) ? googlePlayData.locales : {
592
+ [googlePlayData.defaultLanguage || DEFAULT_LOCALE]: googlePlayData
593
+ };
594
+ for (const [locale, data] of Object.entries(locales)) {
595
+ data.title = sanitizeText(
596
+ data.title,
597
+ `Google Play [${locale}].title`,
598
+ warnings
599
+ );
600
+ data.shortDescription = sanitizeText(
601
+ data.shortDescription,
602
+ `Google Play [${locale}].shortDescription`,
603
+ warnings
604
+ );
605
+ data.fullDescription = sanitizeText(
606
+ data.fullDescription,
607
+ `Google Play [${locale}].fullDescription`,
608
+ warnings
609
+ );
610
+ }
611
+ }
612
+ return { sanitizedData, warnings };
613
+ }
543
614
  function validateFieldLimits(configData) {
544
615
  const issues = [];
545
616
  if (configData.appStore) {
@@ -738,7 +809,8 @@ Before running, review ${FIELD_LIMITS_DOC_PATH} for per-store limits. This prepa
738
809
  async function handlePublicToAso(input) {
739
810
  const { slug, dryRun } = input;
740
811
  const configData = loadAsoFromConfig(slug);
741
- if (!configData.googlePlay && !configData.appStore) {
812
+ const { sanitizedData, warnings: sanitizeWarnings } = sanitizeAsoData(configData);
813
+ if (!sanitizedData.googlePlay && !sanitizedData.appStore) {
742
814
  const productsDir = getProductsDir();
743
815
  const configPath = path4.join(productsDir, slug, "config.json");
744
816
  const localesDir = path4.join(productsDir, slug, "locales");
@@ -819,8 +891,8 @@ Possible causes:
819
891
  4. Locale files don't contain valid ASO data`
820
892
  );
821
893
  }
822
- const storeData = prepareAsoDataForPush(slug, configData);
823
- const validationIssues = validateFieldLimits(configData);
894
+ const storeData = prepareAsoDataForPush(slug, sanitizedData);
895
+ const validationIssues = validateFieldLimits(sanitizedData);
824
896
  const validationMessage = validationIssues.length > 0 ? `\u26A0\uFE0F Field limit issues (see ${FIELD_LIMITS_DOC_PATH}):
825
897
  - ${validationIssues.join(
826
898
  "\n- "
@@ -839,7 +911,9 @@ ${JSON.stringify(
839
911
  2
840
912
  )}
841
913
 
842
- ${validationMessage}`
914
+ ${validationMessage}${sanitizeWarnings.length ? `
915
+ Sanitized invalid characters:
916
+ - ${sanitizeWarnings.join("\n- ")}` : ""}`
843
917
  }
844
918
  ]
845
919
  };
@@ -880,6 +954,13 @@ ${validationMessage}`
880
954
  Next step: Push to stores using pabal-mcp's aso-push tool`;
881
955
  responseText += `
882
956
  Reference: ${FIELD_LIMITS_DOC_PATH}`;
957
+ if (sanitizeWarnings.length > 0) {
958
+ responseText += `
959
+ Sanitized invalid characters:
960
+ - ${sanitizeWarnings.join(
961
+ "\n- "
962
+ )}`;
963
+ }
883
964
  return {
884
965
  content: [
885
966
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-web-mcp",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",