@braze/sanity-plugin-ai-translation 0.2.74 → 0.2.75

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/index.d.ts CHANGED
@@ -340,12 +340,18 @@ export declare interface PluginConfig {
340
340
  * nested paths (e.g., 'meta.internalId'), wildcard arrays (e.g., 'sections[*].legacyId'),
341
341
  * and hierarchical matches (e.g., '**.tmpField').
342
342
  *
343
+ * Each entry can be a plain string (always unset) or an object with `preserveExisting: true`
344
+ * to retain the field's value from the published target document during re-translation.
345
+ *
343
346
  * @example
344
347
  * ```typescript
345
- * unsetFields: ['courseId', 'meta.internalId', 'sections[*].legacyId']
348
+ * unsetFields: [
349
+ * 'legacyId',
350
+ * { field: 'skilljarCourseId', preserveExisting: true }
351
+ * ]
346
352
  * ```
347
353
  */
348
- unsetFields?: string[];
354
+ unsetFields?: UnsetFieldEntry[];
349
355
  /**
350
356
  * Optional telemetry configuration for monitoring translation operations.
351
357
  * Provides callbacks for lightweight events and detailed error bundles.
@@ -717,6 +723,28 @@ declare interface TranslationJobFailedEvent extends TelemetryEventBase {
717
723
 
718
724
  declare type TranslationMode = "sanity-only" | "openai-only";
719
725
 
726
+ /**
727
+ * Configuration for a field that should be unset with additional options.
728
+ * @public
729
+ */
730
+ declare interface UnsetFieldConfig {
731
+ /** Field pattern to unset (same syntax as `excludeFields`) */
732
+ field: string;
733
+ /**
734
+ * When true, preserves the field's value from the published target document
735
+ * during re-translation. Has no effect on first translation (no existing target).
736
+ * Defaults to false.
737
+ */
738
+ preserveExisting?: boolean;
739
+ }
740
+
741
+ /**
742
+ * An entry in the `unsetFields` array: either a plain field pattern string
743
+ * or an object with additional configuration.
744
+ * @public
745
+ */
746
+ declare type UnsetFieldEntry = string | UnsetFieldConfig;
747
+
720
748
  /**
721
749
  * Represents a VTT caption cue with timing and text content.
722
750
  */
package/dist/index.js CHANGED
@@ -1360,10 +1360,16 @@ const COMMON_ENUM_FIELDS = [
1360
1360
  /** SEO and URL-related fields that often shouldn't be translated */
1361
1361
  seo: ["slug", "handle", "permalink", "canonical", "redirect", "robots", "sitemap"]
1362
1362
  };
1363
+ function normalizeUnsetFields(entries) {
1364
+ const allFieldPatterns = [], preserveFieldPatterns = [];
1365
+ for (const entry of entries)
1366
+ typeof entry == "string" ? allFieldPatterns.push(entry) : (allFieldPatterns.push(entry.field), entry.preserveExisting && preserveFieldPatterns.push(entry.field));
1367
+ return { allFieldPatterns, preserveFieldPatterns };
1368
+ }
1363
1369
  function unsetDocumentFields(document, unsetFields) {
1364
1370
  if (!unsetFields.length)
1365
1371
  return document;
1366
- const { filteredDocument, excludedValues } = filterExcludedFields(document, unsetFields);
1372
+ const { allFieldPatterns } = normalizeUnsetFields(unsetFields), { filteredDocument, excludedValues } = filterExcludedFields(document, allFieldPatterns);
1367
1373
  return Object.keys(excludedValues).length > 0 && devLog.info("Unset fields from document (permanently removed)", {
1368
1374
  documentId: document._id || "unknown",
1369
1375
  unsetFieldCount: Object.keys(excludedValues).length,
@@ -2645,12 +2651,39 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
2645
2651
  mainSourceDocumentId,
2646
2652
  telemetryConfig
2647
2653
  }) => {
2648
- const startTime = Date.now(), sourceLanguage = sourceDocument[languageFieldName], safeUnsetFields = unsetFields.filter((field) => field !== languageFieldName);
2654
+ const startTime = Date.now(), sourceLanguage = sourceDocument[languageFieldName], safeUnsetFields = unsetFields.filter((entry) => (typeof entry == "string" ? entry : entry.field) !== languageFieldName);
2649
2655
  unsetFields.length !== safeUnsetFields.length && devLog.warn("Language field was in unsetFields - removing it to prevent translation errors", {
2650
2656
  documentId: sourceDocument._id,
2651
2657
  languageFieldName
2652
2658
  });
2653
- const documentAfterUnset = unsetDocumentFields(sourceDocument, safeUnsetFields), safeExcludeFields = excludeFields.filter((field) => field !== languageFieldName);
2659
+ const documentAfterUnset = unsetDocumentFields(sourceDocument, safeUnsetFields), { preserveFieldPatterns } = normalizeUnsetFields(safeUnsetFields);
2660
+ let documentWithPreserved = documentAfterUnset;
2661
+ if (preserveFieldPatterns.length > 0 && existingTranslationId)
2662
+ try {
2663
+ const publishedTarget = await client.getDocument(existingTranslationId);
2664
+ if (publishedTarget) {
2665
+ const { excludedValues: preserveValues } = filterExcludedFields(
2666
+ publishedTarget,
2667
+ preserveFieldPatterns
2668
+ );
2669
+ Object.keys(preserveValues).length > 0 && (documentWithPreserved = restoreExcludedFields(documentAfterUnset, preserveValues), devLog.info("Preserved fields from published target during re-translation", {
2670
+ documentId: sourceDocument._id,
2671
+ existingTranslationId,
2672
+ preservedFields: Object.keys(preserveValues)
2673
+ }));
2674
+ } else
2675
+ devLog.debug("Published target not found for preserveExisting fields", {
2676
+ documentId: sourceDocument._id,
2677
+ existingTranslationId
2678
+ });
2679
+ } catch (error) {
2680
+ devLog.warn("Failed to fetch published target for preserveExisting fields", {
2681
+ documentId: sourceDocument._id,
2682
+ existingTranslationId,
2683
+ error: error instanceof Error ? error.message : String(error)
2684
+ });
2685
+ }
2686
+ const safeExcludeFields = excludeFields.filter((field) => field !== languageFieldName);
2654
2687
  excludeFields.length !== safeExcludeFields.length && devLog.warn("Language field was in excludeFields - removing it to prevent translation errors", {
2655
2688
  documentId: sourceDocument._id,
2656
2689
  languageFieldName,
@@ -2661,10 +2694,10 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
2661
2694
  documentType: sourceDocument._type,
2662
2695
  excludeFields: safeExcludeFields,
2663
2696
  excludeFieldsLength: safeExcludeFields?.length ?? 0,
2664
- sourceHasTitle: "title" in documentAfterUnset,
2665
- sourceTitleValue: documentAfterUnset.title
2697
+ sourceHasTitle: "title" in documentWithPreserved,
2698
+ sourceTitleValue: documentWithPreserved.title
2666
2699
  });
2667
- const { filteredDocument, excludedValues } = filterExcludedFields(documentAfterUnset, safeExcludeFields);
2700
+ const { filteredDocument, excludedValues } = filterExcludedFields(documentWithPreserved, safeExcludeFields);
2668
2701
  devLog.info("After filtering excluded fields", {
2669
2702
  documentId: sourceDocument._id,
2670
2703
  filteredHasTitle: "title" in filteredDocument,
@@ -3078,7 +3111,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
3078
3111
  metadata: {
3079
3112
  title: releaseTitle,
3080
3113
  description: releaseDescription,
3081
- releaseType: "undecided"
3114
+ releaseType: "asap"
3082
3115
  }
3083
3116
  }),
3084
3117
  {