Skip to content

Commit 7903d7a

Browse files
Merge pull request #15 from splitio/add-factory
Add factory option to provider
2 parents e552b8f + 0d03ee8 commit 7903d7a

File tree

6 files changed

+96
-31
lines changed

6 files changed

+96
-31
lines changed

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
1.2.0 (September 9, 2025)
1+
1.2.0 (September 12, 2025)
22
- Up to date with @openfeature/server-sdk 1.19.0
33
- Added tracking support
44
- Added “evaluate with details” support
5+
- Support provider initialization using splitFactory
56

67
1.1.0 (June 16, 2025)
78
- Uses renamed @openfeature/js-sdk to @openfeature/server-sdk

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,29 @@ npm install @splitsoftware/splitio
2323
npm install @openfeature/server-sdk
2424
```
2525

26-
### Register the Split provider with OpenFeature
26+
### Register the Split provider with OpenFeature using sdk apiKey
27+
```js
28+
const OpenFeature = require('@openfeature/server-sdk').OpenFeature;
29+
const OpenFeatureSplitProvider = require('@splitsoftware/openfeature-js-split-provider').OpenFeatureSplitProvider;
30+
31+
const authorizationKey = 'your auth key'
32+
const provider = new OpenFeatureSplitProvider(authorizationKey);
33+
OpenFeature.setProvider(provider);
34+
```
35+
36+
### Register the Split provider with OpenFeature using splitFactory
37+
```js
38+
const OpenFeature = require('@openfeature/server-sdk').OpenFeature;
39+
const SplitFactory = require('@splitsoftware/splitio').SplitFactory;
40+
const OpenFeatureSplitProvider = require('@splitsoftware/openfeature-js-split-provider').OpenFeatureSplitProvider;
41+
42+
const authorizationKey = 'your auth key'
43+
const splitFactory = SplitFactory({core: {authorizationKey}});
44+
const provider = new OpenFeatureSplitProvider(splitFactory);
45+
OpenFeature.setProvider(provider);
46+
```
47+
48+
### Register the Split provider with OpenFeature using splitClient
2749
```js
2850
const OpenFeature = require('@openfeature/server-sdk').OpenFeature;
2951
const SplitFactory = require('@splitsoftware/splitio').SplitFactory;

src/__tests__/nodeSuites/client.spec.js

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
/* eslint-disable jest/no-conditional-expect */
22
import { OpenFeatureSplitProvider } from '../../lib/js-split-provider';
3-
import { getLocalHostSplitClient } from '../testUtils';
3+
import { getLocalHostSplitClient, getSplitFactory } from '../testUtils';
44

55
import { OpenFeature } from '@openfeature/server-sdk';
66

7-
describe('client tests', () => {
7+
const cases = [
8+
[
9+
'openfeature client tests mode: splitClient',
10+
() => ({ splitClient: getLocalHostSplitClient()}),
11+
12+
],
13+
[
14+
'openfeature client tests mode: splitFactory',
15+
getSplitFactory
16+
],
17+
];
18+
19+
describe.each(cases)('%s', (label, getOptions) => {
820

921
let client;
10-
let splitClient;
1122
let provider;
23+
let options;
1224

1325
beforeEach(() => {
14-
splitClient = getLocalHostSplitClient();
15-
provider = new OpenFeatureSplitProvider({ splitClient });
1626

27+
options = getOptions();
28+
provider = new OpenFeatureSplitProvider(options);
1729
OpenFeature.setProvider(provider);
1830

1931
client = OpenFeature.getClient('test');
@@ -22,9 +34,8 @@ describe('client tests', () => {
2234
};
2335
client.setContext(evaluationContext);
2436
});
25-
afterEach(() => {
26-
splitClient.destroy();
27-
provider = undefined;
37+
afterEach(async () => {
38+
await OpenFeature.close();
2839
});
2940

3041
test('use default test', async () => {
@@ -206,13 +217,13 @@ describe('client tests', () => {
206217
});
207218

208219
test('track: without value', async () => {
209-
const trackSpy = jest.spyOn(splitClient, 'track');
220+
const trackSpy = jest.spyOn(options.splitClient ? options.splitClient : options.client(), 'track');
210221
await client.track('my-event', { targetingKey: 'u1', trafficType: 'user' }, { properties: { prop1: 'value1' } });
211222
expect(trackSpy).toHaveBeenCalledWith('u1', 'user', 'my-event', undefined, { prop1: 'value1' });
212223
});
213224

214225
test('track: with value', async () => {
215-
const trackSpy = jest.spyOn(splitClient, 'track');
226+
const trackSpy = jest.spyOn(options.splitClient ? options.splitClient : options.client(), 'track');
216227
await client.track('my-event', { targetingKey: 'u1', trafficType: 'user' }, { value: 9.99, properties: { prop1: 'value1' } });
217228
expect(trackSpy).toHaveBeenCalledWith('u1', 'user', 'my-event', 9.99, { prop1: 'value1' });
218229
});

src/__tests__/nodeSuites/provider.spec.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
/* eslint-disable jest/no-conditional-expect */
2-
import { getLocalHostSplitClient } from '../testUtils';
2+
import { getLocalHostSplitClient, getSplitFactory } from '../testUtils';
33
import { OpenFeatureSplitProvider } from '../../lib/js-split-provider';
44

5-
describe('provider tests', () => {
5+
const cases = [
6+
[
7+
'provider tests mode: splitClient',
8+
() => ({ splitClient: getLocalHostSplitClient()}),
9+
10+
],
11+
[
12+
'provider tests mode: splitFactory',
13+
getSplitFactory
14+
],
15+
];
16+
17+
describe.each(cases)('%s', (label, getOptions) => {
618

7-
let splitClient;
819
let provider;
20+
let options;
921

1022
beforeEach(() => {
11-
splitClient = getLocalHostSplitClient();
12-
provider = new OpenFeatureSplitProvider({ splitClient });
23+
options = getOptions();
24+
provider = new OpenFeatureSplitProvider(options);
1325
});
1426

15-
afterEach(() => {
16-
splitClient.destroy();
17-
provider = undefined;
27+
afterEach(async () => {
28+
jest.clearAllMocks()
29+
await provider.onClose();
1830
});
1931

2032
test('evaluate Boolean null/empty test', async () => {
@@ -210,14 +222,14 @@ describe('provider tests', () => {
210222
});
211223

212224
test('track: ok without details', async () => {
213-
const trackSpy = jest.spyOn(splitClient, 'track');
225+
const trackSpy = jest.spyOn(options.splitClient ? options.splitClient : options.client(), 'track');
214226
await provider.track('view', { targetingKey: 'u1', trafficType: 'user' }, null);
215227
expect(trackSpy).toHaveBeenCalledTimes(1);
216228
expect(trackSpy).toHaveBeenCalledWith('u1', 'user', 'view', undefined, {});
217229
});
218230

219231
test('track: ok with details', async () => {
220-
const trackSpy = jest.spyOn(splitClient, 'track');
232+
const trackSpy = jest.spyOn(options.splitClient ? options.splitClient : options.client(), 'track');
221233
await provider.track(
222234
'purchase',
223235
{ targetingKey: 'u1', trafficType: 'user' },

src/__tests__/testUtils/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ const config = {
9595
authorizationKey: 'localhost'
9696
},
9797
features: './split.yaml',
98-
debug: 'DEBUG'
9998
}
10099
/**
101100
* get a Split client in localhost mode for testing purposes
@@ -106,4 +105,8 @@ export function getLocalHostSplitClient() {
106105

107106
export function getRedisSplitClient(redisPort) {
108107
return SplitFactory(getRedisConfig(redisPort)).client();
109-
}
108+
}
109+
110+
export function getSplitFactory() {
111+
return SplitFactory(config);
112+
}

src/lib/js-split-provider.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,28 @@ export class OpenFeatureSplitProvider implements Provider {
3636

3737
public readonly events = new OpenFeatureEventEmitter();
3838

39-
constructor(options: SplitProviderOptions | string) {
40-
39+
private getSplitClient(options: SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK) {
4140
if (typeof(options) === 'string') {
4241
const splitFactory = SplitFactory({core: { authorizationKey: options } });
43-
this.client = splitFactory.client();
44-
} else {
45-
this.client = options.splitClient;
42+
return splitFactory.client();
43+
}
44+
45+
let splitClient;
46+
try {
47+
splitClient = (options as SplitIO.ISDK | SplitIO.IAsyncSDK).client();
48+
} catch {
49+
splitClient = (options as SplitProviderOptions).splitClient
4650
}
47-
this.client.on(this.client.Event.SDK_UPDATE, (payload) => {
48-
this.events.emit(ProviderEvents.ConfigurationChanged, payload)
51+
52+
return splitClient;
53+
}
54+
55+
constructor(options: SplitProviderOptions | string | SplitIO.ISDK | SplitIO.IAsyncSDK) {
56+
57+
this.client = this.getSplitClient(options);
58+
59+
this.client.on(this.client.Event.SDK_UPDATE, () => {
60+
this.events.emit(ProviderEvents.ConfigurationChanged)
4961
});
5062
this.initialized = new Promise((resolve) => {
5163
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -191,6 +203,10 @@ export class OpenFeatureSplitProvider implements Provider {
191203
this.client.track(targetingKey, trafficType, trackingEventName, value, properties);
192204
}
193205

206+
async onClose?(): Promise<void> {
207+
return this.client.destroy();
208+
}
209+
194210
//Transform the context into an object useful for the Split API, an key string with arbitrary Split 'Attributes'.
195211
private transformContext(context: EvaluationContext): Consumer {
196212
const { targetingKey, ...attributes } = context;

0 commit comments

Comments
 (0)