@harnessio/ff-react-client-sdk
Advanced tools
Comparing version 1.13.0 to 1.14.0-rc.0
import { FC, PropsWithChildren, ReactNode } from 'react'; | ||
import { Evaluation, Event as FFEvent, Options, Result as InitializeResult, Target } from '@harnessio/ff-javascript-client-sdk'; | ||
import { Evaluation, Event as FFEvent, Options, Result as InitializeResult, Target, DefaultVariationEventPayload } from '@harnessio/ff-javascript-client-sdk'; | ||
export interface FFContextValue { | ||
@@ -18,3 +18,4 @@ loading: boolean; | ||
onError?: (event: NetworkError | 'PropsError', error?: unknown) => void; | ||
onFlagNotFound?: (flagNotFound: DefaultVariationEventPayload, loading: boolean) => void; | ||
} | ||
export declare const FFContextProvider: FC<FFContextProviderProps>; |
@@ -12,6 +12,8 @@ "use strict"; | ||
exports.FFContext = (0, react_1.createContext)({}); | ||
const FFContextProvider = ({ children, apiKey, target, options = {}, fallback = (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }), async = false, initialEvaluations, onError = () => void 0 }) => { | ||
const FFContextProvider = ({ children, apiKey, target, options = {}, fallback = (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }), async = false, initialEvaluations, onError = () => void 0, onFlagNotFound = () => void 0 }) => { | ||
const [loading, setLoading] = (0, react_1.useState)(true); | ||
const [flags, setFlags] = (0, react_1.useState)({}); | ||
const [clientInstance, setClientInstance] = (0, react_1.useState)(); | ||
// Use a reference to keep track of the latest loading state so we can use it with event callbacks. | ||
const loadingRef = (0, react_1.useRef)(true); | ||
(0, react_1.useEffect)(() => { | ||
@@ -33,5 +35,7 @@ if (!apiKey) { | ||
setLoading(true); | ||
loadingRef.current = true; | ||
setClientInstance(client); | ||
const onInitialLoad = (newFlags) => { | ||
setLoading(false); | ||
loadingRef.current = false; | ||
setFlags(newFlags); | ||
@@ -54,2 +58,5 @@ client.on(ff_javascript_client_sdk_1.Event.CHANGED, onFlagChange); | ||
}; | ||
const onFlagNotFoundListener = ({ flag, defaultVariation }) => { | ||
onFlagNotFound({ flag, defaultVariation }, loadingRef.current); | ||
}; | ||
const onAuthError = onNetworkError(ff_javascript_client_sdk_1.Event.ERROR_AUTH); | ||
@@ -66,2 +73,3 @@ const onStreamError = onNetworkError(ff_javascript_client_sdk_1.Event.ERROR_STREAM); | ||
client.on(ff_javascript_client_sdk_1.Event.ERROR_METRICS, onMetricsError); | ||
client.on(ff_javascript_client_sdk_1.Event.ERROR_DEFAULT_VARIATION_RETURNED, onFlagNotFoundListener); | ||
if (initialEvaluations) { | ||
@@ -78,2 +86,3 @@ client.setEvaluations(initialEvaluations); | ||
client.off(ff_javascript_client_sdk_1.Event.ERROR_METRICS, onMetricsError); | ||
client.off(ff_javascript_client_sdk_1.Event.ERROR_DEFAULT_VARIATION_RETURNED, onFlagNotFoundListener); | ||
client.close(); | ||
@@ -80,0 +89,0 @@ }; |
import { FC, PropsWithChildren, ReactNode } from 'react'; | ||
import { Evaluation, Event as FFEvent, Options, Result as InitializeResult, Target } from '@harnessio/ff-javascript-client-sdk'; | ||
import { Evaluation, Event as FFEvent, Options, Result as InitializeResult, Target, DefaultVariationEventPayload } from '@harnessio/ff-javascript-client-sdk'; | ||
export interface FFContextValue { | ||
@@ -18,3 +18,4 @@ loading: boolean; | ||
onError?: (event: NetworkError | 'PropsError', error?: unknown) => void; | ||
onFlagNotFound?: (flagNotFound: DefaultVariationEventPayload, loading: boolean) => void; | ||
} | ||
export declare const FFContextProvider: FC<FFContextProviderProps>; |
import { jsx as _jsx } from "react/jsx-runtime"; | ||
import { createContext, useEffect, useState } from 'react'; | ||
import { createContext, useEffect, useRef, useState } from 'react'; | ||
import { Event as FFEvent, initialize } from '@harnessio/ff-javascript-client-sdk'; | ||
import omit from 'lodash.omit'; | ||
export const FFContext = createContext({}); | ||
export const FFContextProvider = ({ children, apiKey, target, options = {}, fallback = _jsx("p", { children: "Loading..." }), async = false, initialEvaluations, onError = () => void 0 }) => { | ||
export const FFContextProvider = ({ children, apiKey, target, options = {}, fallback = _jsx("p", { children: "Loading..." }), async = false, initialEvaluations, onError = () => void 0, onFlagNotFound = () => void 0 }) => { | ||
const [loading, setLoading] = useState(true); | ||
const [flags, setFlags] = useState({}); | ||
const [clientInstance, setClientInstance] = useState(); | ||
// Use a reference to keep track of the latest loading state so we can use it with event callbacks. | ||
const loadingRef = useRef(true); | ||
useEffect(() => { | ||
@@ -26,5 +28,7 @@ if (!apiKey) { | ||
setLoading(true); | ||
loadingRef.current = true; | ||
setClientInstance(client); | ||
const onInitialLoad = (newFlags) => { | ||
setLoading(false); | ||
loadingRef.current = false; | ||
setFlags(newFlags); | ||
@@ -47,2 +51,5 @@ client.on(FFEvent.CHANGED, onFlagChange); | ||
}; | ||
const onFlagNotFoundListener = ({ flag, defaultVariation }) => { | ||
onFlagNotFound({ flag, defaultVariation }, loadingRef.current); | ||
}; | ||
const onAuthError = onNetworkError(FFEvent.ERROR_AUTH); | ||
@@ -59,2 +66,3 @@ const onStreamError = onNetworkError(FFEvent.ERROR_STREAM); | ||
client.on(FFEvent.ERROR_METRICS, onMetricsError); | ||
client.on(FFEvent.ERROR_DEFAULT_VARIATION_RETURNED, onFlagNotFoundListener); | ||
if (initialEvaluations) { | ||
@@ -71,2 +79,3 @@ client.setEvaluations(initialEvaluations); | ||
client.off(FFEvent.ERROR_METRICS, onMetricsError); | ||
client.off(FFEvent.ERROR_DEFAULT_VARIATION_RETURNED, onFlagNotFoundListener); | ||
client.close(); | ||
@@ -73,0 +82,0 @@ }; |
{ | ||
"name": "@harnessio/ff-react-client-sdk", | ||
"version": "1.13.0", | ||
"version": "1.14.0-rc.0", | ||
"author": "Harness", | ||
@@ -24,3 +24,3 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"@harnessio/ff-javascript-client-sdk": "^1.28.0", | ||
"@harnessio/ff-javascript-client-sdk": "^1.29.0", | ||
"lodash.omit": "^4.5.0" | ||
@@ -27,0 +27,0 @@ }, |
@@ -108,2 +108,35 @@ # React.js Client SDK For Harness Feature Flags | ||
## On Flag Not Found | ||
The `onFlagNotFound` option allows you to handle situations where a default variation is returned. | ||
It includes the flag, variation, and whether the SDK was still initializing (`loading)` when the default was served. | ||
This can happen when: | ||
1. Using `async` mode without `cache` or `initialEvaluations` and where the SDK is still initializing. | ||
2. The flag identifier is incorrect (e.g., due to a typo). | ||
3. The wrong API key is being used, and the expected flags are not available for that project. | ||
```typescript jsx | ||
<FFContextProvider | ||
apiKey="YOUR_API_KEY" | ||
target={{ | ||
identifier: 'reactclientsdk', | ||
name: 'ReactClientSDK' | ||
}} | ||
onFlagNotFound={(flagNotFoundPayload, loading) => { | ||
if (loading) { | ||
console.debug(`Flag "${flagNotFound.flag}" not found because the SDK is still initializing. Returned default: ${flagNotFound.defaultVariation}`); | ||
} else { | ||
console.warn(`Flag "${flagNotFound.flag}" not found. Returned default: ${flagNotFound.defaultVariation}`); | ||
} | ||
}} | ||
> | ||
<MyApp /> | ||
</FFContextProvider> | ||
``` | ||
By using the `onFlagNotFound` prop, your application can be notified whenever a flag is missing and the default variation has been returned. | ||
## Caching evaluations | ||
@@ -110,0 +143,0 @@ |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
73445
51
801
573
1