From 37dc63a7e51e352aea4afc82f5aa6f118e015cfb Mon Sep 17 00:00:00 2001 From: Marco Saia Date: Wed, 27 May 2026 16:54:43 +0200 Subject: [PATCH] feat(core): remove hard attribute cap, warn at 256 limit Remove the hard enforcement that silently dropped attributes beyond the 128-attribute cap. Update MAX_ATTRIBUTES to 256 to match the actual backend limit and emit a single developer warning when that threshold is exceeded, rather than dropping attributes. Aligns behaviour with the iOS SDK change in dd-sdk-ios#2832. --- .../__tests__/attributesEncoding.test.ts | 27 +++++++++---------- .../src/sdk/AttributesEncoding/helpers.ts | 27 +++++++------------ 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts b/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts index d9c9165a9..06a292431 100644 --- a/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts +++ b/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts @@ -216,7 +216,7 @@ describe('encodeAttributes', () => { ); }); - it('does not modify original object when attribute limit is reached', () => { + it('does not modify original object when encoding many attributes', () => { const input: Record = {}; for (let i = 0; i < 200; i++) { input[`k${i}`] = `v${i}`; @@ -224,7 +224,7 @@ describe('encodeAttributes', () => { const snapshot = { ...input }; const result = encodeAttributes(input); - expect(Object.keys(result)).toHaveLength(128); + expect(Object.keys(result)).toHaveLength(200); expect(input).toEqual(snapshot); // original still has 200 keys }); @@ -380,31 +380,30 @@ describe('encodeAttributes', () => { ); }); - it('drops attributes after reaching the 128 limit and warns once', () => { - // Prepare 200 simple attributes — max=128 + it('warns once when the 256 attribute limit is exceeded, but does not drop attributes', () => { + // Prepare 300 simple attributes — exceeds max=256 const input: Record = {}; - for (let i = 0; i < 200; i++) { + for (let i = 0; i < 300; i++) { input[`key${i}`] = i; } const result = encodeAttributes(input); - // Check that only 128 attributes remain - expect(Object.keys(result)).toHaveLength(128); + // All 300 attributes are preserved — no hard cap + expect(Object.keys(result)).toHaveLength(300); - // Check the first ones are preserved + // All attributes are present expect(result).toHaveProperty('key0', 0); - expect(result).toHaveProperty('key127', 127); - - // Check later ones were dropped - expect(result).not.toHaveProperty('key128'); + expect(result).toHaveProperty('key255', 255); + expect(result).toHaveProperty('key256', 256); + expect(result).toHaveProperty('key299', 299); - // Check that a warning was shown at least once + // A single warning is emitted when the limit is exceeded expect(warn).toHaveBeenCalledWith( expect.stringContaining('Attribute limit') ); - // Check there is only one "limit reached" warning (even if multiple attributes were dropped) + // Exactly one "limit exceeded" warning (not one per extra attribute) const limitWarnings = (warn as jest.Mock).mock.calls.filter(([msg]) => msg.includes('Attribute limit') ); diff --git a/packages/core/src/sdk/AttributesEncoding/helpers.ts b/packages/core/src/sdk/AttributesEncoding/helpers.ts index 1fc80dece..c47762312 100644 --- a/packages/core/src/sdk/AttributesEncoding/helpers.ts +++ b/packages/core/src/sdk/AttributesEncoding/helpers.ts @@ -7,7 +7,7 @@ import type { AttributeEncoder, Encodable } from './types'; import { formatPathForLog, isPlainObject, warn } from './utils'; -const MAX_ATTRIBUTES = 128; +const MAX_ATTRIBUTES = 256; export interface EncodeContext { numOfAttributes: number; @@ -152,25 +152,16 @@ function addEncodedAttribute( value: Encodable, context: EncodeContext ): void { - if (context.numOfAttributes >= MAX_ATTRIBUTES) { - // Only warn once to avoid log spam - if (!context.limitReachedWarned) { - warn( - `Attribute limit of ${MAX_ATTRIBUTES} reached; further attributes will be dropped.` - ); - context.limitReachedWarned = true; - } + out[path.join('.')] = value; + context.numOfAttributes++; - // Optional: warn for specific dropped attribute (if desired) + if ( + context.numOfAttributes > MAX_ATTRIBUTES && + !context.limitReachedWarned + ) { warn( - `Dropped attribute at '${formatPathForLog( - path - )}' because limit of ${MAX_ATTRIBUTES} attributes was reached. All further attributes will be dropped.` + `Attribute limit of ${MAX_ATTRIBUTES} exceeded; the backend may drop some attributes.` ); - - return; + context.limitReachedWarned = true; } - - out[path.join('.')] = value; - context.numOfAttributes++; }