@braze/sanity-plugin-ai-translation 0.2.71 → 0.2.73
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 +23 -0
- package/dist/index.js +108 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,7 @@ declare type TelemetryEvent =
|
|
|
476
476
|
| TranslationBatchStartedEvent
|
|
477
477
|
| TranslationBatchCompletedEvent
|
|
478
478
|
| TranslationJobCompletedEvent
|
|
479
|
+
| TranslationJobFailedEvent
|
|
479
480
|
| OpenAIApiCallEvent;
|
|
480
481
|
|
|
481
482
|
/**
|
|
@@ -678,6 +679,28 @@ declare interface TranslationJobCompletedEvent extends TelemetryEventBase {
|
|
|
678
679
|
};
|
|
679
680
|
}
|
|
680
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Event emitted when an individual translation job fails.
|
|
684
|
+
* This is emitted alongside the detailed error bundle (via onError) to enable
|
|
685
|
+
* easy error rate calculations by comparing job_completed vs job_failed counts.
|
|
686
|
+
* @public
|
|
687
|
+
*/
|
|
688
|
+
declare interface TranslationJobFailedEvent extends TelemetryEventBase {
|
|
689
|
+
name: "translation.job_failed";
|
|
690
|
+
data: {
|
|
691
|
+
documentId: string;
|
|
692
|
+
documentType: string;
|
|
693
|
+
sourceLanguage: string;
|
|
694
|
+
targetLanguage: string;
|
|
695
|
+
translationMode: TranslationMode;
|
|
696
|
+
durationMs: number;
|
|
697
|
+
/** Categorized error type for filtering/grouping */
|
|
698
|
+
errorType: TranslationErrorType;
|
|
699
|
+
/** Error message (kept short for metrics; full details in error bundle) */
|
|
700
|
+
errorMessage: string;
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
681
704
|
declare type TranslationMode = "sanity-only" | "openai-only";
|
|
682
705
|
|
|
683
706
|
/**
|
package/dist/index.js
CHANGED
|
@@ -482,8 +482,8 @@ function isNetworkError(error) {
|
|
|
482
482
|
return response.status >= 500 || response.status === 429;
|
|
483
483
|
}
|
|
484
484
|
if (error instanceof Error) {
|
|
485
|
-
const message = error.message;
|
|
486
|
-
if (/\b(50[0-9]|429)\b/.test(message))
|
|
485
|
+
const message = error.message.toLowerCase();
|
|
486
|
+
if (/\b(50[0-9]|429)\b/.test(message) || message.includes("rate limit"))
|
|
487
487
|
return !0;
|
|
488
488
|
}
|
|
489
489
|
return !1;
|
|
@@ -870,7 +870,14 @@ const fetchTranslationPrompts = async ({
|
|
|
870
870
|
languageFieldName
|
|
871
871
|
}) => {
|
|
872
872
|
try {
|
|
873
|
-
const doc = await
|
|
873
|
+
const doc = await retryWithBackoff(
|
|
874
|
+
() => client.fetch("*[_id == $documentId][0]", { documentId }),
|
|
875
|
+
{
|
|
876
|
+
maxAttempts: 3,
|
|
877
|
+
initialDelayMs: 1e3,
|
|
878
|
+
context: { operation: "localizeReferences.fetchDocument", documentId }
|
|
879
|
+
}
|
|
880
|
+
);
|
|
874
881
|
if (!doc) {
|
|
875
882
|
devLog.error("Document not found", new Error("Document not found"), {
|
|
876
883
|
documentId,
|
|
@@ -900,17 +907,24 @@ const fetchTranslationPrompts = async ({
|
|
|
900
907
|
}, updateReferences = async (documentId, client, refs, sourceLanguage, targetLanguage) => {
|
|
901
908
|
if (!refs?.length)
|
|
902
909
|
return [];
|
|
903
|
-
const refIds = refs.map((r) => getPublishedId(r.value)), translations = await
|
|
904
|
-
|
|
910
|
+
const refIds = refs.map((r) => getPublishedId(r.value)), translations = await retryWithBackoff(
|
|
911
|
+
() => client.fetch(
|
|
912
|
+
`*[_type == $translationMetadataSchemaType && array::intersects(translations[].value._ref, $refIds)] {
|
|
905
913
|
"sourceId": translations[_key == $sourceLanguage][0].value._ref,
|
|
906
914
|
"targetId": translations[_key == $targetLanguage][0].value._ref,
|
|
907
915
|
"targetType": translations[_key == $sourceLanguage][0].value -> _type
|
|
908
916
|
}`,
|
|
917
|
+
{
|
|
918
|
+
translationMetadataSchemaType: TRANSLATION_METADATA_TYPE,
|
|
919
|
+
refIds,
|
|
920
|
+
sourceLanguage,
|
|
921
|
+
targetLanguage
|
|
922
|
+
}
|
|
923
|
+
),
|
|
909
924
|
{
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
targetLanguage
|
|
925
|
+
maxAttempts: 3,
|
|
926
|
+
initialDelayMs: 1e3,
|
|
927
|
+
context: { operation: "localizeReferences.fetchTranslations", refCount: refIds.length }
|
|
914
928
|
}
|
|
915
929
|
), translationMap = /* @__PURE__ */ new Map();
|
|
916
930
|
for (const t of translations)
|
|
@@ -948,81 +962,80 @@ const fetchTranslationPrompts = async ({
|
|
|
948
962
|
}, updateBackwardReferences = async ({
|
|
949
963
|
client,
|
|
950
964
|
releaseId,
|
|
951
|
-
sourceDocumentIds,
|
|
952
965
|
targetLanguages,
|
|
953
966
|
sourceLanguage,
|
|
954
967
|
languageFieldName,
|
|
955
968
|
excludeDocumentIds
|
|
956
969
|
}) => {
|
|
957
|
-
if (
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
});
|
|
967
|
-
try {
|
|
968
|
-
for (const targetLanguage of targetLanguages) {
|
|
969
|
-
const existingDocsWithStaleRefs = await client.fetch(
|
|
970
|
+
if (targetLanguages.length) {
|
|
971
|
+
devLog.debug("Starting backward reference update", {
|
|
972
|
+
releaseId,
|
|
973
|
+
targetLanguages,
|
|
974
|
+
excludeCount: excludeDocumentIds.length,
|
|
975
|
+
component: "updateBackwardReferences"
|
|
976
|
+
});
|
|
977
|
+
try {
|
|
978
|
+
const existingDocs = await client.fetch(
|
|
970
979
|
`*[
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
^references(@._id)
|
|
979
|
-
]) > 0
|
|
980
|
-
}[hasStaleRefs == true]`,
|
|
980
|
+
sanity::partOfRelease($releaseId) &&
|
|
981
|
+
@[$languageFieldName] in $targetLanguages &&
|
|
982
|
+
!(_id in $excludeIds)
|
|
983
|
+
]{
|
|
984
|
+
_id,
|
|
985
|
+
"language": @[$languageFieldName]
|
|
986
|
+
}`,
|
|
981
987
|
{
|
|
982
988
|
releaseId,
|
|
983
|
-
|
|
989
|
+
targetLanguages,
|
|
984
990
|
languageFieldName,
|
|
985
|
-
excludeIds: excludeDocumentIds
|
|
986
|
-
sourceDocumentIds: normalizedSourceIds
|
|
991
|
+
excludeIds: excludeDocumentIds
|
|
987
992
|
}
|
|
988
993
|
);
|
|
989
|
-
if (
|
|
990
|
-
devLog.debug("No existing documents
|
|
994
|
+
if (existingDocs.length === 0) {
|
|
995
|
+
devLog.debug("No existing documents found in release for target languages", {
|
|
991
996
|
releaseId,
|
|
992
|
-
|
|
997
|
+
targetLanguages,
|
|
993
998
|
component: "updateBackwardReferences"
|
|
994
999
|
});
|
|
995
|
-
|
|
1000
|
+
return;
|
|
996
1001
|
}
|
|
997
|
-
devLog.info("
|
|
1002
|
+
devLog.info("Processing existing documents for backward reference updates", {
|
|
998
1003
|
releaseId,
|
|
999
|
-
|
|
1000
|
-
count:
|
|
1001
|
-
documentIds: existingDocsWithStaleRefs.map((d) => d._id),
|
|
1004
|
+
targetLanguages,
|
|
1005
|
+
count: existingDocs.length,
|
|
1002
1006
|
component: "updateBackwardReferences"
|
|
1003
|
-
})
|
|
1004
|
-
|
|
1007
|
+
});
|
|
1008
|
+
let updated = 0, errors = 0;
|
|
1009
|
+
for (const { _id } of existingDocs)
|
|
1010
|
+
try {
|
|
1005
1011
|
await localizeReferences({
|
|
1006
1012
|
client,
|
|
1007
1013
|
documentId: _id,
|
|
1008
1014
|
sourceLanguage,
|
|
1009
1015
|
languageFieldName
|
|
1016
|
+
}), updated++;
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
errors++, devLog.warn("Failed to update references for document", {
|
|
1019
|
+
documentId: _id,
|
|
1020
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1021
|
+
component: "updateBackwardReferences"
|
|
1010
1022
|
});
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1023
|
+
}
|
|
1024
|
+
devLog.info("Backward reference update complete", {
|
|
1013
1025
|
releaseId,
|
|
1014
|
-
|
|
1015
|
-
|
|
1026
|
+
targetLanguages,
|
|
1027
|
+
processed: existingDocs.length,
|
|
1028
|
+
updated,
|
|
1029
|
+
errors,
|
|
1030
|
+
component: "updateBackwardReferences"
|
|
1031
|
+
});
|
|
1032
|
+
} catch (error) {
|
|
1033
|
+
devLog.error("Error updating backward references", error instanceof Error ? error : new Error(String(error)), {
|
|
1034
|
+
releaseId,
|
|
1035
|
+
targetLanguages,
|
|
1016
1036
|
component: "updateBackwardReferences"
|
|
1017
1037
|
});
|
|
1018
1038
|
}
|
|
1019
|
-
} catch (error) {
|
|
1020
|
-
devLog.error("Error updating backward references", error instanceof Error ? error : new Error(String(error)), {
|
|
1021
|
-
releaseId,
|
|
1022
|
-
sourceDocumentIds: normalizedSourceIds,
|
|
1023
|
-
targetLanguages,
|
|
1024
|
-
component: "updateBackwardReferences"
|
|
1025
|
-
});
|
|
1026
1039
|
}
|
|
1027
1040
|
}, setupTranslationJobStatuses = (dispatch, sourceDocuments, targetLanguages, mainSourceDocumentId) => {
|
|
1028
1041
|
for (const sourceDocument of sourceDocuments)
|
|
@@ -2892,7 +2905,8 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2892
2905
|
telemetryConfig
|
|
2893
2906
|
}), newDocument = translationResult?.document;
|
|
2894
2907
|
if (!newDocument) {
|
|
2895
|
-
|
|
2908
|
+
const failureError = new Error("Translation returned null");
|
|
2909
|
+
devLog.error("Translation failed: no document returned", failureError, logContext), setJobStatus(
|
|
2896
2910
|
dispatch,
|
|
2897
2911
|
sourceDocument._id,
|
|
2898
2912
|
targetLanguage,
|
|
@@ -2901,7 +2915,20 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2901
2915
|
errorMessage: "Translation failed"
|
|
2902
2916
|
},
|
|
2903
2917
|
mainSourceDocumentId
|
|
2904
|
-
),
|
|
2918
|
+
), emitTelemetryEvent(telemetryConfig, {
|
|
2919
|
+
name: "translation.job_failed",
|
|
2920
|
+
timestamp: createTimestamp(),
|
|
2921
|
+
data: {
|
|
2922
|
+
documentId: sourceDocument._id,
|
|
2923
|
+
documentType: sourceDocument._type,
|
|
2924
|
+
sourceLanguage,
|
|
2925
|
+
targetLanguage,
|
|
2926
|
+
translationMode,
|
|
2927
|
+
durationMs: Date.now() - jobStartTime,
|
|
2928
|
+
errorType: classifyError(failureError),
|
|
2929
|
+
errorMessage: "Translation failed"
|
|
2930
|
+
}
|
|
2931
|
+
}), devLog.timeEnd("translateDocument"), devLog.groupEnd();
|
|
2905
2932
|
return;
|
|
2906
2933
|
}
|
|
2907
2934
|
return setJobStatus(
|
|
@@ -2950,8 +2977,8 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2950
2977
|
}
|
|
2951
2978
|
}), devLog.timeEnd("translateDocument"), devLog.groupEnd(), newDocument._id;
|
|
2952
2979
|
} catch (error) {
|
|
2953
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2954
|
-
devLog.error("Translation failed",
|
|
2980
|
+
const errorMessage = error instanceof Error ? error.message : String(error), errorObj = error instanceof Error ? error : new Error(String(error));
|
|
2981
|
+
devLog.error("Translation failed", errorObj, logContext), setJobStatus(
|
|
2955
2982
|
dispatch,
|
|
2956
2983
|
sourceDocument._id,
|
|
2957
2984
|
targetLanguage,
|
|
@@ -2960,7 +2987,20 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2960
2987
|
errorMessage
|
|
2961
2988
|
},
|
|
2962
2989
|
mainSourceDocumentId
|
|
2963
|
-
),
|
|
2990
|
+
), emitTelemetryEvent(telemetryConfig, {
|
|
2991
|
+
name: "translation.job_failed",
|
|
2992
|
+
timestamp: createTimestamp(),
|
|
2993
|
+
data: {
|
|
2994
|
+
documentId: sourceDocument._id,
|
|
2995
|
+
documentType: sourceDocument._type,
|
|
2996
|
+
sourceLanguage,
|
|
2997
|
+
targetLanguage,
|
|
2998
|
+
translationMode,
|
|
2999
|
+
durationMs: Date.now() - jobStartTime,
|
|
3000
|
+
errorType: classifyError(errorObj),
|
|
3001
|
+
errorMessage
|
|
3002
|
+
}
|
|
3003
|
+
}), devLog.timeEnd("translateDocument"), devLog.groupEnd();
|
|
2964
3004
|
return;
|
|
2965
3005
|
}
|
|
2966
3006
|
}, translationSemaphore = new Semaphore(2), translateDocumentSet = async ({
|
|
@@ -3149,10 +3189,14 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3149
3189
|
languageFieldName
|
|
3150
3190
|
});
|
|
3151
3191
|
})
|
|
3152
|
-
),
|
|
3192
|
+
), devLog.debug("Checking if backward reference update is needed", {
|
|
3193
|
+
releaseMode: releaseConfig.mode,
|
|
3194
|
+
releaseId,
|
|
3195
|
+
willUpdate: releaseConfig.mode === "existing" && !!releaseId,
|
|
3196
|
+
component: "translateDocumentSet"
|
|
3197
|
+
}), releaseConfig.mode === "existing" && releaseId && await updateBackwardReferences({
|
|
3153
3198
|
client,
|
|
3154
3199
|
releaseId,
|
|
3155
|
-
sourceDocumentIds,
|
|
3156
3200
|
targetLanguages,
|
|
3157
3201
|
sourceLanguage,
|
|
3158
3202
|
languageFieldName,
|