From 8ad29c68bdd1e954011b35a464c9b09c4bccac8f Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 09:47:35 -0400 Subject: [PATCH 1/5] Support _keepTypedInAdditionalProperties for UsageSummary models Add a static `_keepTypedInAdditionalProperties = true` flag to UsageSummaryDate, UsageSummaryDateOrg, and UsageSummaryResponse. Update ObjectSerializer (v1 + v2) to include typed keys in additionalProperties when a model sets this flag, giving a single unified access pattern for all fields. Note: ObjectSerializer is auto-generated; the upstream generator also needs updating to emit the keepAllInAdditional guard for flagged models. Co-Authored-By: Claude Sonnet 4.6 --- packages/datadog-api-client-v1/models/ObjectSerializer.ts | 3 ++- packages/datadog-api-client-v1/models/UsageSummaryDate.ts | 5 +++++ packages/datadog-api-client-v1/models/UsageSummaryDateOrg.ts | 5 +++++ .../datadog-api-client-v1/models/UsageSummaryResponse.ts | 5 +++++ packages/datadog-api-client-v2/models/ObjectSerializer.ts | 3 ++- 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/datadog-api-client-v1/models/ObjectSerializer.ts b/packages/datadog-api-client-v1/models/ObjectSerializer.ts index e5d375b7657f..a77d57793d14 100644 --- a/packages/datadog-api-client-v1/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v1/models/ObjectSerializer.ts @@ -3343,8 +3343,9 @@ export class ObjectSerializer { (o, key) => Object.assign(o, { [attributesMap[key].baseName]: "" }), {} ); + const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; const extraAttributes = Object.keys(data).filter( - (key) => !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) + (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); if (extraAttributes.length > 0) { diff --git a/packages/datadog-api-client-v1/models/UsageSummaryDate.ts b/packages/datadog-api-client-v1/models/UsageSummaryDate.ts index dc74ed981206..9f9bba0933c3 100644 --- a/packages/datadog-api-client-v1/models/UsageSummaryDate.ts +++ b/packages/datadog-api-client-v1/models/UsageSummaryDate.ts @@ -1269,6 +1269,11 @@ export class UsageSummaryDate { */ "_unparsed"?: boolean; + /** + * @ignore + */ + static readonly _keepTypedInAdditionalProperties = true; + /** * @ignore */ diff --git a/packages/datadog-api-client-v1/models/UsageSummaryDateOrg.ts b/packages/datadog-api-client-v1/models/UsageSummaryDateOrg.ts index 2180f8b16ba4..5bd804d09d3e 100644 --- a/packages/datadog-api-client-v1/models/UsageSummaryDateOrg.ts +++ b/packages/datadog-api-client-v1/models/UsageSummaryDateOrg.ts @@ -1292,6 +1292,11 @@ export class UsageSummaryDateOrg { */ "_unparsed"?: boolean; + /** + * @ignore + */ + static readonly _keepTypedInAdditionalProperties = true; + /** * @ignore */ diff --git a/packages/datadog-api-client-v1/models/UsageSummaryResponse.ts b/packages/datadog-api-client-v1/models/UsageSummaryResponse.ts index 0aff482a5798..45180af90e89 100644 --- a/packages/datadog-api-client-v1/models/UsageSummaryResponse.ts +++ b/packages/datadog-api-client-v1/models/UsageSummaryResponse.ts @@ -1315,6 +1315,11 @@ export class UsageSummaryResponse { */ "_unparsed"?: boolean; + /** + * @ignore + */ + static readonly _keepTypedInAdditionalProperties = true; + /** * @ignore */ diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index f435551d4819..03755e1f28ef 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -14705,8 +14705,9 @@ export class ObjectSerializer { (o, key) => Object.assign(o, { [attributesMap[key].baseName]: "" }), {} ); + const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; const extraAttributes = Object.keys(data).filter( - (key) => !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) + (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); if (extraAttributes.length > 0) { From 38012093ea283a7a6ad1500f765d33579793070a Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 10:11:11 -0400 Subject: [PATCH 2/5] fix: preserve int64 precision for typed fields in keepAllInAdditional mode When _keepTypedInAdditionalProperties is true, known typed attributes are now deserialized with their declared type/format before being stored in additionalProperties. This routes int64 fields through the BigInt conversion path instead of raw JSON number assignment. Also removes the redundant instance.additionalProperties initialization guard that was immediately overwritten. Co-Authored-By: Claude Sonnet 4.6 --- .../models/ObjectSerializer.ts | 39 ++++++++++++------- .../models/ObjectSerializer.ts | 39 ++++++++++++------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/packages/datadog-api-client-v1/models/ObjectSerializer.ts b/packages/datadog-api-client-v1/models/ObjectSerializer.ts index a77d57793d14..145499f45b08 100644 --- a/packages/datadog-api-client-v1/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v1/models/ObjectSerializer.ts @@ -3350,21 +3350,34 @@ export class ObjectSerializer { if (extraAttributes.length > 0) { if ("additionalProperties" in attributesMap) { - if (!instance.additionalProperties) { - instance.additionalProperties = {}; - } - const additionalProperties: { [key: string]: any } = {}; - for (const key of extraAttributes) { - additionalProperties[key] = data[key]; + if (keepAllInAdditional) { + // Build reverse map from JSON baseName → attribute config for per-field deserialization. + // This preserves int64 precision for typed numeric fields via their declared format. + const baseNameToAttr: { [key: string]: any } = {}; + for (const attrName in attributesMap) { + if (attrName !== "additionalProperties") { + baseNameToAttr[attributesMap[attrName].baseName] = attributesMap[attrName]; + } + } + for (const key of extraAttributes) { + const attrInfo = baseNameToAttr[key]; + additionalProperties[key] = attrInfo + ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) + : data[key]; + } + instance.additionalProperties = additionalProperties; + } else { + for (const key of extraAttributes) { + additionalProperties[key] = data[key]; + } + const attributeObj = attributesMap["additionalProperties"]; + instance.additionalProperties = ObjectSerializer.deserialize( + additionalProperties, + attributeObj.type, + attributeObj.format + ); } - - const attributeObj = attributesMap["additionalProperties"]; - instance.additionalProperties = ObjectSerializer.deserialize( - additionalProperties, - attributeObj.type, - attributeObj.format - ); } else { throw new Error( `found extra attributes '${extraAttributes}' in ${type}` diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index 03755e1f28ef..aff8c022d6c2 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -14712,21 +14712,34 @@ export class ObjectSerializer { if (extraAttributes.length > 0) { if ("additionalProperties" in attributesMap) { - if (!instance.additionalProperties) { - instance.additionalProperties = {}; - } - const additionalProperties: { [key: string]: any } = {}; - for (const key of extraAttributes) { - additionalProperties[key] = data[key]; + if (keepAllInAdditional) { + // Build reverse map from JSON baseName → attribute config for per-field deserialization. + // This preserves int64 precision for typed numeric fields via their declared format. + const baseNameToAttr: { [key: string]: any } = {}; + for (const attrName in attributesMap) { + if (attrName !== "additionalProperties") { + baseNameToAttr[attributesMap[attrName].baseName] = attributesMap[attrName]; + } + } + for (const key of extraAttributes) { + const attrInfo = baseNameToAttr[key]; + additionalProperties[key] = attrInfo + ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) + : data[key]; + } + instance.additionalProperties = additionalProperties; + } else { + for (const key of extraAttributes) { + additionalProperties[key] = data[key]; + } + const attributeObj = attributesMap["additionalProperties"]; + instance.additionalProperties = ObjectSerializer.deserialize( + additionalProperties, + attributeObj.type, + attributeObj.format + ); } - - const attributeObj = attributesMap["additionalProperties"]; - instance.additionalProperties = ObjectSerializer.deserialize( - additionalProperties, - attributeObj.type, - attributeObj.format - ); } else { throw new Error( `found extra attributes '${extraAttributes}' in ${type}` From 65720068932eca3607ee59c8ed0a4af215ffbbc4 Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 10:59:15 -0400 Subject: [PATCH 3/5] perf: merge attributesBaseNames and baseNameToAttr into a single attributesMap pass Previously the keepAllInAdditional path rebuilt a baseNameToAttr reverse map inside the conditional on every deserialization call. Hoisting it to a single combined loop halves the attributesMap iterations per call for flagged models. Co-Authored-By: Claude Sonnet 4.6 --- .../models/ObjectSerializer.ts | 24 +++++++++---------- .../models/ObjectSerializer.ts | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/datadog-api-client-v1/models/ObjectSerializer.ts b/packages/datadog-api-client-v1/models/ObjectSerializer.ts index 145499f45b08..a57e03604deb 100644 --- a/packages/datadog-api-client-v1/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v1/models/ObjectSerializer.ts @@ -3339,11 +3339,18 @@ export class ObjectSerializer { const instance = new typeMap[type](); const attributesMap = typeMap[type].getAttributeTypeMap(); - const attributesBaseNames = Object.keys(attributesMap).reduce( - (o, key) => Object.assign(o, { [attributesMap[key].baseName]: "" }), - {} - ); const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; + // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, + // baseNameToAttr (for per-field typed deserialization preserving int64 precision). + const attributesBaseNames: { [key: string]: string } = {}; + const baseNameToAttr: { [key: string]: any } = keepAllInAdditional ? {} : null; + for (const attrName in attributesMap) { + const baseName = attributesMap[attrName].baseName; + attributesBaseNames[baseName] = ""; + if (keepAllInAdditional && attrName !== "additionalProperties") { + baseNameToAttr[baseName] = attributesMap[attrName]; + } + } const extraAttributes = Object.keys(data).filter( (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); @@ -3352,16 +3359,9 @@ export class ObjectSerializer { if ("additionalProperties" in attributesMap) { const additionalProperties: { [key: string]: any } = {}; if (keepAllInAdditional) { - // Build reverse map from JSON baseName → attribute config for per-field deserialization. - // This preserves int64 precision for typed numeric fields via their declared format. - const baseNameToAttr: { [key: string]: any } = {}; - for (const attrName in attributesMap) { - if (attrName !== "additionalProperties") { - baseNameToAttr[attributesMap[attrName].baseName] = attributesMap[attrName]; - } - } for (const key of extraAttributes) { const attrInfo = baseNameToAttr[key]; + // Use per-field type/format for typed attrs to preserve int64 precision. additionalProperties[key] = attrInfo ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) : data[key]; diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index aff8c022d6c2..fd9c4e7687a3 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -14701,11 +14701,18 @@ export class ObjectSerializer { const instance = new typeMap[type](); const attributesMap = typeMap[type].getAttributeTypeMap(); - const attributesBaseNames = Object.keys(attributesMap).reduce( - (o, key) => Object.assign(o, { [attributesMap[key].baseName]: "" }), - {} - ); const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; + // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, + // baseNameToAttr (for per-field typed deserialization preserving int64 precision). + const attributesBaseNames: { [key: string]: string } = {}; + const baseNameToAttr: { [key: string]: any } = keepAllInAdditional ? {} : null; + for (const attrName in attributesMap) { + const baseName = attributesMap[attrName].baseName; + attributesBaseNames[baseName] = ""; + if (keepAllInAdditional && attrName !== "additionalProperties") { + baseNameToAttr[baseName] = attributesMap[attrName]; + } + } const extraAttributes = Object.keys(data).filter( (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); @@ -14714,16 +14721,9 @@ export class ObjectSerializer { if ("additionalProperties" in attributesMap) { const additionalProperties: { [key: string]: any } = {}; if (keepAllInAdditional) { - // Build reverse map from JSON baseName → attribute config for per-field deserialization. - // This preserves int64 precision for typed numeric fields via their declared format. - const baseNameToAttr: { [key: string]: any } = {}; - for (const attrName in attributesMap) { - if (attrName !== "additionalProperties") { - baseNameToAttr[attributesMap[attrName].baseName] = attributesMap[attrName]; - } - } for (const key of extraAttributes) { const attrInfo = baseNameToAttr[key]; + // Use per-field type/format for typed attrs to preserve int64 precision. additionalProperties[key] = attrInfo ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) : data[key]; From 4749b021817a1c518503144f83462d91d2e778be Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 11:09:54 -0400 Subject: [PATCH 4/5] fix: remove null assignment to fix strictNullChecks compile error in ObjectSerializer baseNameToAttr was conditionally set to null when keepAllInAdditional is false, which fails under strict: true. Always initialize to {} and skip population via the existing keepAllInAdditional guard in the loop body. Co-Authored-By: Claude Sonnet 4.6 --- packages/datadog-api-client-v1/models/ObjectSerializer.ts | 2 +- packages/datadog-api-client-v2/models/ObjectSerializer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/datadog-api-client-v1/models/ObjectSerializer.ts b/packages/datadog-api-client-v1/models/ObjectSerializer.ts index a57e03604deb..3dac06ab8f9c 100644 --- a/packages/datadog-api-client-v1/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v1/models/ObjectSerializer.ts @@ -3343,7 +3343,7 @@ export class ObjectSerializer { // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, // baseNameToAttr (for per-field typed deserialization preserving int64 precision). const attributesBaseNames: { [key: string]: string } = {}; - const baseNameToAttr: { [key: string]: any } = keepAllInAdditional ? {} : null; + const baseNameToAttr: { [key: string]: any } = {}; for (const attrName in attributesMap) { const baseName = attributesMap[attrName].baseName; attributesBaseNames[baseName] = ""; diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index fd9c4e7687a3..6c4be7d54296 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -14705,7 +14705,7 @@ export class ObjectSerializer { // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, // baseNameToAttr (for per-field typed deserialization preserving int64 precision). const attributesBaseNames: { [key: string]: string } = {}; - const baseNameToAttr: { [key: string]: any } = keepAllInAdditional ? {} : null; + const baseNameToAttr: { [key: string]: any } = {}; for (const attrName in attributesMap) { const baseName = attributesMap[attrName].baseName; attributesBaseNames[baseName] = ""; From 716e0cdc1c216c5d94fd1a875d78710a3a2cdcd2 Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Fri, 12 Jun 2026 18:04:14 +0000 Subject: [PATCH 5/5] pre-commit fixes --- .../models/ObjectSerializer.ts | 13 ++++++++++--- .../models/ObjectSerializer.ts | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/datadog-api-client-v1/models/ObjectSerializer.ts b/packages/datadog-api-client-v1/models/ObjectSerializer.ts index 3dac06ab8f9c..997512e3b7af 100644 --- a/packages/datadog-api-client-v1/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v1/models/ObjectSerializer.ts @@ -3339,7 +3339,8 @@ export class ObjectSerializer { const instance = new typeMap[type](); const attributesMap = typeMap[type].getAttributeTypeMap(); - const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; + const keepAllInAdditional = + (typeMap[type] as any)._keepTypedInAdditionalProperties === true; // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, // baseNameToAttr (for per-field typed deserialization preserving int64 precision). const attributesBaseNames: { [key: string]: string } = {}; @@ -3352,7 +3353,9 @@ export class ObjectSerializer { } } const extraAttributes = Object.keys(data).filter( - (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) + (key) => + keepAllInAdditional || + !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); if (extraAttributes.length > 0) { @@ -3363,7 +3366,11 @@ export class ObjectSerializer { const attrInfo = baseNameToAttr[key]; // Use per-field type/format for typed attrs to preserve int64 precision. additionalProperties[key] = attrInfo - ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) + ? ObjectSerializer.deserialize( + data[key], + attrInfo.type, + attrInfo.format + ) : data[key]; } instance.additionalProperties = additionalProperties; diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index 6c4be7d54296..7a7939949d3f 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -14701,7 +14701,8 @@ export class ObjectSerializer { const instance = new typeMap[type](); const attributesMap = typeMap[type].getAttributeTypeMap(); - const keepAllInAdditional = (typeMap[type] as any)._keepTypedInAdditionalProperties === true; + const keepAllInAdditional = + (typeMap[type] as any)._keepTypedInAdditionalProperties === true; // Single pass: build attributesBaseNames (for extra-key detection) and, when needed, // baseNameToAttr (for per-field typed deserialization preserving int64 precision). const attributesBaseNames: { [key: string]: string } = {}; @@ -14714,7 +14715,9 @@ export class ObjectSerializer { } } const extraAttributes = Object.keys(data).filter( - (key) => keepAllInAdditional || !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) + (key) => + keepAllInAdditional || + !Object.prototype.hasOwnProperty.call(attributesBaseNames, key) ); if (extraAttributes.length > 0) { @@ -14725,7 +14728,11 @@ export class ObjectSerializer { const attrInfo = baseNameToAttr[key]; // Use per-field type/format for typed attrs to preserve int64 precision. additionalProperties[key] = attrInfo - ? ObjectSerializer.deserialize(data[key], attrInfo.type, attrInfo.format) + ? ObjectSerializer.deserialize( + data[key], + attrInfo.type, + attrInfo.format + ) : data[key]; } instance.additionalProperties = additionalProperties;