@featurevisor/react 1.35.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/dist/index.js +1 -1
- package/dist/index.js.gz +0 -0
- package/dist/index.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/onFeatureChange.d.ts +3 -0
- package/lib/onFeatureChange.js +24 -0
- package/lib/onFeatureChange.js.map +1 -0
- package/lib/useFlag.d.ts +1 -1
- package/lib/useFlag.js +16 -1
- package/lib/useFlag.js.map +1 -1
- package/lib/useVariable.d.ts +2 -2
- package/lib/useVariable.js +16 -1
- package/lib/useVariable.js.map +1 -1
- package/lib/useVariation.d.ts +1 -1
- package/lib/useVariation.js +16 -1
- package/lib/useVariation.js.map +1 -1
- package/package.json +6 -5
- package/src/index.ts +3 -2
- package/src/onFeatureChange.ts +29 -0
- package/src/useFlag.spec.tsx +57 -21
- package/src/useFlag.ts +21 -2
- package/src/useSdk.spec.tsx +10 -9
- package/src/useVariable.spec.tsx +65 -38
- package/src/useVariable.ts +22 -3
- package/src/useVariation.spec.tsx +68 -25
- package/src/useVariation.ts +21 -5
- package/lib/activateFeature.d.ts +0 -2
- package/lib/activateFeature.js +0 -6
- package/lib/activateFeature.js.map +0 -1
- package/lib/activateFeature.spec.d.ts +0 -1
- package/lib/useStatus.d.ts +0 -4
- package/lib/useStatus.js +0 -18
- package/lib/useStatus.js.map +0 -1
- package/lib/useStatus.spec.d.ts +0 -1
- package/src/activateFeature.spec.tsx +0 -60
- package/src/activateFeature.ts +0 -12
- package/src/useStatus.spec.tsx +0 -60
- package/src/useStatus.ts +0 -28
package/README.md
CHANGED
|
@@ -4,12 +4,6 @@ React components and hooks for Featurevisor.
|
|
|
4
4
|
|
|
5
5
|
Visit [https://featurevisor.com/docs/react/](https://featurevisor.com/docs/react/) for more information
|
|
6
6
|
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
$ npm install --save @featurevisor/react
|
|
11
|
-
```
|
|
12
|
-
|
|
13
7
|
## License <!-- omit in toc -->
|
|
14
8
|
|
|
15
9
|
MIT © [Fahad Heylaal](https://fahad19.com)
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.FeaturevisorReact=t(require("react")):e.FeaturevisorReact=t(e.React)}(this,(e=>(()=>{"use strict";var t={253:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FeaturevisorContext=void 0;var
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.FeaturevisorReact=t(require("react")):e.FeaturevisorReact=t(e.React)}(this,(e=>(()=>{"use strict";var t={253:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FeaturevisorContext=void 0;var n=r(12);t.FeaturevisorContext=n.createContext(void 0)},567:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FeaturevisorProvider=function(e){return n.createElement(o.FeaturevisorContext.Provider,{value:e.instance},e.children)};var n=r(12),o=r(253)},869:function(e,t,r){var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r);var o=Object.getOwnPropertyDescriptor(t,r);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__exportStar||function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||n(t,e,r)};Object.defineProperty(t,"__esModule",{value:!0}),o(r(253),t),o(r(567),t),o(r(316),t),o(r(926),t),o(r(929),t),o(r(940),t),o(r(576),t)},576:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.onFeatureChange=function(e,t,r){var n=e.on("datafile_set",(function(e){var n=e.features;Array.isArray(n)&&n.indexOf(t)>-1&&r()})),o=e.on("context_set",(function(){r()})),a=e.on("sticky_set",(function(e){var n=e.features;Array.isArray(n)&&n.indexOf(t)>-1&&r()}));return function(){n(),o(),a()}}},940:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.useFlag=function(e,t){void 0===t&&(t={});var r=(0,o.useSdk)(),u=r.isEnabled(e,t),i=(0,n.useState)(u),c=i[0],s=i[1];return(0,n.useEffect)((function(){var n=(0,a.onFeatureChange)(r,e,(function(){var n=r.isEnabled(e,t);n!==c&&s(n)}));return function(){n()}}),[e,t]),c};var n=r(12),o=r(316),a=r(576)},316:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.useSdk=function(){return n.useContext(o.FeaturevisorContext)};var n=r(12),o=r(253)},926:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.useVariable=function(e,t,r){void 0===r&&(r={});var u=(0,o.useSdk)(),i=u.getVariable(e,t,r),c=(0,n.useState)(i),s=c[0],f=c[1];return(0,n.useEffect)((function(){var n=(0,a.onFeatureChange)(u,e,(function(){var n=u.getVariable(e,t,r);n!==s&&f(n)}));return function(){n()}}),[e,t,r]),s};var n=r(12),o=r(316),a=r(576)},929:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.useVariation=function(e,t){void 0===t&&(t={});var r=(0,o.useSdk)(),u=r.getVariation(e,t),i=(0,n.useState)(u),c=i[0],s=i[1];return(0,n.useEffect)((function(){var n=(0,a.onFeatureChange)(r,e,(function(){var n=r.getVariation(e,t);n!==c&&s(n)}));return function(){n()}}),[e,t]),c};var n=r(12),o=r(316),a=r(576)},12:t=>{t.exports=e}},r={};return function e(n){var o=r[n];if(void 0!==o)return o.exports;var a=r[n]={exports:{}};return t[n].call(a.exports,a,a.exports,e),a.exports}(869)})()));
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.gz
CHANGED
|
Binary file
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,EAAQG,QAAQ,UACR,mBAAXC,QAAyBA,OAAOC,IAC9CD,OAAO,CAAC,SAAUJ,GACQ,iBAAZC,QACdA,QAA2B,kBAAID,EAAQG,QAAQ,UAE/CJ,EAAwB,kBAAIC,EAAQD,EAAY,MACjD,CATD,CASGO,MAAOC,G,sHCTV,YAGa,EAAAC,oBAAsBC,EAAMC,mBAAgDC,E,iECOzF,gCAAqCC,GACnC,OACE,gBAAC,EAAAJ,oBAAoBK,SAAQ,CAACC,MAAOF,EAAMG,UACxCH,EAAMI,SAGb,EAhBA,YAGA,Q,
|
|
1
|
+
{"version":3,"file":"index.js","mappings":"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","sources":["webpack://FeaturevisorReact/webpack/universalModuleDefinition","webpack://FeaturevisorReact/./src/FeaturevisorContext.ts","webpack://FeaturevisorReact/./src/FeaturevisorProvider.tsx","webpack://FeaturevisorReact/./src/index.ts","webpack://FeaturevisorReact/./src/onFeatureChange.ts","webpack://FeaturevisorReact/./src/useFlag.ts","webpack://FeaturevisorReact/./src/useSdk.ts","webpack://FeaturevisorReact/./src/useVariable.ts","webpack://FeaturevisorReact/./src/useVariation.ts","webpack://FeaturevisorReact/external umd {\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"react\",\"root\":\"React\"}","webpack://FeaturevisorReact/webpack/bootstrap","webpack://FeaturevisorReact/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"react\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"FeaturevisorReact\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"FeaturevisorReact\"] = factory(root[\"React\"]);\n})(this, (__WEBPACK_EXTERNAL_MODULE__12__) => {\nreturn ","import * as React from \"react\";\nimport { FeaturevisorInstance } from \"@featurevisor/sdk\";\n\nexport const FeaturevisorContext = React.createContext<FeaturevisorInstance | undefined>(undefined);\n","import * as React from \"react\";\nimport { FeaturevisorInstance } from \"@featurevisor/sdk\";\n\nimport { FeaturevisorContext } from \"./FeaturevisorContext\";\n\nexport interface FeaturevisorProviderProps {\n instance: FeaturevisorInstance;\n children: React.ReactNode;\n}\n\nexport function FeaturevisorProvider(props: FeaturevisorProviderProps) {\n return (\n <FeaturevisorContext.Provider value={props.instance}>\n {props.children}\n </FeaturevisorContext.Provider>\n );\n}\n","// contexts\nexport * from \"./FeaturevisorContext\";\n\n// components\nexport * from \"./FeaturevisorProvider\";\n\n// hooks\nexport * from \"./useSdk\";\nexport * from \"./useVariable\";\nexport * from \"./useVariation\";\nexport * from \"./useFlag\";\n\n// utils\nexport * from \"./onFeatureChange\";\n","import { FeaturevisorInstance } from \"@featurevisor/sdk\";\nimport type { FeatureKey } from \"@featurevisor/types\";\n\nexport function onFeatureChange(sdk: FeaturevisorInstance, featureKey: FeatureKey, fn) {\n // datafile_set\n const unsubscribeDatafileSet = sdk.on(\"datafile_set\", ({ features }) => {\n if (Array.isArray(features) && features.indexOf(featureKey) > -1) {\n fn();\n }\n });\n\n // context_set\n const unsubscribeContextSet = sdk.on(\"context_set\", () => {\n fn();\n });\n\n // sticky_set\n const unsubscribeStickySet = sdk.on(\"sticky_set\", ({ features }) => {\n if (Array.isArray(features) && features.indexOf(featureKey) > -1) {\n fn();\n }\n });\n\n return function () {\n unsubscribeDatafileSet();\n unsubscribeContextSet();\n unsubscribeStickySet();\n };\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { Context, FeatureKey } from \"@featurevisor/types\";\n\nimport { useSdk } from \"./useSdk\";\nimport { onFeatureChange } from \"./onFeatureChange\";\n\nexport function useFlag(featureKey: FeatureKey, context: Context = {}): boolean {\n const sdk = useSdk();\n const initialValue = sdk.isEnabled(featureKey, context);\n const [isEnabled, setIsEnabled] = useState(initialValue);\n\n useEffect(() => {\n const unsubscribe = onFeatureChange(sdk, featureKey, () => {\n const newValue = sdk.isEnabled(featureKey, context);\n\n if (newValue !== isEnabled) {\n setIsEnabled(newValue);\n }\n });\n\n return () => {\n unsubscribe();\n };\n }, [featureKey, context]);\n\n return isEnabled;\n}\n","import * as React from \"react\";\nimport { FeaturevisorInstance } from \"@featurevisor/sdk\";\n\nimport { FeaturevisorContext } from \"./FeaturevisorContext\";\n\nexport function useSdk(): FeaturevisorInstance {\n const sdk = React.useContext(FeaturevisorContext);\n\n return sdk as FeaturevisorInstance;\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { Context, FeatureKey, VariableKey, VariableValue } from \"@featurevisor/types\";\n\nimport { useSdk } from \"./useSdk\";\nimport { onFeatureChange } from \"./onFeatureChange\";\n\nexport function useVariable(\n featureKey: FeatureKey,\n variableKey: VariableKey,\n context: Context = {},\n): VariableValue | null {\n const sdk = useSdk();\n const initialValue = sdk.getVariable(featureKey, variableKey, context);\n const [variableValue, setVariableValue] = useState<VariableValue | null>(initialValue);\n\n useEffect(() => {\n const unsubscribe = onFeatureChange(sdk, featureKey, () => {\n const newValue = sdk.getVariable(featureKey, variableKey, context);\n\n if (newValue !== variableValue) {\n setVariableValue(newValue);\n }\n });\n\n return () => {\n unsubscribe();\n };\n }, [featureKey, variableKey, context]);\n\n return variableValue;\n}\n","import { useEffect, useState } from \"react\";\n\nimport { Context, FeatureKey, VariationValue } from \"@featurevisor/types\";\n\nimport { useSdk } from \"./useSdk\";\nimport { onFeatureChange } from \"./onFeatureChange\";\n\nexport function useVariation(featureKey: FeatureKey, context: Context = {}): VariationValue | null {\n const sdk = useSdk();\n const initialValue = sdk.getVariation(featureKey, context);\n const [variationValue, setVariationValue] = useState<VariationValue | null>(initialValue);\n\n useEffect(() => {\n const unsubscribe = onFeatureChange(sdk, featureKey, () => {\n const newValue = sdk.getVariation(featureKey, context);\n\n if (newValue !== variationValue) {\n setVariationValue(newValue);\n }\n });\n\n return () => {\n unsubscribe();\n };\n }, [featureKey, context]);\n\n return variationValue;\n}\n","module.exports = __WEBPACK_EXTERNAL_MODULE__12__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(869);\n"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__12__","FeaturevisorContext","React","createContext","undefined","props","Provider","value","instance","children","sdk","featureKey","fn","unsubscribeDatafileSet","on","features","Array","isArray","indexOf","unsubscribeContextSet","unsubscribeStickySet","context","useSdk","initialValue","isEnabled","useState","setIsEnabled","useEffect","unsubscribe","onFeatureChange","newValue","useContext","variableKey","getVariable","variableValue","setVariableValue","getVariation","variationValue","setVariationValue","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","call"],"sourceRoot":""}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export * from "./FeaturevisorContext";
|
|
2
2
|
export * from "./FeaturevisorProvider";
|
|
3
|
-
export * from "./activateFeature";
|
|
4
3
|
export * from "./useSdk";
|
|
5
|
-
export * from "./useStatus";
|
|
6
4
|
export * from "./useVariable";
|
|
7
5
|
export * from "./useVariation";
|
|
8
6
|
export * from "./useFlag";
|
|
7
|
+
export * from "./onFeatureChange";
|
package/lib/index.js
CHANGED
|
@@ -3,10 +3,10 @@ export * from "./FeaturevisorContext";
|
|
|
3
3
|
// components
|
|
4
4
|
export * from "./FeaturevisorProvider";
|
|
5
5
|
// hooks
|
|
6
|
-
export * from "./activateFeature";
|
|
7
6
|
export * from "./useSdk";
|
|
8
|
-
export * from "./useStatus";
|
|
9
7
|
export * from "./useVariable";
|
|
10
8
|
export * from "./useVariation";
|
|
11
9
|
export * from "./useFlag";
|
|
10
|
+
// utils
|
|
11
|
+
export * from "./onFeatureChange";
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,cAAc,uBAAuB,CAAC;AAEtC,aAAa;AACb,cAAc,wBAAwB,CAAC;AAEvC,QAAQ;AACR,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,cAAc,uBAAuB,CAAC;AAEtC,aAAa;AACb,cAAc,wBAAwB,CAAC;AAEvC,QAAQ;AACR,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAE1B,QAAQ;AACR,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function onFeatureChange(sdk, featureKey, fn) {
|
|
2
|
+
// datafile_set
|
|
3
|
+
const unsubscribeDatafileSet = sdk.on("datafile_set", ({ features }) => {
|
|
4
|
+
if (Array.isArray(features) && features.indexOf(featureKey) > -1) {
|
|
5
|
+
fn();
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
// context_set
|
|
9
|
+
const unsubscribeContextSet = sdk.on("context_set", () => {
|
|
10
|
+
fn();
|
|
11
|
+
});
|
|
12
|
+
// sticky_set
|
|
13
|
+
const unsubscribeStickySet = sdk.on("sticky_set", ({ features }) => {
|
|
14
|
+
if (Array.isArray(features) && features.indexOf(featureKey) > -1) {
|
|
15
|
+
fn();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return function () {
|
|
19
|
+
unsubscribeDatafileSet();
|
|
20
|
+
unsubscribeContextSet();
|
|
21
|
+
unsubscribeStickySet();
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=onFeatureChange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onFeatureChange.js","sourceRoot":"","sources":["../src/onFeatureChange.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAAC,GAAyB,EAAE,UAAsB,EAAE,EAAE;IACnF,eAAe;IACf,MAAM,sBAAsB,GAAG,GAAG,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACjE,EAAE,EAAE,CAAC;QACP,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,cAAc;IACd,MAAM,qBAAqB,GAAG,GAAG,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;QACvD,EAAE,EAAE,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,MAAM,oBAAoB,GAAG,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACjE,EAAE,EAAE,CAAC;QACP,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,sBAAsB,EAAE,CAAC;QACzB,qBAAqB,EAAE,CAAC;QACxB,oBAAoB,EAAE,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC"}
|
package/lib/useFlag.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Context, FeatureKey } from "@featurevisor/types";
|
|
1
|
+
import type { Context, FeatureKey } from "@featurevisor/types";
|
|
2
2
|
export declare function useFlag(featureKey: FeatureKey, context?: Context): boolean;
|
package/lib/useFlag.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
1
2
|
import { useSdk } from "./useSdk";
|
|
3
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
2
4
|
export function useFlag(featureKey, context = {}) {
|
|
3
5
|
const sdk = useSdk();
|
|
4
|
-
|
|
6
|
+
const initialValue = sdk.isEnabled(featureKey, context);
|
|
7
|
+
const [isEnabled, setIsEnabled] = useState(initialValue);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
10
|
+
const newValue = sdk.isEnabled(featureKey, context);
|
|
11
|
+
if (newValue !== isEnabled) {
|
|
12
|
+
setIsEnabled(newValue);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
unsubscribe();
|
|
17
|
+
};
|
|
18
|
+
}, [featureKey, context]);
|
|
19
|
+
return isEnabled;
|
|
5
20
|
}
|
|
6
21
|
//# sourceMappingURL=useFlag.js.map
|
package/lib/useFlag.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFlag.js","sourceRoot":"","sources":["../src/useFlag.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useFlag.js","sourceRoot":"","sources":["../src/useFlag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,OAAO,CAAC,UAAsB,EAAE,UAAmB,EAAE;IACnE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IAEzD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEpD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,YAAY,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1B,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/lib/useVariable.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Context, FeatureKey, VariableKey, VariableValue } from "@featurevisor/types";
|
|
2
|
-
export declare function useVariable(featureKey: FeatureKey, variableKey: VariableKey, context?: Context): VariableValue |
|
|
1
|
+
import type { Context, FeatureKey, VariableKey, VariableValue } from "@featurevisor/types";
|
|
2
|
+
export declare function useVariable(featureKey: FeatureKey, variableKey: VariableKey, context?: Context): VariableValue | null;
|
package/lib/useVariable.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
1
2
|
import { useSdk } from "./useSdk";
|
|
3
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
2
4
|
export function useVariable(featureKey, variableKey, context = {}) {
|
|
3
5
|
const sdk = useSdk();
|
|
4
|
-
|
|
6
|
+
const initialValue = sdk.getVariable(featureKey, variableKey, context);
|
|
7
|
+
const [variableValue, setVariableValue] = useState(initialValue);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
10
|
+
const newValue = sdk.getVariable(featureKey, variableKey, context);
|
|
11
|
+
if (newValue !== variableValue) {
|
|
12
|
+
setVariableValue(newValue);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
unsubscribe();
|
|
17
|
+
};
|
|
18
|
+
}, [featureKey, variableKey, context]);
|
|
19
|
+
return variableValue;
|
|
5
20
|
}
|
|
6
21
|
//# sourceMappingURL=useVariable.js.map
|
package/lib/useVariable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVariable.js","sourceRoot":"","sources":["../src/useVariable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useVariable.js","sourceRoot":"","sources":["../src/useVariable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,WAAW,CACzB,UAAsB,EACtB,WAAwB,EACxB,UAAmB,EAAE;IAErB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACvE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAuB,YAAY,CAAC,CAAC;IAEvF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;YAEnE,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC/B,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAEvC,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
package/lib/useVariation.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Context, FeatureKey, VariationValue } from "@featurevisor/types";
|
|
2
|
-
export declare function useVariation(featureKey: FeatureKey, context?: Context): VariationValue |
|
|
2
|
+
export declare function useVariation(featureKey: FeatureKey, context?: Context): VariationValue | null;
|
package/lib/useVariation.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
1
2
|
import { useSdk } from "./useSdk";
|
|
3
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
2
4
|
export function useVariation(featureKey, context = {}) {
|
|
3
5
|
const sdk = useSdk();
|
|
4
|
-
|
|
6
|
+
const initialValue = sdk.getVariation(featureKey, context);
|
|
7
|
+
const [variationValue, setVariationValue] = useState(initialValue);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
10
|
+
const newValue = sdk.getVariation(featureKey, context);
|
|
11
|
+
if (newValue !== variationValue) {
|
|
12
|
+
setVariationValue(newValue);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
unsubscribe();
|
|
17
|
+
};
|
|
18
|
+
}, [featureKey, context]);
|
|
19
|
+
return variationValue;
|
|
5
20
|
}
|
|
6
21
|
//# sourceMappingURL=useVariation.js.map
|
package/lib/useVariation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVariation.js","sourceRoot":"","sources":["../src/useVariation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useVariation.js","sourceRoot":"","sources":["../src/useVariation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,UAAsB,EAAE,UAAmB,EAAE;IACxE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC3D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAwB,YAAY,CAAC,CAAC;IAE1F,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;YACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEvD,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;gBAChC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1B,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featurevisor/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "React package for Featurevisor",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"transpile": "rimraf lib && tsc --project tsconfig.esm.json",
|
|
10
10
|
"dist": "webpack --config ./webpack.config.js",
|
|
11
|
-
"build": "npm run transpile && npm run dist"
|
|
11
|
+
"build": "npm run transpile && npm run dist",
|
|
12
|
+
"test": "jest --config jest.config.js"
|
|
12
13
|
},
|
|
13
14
|
"author": {
|
|
14
15
|
"name": "Fahad Heylaal",
|
|
@@ -40,8 +41,8 @@
|
|
|
40
41
|
"url": "https://github.com/featurevisor/featurevisor/issues"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
|
-
"@featurevisor/sdk": "
|
|
44
|
-
"@featurevisor/types": "
|
|
44
|
+
"@featurevisor/sdk": "2.0.0",
|
|
45
|
+
"@featurevisor/types": "2.0.0"
|
|
45
46
|
},
|
|
46
47
|
"license": "MIT",
|
|
47
48
|
"devDependencies": {
|
|
@@ -49,5 +50,5 @@
|
|
|
49
50
|
"@testing-library/react": "^14.0.0",
|
|
50
51
|
"jest-environment-jsdom": "^29.5.0"
|
|
51
52
|
},
|
|
52
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "9817e05a07735294c750ee921991509b67015afd"
|
|
53
54
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,9 +5,10 @@ export * from "./FeaturevisorContext";
|
|
|
5
5
|
export * from "./FeaturevisorProvider";
|
|
6
6
|
|
|
7
7
|
// hooks
|
|
8
|
-
export * from "./activateFeature";
|
|
9
8
|
export * from "./useSdk";
|
|
10
|
-
export * from "./useStatus";
|
|
11
9
|
export * from "./useVariable";
|
|
12
10
|
export * from "./useVariation";
|
|
13
11
|
export * from "./useFlag";
|
|
12
|
+
|
|
13
|
+
// utils
|
|
14
|
+
export * from "./onFeatureChange";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FeaturevisorInstance } from "@featurevisor/sdk";
|
|
2
|
+
import type { FeatureKey } from "@featurevisor/types";
|
|
3
|
+
|
|
4
|
+
export function onFeatureChange(sdk: FeaturevisorInstance, featureKey: FeatureKey, fn) {
|
|
5
|
+
// datafile_set
|
|
6
|
+
const unsubscribeDatafileSet = sdk.on("datafile_set", ({ features }) => {
|
|
7
|
+
if (Array.isArray(features) && features.indexOf(featureKey) > -1) {
|
|
8
|
+
fn();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
// context_set
|
|
13
|
+
const unsubscribeContextSet = sdk.on("context_set", () => {
|
|
14
|
+
fn();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// sticky_set
|
|
18
|
+
const unsubscribeStickySet = sdk.on("sticky_set", ({ features }) => {
|
|
19
|
+
if (Array.isArray(features) && features.indexOf(featureKey) > -1) {
|
|
20
|
+
fn();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return function () {
|
|
25
|
+
unsubscribeDatafileSet();
|
|
26
|
+
unsubscribeContextSet();
|
|
27
|
+
unsubscribeStickySet();
|
|
28
|
+
};
|
|
29
|
+
}
|
package/src/useFlag.spec.tsx
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { render, screen, waitFor, act } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
5
|
import { FeaturevisorProvider } from "./FeaturevisorProvider";
|
|
6
6
|
import { useFlag } from "./useFlag";
|
|
7
7
|
import { createInstance } from "@featurevisor/sdk";
|
|
8
8
|
|
|
9
|
+
function getNewDatafile(enabled = true) {
|
|
10
|
+
return {
|
|
11
|
+
schemaVersion: "2",
|
|
12
|
+
revision: "1.0",
|
|
13
|
+
features: {
|
|
14
|
+
test: {
|
|
15
|
+
key: "test",
|
|
16
|
+
bucketBy: "userId",
|
|
17
|
+
traffic: [
|
|
18
|
+
{
|
|
19
|
+
key: "1",
|
|
20
|
+
segments: "*",
|
|
21
|
+
percentage: enabled ? 100000 : 0,
|
|
22
|
+
allocation: [],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
hash: Math.random().toString(10).substring(2, 15),
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
segments: {},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
function getNewInstance(enabled = true) {
|
|
10
33
|
const sdk = createInstance({
|
|
11
|
-
datafile:
|
|
12
|
-
schemaVersion: "1",
|
|
13
|
-
revision: "1.0",
|
|
14
|
-
features: [
|
|
15
|
-
{
|
|
16
|
-
key: "test",
|
|
17
|
-
bucketBy: "userId",
|
|
18
|
-
traffic: [
|
|
19
|
-
{
|
|
20
|
-
key: "1",
|
|
21
|
-
segments: "*",
|
|
22
|
-
percentage: enabled ? 100000 : 0,
|
|
23
|
-
allocation: [],
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
attributes: [],
|
|
29
|
-
segments: [],
|
|
30
|
-
},
|
|
34
|
+
datafile: getNewDatafile(enabled),
|
|
31
35
|
});
|
|
32
36
|
|
|
33
37
|
return sdk;
|
|
@@ -52,6 +56,7 @@ describe("react: useFlag", function () {
|
|
|
52
56
|
);
|
|
53
57
|
|
|
54
58
|
expect(screen.getByText("True")).toBeInTheDocument();
|
|
59
|
+
expect(screen.queryByText("False")).not.toBeInTheDocument();
|
|
55
60
|
});
|
|
56
61
|
|
|
57
62
|
test("should check if feature is disabled", function () {
|
|
@@ -68,5 +73,36 @@ describe("react: useFlag", function () {
|
|
|
68
73
|
);
|
|
69
74
|
|
|
70
75
|
expect(screen.getByText("False")).toBeInTheDocument();
|
|
76
|
+
expect(screen.queryByText("True")).not.toBeInTheDocument();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("should check if feature evaluation is reactive", async function () {
|
|
80
|
+
function TestComponent() {
|
|
81
|
+
const isEnabled = useFlag("test", { userId: "1" });
|
|
82
|
+
|
|
83
|
+
return isEnabled ? <p>True</p> : <p>False</p>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const f = getNewInstance(true);
|
|
87
|
+
|
|
88
|
+
render(
|
|
89
|
+
<FeaturevisorProvider instance={f}>
|
|
90
|
+
<TestComponent />
|
|
91
|
+
</FeaturevisorProvider>,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(screen.getByText("True")).toBeInTheDocument();
|
|
95
|
+
expect(screen.queryByText("False")).not.toBeInTheDocument();
|
|
96
|
+
|
|
97
|
+
// set new datafile
|
|
98
|
+
await act(async () => {
|
|
99
|
+
const newDatafile = getNewDatafile(false); // true => false
|
|
100
|
+
f.setDatafile(newDatafile);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect(screen.getByText("False")).toBeInTheDocument();
|
|
105
|
+
expect(screen.queryByText("True")).not.toBeInTheDocument();
|
|
106
|
+
});
|
|
71
107
|
});
|
|
72
108
|
});
|
package/src/useFlag.ts
CHANGED
|
@@ -1,9 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import type { Context, FeatureKey } from "@featurevisor/types";
|
|
2
4
|
|
|
3
5
|
import { useSdk } from "./useSdk";
|
|
6
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
4
7
|
|
|
5
8
|
export function useFlag(featureKey: FeatureKey, context: Context = {}): boolean {
|
|
6
9
|
const sdk = useSdk();
|
|
10
|
+
const initialValue = sdk.isEnabled(featureKey, context);
|
|
11
|
+
const [isEnabled, setIsEnabled] = useState(initialValue);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
15
|
+
const newValue = sdk.isEnabled(featureKey, context);
|
|
16
|
+
|
|
17
|
+
if (newValue !== isEnabled) {
|
|
18
|
+
setIsEnabled(newValue);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
unsubscribe();
|
|
24
|
+
};
|
|
25
|
+
}, [featureKey, context]);
|
|
7
26
|
|
|
8
|
-
return
|
|
27
|
+
return isEnabled;
|
|
9
28
|
}
|
package/src/useSdk.spec.tsx
CHANGED
|
@@ -9,10 +9,10 @@ import { createInstance } from "@featurevisor/sdk";
|
|
|
9
9
|
function getNewInstance() {
|
|
10
10
|
const sdk = createInstance({
|
|
11
11
|
datafile: {
|
|
12
|
-
schemaVersion: "
|
|
12
|
+
schemaVersion: "2",
|
|
13
13
|
revision: "1.0",
|
|
14
|
-
features:
|
|
15
|
-
{
|
|
14
|
+
features: {
|
|
15
|
+
test: {
|
|
16
16
|
key: "test",
|
|
17
17
|
bucketBy: "userId",
|
|
18
18
|
variations: [{ value: "control" }, { value: "treatment" }],
|
|
@@ -28,9 +28,8 @@ function getNewInstance() {
|
|
|
28
28
|
},
|
|
29
29
|
],
|
|
30
30
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
segments: [],
|
|
31
|
+
},
|
|
32
|
+
segments: {},
|
|
34
33
|
},
|
|
35
34
|
});
|
|
36
35
|
|
|
@@ -43,10 +42,10 @@ describe("react: useSdk", function () {
|
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
test("should return the sdk", function () {
|
|
46
|
-
|
|
47
|
-
const sdk = useSdk();
|
|
45
|
+
let sdk;
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
function TestComponent() {
|
|
48
|
+
sdk = useSdk();
|
|
50
49
|
|
|
51
50
|
return <p>Test</p>;
|
|
52
51
|
}
|
|
@@ -58,5 +57,7 @@ describe("react: useSdk", function () {
|
|
|
58
57
|
);
|
|
59
58
|
|
|
60
59
|
expect(screen.getByText("Test")).toBeInTheDocument();
|
|
60
|
+
|
|
61
|
+
expect(sdk).toBeDefined();
|
|
61
62
|
});
|
|
62
63
|
});
|
package/src/useVariable.spec.tsx
CHANGED
|
@@ -1,50 +1,49 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { render, screen, waitFor, act } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
|
+
import { createInstance } from "@featurevisor/sdk";
|
|
6
|
+
import { DatafileContent } from "@featurevisor/types";
|
|
7
|
+
|
|
5
8
|
import { FeaturevisorProvider } from "./FeaturevisorProvider";
|
|
6
9
|
import { useVariable } from "./useVariable";
|
|
7
|
-
import { createInstance } from "@featurevisor/sdk";
|
|
8
10
|
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ key: "color", type: "string", defaultValue: "red" },
|
|
33
|
-
{
|
|
34
|
-
key: "hero",
|
|
35
|
-
type: "object",
|
|
36
|
-
defaultValue: {
|
|
37
|
-
title: "Hero Title",
|
|
38
|
-
subtitle: "Hero Subtitle",
|
|
39
|
-
alignment: "center",
|
|
40
|
-
},
|
|
11
|
+
function getNewDatafile(colorValue = "red"): DatafileContent {
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: "2",
|
|
14
|
+
revision: "1.0",
|
|
15
|
+
features: {
|
|
16
|
+
test: {
|
|
17
|
+
key: "test",
|
|
18
|
+
bucketBy: "userId",
|
|
19
|
+
traffic: [
|
|
20
|
+
{
|
|
21
|
+
key: "1",
|
|
22
|
+
segments: "*",
|
|
23
|
+
percentage: 100000,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
variablesSchema: {
|
|
27
|
+
color: { type: "string", defaultValue: colorValue },
|
|
28
|
+
hero: {
|
|
29
|
+
type: "object",
|
|
30
|
+
defaultValue: {
|
|
31
|
+
title: "Hero Title",
|
|
32
|
+
subtitle: "Hero Subtitle",
|
|
33
|
+
alignment: "center",
|
|
41
34
|
},
|
|
42
|
-
|
|
35
|
+
},
|
|
43
36
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
segments: [],
|
|
37
|
+
hash: Math.random().toString(10).substring(2, 15),
|
|
38
|
+
},
|
|
47
39
|
},
|
|
40
|
+
segments: {},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getNewInstance() {
|
|
45
|
+
const sdk = createInstance({
|
|
46
|
+
datafile: getNewDatafile(),
|
|
48
47
|
});
|
|
49
48
|
|
|
50
49
|
return sdk;
|
|
@@ -70,4 +69,32 @@ describe("react: useVariable", function () {
|
|
|
70
69
|
|
|
71
70
|
expect(screen.getByText("Red")).toBeInTheDocument();
|
|
72
71
|
});
|
|
72
|
+
|
|
73
|
+
test("should return the variable reactively", function () {
|
|
74
|
+
function TestComponent() {
|
|
75
|
+
const variable = useVariable("test", "color", { userId: "1" });
|
|
76
|
+
|
|
77
|
+
return variable === "red" ? <p>Red</p> : <p>Some other colour</p>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const f = getNewInstance();
|
|
81
|
+
|
|
82
|
+
render(
|
|
83
|
+
<FeaturevisorProvider instance={f}>
|
|
84
|
+
<TestComponent />
|
|
85
|
+
</FeaturevisorProvider>,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(screen.getByText("Red")).toBeInTheDocument();
|
|
89
|
+
|
|
90
|
+
// set new datafile
|
|
91
|
+
act(() => {
|
|
92
|
+
const newDatafile = getNewDatafile("blue"); // red => blue
|
|
93
|
+
f.setDatafile(newDatafile);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
waitFor(() => {
|
|
97
|
+
expect(screen.getByText("Some other colour")).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
73
100
|
});
|
package/src/useVariable.ts
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import type { Context, FeatureKey, VariableKey, VariableValue } from "@featurevisor/types";
|
|
2
4
|
|
|
3
5
|
import { useSdk } from "./useSdk";
|
|
6
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
4
7
|
|
|
5
8
|
export function useVariable(
|
|
6
9
|
featureKey: FeatureKey,
|
|
7
10
|
variableKey: VariableKey,
|
|
8
11
|
context: Context = {},
|
|
9
|
-
): VariableValue |
|
|
12
|
+
): VariableValue | null {
|
|
10
13
|
const sdk = useSdk();
|
|
14
|
+
const initialValue = sdk.getVariable(featureKey, variableKey, context);
|
|
15
|
+
const [variableValue, setVariableValue] = useState<VariableValue | null>(initialValue);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
19
|
+
const newValue = sdk.getVariable(featureKey, variableKey, context);
|
|
20
|
+
|
|
21
|
+
if (newValue !== variableValue) {
|
|
22
|
+
setVariableValue(newValue);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
unsubscribe();
|
|
28
|
+
};
|
|
29
|
+
}, [featureKey, variableKey, context]);
|
|
11
30
|
|
|
12
|
-
return
|
|
31
|
+
return variableValue;
|
|
13
32
|
}
|
|
@@ -1,37 +1,51 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { render, screen, waitFor, act } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
5
|
import { FeaturevisorProvider } from "./FeaturevisorProvider";
|
|
6
6
|
import { useVariation } from "./useVariation";
|
|
7
7
|
import { createInstance } from "@featurevisor/sdk";
|
|
8
|
+
import type { DatafileContent } from "@featurevisor/types";
|
|
9
|
+
|
|
10
|
+
function getNewDatafile(variationValue = "control") {
|
|
11
|
+
return {
|
|
12
|
+
schemaVersion: "2",
|
|
13
|
+
revision: "1.0",
|
|
14
|
+
features: {
|
|
15
|
+
test: {
|
|
16
|
+
key: "test",
|
|
17
|
+
bucketBy: "userId",
|
|
18
|
+
variations: [
|
|
19
|
+
{ value: "control", weight: variationValue === "control" ? 100 : 0 },
|
|
20
|
+
{ value: "treatment", weight: variationValue === "treatment" ? 100 : 0 },
|
|
21
|
+
],
|
|
22
|
+
traffic: [
|
|
23
|
+
{
|
|
24
|
+
key: "1",
|
|
25
|
+
segments: "*",
|
|
26
|
+
percentage: 100000,
|
|
27
|
+
allocation: [
|
|
28
|
+
{
|
|
29
|
+
variation: "control",
|
|
30
|
+
range: [0, variationValue === "control" ? 100000 : 0] as [number, number],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
variation: "treatment",
|
|
34
|
+
range: [variationValue === "control" ? 100000 : 0, 100000] as [number, number],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
hash: Math.random().toString(10).substring(2, 15),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
segments: {},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
8
45
|
|
|
9
46
|
function getNewInstance() {
|
|
10
47
|
const sdk = createInstance({
|
|
11
|
-
datafile:
|
|
12
|
-
schemaVersion: "1",
|
|
13
|
-
revision: "1.0",
|
|
14
|
-
features: [
|
|
15
|
-
{
|
|
16
|
-
key: "test",
|
|
17
|
-
bucketBy: "userId",
|
|
18
|
-
variations: [{ value: "control" }, { value: "treatment" }],
|
|
19
|
-
traffic: [
|
|
20
|
-
{
|
|
21
|
-
key: "1",
|
|
22
|
-
segments: "*",
|
|
23
|
-
percentage: 100000,
|
|
24
|
-
allocation: [
|
|
25
|
-
{ variation: "control", range: [0, 100000] },
|
|
26
|
-
{ variation: "treatment", range: [0, 0] },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
attributes: [],
|
|
33
|
-
segments: [],
|
|
34
|
-
},
|
|
48
|
+
datafile: getNewDatafile(),
|
|
35
49
|
});
|
|
36
50
|
|
|
37
51
|
return sdk;
|
|
@@ -57,4 +71,33 @@ describe("react: useVariation", function () {
|
|
|
57
71
|
|
|
58
72
|
expect(screen.getByText("True")).toBeInTheDocument();
|
|
59
73
|
});
|
|
74
|
+
|
|
75
|
+
test("should return the variation reactively", function () {
|
|
76
|
+
function TestComponent() {
|
|
77
|
+
const variation = useVariation("test", { userId: "1" });
|
|
78
|
+
|
|
79
|
+
return variation === "control" ? <p>True</p> : <p>False</p>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const f = getNewInstance();
|
|
83
|
+
|
|
84
|
+
render(
|
|
85
|
+
<FeaturevisorProvider instance={f}>
|
|
86
|
+
<TestComponent />
|
|
87
|
+
</FeaturevisorProvider>,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(screen.getByText("True")).toBeInTheDocument();
|
|
91
|
+
|
|
92
|
+
// set new datafile
|
|
93
|
+
act(() => {
|
|
94
|
+
const newDatafile: DatafileContent = getNewDatafile("treatment"); // control => treatment
|
|
95
|
+
f.setDatafile(newDatafile);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
waitFor(() => {
|
|
99
|
+
expect(screen.getByText("False")).toBeInTheDocument();
|
|
100
|
+
expect(screen.queryByText("True")).not.toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
60
103
|
});
|
package/src/useVariation.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
1
3
|
import { Context, FeatureKey, VariationValue } from "@featurevisor/types";
|
|
2
4
|
|
|
3
5
|
import { useSdk } from "./useSdk";
|
|
6
|
+
import { onFeatureChange } from "./onFeatureChange";
|
|
4
7
|
|
|
5
|
-
export function useVariation(
|
|
6
|
-
featureKey: FeatureKey,
|
|
7
|
-
context: Context = {},
|
|
8
|
-
): VariationValue | undefined {
|
|
8
|
+
export function useVariation(featureKey: FeatureKey, context: Context = {}): VariationValue | null {
|
|
9
9
|
const sdk = useSdk();
|
|
10
|
+
const initialValue = sdk.getVariation(featureKey, context);
|
|
11
|
+
const [variationValue, setVariationValue] = useState<VariationValue | null>(initialValue);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const unsubscribe = onFeatureChange(sdk, featureKey, () => {
|
|
15
|
+
const newValue = sdk.getVariation(featureKey, context);
|
|
16
|
+
|
|
17
|
+
if (newValue !== variationValue) {
|
|
18
|
+
setVariationValue(newValue);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
unsubscribe();
|
|
24
|
+
};
|
|
25
|
+
}, [featureKey, context]);
|
|
10
26
|
|
|
11
|
-
return
|
|
27
|
+
return variationValue;
|
|
12
28
|
}
|
package/lib/activateFeature.d.ts
DELETED
package/lib/activateFeature.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"activateFeature.js","sourceRoot":"","sources":["../src/activateFeature.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,UAAU,eAAe,CAC7B,UAAsB,EACtB,UAAmB,EAAE;IAErB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IAErB,OAAO,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "@testing-library/jest-dom";
|
package/lib/useStatus.d.ts
DELETED
package/lib/useStatus.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useSdk } from "./useSdk";
|
|
3
|
-
export function useStatus() {
|
|
4
|
-
const sdk = useSdk();
|
|
5
|
-
const initialStatus = sdk.isReady();
|
|
6
|
-
const [isReady, setIsReady] = React.useState(initialStatus);
|
|
7
|
-
React.useEffect(function () {
|
|
8
|
-
function handleReady() {
|
|
9
|
-
setIsReady(true);
|
|
10
|
-
}
|
|
11
|
-
sdk.on("ready", handleReady);
|
|
12
|
-
return function () {
|
|
13
|
-
sdk.off("ready", handleReady);
|
|
14
|
-
};
|
|
15
|
-
}, []);
|
|
16
|
-
return { isReady };
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=useStatus.js.map
|
package/lib/useStatus.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useStatus.js","sourceRoot":"","sources":["../src/useStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMlC,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;IAEpC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAE5D,KAAK,CAAC,SAAS,CAAC;QACd,SAAS,WAAW;YAClB,UAAU,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAED,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAE7B,OAAO;YACL,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAChC,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
|
package/lib/useStatus.spec.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "@testing-library/jest-dom";
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import "@testing-library/jest-dom";
|
|
4
|
-
|
|
5
|
-
import { FeaturevisorProvider } from "./FeaturevisorProvider";
|
|
6
|
-
import { activateFeature } from "./activateFeature";
|
|
7
|
-
import { createInstance } from "@featurevisor/sdk";
|
|
8
|
-
|
|
9
|
-
function getNewInstance() {
|
|
10
|
-
const sdk = createInstance({
|
|
11
|
-
datafile: {
|
|
12
|
-
schemaVersion: "1",
|
|
13
|
-
revision: "1.0",
|
|
14
|
-
features: [
|
|
15
|
-
{
|
|
16
|
-
key: "test",
|
|
17
|
-
bucketBy: "userId",
|
|
18
|
-
variations: [{ value: "control" }, { value: "treatment" }],
|
|
19
|
-
traffic: [
|
|
20
|
-
{
|
|
21
|
-
key: "1",
|
|
22
|
-
segments: "*",
|
|
23
|
-
percentage: 100000,
|
|
24
|
-
allocation: [
|
|
25
|
-
{ variation: "control", range: [0, 100000] },
|
|
26
|
-
{ variation: "treatment", range: [0, 0] },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
attributes: [],
|
|
33
|
-
segments: [],
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return sdk;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
describe("react: activateFeature", function () {
|
|
41
|
-
test("should be a function", function () {
|
|
42
|
-
expect(activateFeature).toBeInstanceOf(Function);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("should return the variation", function () {
|
|
46
|
-
function TestComponent() {
|
|
47
|
-
const variation = activateFeature("test", { userId: "1" });
|
|
48
|
-
|
|
49
|
-
return variation === "control" ? <p>True</p> : <p>False</p>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render(
|
|
53
|
-
<FeaturevisorProvider instance={getNewInstance()}>
|
|
54
|
-
<TestComponent />
|
|
55
|
-
</FeaturevisorProvider>,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(screen.getByText("True")).toBeInTheDocument();
|
|
59
|
-
});
|
|
60
|
-
});
|
package/src/activateFeature.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Context, FeatureKey, VariationValue } from "@featurevisor/types";
|
|
2
|
-
|
|
3
|
-
import { useSdk } from "./useSdk";
|
|
4
|
-
|
|
5
|
-
export function activateFeature(
|
|
6
|
-
featureKey: FeatureKey,
|
|
7
|
-
context: Context = {},
|
|
8
|
-
): VariationValue | undefined {
|
|
9
|
-
const sdk = useSdk();
|
|
10
|
-
|
|
11
|
-
return sdk.activate(featureKey, context);
|
|
12
|
-
}
|
package/src/useStatus.spec.tsx
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import "@testing-library/jest-dom";
|
|
4
|
-
|
|
5
|
-
import { FeaturevisorProvider } from "./FeaturevisorProvider";
|
|
6
|
-
import { useStatus } from "./useStatus";
|
|
7
|
-
import { createInstance } from "@featurevisor/sdk";
|
|
8
|
-
|
|
9
|
-
function getNewInstance() {
|
|
10
|
-
const sdk = createInstance({
|
|
11
|
-
datafile: {
|
|
12
|
-
schemaVersion: "1",
|
|
13
|
-
revision: "1.0",
|
|
14
|
-
features: [
|
|
15
|
-
{
|
|
16
|
-
key: "test",
|
|
17
|
-
bucketBy: "userId",
|
|
18
|
-
variations: [{ value: "control" }, { value: "treatment" }],
|
|
19
|
-
traffic: [
|
|
20
|
-
{
|
|
21
|
-
key: "1",
|
|
22
|
-
segments: "*",
|
|
23
|
-
percentage: 100000,
|
|
24
|
-
allocation: [
|
|
25
|
-
{ variation: "control", range: [0, 100000] },
|
|
26
|
-
{ variation: "treatment", range: [0, 0] },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
attributes: [],
|
|
33
|
-
segments: [],
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return sdk;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
describe("react: useStatus", function () {
|
|
41
|
-
test("should be a function", function () {
|
|
42
|
-
expect(useStatus).toBeInstanceOf(Function);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("should return the variation", function () {
|
|
46
|
-
function TestComponent() {
|
|
47
|
-
const { isReady } = useStatus();
|
|
48
|
-
|
|
49
|
-
return isReady ? <p>Ready</p> : <p>Loading...</p>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render(
|
|
53
|
-
<FeaturevisorProvider instance={getNewInstance()}>
|
|
54
|
-
<TestComponent />
|
|
55
|
-
</FeaturevisorProvider>,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(screen.getByText("Ready")).toBeInTheDocument();
|
|
59
|
-
});
|
|
60
|
-
});
|
package/src/useStatus.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { useSdk } from "./useSdk";
|
|
4
|
-
|
|
5
|
-
export interface Status {
|
|
6
|
-
isReady: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function useStatus(): Status {
|
|
10
|
-
const sdk = useSdk();
|
|
11
|
-
const initialStatus = sdk.isReady();
|
|
12
|
-
|
|
13
|
-
const [isReady, setIsReady] = React.useState(initialStatus);
|
|
14
|
-
|
|
15
|
-
React.useEffect(function () {
|
|
16
|
-
function handleReady() {
|
|
17
|
-
setIsReady(true);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
sdk.on("ready", handleReady);
|
|
21
|
-
|
|
22
|
-
return function () {
|
|
23
|
-
sdk.off("ready", handleReady);
|
|
24
|
-
};
|
|
25
|
-
}, []);
|
|
26
|
-
|
|
27
|
-
return { isReady };
|
|
28
|
-
}
|