Skip to content

Commit 4a9c03b

Browse files
Merge pull request #498 from splitio/development
Release v2.12.1
2 parents 3979c59 + c6fe211 commit 4a9c03b

41 files changed

Lines changed: 750 additions & 814 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@
1212

1313
## coverage info
1414
/coverage
15+
16+
## worktrees
17+
/.worktrees
18+
19+
## agents files
20+
/AGENTS.md
21+
/CLAUDE.md
22+
/.claude

CHANGES.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
2.12.1 (June 25, 2026)
2+
- Updated internal modules to handle `null` values from `/splitChanges` response.
3+
- Updated some dependencies for vulnerability fixes.
4+
15
2.12.0 (February 24, 2026)
2-
- Added support for ioredis v5.
6+
- Added support for ioredis v5 (Related to issue https://github.com/splitio/javascript-commons/issues/471).
37

48
2.11.0 (January 28, 2026)
59
- Added functionality to provide metadata alongside SDK update and READY events. Read more in our docs.

package-lock.json

Lines changed: 401 additions & 424 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@splitsoftware/splitio-commons",
3-
"version": "2.12.0",
3+
"version": "2.12.1",
44
"description": "Split JavaScript SDK common components",
55
"main": "cjs/index.js",
66
"module": "esm/index.js",
@@ -60,10 +60,10 @@
6060
"@types/ioredis": "^4.28.0",
6161
"@types/jest": "^27.0.0",
6262
"@types/lodash": "^4.14.162",
63-
"@typescript-eslint/eslint-plugin": "^6.6.0",
64-
"@typescript-eslint/parser": "^6.6.0",
63+
"@typescript-eslint/eslint-plugin": "^7.18.0",
64+
"@typescript-eslint/parser": "^7.18.0",
6565
"cross-env": "^7.0.2",
66-
"eslint": "^8.48.0",
66+
"eslint": "^8.56.0",
6767
"eslint-plugin-compat": "^6.0.1",
6868
"eslint-plugin-import": "^2.25.3",
6969
"eslint-plugin-tsdoc": "^0.3.0",
@@ -76,7 +76,7 @@
7676
"redis-server": "1.2.2",
7777
"rimraf": "^3.0.2",
7878
"ts-jest": "^27.0.5",
79-
"typescript": "4.4.4"
79+
"typescript": "4.7.4"
8080
},
8181
"sideEffects": false
8282
}

src/dtos/types.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface IBetweenStringMatcherData {
2323
}
2424

2525
export interface IWhitelistMatcherData {
26-
whitelist: string[]
26+
whitelist?: string[] | null
2727
}
2828

2929
export interface IInSegmentMatcherData {
@@ -41,10 +41,10 @@ export interface IDependencyMatcherData {
4141

4242
interface ISplitMatcherBase {
4343
matcherType: string
44-
negate: boolean
45-
keySelector: null | {
44+
negate?: boolean
45+
keySelector?: null | {
4646
trafficType: string,
47-
attribute: string | null
47+
attribute?: string | null
4848
}
4949
userDefinedSegmentMatcherData?: null | IInSegmentMatcherData
5050
userDefinedLargeSegmentMatcherData?: null | IInLargeSegmentMatcherData
@@ -207,18 +207,18 @@ export interface IExcludedSegment {
207207
export interface IRBSegment {
208208
name: string,
209209
changeNumber: number,
210-
status: 'ACTIVE' | 'ARCHIVED',
211-
conditions?: ISplitCondition[],
210+
status?: 'ACTIVE' | 'ARCHIVED',
211+
conditions?: ISplitCondition[] | null,
212212
excluded?: {
213213
keys?: string[] | null,
214214
segments?: IExcludedSegment[] | null
215-
}
215+
} | null
216216
}
217217

218218
export interface ISplit {
219219
name: string,
220220
changeNumber: number,
221-
status: 'ACTIVE' | 'ARCHIVED',
221+
status?: 'ACTIVE' | 'ARCHIVED',
222222
conditions: ISplitCondition[],
223223
prerequisites?: null | {
224224
n: string,
@@ -232,9 +232,9 @@ export interface ISplit {
232232
trafficAllocationSeed?: number
233233
configurations?: {
234234
[treatmentName: string]: string
235-
},
236-
sets?: string[],
237-
impressionsDisabled?: boolean
235+
} | null,
236+
sets?: string[] | null,
237+
impressionsDisabled?: boolean | null
238238
}
239239

240240
// Split definition used in offline mode
@@ -245,13 +245,13 @@ export interface ISplitChangesResponse {
245245
ff?: {
246246
t: number,
247247
s?: number,
248-
d: ISplit[]
249-
},
248+
d?: ISplit[] | null,
249+
} | null,
250250
rbs?: {
251251
t: number,
252252
s?: number,
253-
d: IRBSegment[]
254-
}
253+
d?: IRBSegment[] | null,
254+
} | null,
255255
}
256256

257257
/** Interface of the parsed JSON response of `/segmentChanges/{segmentName}` */

src/evaluator/__tests__/evaluate-feature.spec.ts

Lines changed: 24 additions & 23 deletions
Large diffs are not rendered by default.

src/evaluator/__tests__/evaluate-features.spec.ts

Lines changed: 26 additions & 27 deletions
Large diffs are not rendered by default.

src/evaluator/condition/engineUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export function getTreatment(log: ILogger, key: string, seed: number | undefined
1818
/**
1919
* Evaluates the traffic allocation to see if we should apply rollout conditions or not.
2020
*/
21-
export function shouldApplyRollout(trafficAllocation: number, key: string, trafficAllocationSeed: number) {
21+
export function shouldApplyRollout(trafficAllocation: number, bucketingKey: string, trafficAllocationSeed: number) {
2222
// For rollout, if traffic allocation for splits is 100%, we don't need to filter it because everything should evaluate the rollout.
2323
if (trafficAllocation < 100) {
24-
const _bucket = bucket(key, trafficAllocationSeed);
24+
const _bucket = bucket(bucketingKey, trafficAllocationSeed);
2525

2626
if (_bucket > trafficAllocation) {
2727
return false;

src/evaluator/fallbackTreatmentsCalculator/__tests__/fallback-calculator.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ describe('FallbackTreatmentsCalculator' , () => {
99
'featureA': { treatment: 'TREATMENT_A', config: '{ value: 1 }' },
1010
},
1111
};
12-
const calculator = new FallbackTreatmentsCalculator(config);
13-
const result = calculator.resolve('featureA', 'label by flag');
12+
const calculator = FallbackTreatmentsCalculator(config);
13+
const result = calculator('featureA', 'label by flag');
1414

1515
expect(result).toEqual({
1616
treatment: 'TREATMENT_A',
@@ -24,8 +24,8 @@ describe('FallbackTreatmentsCalculator' , () => {
2424
byFlag: {},
2525
global: { treatment: 'GLOBAL_TREATMENT', config: '{ global: true }' },
2626
};
27-
const calculator = new FallbackTreatmentsCalculator(config);
28-
const result = calculator.resolve('missingFlag', 'label by global');
27+
const calculator = FallbackTreatmentsCalculator(config);
28+
const result = calculator('missingFlag', 'label by global');
2929

3030
expect(result).toEqual({
3131
treatment: 'GLOBAL_TREATMENT',
@@ -38,8 +38,8 @@ describe('FallbackTreatmentsCalculator' , () => {
3838
const config: FallbackTreatmentConfiguration = {
3939
byFlag: {},
4040
};
41-
const calculator = new FallbackTreatmentsCalculator(config);
42-
const result = calculator.resolve('missingFlag', 'label by noFallback');
41+
const calculator = FallbackTreatmentsCalculator(config);
42+
const result = calculator('missingFlag', 'label by noFallback');
4343

4444
expect(result).toEqual({
4545
treatment: CONTROL,
Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,32 @@
1-
import { FallbackTreatmentConfiguration, Treatment, TreatmentWithConfig } from '../../../types/splitio';
1+
import { FallbackTreatmentConfiguration, TreatmentWithConfig } from '../../../types/splitio';
22
import { CONTROL } from '../../utils/constants';
33
import { isString } from '../../utils/lang';
44

5-
export type IFallbackTreatmentsCalculator = {
6-
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string };
7-
}
5+
export type IFallbackTreatmentsCalculator = (flagName: string, label?: string) => TreatmentWithConfig & { label: string };
86

97
export const FALLBACK_PREFIX = 'fallback - ';
108

11-
export class FallbackTreatmentsCalculator implements IFallbackTreatmentsCalculator {
12-
private readonly fallbacks: FallbackTreatmentConfiguration;
13-
14-
constructor(fallbacks: FallbackTreatmentConfiguration = {}) {
15-
this.fallbacks = fallbacks;
16-
}
17-
18-
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string } {
19-
const treatment = this.fallbacks.byFlag?.[flagName];
20-
if (treatment) {
21-
return this.copyWithLabel(treatment, label);
22-
}
23-
24-
if (this.fallbacks.global) {
25-
return this.copyWithLabel(this.fallbacks.global, label);
26-
}
27-
28-
return {
29-
treatment: CONTROL,
30-
config: null,
31-
label,
32-
};
33-
}
34-
35-
private copyWithLabel(fallback: Treatment | TreatmentWithConfig, label: string): TreatmentWithConfig & { label: string } {
36-
if (isString(fallback)) {
37-
return {
38-
treatment: fallback,
9+
export function FallbackTreatmentsCalculator(fallbacks: FallbackTreatmentConfiguration = {}): IFallbackTreatmentsCalculator {
10+
11+
return (flagName: string, label = '') => {
12+
const fallback = fallbacks.byFlag?.[flagName] || fallbacks.global;
13+
14+
return fallback ?
15+
isString(fallback) ?
16+
{
17+
treatment: fallback,
18+
config: null,
19+
label: `${FALLBACK_PREFIX}${label}`,
20+
} :
21+
{
22+
treatment: fallback.treatment,
23+
config: fallback.config,
24+
label: `${FALLBACK_PREFIX}${label}`,
25+
} :
26+
{
27+
treatment: CONTROL,
3928
config: null,
40-
label: `${FALLBACK_PREFIX}${label}`,
29+
label,
4130
};
42-
}
43-
44-
return {
45-
treatment: fallback.treatment,
46-
config: fallback.config,
47-
label: `${FALLBACK_PREFIX}${label}`,
48-
};
49-
}
31+
};
5032
}

0 commit comments

Comments
 (0)