From a2edbe363e6202458bc5e57240d07d48cf52c955 Mon Sep 17 00:00:00 2001 From: Donny Yung Date: Wed, 11 Mar 2026 21:14:50 -0400 Subject: [PATCH] fix: preserve language_presets locale code keys from case conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Locale codes like "pt-br" under language_presets are user-defined identifiers, not schema fields. Without this fix, they get incorrectly converted (pt-br → ptBr / pt_br) during push/pull, breaking the API. Co-Authored-By: Claude Opus 4.6 --- src/__tests__/utils.test.ts | 103 ++++++++++++++++++++++++++++++++++++ src/shared/utils.ts | 1 + 2 files changed, 104 insertions(+) diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 420ede4..b85f514 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -594,6 +594,109 @@ describe("Utils", () => { }); }); + it("should preserve language_presets locale keys in toCamelCaseKeys", () => { + const input = { + conversation_config: { + language_presets: { + "pt-br": { + overrides: { + agent: { + first_message: "Olá!" + } + } + }, + "en": { + overrides: { + agent: { + first_message: "Hello!" + } + } + } + } + } + }; + + const result = toCamelCaseKeys(input); + + expect(result).toEqual({ + conversationConfig: { + languagePresets: { + "pt-br": { // preserved - locale code, NOT converted to "ptBr" + overrides: { + agent: { + firstMessage: "Olá!" // converted - schema field + } + } + }, + "en": { // preserved - locale code + overrides: { + agent: { + firstMessage: "Hello!" // converted - schema field + } + } + } + } + } + }); + }); + + it("should preserve languagePresets locale keys in toSnakeCaseKeys", () => { + const input = { + conversationConfig: { + languagePresets: { + "pt-br": { + overrides: { + agent: { + firstMessage: "Olá!" + } + } + } + } + } + }; + + const result = toSnakeCaseKeys(input); + + expect(result).toEqual({ + conversation_config: { + language_presets: { + "pt-br": { // preserved - locale code, NOT converted to "pt_br" + overrides: { + agent: { + first_message: "Olá!" // converted - schema field + } + } + } + } + } + }); + }); + + it("should maintain round-trip conversion symmetry for language_presets", () => { + const original = { + conversation_config: { + language_presets: { + "pt-br": { + overrides: { + agent: { + first_message: "Olá!" + } + }, + first_message_translation: { + source_hash: "test", + text: "Olá!" + } + } + } + } + }; + + const afterPush = toCamelCaseKeys(original); + const afterPull = toSnakeCaseKeys(afterPush); + + expect(afterPull).toEqual(original); + }); + it("should preserve workflow nodes keys in toCamelCaseKeys", () => { const input = { workflow: { diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 6bf2744..cac2116 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -123,6 +123,7 @@ function toSnakeCaseKey(key: string): string { const PRESERVE_CHILD_KEYS = new Set([ 'request_headers', 'requestHeaders', 'dynamic_variables', 'dynamicVariables', + 'language_presets', 'languagePresets', 'nodes', 'edges', ]);