@openfeature/config-cat-provider
Advanced tools
Comparing version 0.6.1 to 0.7.0
204
index.cjs.js
@@ -6,3 +6,4 @@ 'use strict'; | ||
var serverSdk = require('@openfeature/server-sdk'); | ||
var configcatJsSsr = require('configcat-js-ssr'); | ||
var configCatCore = require('@openfeature/config-cat-core'); | ||
var configcatNode = require('configcat-node'); | ||
@@ -51,100 +52,38 @@ /****************************************************************************** | ||
function contextValueToString(contextValue) { | ||
if (typeof contextValue === 'string') { | ||
return contextValue; | ||
} | ||
if (typeof contextValue === 'boolean' || typeof contextValue === 'number' || contextValue === null) { | ||
return String(contextValue); | ||
} | ||
if (typeof contextValue === 'undefined') { | ||
return contextValue; | ||
} | ||
if (contextValue instanceof Date) { | ||
return contextValue.toISOString(); | ||
} | ||
return JSON.stringify(contextValue); | ||
} | ||
function transformContextValues(contextValue) { | ||
if (contextValue === null) { | ||
return {}; | ||
} | ||
if (typeof contextValue !== 'object' || Array.isArray(contextValue)) { | ||
const value = contextValueToString(contextValue); | ||
return value ? { value } : {}; | ||
} | ||
if (contextValue instanceof Date) { | ||
return { value: contextValue.toISOString() }; | ||
} | ||
return Object.entries(contextValue).reduce((context, [key, value]) => { | ||
const transformedValue = contextValueToString(value); | ||
return transformedValue ? Object.assign(Object.assign({}, context), { [key]: transformedValue }) : context; | ||
}, {}); | ||
} | ||
function stringOrUndefined(param) { | ||
if (typeof param === 'string') { | ||
return param; | ||
} | ||
return undefined; | ||
} | ||
function transformContext(context) { | ||
const { targetingKey, email, country } = context, attributes = __rest(context, ["targetingKey", "email", "country"]); | ||
if (!targetingKey) { | ||
throw new serverSdk.TargetingKeyMissingError('ConfigCat evaluation context can only be used if a targetingKey is given'); | ||
} | ||
return { | ||
identifier: targetingKey, | ||
email: stringOrUndefined(email), | ||
country: stringOrUndefined(country), | ||
custom: transformContextValues(attributes), | ||
}; | ||
} | ||
class ConfigCatProvider { | ||
constructor(...params) { | ||
constructor(clientFactory) { | ||
this.events = new serverSdk.OpenFeatureEventEmitter(); | ||
this._status = serverSdk.ProviderStatus.NOT_READY; | ||
this._hasError = false; | ||
this.runsOn = 'server'; | ||
this.metadata = { | ||
name: ConfigCatProvider.name, | ||
}; | ||
this._clientParameters = params; | ||
this._clientFactory = clientFactory; | ||
} | ||
static create(...params) { | ||
return new ConfigCatProvider(...params); | ||
static create(sdkKey, pollingMode, options) { | ||
// Let's create a shallow copy to not mess up caller's options object. | ||
options = options ? Object.assign({}, options) : {}; | ||
return new ConfigCatProvider((provider) => { | ||
const oldSetupHooks = options === null || options === void 0 ? void 0 : options.setupHooks; | ||
options.setupHooks = (hooks) => { | ||
oldSetupHooks === null || oldSetupHooks === void 0 ? void 0 : oldSetupHooks(hooks); | ||
hooks.on('configChanged', (projectConfig) => provider.events.emit(serverSdk.ProviderEvents.ConfigurationChanged, { | ||
flagsChanged: projectConfig ? Object.keys(projectConfig.settings) : undefined, | ||
})); | ||
hooks.on('clientError', (message, error) => { | ||
provider._hasError = true; | ||
provider.events.emit(serverSdk.ProviderEvents.Error, { | ||
message: message, | ||
metadata: error, | ||
}); | ||
}); | ||
}; | ||
return configcatNode.getClient(sdkKey, pollingMode, options); | ||
}); | ||
} | ||
get status() { | ||
return this._status; | ||
} | ||
initialize() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve) => { | ||
var _a; | ||
const originalParameters = this._clientParameters; | ||
(_a = originalParameters[2]) !== null && _a !== void 0 ? _a : (originalParameters[2] = {}); | ||
const options = originalParameters[2]; | ||
const oldSetupHooks = options.setupHooks; | ||
options.setupHooks = (hooks) => { | ||
oldSetupHooks === null || oldSetupHooks === void 0 ? void 0 : oldSetupHooks(hooks); | ||
// After resolving, once, we can simply emit events the next time | ||
const onProviderReady = () => { | ||
this.events.emit(serverSdk.ProviderEvents.Ready); | ||
this._status = serverSdk.ProviderStatus.READY; | ||
}; | ||
hooks.once('clientReady', () => { | ||
hooks.on('clientReady', onProviderReady); | ||
onProviderReady(); | ||
resolve(); | ||
}); | ||
hooks.on('configChanged', (projectConfig) => this.events.emit(serverSdk.ProviderEvents.ConfigurationChanged, { | ||
flagsChanged: projectConfig ? Object.keys(projectConfig.settings) : undefined, | ||
})); | ||
hooks.on('clientError', (message, error) => { | ||
this._status = serverSdk.ProviderStatus.ERROR; | ||
this.events.emit(serverSdk.ProviderEvents.Error, { | ||
message: message, | ||
metadata: error, | ||
}); | ||
}); | ||
}; | ||
this._client = configcatJsSsr.getClient(...originalParameters); | ||
}); | ||
const client = this._clientFactory(this); | ||
yield client.waitForReady(); | ||
this._client = client; | ||
}); | ||
@@ -163,10 +102,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new serverSdk.GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('boolean', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, serverSdk.StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'boolean', context); | ||
}); | ||
@@ -176,10 +108,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new serverSdk.GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('string', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, serverSdk.StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'string', context); | ||
}); | ||
@@ -189,10 +114,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new serverSdk.GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('number', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, serverSdk.StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'number', context); | ||
}); | ||
@@ -202,51 +120,37 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const objectValue = yield this.evaluate(flagKey, 'object', context); | ||
return objectValue; | ||
}); | ||
} | ||
evaluate(flagKey, flagType, context) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new serverSdk.GeneralError('Provider is not initialized'); | ||
throw new serverSdk.ProviderNotReadyError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, configCatCore.transformContext(context)), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
if (this._hasError && !evaluationData.errorMessage && !evaluationData.errorException) { | ||
this._hasError = false; | ||
this.events.emit(serverSdk.ProviderEvents.Ready); | ||
} | ||
if (typeof value === 'undefined') { | ||
return toResolutionDetails(defaultValue, evaluationData, serverSdk.StandardResolutionReasons.DEFAULT); | ||
throw new serverSdk.FlagNotFoundError(); | ||
} | ||
if (!isType('string', value)) { | ||
throw new serverSdk.TypeMismatchError(`Requested object flag but the actual value is not a JSON string`); | ||
if (flagType !== 'object') { | ||
return configCatCore.toResolutionDetails(flagType, value, evaluationData); | ||
} | ||
if (!configCatCore.isType('string', value)) { | ||
throw new serverSdk.TypeMismatchError(); | ||
} | ||
let json; | ||
try { | ||
const object = JSON.parse(value); | ||
if (typeof object !== 'object') { | ||
throw new serverSdk.TypeMismatchError(`Requested object flag but the actual value is ${typeof value}`); | ||
} | ||
return toResolutionDetails(object, evaluationData); | ||
json = JSON.parse(value); | ||
} | ||
catch (e) { | ||
if (e instanceof serverSdk.TypeMismatchError) { | ||
throw e; | ||
} | ||
throw new serverSdk.ParseError(`Unable to parse '${value}' as JSON`); | ||
throw new serverSdk.ParseError(`Unable to parse "${value}" as JSON`); | ||
} | ||
return configCatCore.toResolutionDetails(flagType, json, evaluationData); | ||
}); | ||
} | ||
} | ||
function toResolutionDetails(value, data, reason) { | ||
var _a; | ||
const matchedTargeting = 'matchedEvaluationRule' in data ? data.matchedEvaluationRule : data.matchedTargetingRule; | ||
const matchedPercentage = 'matchedEvaluationPercentageRule' in data ? data.matchedEvaluationPercentageRule : data.matchedPercentageOption; | ||
const matchedRule = Boolean(matchedTargeting || matchedPercentage); | ||
const evaluatedReason = matchedRule ? serverSdk.StandardResolutionReasons.TARGETING_MATCH : serverSdk.StandardResolutionReasons.STATIC; | ||
return { | ||
value, | ||
reason: reason !== null && reason !== void 0 ? reason : evaluatedReason, | ||
errorMessage: data.errorMessage, | ||
variant: (_a = data.variationId) !== null && _a !== void 0 ? _a : undefined, | ||
}; | ||
} | ||
function isType(type, value) { | ||
return typeof value === type; | ||
} | ||
function validateFlagType(type, value) { | ||
if (typeof value !== 'undefined' && !isType(type, value)) { | ||
throw new serverSdk.TypeMismatchError(`Requested ${type} flag but the actual value is ${typeof value}`); | ||
} | ||
return value; | ||
} | ||
exports.ConfigCatProvider = ConfigCatProvider; |
204
index.esm.js
@@ -1,3 +0,4 @@ | ||
import { TargetingKeyMissingError, OpenFeatureEventEmitter, ProviderStatus, ProviderEvents, GeneralError, StandardResolutionReasons, TypeMismatchError, ParseError } from '@openfeature/server-sdk'; | ||
import { getClient } from 'configcat-js-ssr'; | ||
import { OpenFeatureEventEmitter, ProviderEvents, ProviderNotReadyError, FlagNotFoundError, TypeMismatchError, ParseError } from '@openfeature/server-sdk'; | ||
import { transformContext, toResolutionDetails, isType } from '@openfeature/config-cat-core'; | ||
import { getClient } from 'configcat-node'; | ||
@@ -46,100 +47,38 @@ /****************************************************************************** | ||
function contextValueToString(contextValue) { | ||
if (typeof contextValue === 'string') { | ||
return contextValue; | ||
} | ||
if (typeof contextValue === 'boolean' || typeof contextValue === 'number' || contextValue === null) { | ||
return String(contextValue); | ||
} | ||
if (typeof contextValue === 'undefined') { | ||
return contextValue; | ||
} | ||
if (contextValue instanceof Date) { | ||
return contextValue.toISOString(); | ||
} | ||
return JSON.stringify(contextValue); | ||
} | ||
function transformContextValues(contextValue) { | ||
if (contextValue === null) { | ||
return {}; | ||
} | ||
if (typeof contextValue !== 'object' || Array.isArray(contextValue)) { | ||
const value = contextValueToString(contextValue); | ||
return value ? { value } : {}; | ||
} | ||
if (contextValue instanceof Date) { | ||
return { value: contextValue.toISOString() }; | ||
} | ||
return Object.entries(contextValue).reduce((context, [key, value]) => { | ||
const transformedValue = contextValueToString(value); | ||
return transformedValue ? Object.assign(Object.assign({}, context), { [key]: transformedValue }) : context; | ||
}, {}); | ||
} | ||
function stringOrUndefined(param) { | ||
if (typeof param === 'string') { | ||
return param; | ||
} | ||
return undefined; | ||
} | ||
function transformContext(context) { | ||
const { targetingKey, email, country } = context, attributes = __rest(context, ["targetingKey", "email", "country"]); | ||
if (!targetingKey) { | ||
throw new TargetingKeyMissingError('ConfigCat evaluation context can only be used if a targetingKey is given'); | ||
} | ||
return { | ||
identifier: targetingKey, | ||
email: stringOrUndefined(email), | ||
country: stringOrUndefined(country), | ||
custom: transformContextValues(attributes), | ||
}; | ||
} | ||
class ConfigCatProvider { | ||
constructor(...params) { | ||
constructor(clientFactory) { | ||
this.events = new OpenFeatureEventEmitter(); | ||
this._status = ProviderStatus.NOT_READY; | ||
this._hasError = false; | ||
this.runsOn = 'server'; | ||
this.metadata = { | ||
name: ConfigCatProvider.name, | ||
}; | ||
this._clientParameters = params; | ||
this._clientFactory = clientFactory; | ||
} | ||
static create(...params) { | ||
return new ConfigCatProvider(...params); | ||
static create(sdkKey, pollingMode, options) { | ||
// Let's create a shallow copy to not mess up caller's options object. | ||
options = options ? Object.assign({}, options) : {}; | ||
return new ConfigCatProvider((provider) => { | ||
const oldSetupHooks = options === null || options === void 0 ? void 0 : options.setupHooks; | ||
options.setupHooks = (hooks) => { | ||
oldSetupHooks === null || oldSetupHooks === void 0 ? void 0 : oldSetupHooks(hooks); | ||
hooks.on('configChanged', (projectConfig) => provider.events.emit(ProviderEvents.ConfigurationChanged, { | ||
flagsChanged: projectConfig ? Object.keys(projectConfig.settings) : undefined, | ||
})); | ||
hooks.on('clientError', (message, error) => { | ||
provider._hasError = true; | ||
provider.events.emit(ProviderEvents.Error, { | ||
message: message, | ||
metadata: error, | ||
}); | ||
}); | ||
}; | ||
return getClient(sdkKey, pollingMode, options); | ||
}); | ||
} | ||
get status() { | ||
return this._status; | ||
} | ||
initialize() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve) => { | ||
var _a; | ||
const originalParameters = this._clientParameters; | ||
(_a = originalParameters[2]) !== null && _a !== void 0 ? _a : (originalParameters[2] = {}); | ||
const options = originalParameters[2]; | ||
const oldSetupHooks = options.setupHooks; | ||
options.setupHooks = (hooks) => { | ||
oldSetupHooks === null || oldSetupHooks === void 0 ? void 0 : oldSetupHooks(hooks); | ||
// After resolving, once, we can simply emit events the next time | ||
const onProviderReady = () => { | ||
this.events.emit(ProviderEvents.Ready); | ||
this._status = ProviderStatus.READY; | ||
}; | ||
hooks.once('clientReady', () => { | ||
hooks.on('clientReady', onProviderReady); | ||
onProviderReady(); | ||
resolve(); | ||
}); | ||
hooks.on('configChanged', (projectConfig) => this.events.emit(ProviderEvents.ConfigurationChanged, { | ||
flagsChanged: projectConfig ? Object.keys(projectConfig.settings) : undefined, | ||
})); | ||
hooks.on('clientError', (message, error) => { | ||
this._status = ProviderStatus.ERROR; | ||
this.events.emit(ProviderEvents.Error, { | ||
message: message, | ||
metadata: error, | ||
}); | ||
}); | ||
}; | ||
this._client = getClient(...originalParameters); | ||
}); | ||
const client = this._clientFactory(this); | ||
yield client.waitForReady(); | ||
this._client = client; | ||
}); | ||
@@ -158,10 +97,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('boolean', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'boolean', context); | ||
}); | ||
@@ -171,10 +103,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('string', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'string', context); | ||
}); | ||
@@ -184,10 +109,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new GeneralError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const validatedValue = validateFlagType('number', value); | ||
return validatedValue | ||
? toResolutionDetails(validatedValue, evaluationData) | ||
: toResolutionDetails(defaultValue, evaluationData, StandardResolutionReasons.DEFAULT); | ||
return this.evaluate(flagKey, 'number', context); | ||
}); | ||
@@ -197,51 +115,37 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const objectValue = yield this.evaluate(flagKey, 'object', context); | ||
return objectValue; | ||
}); | ||
} | ||
evaluate(flagKey, flagType, context) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this._client) { | ||
throw new GeneralError('Provider is not initialized'); | ||
throw new ProviderNotReadyError('Provider is not initialized'); | ||
} | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, context.targetingKey != null ? transformContext(context) : undefined), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
const _a = yield this._client.getValueDetailsAsync(flagKey, undefined, transformContext(context)), { value } = _a, evaluationData = __rest(_a, ["value"]); | ||
if (this._hasError && !evaluationData.errorMessage && !evaluationData.errorException) { | ||
this._hasError = false; | ||
this.events.emit(ProviderEvents.Ready); | ||
} | ||
if (typeof value === 'undefined') { | ||
return toResolutionDetails(defaultValue, evaluationData, StandardResolutionReasons.DEFAULT); | ||
throw new FlagNotFoundError(); | ||
} | ||
if (flagType !== 'object') { | ||
return toResolutionDetails(flagType, value, evaluationData); | ||
} | ||
if (!isType('string', value)) { | ||
throw new TypeMismatchError(`Requested object flag but the actual value is not a JSON string`); | ||
throw new TypeMismatchError(); | ||
} | ||
let json; | ||
try { | ||
const object = JSON.parse(value); | ||
if (typeof object !== 'object') { | ||
throw new TypeMismatchError(`Requested object flag but the actual value is ${typeof value}`); | ||
} | ||
return toResolutionDetails(object, evaluationData); | ||
json = JSON.parse(value); | ||
} | ||
catch (e) { | ||
if (e instanceof TypeMismatchError) { | ||
throw e; | ||
} | ||
throw new ParseError(`Unable to parse '${value}' as JSON`); | ||
throw new ParseError(`Unable to parse "${value}" as JSON`); | ||
} | ||
return toResolutionDetails(flagType, json, evaluationData); | ||
}); | ||
} | ||
} | ||
function toResolutionDetails(value, data, reason) { | ||
var _a; | ||
const matchedTargeting = 'matchedEvaluationRule' in data ? data.matchedEvaluationRule : data.matchedTargetingRule; | ||
const matchedPercentage = 'matchedEvaluationPercentageRule' in data ? data.matchedEvaluationPercentageRule : data.matchedPercentageOption; | ||
const matchedRule = Boolean(matchedTargeting || matchedPercentage); | ||
const evaluatedReason = matchedRule ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC; | ||
return { | ||
value, | ||
reason: reason !== null && reason !== void 0 ? reason : evaluatedReason, | ||
errorMessage: data.errorMessage, | ||
variant: (_a = data.variationId) !== null && _a !== void 0 ? _a : undefined, | ||
}; | ||
} | ||
function isType(type, value) { | ||
return typeof value === type; | ||
} | ||
function validateFlagType(type, value) { | ||
if (typeof value !== 'undefined' && !isType(type, value)) { | ||
throw new TypeMismatchError(`Requested ${type} flag but the actual value is ${typeof value}`); | ||
} | ||
return value; | ||
} | ||
export { ConfigCatProvider }; |
{ | ||
"name": "@openfeature/config-cat-provider", | ||
"version": "0.6.1", | ||
"version": "0.7.0", | ||
"scripts": { | ||
@@ -9,4 +9,4 @@ "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi", | ||
"peerDependencies": { | ||
"@openfeature/server-sdk": "^1.13.0", | ||
"configcat-js-ssr": ">=7.1.2" | ||
"@openfeature/server-sdk": "^1.13.5", | ||
"configcat-node": "^11.0.0" | ||
}, | ||
@@ -22,3 +22,8 @@ "exports": { | ||
"module": "./index.esm.js", | ||
"main": "./index.cjs.js" | ||
"main": "./index.cjs.js", | ||
"dependencies": { | ||
"@openfeature/config-cat-core": "0.1.0", | ||
"configcat-common": "9.3.0", | ||
"configcat-js-ssr": "8.4.1" | ||
} | ||
} |
@@ -17,6 +17,6 @@ # ConfigCat Provider | ||
The minimum required version of `configcat-js-ssr` currently is `7.1.2`. | ||
The minimum required version of `configcat-node` currently is `11.0.0`. | ||
``` | ||
$ npm install @openfeature/server-sdk configcat-js-ssr | ||
$ npm install @openfeature/server-sdk configcat-node | ||
``` | ||
@@ -26,9 +26,7 @@ | ||
The ConfigCat provider uses the [ConfigCat JavaScript (SSR) SDK](https://configcat.com/docs/sdk-reference/js-ssr/). | ||
This means that the provider can be used in both server (e.g. Node.js) and client (browser) applications. | ||
The ConfigCat provider uses the [ConfigCat JavaScript SDK](https://configcat.com/docs/sdk-reference/js/). | ||
It can either be created by passing the ConfigCat SDK options to ```ConfigCatProvider.create``` or | ||
the ```ConfigCatProvider``` constructor. | ||
It can be created by passing the ConfigCat SDK options to ```ConfigCatProvider.create```. | ||
The available options can be found in the [ConfigCat JavaScript (SSR) SDK](https://configcat.com/docs/sdk-reference/js-ssr/). | ||
The available options can be found in the [ConfigCat JavaScript SDK](https://configcat.com/docs/sdk-reference/js/). | ||
@@ -58,9 +56,6 @@ ### Example using the default configuration | ||
ConfigCat only supports string values in its "evaluation | ||
context", [there known as User Object](https://configcat.com/docs/advanced/user-object/). | ||
The OpenFeature Evaluation Context is mapped to the [ConfigCat user object](https://configcat.com/docs/advanced/user-object/). | ||
This means that every value is converted to a string. This is trivial for numbers and booleans. Objects and arrays are | ||
converted to JSON strings that can be interpreted in ConfigCat. | ||
ConfigCat has three known attributes, and allows for additional attributes. | ||
The [ConfigCat user object](https://configcat.com/docs/advanced/user-object/) has three known attributes, | ||
and allows for additional attributes. | ||
The following shows how the attributes are mapped: | ||
@@ -75,2 +70,13 @@ | ||
The custom types are mapped the following way: | ||
| OpenFeature EvaluationContext Field Type | ConfigCat User Field Type | | ||
|-----------------------------------------------|---------------------------| | ||
| string | string | | ||
| number | number | | ||
| boolean | string | | ||
| Array<string> | Array<string> | | ||
| Array | Array | | ||
| object | string | | ||
The following example shows the conversion between an OpenFeature Evaluation Context and the corresponding ConfigCat | ||
@@ -93,2 +99,3 @@ User: | ||
}, | ||
"customStringArray": ["one", "two"], | ||
"customArray": [ | ||
@@ -112,4 +119,5 @@ 1, | ||
"customBoolean": "true", | ||
"customNumber": "1", | ||
"customNumber": 1, | ||
"customObject": "{\"prop1\":\"1\",\"prop2\":2}", | ||
"customStringArray": ["one", "two"], | ||
"customArray": "[1,\"2\",false]" | ||
@@ -116,0 +124,0 @@ } |
@@ -1,14 +0,16 @@ | ||
import { EvaluationContext, JsonValue, OpenFeatureEventEmitter, Provider, ProviderStatus, ResolutionDetails } from '@openfeature/server-sdk'; | ||
import { getClient, IConfigCatClient } from 'configcat-js-ssr'; | ||
import { EvaluationContext, JsonValue, OpenFeatureEventEmitter, Provider, ResolutionDetails, Paradigm } from '@openfeature/server-sdk'; | ||
import { PrimitiveType, PrimitiveTypeName } from '@openfeature/config-cat-core'; | ||
import { PollingMode } from 'configcat-common'; | ||
import { IConfigCatClient, OptionsForPollingMode } from 'configcat-node'; | ||
export declare class ConfigCatProvider implements Provider { | ||
readonly events: OpenFeatureEventEmitter; | ||
private _status; | ||
private readonly _clientParameters; | ||
private readonly _clientFactory; | ||
private _hasError; | ||
private _client?; | ||
runsOn: Paradigm; | ||
metadata: { | ||
name: string; | ||
}; | ||
constructor(...params: Parameters<typeof getClient>); | ||
static create(...params: Parameters<typeof getClient>): ConfigCatProvider; | ||
get status(): ProviderStatus; | ||
protected constructor(clientFactory: (provider: ConfigCatProvider) => IConfigCatClient); | ||
static create<TMode extends PollingMode>(sdkKey: string, pollingMode?: TMode, options?: OptionsForPollingMode<TMode>): ConfigCatProvider; | ||
initialize(): Promise<void>; | ||
@@ -21,2 +23,3 @@ get configCatClient(): IConfigCatClient | undefined; | ||
resolveObjectEvaluation<U extends JsonValue>(flagKey: string, defaultValue: U, context: EvaluationContext): Promise<ResolutionDetails<U>>; | ||
protected evaluate<T extends PrimitiveTypeName>(flagKey: string, flagType: T, context: EvaluationContext): Promise<ResolutionDetails<PrimitiveType<T>>>; | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
138
31401
5
11
305
1
+ Addedconfigcat-common@9.3.0
+ Addedconfigcat-js-ssr@8.4.1
+ Added@openfeature/config-cat-core@0.1.0(transitive)
+ Added@openfeature/core@1.0.0(transitive)
+ Addedconfigcat-common@9.3.0(transitive)
+ Addedconfigcat-js-ssr@8.4.1(transitive)
+ Addedconfigcat-node@11.3.1(transitive)
+ Addedtunnel@0.0.6(transitive)
- Removedconfigcat-js-ssr@8.4.4(transitive)