fix(ts-sdk): preserve user metadata keys across the case-conversion round-trip (#5515)
This commit is contained in:
@@ -14,9 +14,27 @@ function snakeToCamel(str: string): string {
|
||||
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys whose values are user-controlled, opaque blobs. Their nested keys must
|
||||
* be passed through verbatim — converting them would silently rewrite the
|
||||
* user's own keys and break round-trips (see issue #5055).
|
||||
*
|
||||
* The check runs against the source key, so a multi-word key must be listed in
|
||||
* both casings to be covered in both directions: the camelCase form for the
|
||||
* outbound `camelToSnakeKeys` path and the snake_case form for the inbound
|
||||
* `snakeToCamelKeys` path. `metadata` is spelled identically in both, so one
|
||||
* entry suffices; `structuredDataSchema` needs both.
|
||||
*/
|
||||
const OPAQUE_VALUE_KEYS = new Set([
|
||||
"metadata",
|
||||
"structuredDataSchema",
|
||||
"structured_data_schema",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Recursively converts all keys of an object from camelCase to snake_case.
|
||||
* Used for converting user-facing camelCase params to API snake_case payloads.
|
||||
* Values under {@link OPAQUE_VALUE_KEYS} (e.g. `metadata`) are left untouched.
|
||||
*/
|
||||
export function camelToSnakeKeys(obj: any): any {
|
||||
if (obj === null || obj === undefined || typeof obj !== "object") return obj;
|
||||
@@ -26,7 +44,7 @@ export function camelToSnakeKeys(obj: any): any {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([key, value]) => [
|
||||
camelToSnake(key),
|
||||
camelToSnakeKeys(value),
|
||||
OPAQUE_VALUE_KEYS.has(key) ? value : camelToSnakeKeys(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@@ -34,6 +52,7 @@ export function camelToSnakeKeys(obj: any): any {
|
||||
/**
|
||||
* Recursively converts all keys of an object from snake_case to camelCase.
|
||||
* Used for converting API snake_case responses to user-facing camelCase.
|
||||
* Values under {@link OPAQUE_VALUE_KEYS} (e.g. `metadata`) are left untouched.
|
||||
*/
|
||||
export function snakeToCamelKeys(obj: any): any {
|
||||
if (obj === null || obj === undefined || typeof obj !== "object") return obj;
|
||||
@@ -43,7 +62,7 @@ export function snakeToCamelKeys(obj: any): any {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([key, value]) => [
|
||||
snakeToCamel(key),
|
||||
snakeToCamelKeys(value),
|
||||
OPAQUE_VALUE_KEYS.has(key) ? value : snakeToCamelKeys(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user