From 54f12cef45fe95fb6871f972c8f28296060ea142 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 21 Apr 2026 18:47:01 -0300 Subject: [PATCH 1/2] Add support for entityType field in /testImpressions/bulk payload --- src/listeners/browser.ts | 4 ++-- src/sdkFactory/types.ts | 6 +++++- src/sync/submitters/impressionsSubmitter.ts | 12 +++++++----- src/sync/submitters/types.ts | 3 +++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/listeners/browser.ts b/src/listeners/browser.ts index 0792c3a6..c99675bf 100644 --- a/src/listeners/browser.ts +++ b/src/listeners/browser.ts @@ -28,14 +28,14 @@ export class BrowserSignalListener implements ISignalListener { private serviceApi: ISplitApi; private fromImpressionsCollector: (data: SplitIO.ImpressionDTO[]) => ImpressionsPayload; - constructor({ syncManager, settings, storage, splitApi }: ISdkFactoryContextSync) { + constructor({ syncManager, settings, storage, splitApi, entityType }: ISdkFactoryContextSync) { this.syncManager = syncManager; this.settings = settings; this.storage = storage; this.serviceApi = splitApi; this.flushData = this.flushData.bind(this); this.flushDataIfHidden = this.flushDataIfHidden.bind(this); - this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled); + this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled, entityType); } /** diff --git a/src/sdkFactory/types.ts b/src/sdkFactory/types.ts index 2b822dd0..1ef00591 100644 --- a/src/sdkFactory/types.ts +++ b/src/sdkFactory/types.ts @@ -43,6 +43,9 @@ export interface IPlatform { SignalListener?: new (params: ISdkFactoryContext) => ISignalListener, // Used by BrowserSignalListener } +// Definition type +export type EntityType = 'config' | 'flag'; + export interface ISdkFactoryContext { platform: IPlatform, sdkReadinessManager: ISdkReadinessManager, @@ -55,7 +58,8 @@ export interface ISdkFactoryContext { splitApi?: ISplitApi, syncManager?: ISyncManager, clients: Record, - fallbackCalculator: IFallbackCalculator + fallbackCalculator: IFallbackCalculator, + entityType?: EntityType } export interface ISdkFactoryContextSync extends ISdkFactoryContext { diff --git a/src/sync/submitters/impressionsSubmitter.ts b/src/sync/submitters/impressionsSubmitter.ts index 2fa85ab4..7d2c74e5 100644 --- a/src/sync/submitters/impressionsSubmitter.ts +++ b/src/sync/submitters/impressionsSubmitter.ts @@ -3,18 +3,19 @@ import SplitIO from '../../../types/splitio'; import { submitterFactory } from './submitter'; import { ImpressionsPayload } from './types'; import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants'; -import { ISdkFactoryContextSync } from '../../sdkFactory/types'; +import { EntityType, ISdkFactoryContextSync } from '../../sdkFactory/types'; /** * Converts `impressions` data from cache into request payload. */ -export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.ImpressionDTO[]): ImpressionsPayload { +export function fromImpressionsCollector(sendLabels: boolean, entityType: EntityType | undefined, data: SplitIO.ImpressionDTO[]): ImpressionsPayload { let groupedByFeature = groupBy(data, 'feature'); let dto: ImpressionsPayload = []; forOwn(groupedByFeature, (value, name) => { dto.push({ - f: name, // Test Name + f: name, // Definition type + et: entityType, // Definition type i: value.map(entry => { // Key Impressions const keyImpression = { k: entry.keyName, // Key @@ -43,11 +44,12 @@ export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) { const { settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } }, splitApi: { postTestImpressionsBulk }, - storage: { impressions } + storage: { impressions }, + entityType } = params; // retry impressions only once. - const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1); + const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled, entityType), 1); // register impressions submitter to be executed when impressions cache is full impressions.setOnFullQueueCb(() => { diff --git a/src/sync/submitters/types.ts b/src/sync/submitters/types.ts index 36a76c9b..7e86776b 100644 --- a/src/sync/submitters/types.ts +++ b/src/sync/submitters/types.ts @@ -2,6 +2,7 @@ import { IMetadata } from '../../dtos/types'; import SplitIO from '../../../types/splitio'; import { ISyncTask } from '../types'; +import { EntityType } from '../../sdkFactory/types'; type ImpressionPayload = { /** Matching Key */ @@ -25,6 +26,8 @@ type ImpressionPayload = { export type ImpressionsPayload = { /** Split name */ f: string, + /** Definition type */ + et?: EntityType, /** Key Impressions */ i: ImpressionPayload[] }[] From 5dd58c00804402f4445238eaf5ab944689d51853 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 22 Apr 2026 11:36:42 -0300 Subject: [PATCH 2/2] Update /testImpressions/bulk payload --- .../__tests__/impressionsSubmitter.spec.ts | 19 ++++++++++++++++++- src/sync/submitters/impressionsSubmitter.ts | 8 +++----- src/sync/submitters/types.ts | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/sync/submitters/__tests__/impressionsSubmitter.spec.ts b/src/sync/submitters/__tests__/impressionsSubmitter.spec.ts index 135abb2e..92c5f511 100644 --- a/src/sync/submitters/__tests__/impressionsSubmitter.spec.ts +++ b/src/sync/submitters/__tests__/impressionsSubmitter.spec.ts @@ -1,4 +1,4 @@ -import { impressionsSubmitterFactory } from '../impressionsSubmitter'; +import { fromImpressionsCollector, impressionsSubmitterFactory } from '../impressionsSubmitter'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; import { ImpressionsCacheInMemory } from '../../../storages/inMemory/ImpressionsCacheInMemory'; @@ -96,3 +96,20 @@ describe('Impressions submitter', () => { }); }); + +describe('fromImpressionsCollector', () => { + + test('includes entityType in payload when provided', () => { + const impressions = [imp1, imp2]; + const result = fromImpressionsCollector(false, 'config', impressions); + + expect(result).toEqual([{ + f: 'someFeature', + i: [ + { k: 'k1', t: 'someTreatment', m: 0, c: 123, et: 'config' }, + { k: 'k2', t: 'someTreatment', m: 0, c: 123, et: 'config' }, + ] + }]); + }); + +}); diff --git a/src/sync/submitters/impressionsSubmitter.ts b/src/sync/submitters/impressionsSubmitter.ts index 7d2c74e5..b756a34e 100644 --- a/src/sync/submitters/impressionsSubmitter.ts +++ b/src/sync/submitters/impressionsSubmitter.ts @@ -15,9 +15,8 @@ export function fromImpressionsCollector(sendLabels: boolean, entityType: Entity forOwn(groupedByFeature, (value, name) => { dto.push({ f: name, // Definition type - et: entityType, // Definition type i: value.map(entry => { // Key Impressions - const keyImpression = { + return { k: entry.keyName, // Key t: entry.treatment, // Treatment m: entry.time, // Timestamp @@ -25,10 +24,9 @@ export function fromImpressionsCollector(sendLabels: boolean, entityType: Entity r: sendLabels ? entry.label : undefined, // Rule b: entry.bucketingKey, // Bucketing Key pt: entry.pt, // Previous time - properties: entry.properties // Properties + properties: entry.properties, // Properties + et: entityType, // Definition type }; - - return keyImpression; }) }); }); diff --git a/src/sync/submitters/types.ts b/src/sync/submitters/types.ts index 7e86776b..c5c44381 100644 --- a/src/sync/submitters/types.ts +++ b/src/sync/submitters/types.ts @@ -21,13 +21,13 @@ type ImpressionPayload = { pt?: number; /** Stringified JSON object with properties */ properties?: string; + /** Definition type */ + et?: EntityType, }; export type ImpressionsPayload = { /** Split name */ f: string, - /** Definition type */ - et?: EntityType, /** Key Impressions */ i: ImpressionPayload[] }[]