Skip to content

Commit e014e54

Browse files
author
Josh Sirota
authored
Merge pull request #2 from beeme1mr/main
Automatically generate types and bump OpenFeature to v0.5.0
2 parents b954231 + f163710 commit e014e54

File tree

7 files changed

+87
-57
lines changed

7 files changed

+87
-57
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,8 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# Build output
107+
es/
108+
lib/
109+
types/

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,27 @@ This Provider is designed to allow the use of OpenFeature with Split, the platfo
1010
## Getting started
1111
Below is a simple example that describes the instantiation of the Split Provider. Please see the [OpenFeature Documentation](https://docs.openfeature.dev/docs/reference/concepts/evaluation-api) for details on how to use the OpenFeature SDK.
1212

13+
### Add the Split provider
14+
15+
```sh
16+
npm install @splitsoftware/openfeature-js-split-provider
17+
```
18+
19+
### Confirm peer dependencies are installed
20+
```sh
21+
npm install @splitsoftware/splitio
22+
npm install @openfeature/js-sdk
23+
```
24+
25+
### Register the Split provider with OpenFeature
1326
```js
1427
const OpenFeature = require('@openfeature/js-sdk').OpenFeature;
1528
const SplitFactory = require('@splitsoftware/splitio').SplitFactory;
1629
const OpenFeatureSplitProvider = require('@splitsoftware/openfeature-js-split-provider').OpenFeatureSplitProvider;
1730

18-
splitClient = SplitFactory({core: {authorizationKey: 'localhost'}}).client();
19-
provider = new OpenFeatureSplitProvider({splitClient});
31+
const authorizationKey = 'your auth key'
32+
const splitClient = SplitFactory({core: {authorizationKey}}).client();
33+
const provider = new OpenFeatureSplitProvider({splitClient});
2034
openFeature.setProvider(provider);
2135
```
2236

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@
1717
"bugs": "https://github.com/splitio/openfeature-split-provider-js/issues",
1818
"license": "Apache-2.0",
1919
"author": "Josh Sirota <josh.sirota@split.io>",
20-
"contributors": [
21-
],
2220
"main": "lib/index.js",
2321
"module": "es/index.js",
2422
"types": "types",
2523
"engines": {
2624
"npm": ">=3",
2725
"node": ">=6"
2826
},
29-
"dependencies": {
30-
"@openfeature/js-sdk": "^0.4.0",
27+
"dependencies": {},
28+
"peerDependencies": {
29+
"@openfeature/js-sdk": "^0.5.0",
3130
"@splitsoftware/splitio": "^10.21.1"
3231
},
3332
"devDependencies": {
33+
"@openfeature/js-sdk": "^0.5.0",
34+
"@splitsoftware/splitio": "^10.21.1",
3435
"copyfiles": "^2.4.1",
3536
"cross-env": "^7.0.3",
3637
"replace": "^1.2.1",
@@ -63,4 +64,4 @@
6364
"karma-webpack"
6465
]
6566
}
66-
}
67+
}

src/__tests__/nodeSuites/client.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export default async function(assert) {
3737
const getControlVariantNonExistentSplit = async (client) => {
3838
let details = await client.getBooleanDetails('non-existent-feature', false);
3939
assert.equals(details.value, false);
40-
assert.equals(details.variant, 'control');
41-
assert.equals(details.reason, 'FLAG_NOT_FOUND');
40+
assert.equals(details.errorCode, 'FLAG_NOT_FOUND');
41+
assert.equals(details.reason, 'ERROR');
4242
};
4343

4444
const getBooleanSplitTest = async (client) => {

src/lib/js-split-provider.ts

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
import { EvaluationContext, Provider, ResolutionDetails, ParseError, FlagNotFoundError, JsonValue, OpenFeatureError, StandardResolutionReasons } from '@openfeature/js-sdk';
2-
import SplitIO from '@splitsoftware/splitio/types/splitio';
1+
import {
2+
EvaluationContext,
3+
Provider,
4+
ResolutionDetails,
5+
ParseError,
6+
FlagNotFoundError,
7+
JsonValue,
8+
TargetingKeyMissingError,
9+
StandardResolutionReasons,
10+
} from "@openfeature/js-sdk";
11+
import type SplitIO from "@splitsoftware/splitio/types/splitio";
312

413
export interface SplitProviderOptions {
514
splitClient: SplitIO.IClient;
@@ -10,9 +19,11 @@ type Consumer = {
1019
attributes: SplitIO.Attributes;
1120
};
1221

22+
const CONTROL_VALUE_ERROR_MESSAGE = "Received the 'control' value from Split.";
23+
1324
export class OpenFeatureSplitProvider implements Provider {
1425
metadata = {
15-
name: 'split',
26+
name: "split",
1627
};
1728
private initialized: Promise<void>;
1829
private client: SplitIO.IClient;
@@ -29,23 +40,26 @@ export class OpenFeatureSplitProvider implements Provider {
2940

3041
async resolveBooleanEvaluation(
3142
flagKey: string,
32-
defaultValue: boolean,
43+
_: boolean,
3344
context: EvaluationContext
3445
): Promise<ResolutionDetails<boolean>> {
35-
const details = await this.evaluateTreatment(flagKey, this.transformContext(context));
46+
const details = await this.evaluateTreatment(
47+
flagKey,
48+
this.transformContext(context)
49+
);
3650

3751
let value: boolean;
3852
switch (details.value as unknown) {
39-
case 'on':
53+
case "on":
4054
value = true;
4155
break;
42-
case 'off':
56+
case "off":
4357
value = false;
4458
break;
45-
case 'true':
59+
case "true":
4660
value = true;
4761
break;
48-
case 'false':
62+
case "false":
4963
value = false;
5064
break;
5165
case true:
@@ -54,10 +68,8 @@ export class OpenFeatureSplitProvider implements Provider {
5468
case false:
5569
value = false;
5670
break;
57-
case 'control':
58-
value = defaultValue;
59-
details.reason = 'FLAG_NOT_FOUND';
60-
break;
71+
case "control":
72+
throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE);
6173
default:
6274
throw new ParseError(`Invalid boolean value for ${details.value}`);
6375
}
@@ -69,9 +81,12 @@ export class OpenFeatureSplitProvider implements Provider {
6981
_: string,
7082
context: EvaluationContext
7183
): Promise<ResolutionDetails<string>> {
72-
const details = await this.evaluateTreatment(flagKey, this.transformContext(context));
73-
if (details.value == 'control') {
74-
throw new FlagNotFoundError(`Got error for split ${flagKey}`);
84+
const details = await this.evaluateTreatment(
85+
flagKey,
86+
this.transformContext(context)
87+
);
88+
if (details.value === "control") {
89+
throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE);
7590
}
7691
return details;
7792
}
@@ -81,7 +96,10 @@ export class OpenFeatureSplitProvider implements Provider {
8196
_: number,
8297
context: EvaluationContext
8398
): Promise<ResolutionDetails<number>> {
84-
const details = await this.evaluateTreatment(flagKey, this.transformContext(context));
99+
const details = await this.evaluateTreatment(
100+
flagKey,
101+
this.transformContext(context)
102+
);
85103
return { ...details, value: this.parseValidNumber(details.value) };
86104
}
87105

@@ -90,26 +108,32 @@ export class OpenFeatureSplitProvider implements Provider {
90108
_: U,
91109
context: EvaluationContext
92110
): Promise<ResolutionDetails<U>> {
93-
const details = await this.evaluateTreatment(flagKey, this.transformContext(context));
111+
const details = await this.evaluateTreatment(
112+
flagKey,
113+
this.transformContext(context)
114+
);
94115
return { ...details, value: this.parseValidJsonObject(details.value) };
95116
}
96117

97-
private async evaluateTreatment(flagKey: string, consumer: Consumer): Promise<ResolutionDetails<string>> {
118+
private async evaluateTreatment(
119+
flagKey: string,
120+
consumer: Consumer
121+
): Promise<ResolutionDetails<string>> {
98122
if (!consumer.key) {
99-
const details: ResolutionDetails<string> = {
100-
value: 'control',
101-
variant: 'control',
102-
reason: StandardResolutionReasons.ERROR,
103-
errorCode: 'TARGETING_KEY_MISSING'
104-
}
105-
return details;
123+
throw new TargetingKeyMissingError(
124+
"The Split provider requires a targeting key."
125+
);
106126
} else {
107127
await this.initialized;
108-
const value = this.client.getTreatment(consumer.key, flagKey, consumer.attributes);
128+
const value = this.client.getTreatment(
129+
consumer.key,
130+
flagKey,
131+
consumer.attributes
132+
);
109133
const details: ResolutionDetails<string> = {
110134
value: value,
111135
variant: value,
112-
reason: StandardResolutionReasons.TARGETING_MATCH
136+
reason: StandardResolutionReasons.TARGETING_MATCH,
113137
};
114138
return details;
115139
}
@@ -136,14 +160,16 @@ export class OpenFeatureSplitProvider implements Provider {
136160
return result;
137161
}
138162

139-
private parseValidJsonObject<T extends JsonValue>(stringValue: string | undefined): T {
163+
private parseValidJsonObject<T extends JsonValue>(
164+
stringValue: string | undefined
165+
): T {
140166
if (stringValue === undefined) {
141167
throw new ParseError(`Invalid 'undefined' JSON value.`);
142168
}
143169
// we may want to allow the parsing to be customized.
144170
try {
145171
const value = JSON.parse(stringValue);
146-
if (typeof value !== 'object') {
172+
if (typeof value !== "object") {
147173
throw new ParseError(
148174
`Flag value ${stringValue} had unexpected type ${typeof value}, expected "object"`
149175
);

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"allowJs": true, /* Allow javascript files to be compiled. */
99
// "checkJs": true, /* Report errors in .js files. */
1010
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11-
"declaration": false, /* Generates corresponding '.d.ts' file. */
11+
"declaration": true, /* Generates corresponding '.d.ts' file. */
12+
"declarationDir": "types", /* Specify the output directory for generated declaration files. */
1213
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
1314
// "sourceMap": true, /* Generates corresponding '.map' file. */
1415
// "outFile": "./", /* Concatenate and emit output to single file. */

types/index.d.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)