@bluealba/pae-feature-flags 1.0.0-feature-initial-feature-flags-poc-1233
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 +239 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +21 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/types.d.ts +63 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +16 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/FeatureFlagsClient.d.ts +99 -0
- package/dist/nestjs/FeatureFlagsClient.d.ts.map +1 -0
- package/dist/nestjs/FeatureFlagsClient.js +173 -0
- package/dist/nestjs/FeatureFlagsClient.js.map +1 -0
- package/dist/nestjs/FeatureFlagsModule.d.ts +79 -0
- package/dist/nestjs/FeatureFlagsModule.d.ts.map +1 -0
- package/dist/nestjs/FeatureFlagsModule.js +98 -0
- package/dist/nestjs/FeatureFlagsModule.js.map +1 -0
- package/dist/nestjs/index.d.ts +20 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +36 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/react/FeatureFlagGuard.d.ts +60 -0
- package/dist/react/FeatureFlagGuard.d.ts.map +1 -0
- package/dist/react/FeatureFlagGuard.js +48 -0
- package/dist/react/FeatureFlagGuard.js.map +1 -0
- package/dist/react/FeatureFlagsProvider.d.ts +102 -0
- package/dist/react/FeatureFlagsProvider.d.ts.map +1 -0
- package/dist/react/FeatureFlagsProvider.js +194 -0
- package/dist/react/FeatureFlagsProvider.js.map +1 -0
- package/dist/react/index.d.ts +10 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +19 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useFeatureFlag.d.ts +26 -0
- package/dist/react/useFeatureFlag.d.ts.map +1 -0
- package/dist/react/useFeatureFlag.js +91 -0
- package/dist/react/useFeatureFlag.js.map +1 -0
- package/dist/react/useFeatureFlags.d.ts +38 -0
- package/dist/react/useFeatureFlags.d.ts.map +1 -0
- package/dist/react/useFeatureFlags.js +49 -0
- package/dist/react/useFeatureFlags.js.map +1 -0
- package/dist/react/useVariant.d.ts +48 -0
- package/dist/react/useVariant.d.ts.map +1 -0
- package/dist/react/useVariant.js +108 -0
- package/dist/react/useVariant.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FeatureFlagsProvider
|
|
4
|
+
*
|
|
5
|
+
* A React Context provider that manages feature flag state with prefetching and caching capabilities.
|
|
6
|
+
* This provider should wrap your application or a section of it to provide feature flag access to child components.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Prefetches specified flags on mount
|
|
10
|
+
* - Optional automatic refresh at configurable intervals
|
|
11
|
+
* - Caches flag values for efficient access
|
|
12
|
+
* - Provides both boolean flags and multivariant flags
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <FeatureFlagsProvider
|
|
17
|
+
* gatewayUrl="/api"
|
|
18
|
+
* prefetchFlags={['new-ui', 'beta-feature']}
|
|
19
|
+
* refreshInterval={60000}
|
|
20
|
+
* >
|
|
21
|
+
* <App />
|
|
22
|
+
* </FeatureFlagsProvider>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
30
|
+
}
|
|
31
|
+
Object.defineProperty(o, k2, desc);
|
|
32
|
+
}) : (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
o[k2] = m[k];
|
|
35
|
+
}));
|
|
36
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
37
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
38
|
+
}) : function(o, v) {
|
|
39
|
+
o["default"] = v;
|
|
40
|
+
});
|
|
41
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
42
|
+
var ownKeys = function(o) {
|
|
43
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
44
|
+
var ar = [];
|
|
45
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
46
|
+
return ar;
|
|
47
|
+
};
|
|
48
|
+
return ownKeys(o);
|
|
49
|
+
};
|
|
50
|
+
return function (mod) {
|
|
51
|
+
if (mod && mod.__esModule) return mod;
|
|
52
|
+
var result = {};
|
|
53
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
54
|
+
__setModuleDefault(result, mod);
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
57
|
+
})();
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.FeatureFlagsProvider = exports.FeatureFlagsContext = void 0;
|
|
60
|
+
const react_1 = __importStar(require("react"));
|
|
61
|
+
/**
|
|
62
|
+
* Default context value
|
|
63
|
+
*/
|
|
64
|
+
const defaultContextValue = {
|
|
65
|
+
flags: new Map(),
|
|
66
|
+
variants: new Map(),
|
|
67
|
+
isLoading: false,
|
|
68
|
+
error: null,
|
|
69
|
+
checkFlag: () => false,
|
|
70
|
+
getVariant: () => null,
|
|
71
|
+
refresh: async () => { },
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* React Context for feature flags
|
|
75
|
+
*/
|
|
76
|
+
exports.FeatureFlagsContext = (0, react_1.createContext)(defaultContextValue);
|
|
77
|
+
/**
|
|
78
|
+
* Provider component for feature flags
|
|
79
|
+
*/
|
|
80
|
+
const FeatureFlagsProvider = ({ gatewayUrl = '', prefetchFlags = [], refreshInterval, children, }) => {
|
|
81
|
+
const [flags, setFlags] = (0, react_1.useState)(new Map());
|
|
82
|
+
const [variants, setVariants] = (0, react_1.useState)(new Map());
|
|
83
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
84
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
85
|
+
/**
|
|
86
|
+
* Fetch flags from the gateway API
|
|
87
|
+
*/
|
|
88
|
+
const fetchFlags = (0, react_1.useCallback)(async (flagNames) => {
|
|
89
|
+
if (flagNames.length === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setIsLoading(true);
|
|
93
|
+
setError(null);
|
|
94
|
+
try {
|
|
95
|
+
const url = `${gatewayUrl}/feature-flags/evaluate`;
|
|
96
|
+
const response = await fetch(url, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: {
|
|
99
|
+
'Content-Type': 'application/json',
|
|
100
|
+
},
|
|
101
|
+
body: JSON.stringify({ flags: flagNames }),
|
|
102
|
+
credentials: 'include', // Include cookies for authentication
|
|
103
|
+
});
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(`Failed to fetch feature flags: ${response.status} ${response.statusText}`);
|
|
106
|
+
}
|
|
107
|
+
const data = await response.json();
|
|
108
|
+
const evaluations = data.flags;
|
|
109
|
+
// Update flags map
|
|
110
|
+
const newFlags = new Map();
|
|
111
|
+
const newVariants = new Map();
|
|
112
|
+
// Handle both Map and Record response formats
|
|
113
|
+
const entries = evaluations instanceof Map ? Array.from(evaluations.entries()) : Object.entries(evaluations);
|
|
114
|
+
entries.forEach(([flagName, evaluation]) => {
|
|
115
|
+
newFlags.set(flagName, evaluation.enabled);
|
|
116
|
+
if (evaluation.variant !== undefined) {
|
|
117
|
+
newVariants.set(flagName, {
|
|
118
|
+
variant: evaluation.variant || null,
|
|
119
|
+
payload: evaluation.payload,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
setFlags(newFlags);
|
|
124
|
+
setVariants(newVariants);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
const error = err instanceof Error ? err : new Error('Unknown error fetching feature flags');
|
|
128
|
+
setError(error);
|
|
129
|
+
console.error('Error fetching feature flags:', error);
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
setIsLoading(false);
|
|
133
|
+
}
|
|
134
|
+
}, [gatewayUrl]);
|
|
135
|
+
/**
|
|
136
|
+
* Refresh all prefetched flags
|
|
137
|
+
*/
|
|
138
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
139
|
+
if (prefetchFlags.length > 0) {
|
|
140
|
+
await fetchFlags(prefetchFlags);
|
|
141
|
+
}
|
|
142
|
+
}, [prefetchFlags, fetchFlags]);
|
|
143
|
+
/**
|
|
144
|
+
* Initial prefetch on mount
|
|
145
|
+
*/
|
|
146
|
+
(0, react_1.useEffect)(() => {
|
|
147
|
+
if (prefetchFlags.length > 0) {
|
|
148
|
+
fetchFlags(prefetchFlags);
|
|
149
|
+
}
|
|
150
|
+
}, [prefetchFlags, fetchFlags]);
|
|
151
|
+
/**
|
|
152
|
+
* Set up automatic refresh interval
|
|
153
|
+
*/
|
|
154
|
+
(0, react_1.useEffect)(() => {
|
|
155
|
+
if (refreshInterval && refreshInterval > 0 && prefetchFlags.length > 0) {
|
|
156
|
+
const intervalId = setInterval(() => {
|
|
157
|
+
fetchFlags(prefetchFlags);
|
|
158
|
+
}, refreshInterval);
|
|
159
|
+
return () => {
|
|
160
|
+
clearInterval(intervalId);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}, [refreshInterval, prefetchFlags, fetchFlags]);
|
|
164
|
+
/**
|
|
165
|
+
* Check if a flag is enabled from cache
|
|
166
|
+
*/
|
|
167
|
+
const checkFlag = (0, react_1.useCallback)((flagName, defaultValue = false) => {
|
|
168
|
+
var _a;
|
|
169
|
+
return (_a = flags.get(flagName)) !== null && _a !== void 0 ? _a : defaultValue;
|
|
170
|
+
}, [flags]);
|
|
171
|
+
/**
|
|
172
|
+
* Get variant from cache
|
|
173
|
+
*/
|
|
174
|
+
const getVariant = (0, react_1.useCallback)((flagName) => {
|
|
175
|
+
var _a;
|
|
176
|
+
return (_a = variants.get(flagName)) !== null && _a !== void 0 ? _a : null;
|
|
177
|
+
}, [variants]);
|
|
178
|
+
/**
|
|
179
|
+
* Memoized context value
|
|
180
|
+
*/
|
|
181
|
+
const contextValue = (0, react_1.useMemo)(() => ({
|
|
182
|
+
flags,
|
|
183
|
+
variants,
|
|
184
|
+
isLoading,
|
|
185
|
+
error,
|
|
186
|
+
checkFlag,
|
|
187
|
+
getVariant,
|
|
188
|
+
refresh,
|
|
189
|
+
}), [flags, variants, isLoading, error, checkFlag, getVariant, refresh]);
|
|
190
|
+
return (react_1.default.createElement(exports.FeatureFlagsContext.Provider, { value: contextValue }, children));
|
|
191
|
+
};
|
|
192
|
+
exports.FeatureFlagsProvider = FeatureFlagsProvider;
|
|
193
|
+
exports.FeatureFlagsProvider.displayName = 'FeatureFlagsProvider';
|
|
194
|
+
//# sourceMappingURL=FeatureFlagsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureFlagsProvider.js","sourceRoot":"","sources":["../../src/react/FeatureFlagsProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React implementation for feature flags
|
|
3
|
+
* @module react
|
|
4
|
+
*/
|
|
5
|
+
export { FeatureFlagsProvider, FeatureFlagsContext, type FeatureFlagsProviderProps, type FeatureFlagsContextValue } from './FeatureFlagsProvider';
|
|
6
|
+
export { useFeatureFlag } from './useFeatureFlag';
|
|
7
|
+
export { useFeatureFlags } from './useFeatureFlags';
|
|
8
|
+
export { useVariant, type UseVariantResult } from './useVariant';
|
|
9
|
+
export { FeatureFlagGuard, type FeatureFlagGuardProps } from './FeatureFlagGuard';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,KAAK,yBAAyB,EAAE,KAAK,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClJ,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* React implementation for feature flags
|
|
4
|
+
* @module react
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.FeatureFlagGuard = exports.useVariant = exports.useFeatureFlags = exports.useFeatureFlag = exports.FeatureFlagsContext = exports.FeatureFlagsProvider = void 0;
|
|
8
|
+
var FeatureFlagsProvider_1 = require("./FeatureFlagsProvider");
|
|
9
|
+
Object.defineProperty(exports, "FeatureFlagsProvider", { enumerable: true, get: function () { return FeatureFlagsProvider_1.FeatureFlagsProvider; } });
|
|
10
|
+
Object.defineProperty(exports, "FeatureFlagsContext", { enumerable: true, get: function () { return FeatureFlagsProvider_1.FeatureFlagsContext; } });
|
|
11
|
+
var useFeatureFlag_1 = require("./useFeatureFlag");
|
|
12
|
+
Object.defineProperty(exports, "useFeatureFlag", { enumerable: true, get: function () { return useFeatureFlag_1.useFeatureFlag; } });
|
|
13
|
+
var useFeatureFlags_1 = require("./useFeatureFlags");
|
|
14
|
+
Object.defineProperty(exports, "useFeatureFlags", { enumerable: true, get: function () { return useFeatureFlags_1.useFeatureFlags; } });
|
|
15
|
+
var useVariant_1 = require("./useVariant");
|
|
16
|
+
Object.defineProperty(exports, "useVariant", { enumerable: true, get: function () { return useVariant_1.useVariant; } });
|
|
17
|
+
var FeatureFlagGuard_1 = require("./FeatureFlagGuard");
|
|
18
|
+
Object.defineProperty(exports, "FeatureFlagGuard", { enumerable: true, get: function () { return FeatureFlagGuard_1.FeatureFlagGuard; } });
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAkJ;AAAzI,4HAAA,oBAAoB,OAAA;AAAE,2HAAA,mBAAmB,OAAA;AAClD,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,2CAAiE;AAAxD,wGAAA,UAAU,OAAA;AACnB,uDAAkF;AAAzE,oHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFeatureFlag Hook
|
|
3
|
+
*
|
|
4
|
+
* A React hook for evaluating a single boolean feature flag.
|
|
5
|
+
* This hook first checks if the flag is in the prefetched cache (from FeatureFlagsProvider).
|
|
6
|
+
* If not found in cache, it fetches the flag individually from the API.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const isNewUIEnabled = useFeatureFlag('new-ui', false);
|
|
12
|
+
*
|
|
13
|
+
* return isNewUIEnabled ? <NewUI /> : <OldUI />;
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Hook for evaluating a single boolean feature flag
|
|
19
|
+
*
|
|
20
|
+
* @param flagName - Name of the feature flag to evaluate
|
|
21
|
+
* @param defaultValue - Default value to use if flag cannot be evaluated (default: false)
|
|
22
|
+
* @param gatewayUrl - Base URL for the gateway API (default: '')
|
|
23
|
+
* @returns Boolean indicating whether the flag is enabled
|
|
24
|
+
*/
|
|
25
|
+
export declare function useFeatureFlag(flagName: string, defaultValue?: boolean, gatewayUrl?: string): boolean;
|
|
26
|
+
//# sourceMappingURL=useFeatureFlag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlag.d.ts","sourceRoot":"","sources":["../../src/react/useFeatureFlag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,OAAe,EAC7B,UAAU,GAAE,MAAW,GACtB,OAAO,CAqET"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useFeatureFlag Hook
|
|
4
|
+
*
|
|
5
|
+
* A React hook for evaluating a single boolean feature flag.
|
|
6
|
+
* This hook first checks if the flag is in the prefetched cache (from FeatureFlagsProvider).
|
|
7
|
+
* If not found in cache, it fetches the flag individually from the API.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function MyComponent() {
|
|
12
|
+
* const isNewUIEnabled = useFeatureFlag('new-ui', false);
|
|
13
|
+
*
|
|
14
|
+
* return isNewUIEnabled ? <NewUI /> : <OldUI />;
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.useFeatureFlag = useFeatureFlag;
|
|
20
|
+
const react_1 = require("react");
|
|
21
|
+
const FeatureFlagsProvider_1 = require("./FeatureFlagsProvider");
|
|
22
|
+
/**
|
|
23
|
+
* Hook for evaluating a single boolean feature flag
|
|
24
|
+
*
|
|
25
|
+
* @param flagName - Name of the feature flag to evaluate
|
|
26
|
+
* @param defaultValue - Default value to use if flag cannot be evaluated (default: false)
|
|
27
|
+
* @param gatewayUrl - Base URL for the gateway API (default: '')
|
|
28
|
+
* @returns Boolean indicating whether the flag is enabled
|
|
29
|
+
*/
|
|
30
|
+
function useFeatureFlag(flagName, defaultValue = false, gatewayUrl = '') {
|
|
31
|
+
const context = (0, react_1.useContext)(FeatureFlagsProvider_1.FeatureFlagsContext);
|
|
32
|
+
const [flagValue, setFlagValue] = (0, react_1.useState)(defaultValue);
|
|
33
|
+
const [isInitialized, setIsInitialized] = (0, react_1.useState)(false);
|
|
34
|
+
(0, react_1.useEffect)(() => {
|
|
35
|
+
// First, check if the flag is in the prefetched cache
|
|
36
|
+
const cachedValue = context.checkFlag(flagName, null);
|
|
37
|
+
if (cachedValue !== null && cachedValue !== undefined) {
|
|
38
|
+
// Flag is in cache, use it
|
|
39
|
+
setFlagValue(cachedValue);
|
|
40
|
+
setIsInitialized(true);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Flag not in cache, fetch it individually
|
|
44
|
+
let isMounted = true;
|
|
45
|
+
const fetchFlag = async () => {
|
|
46
|
+
var _a;
|
|
47
|
+
try {
|
|
48
|
+
const url = `${gatewayUrl}/feature-flags/${encodeURIComponent(flagName)}?defaultValue=${defaultValue}`;
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
method: 'GET',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
},
|
|
54
|
+
credentials: 'include', // Include cookies for authentication
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
console.warn(`Failed to fetch feature flag '${flagName}': ${response.status} ${response.statusText}`);
|
|
58
|
+
if (isMounted) {
|
|
59
|
+
setFlagValue(defaultValue);
|
|
60
|
+
setIsInitialized(true);
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
if (isMounted) {
|
|
66
|
+
setFlagValue((_a = data.enabled) !== null && _a !== void 0 ? _a : defaultValue);
|
|
67
|
+
setIsInitialized(true);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(`Error fetching feature flag '${flagName}':`, error);
|
|
72
|
+
if (isMounted) {
|
|
73
|
+
setFlagValue(defaultValue);
|
|
74
|
+
setIsInitialized(true);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
fetchFlag();
|
|
79
|
+
return () => {
|
|
80
|
+
isMounted = false;
|
|
81
|
+
};
|
|
82
|
+
}, [flagName, defaultValue, gatewayUrl, context]);
|
|
83
|
+
// Return cached value if available, otherwise return the fetched value
|
|
84
|
+
// If not initialized yet, return default value
|
|
85
|
+
if (!isInitialized && context.flags.size === 0) {
|
|
86
|
+
return defaultValue;
|
|
87
|
+
}
|
|
88
|
+
const cachedValue = context.checkFlag(flagName, null);
|
|
89
|
+
return cachedValue !== null && cachedValue !== undefined ? cachedValue : flagValue;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=useFeatureFlag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlag.js","sourceRoot":"","sources":["../../src/react/useFeatureFlag.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFeatureFlags Hook
|
|
3
|
+
*
|
|
4
|
+
* A React hook for accessing the full feature flags context.
|
|
5
|
+
* This hook provides access to all prefetched flags, variants, loading state,
|
|
6
|
+
* and utility functions for checking flags and refreshing the cache.
|
|
7
|
+
*
|
|
8
|
+
* This hook MUST be used within a FeatureFlagsProvider.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* function MyComponent() {
|
|
13
|
+
* const { flags, checkFlag, refresh, isLoading } = useFeatureFlags();
|
|
14
|
+
*
|
|
15
|
+
* const handleRefresh = async () => {
|
|
16
|
+
* await refresh();
|
|
17
|
+
* };
|
|
18
|
+
*
|
|
19
|
+
* return (
|
|
20
|
+
* <div>
|
|
21
|
+
* <button onClick={handleRefresh} disabled={isLoading}>
|
|
22
|
+
* Refresh Flags
|
|
23
|
+
* </button>
|
|
24
|
+
* <div>Total flags: {flags.size}</div>
|
|
25
|
+
* </div>
|
|
26
|
+
* );
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import { type FeatureFlagsContextValue } from './FeatureFlagsProvider';
|
|
31
|
+
/**
|
|
32
|
+
* Hook for accessing the feature flags context
|
|
33
|
+
*
|
|
34
|
+
* @throws Error if used outside of FeatureFlagsProvider
|
|
35
|
+
* @returns The full feature flags context
|
|
36
|
+
*/
|
|
37
|
+
export declare function useFeatureFlags(): FeatureFlagsContextValue;
|
|
38
|
+
//# sourceMappingURL=useFeatureFlags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.d.ts","sourceRoot":"","sources":["../../src/react/useFeatureFlags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAuB,KAAK,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE5F;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,wBAAwB,CAW1D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useFeatureFlags Hook
|
|
4
|
+
*
|
|
5
|
+
* A React hook for accessing the full feature flags context.
|
|
6
|
+
* This hook provides access to all prefetched flags, variants, loading state,
|
|
7
|
+
* and utility functions for checking flags and refreshing the cache.
|
|
8
|
+
*
|
|
9
|
+
* This hook MUST be used within a FeatureFlagsProvider.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* function MyComponent() {
|
|
14
|
+
* const { flags, checkFlag, refresh, isLoading } = useFeatureFlags();
|
|
15
|
+
*
|
|
16
|
+
* const handleRefresh = async () => {
|
|
17
|
+
* await refresh();
|
|
18
|
+
* };
|
|
19
|
+
*
|
|
20
|
+
* return (
|
|
21
|
+
* <div>
|
|
22
|
+
* <button onClick={handleRefresh} disabled={isLoading}>
|
|
23
|
+
* Refresh Flags
|
|
24
|
+
* </button>
|
|
25
|
+
* <div>Total flags: {flags.size}</div>
|
|
26
|
+
* </div>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.useFeatureFlags = useFeatureFlags;
|
|
33
|
+
const react_1 = require("react");
|
|
34
|
+
const FeatureFlagsProvider_1 = require("./FeatureFlagsProvider");
|
|
35
|
+
/**
|
|
36
|
+
* Hook for accessing the feature flags context
|
|
37
|
+
*
|
|
38
|
+
* @throws Error if used outside of FeatureFlagsProvider
|
|
39
|
+
* @returns The full feature flags context
|
|
40
|
+
*/
|
|
41
|
+
function useFeatureFlags() {
|
|
42
|
+
const context = (0, react_1.useContext)(FeatureFlagsProvider_1.FeatureFlagsContext);
|
|
43
|
+
if (!context) {
|
|
44
|
+
throw new Error('useFeatureFlags must be used within a FeatureFlagsProvider. ' +
|
|
45
|
+
'Wrap your component tree with <FeatureFlagsProvider> to use this hook.');
|
|
46
|
+
}
|
|
47
|
+
return context;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=useFeatureFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.js","sourceRoot":"","sources":["../../src/react/useFeatureFlags.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;AAWH,0CAWC;AApBD,iCAAmC;AACnC,iEAA4F;AAE5F;;;;;GAKG;AACH,SAAgB,eAAe;IAC7B,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,0CAAmB,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,8DAA8D;YAC9D,wEAAwE,CACzE,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useVariant Hook
|
|
3
|
+
*
|
|
4
|
+
* A React hook for getting the variant value of a multivariant feature flag.
|
|
5
|
+
* This hook first checks if the variant is in the prefetched cache (from FeatureFlagsProvider).
|
|
6
|
+
* If not found in cache, it fetches the variant individually from the API.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const { variant, payload, isLoading } = useVariant('checkout-flow');
|
|
12
|
+
*
|
|
13
|
+
* if (isLoading) return <Spinner />;
|
|
14
|
+
*
|
|
15
|
+
* if (variant === 'new-checkout') {
|
|
16
|
+
* return <NewCheckout config={payload} />;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* return <OldCheckout />;
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Return type for the useVariant hook
|
|
25
|
+
*/
|
|
26
|
+
export interface UseVariantResult {
|
|
27
|
+
/**
|
|
28
|
+
* The selected variant name, or null if no variant is selected
|
|
29
|
+
*/
|
|
30
|
+
variant: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* The payload data associated with the variant
|
|
33
|
+
*/
|
|
34
|
+
payload: unknown;
|
|
35
|
+
/**
|
|
36
|
+
* Whether the variant is currently being loaded
|
|
37
|
+
*/
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Hook for getting the variant value of a multivariant feature flag
|
|
42
|
+
*
|
|
43
|
+
* @param flagName - Name of the feature flag
|
|
44
|
+
* @param gatewayUrl - Base URL for the gateway API (default: '')
|
|
45
|
+
* @returns Object containing variant, payload, and loading state
|
|
46
|
+
*/
|
|
47
|
+
export declare function useVariant(flagName: string, gatewayUrl?: string): UseVariantResult;
|
|
48
|
+
//# sourceMappingURL=useVariant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVariant.d.ts","sourceRoot":"","sources":["../../src/react/useVariant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,MAAW,GACtB,gBAAgB,CAmFlB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useVariant Hook
|
|
4
|
+
*
|
|
5
|
+
* A React hook for getting the variant value of a multivariant feature flag.
|
|
6
|
+
* This hook first checks if the variant is in the prefetched cache (from FeatureFlagsProvider).
|
|
7
|
+
* If not found in cache, it fetches the variant individually from the API.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function MyComponent() {
|
|
12
|
+
* const { variant, payload, isLoading } = useVariant('checkout-flow');
|
|
13
|
+
*
|
|
14
|
+
* if (isLoading) return <Spinner />;
|
|
15
|
+
*
|
|
16
|
+
* if (variant === 'new-checkout') {
|
|
17
|
+
* return <NewCheckout config={payload} />;
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* return <OldCheckout />;
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.useVariant = useVariant;
|
|
26
|
+
const react_1 = require("react");
|
|
27
|
+
const FeatureFlagsProvider_1 = require("./FeatureFlagsProvider");
|
|
28
|
+
/**
|
|
29
|
+
* Hook for getting the variant value of a multivariant feature flag
|
|
30
|
+
*
|
|
31
|
+
* @param flagName - Name of the feature flag
|
|
32
|
+
* @param gatewayUrl - Base URL for the gateway API (default: '')
|
|
33
|
+
* @returns Object containing variant, payload, and loading state
|
|
34
|
+
*/
|
|
35
|
+
function useVariant(flagName, gatewayUrl = '') {
|
|
36
|
+
const context = (0, react_1.useContext)(FeatureFlagsProvider_1.FeatureFlagsContext);
|
|
37
|
+
const [variant, setVariant] = (0, react_1.useState)(null);
|
|
38
|
+
const [payload, setPayload] = (0, react_1.useState)(undefined);
|
|
39
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(true);
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
41
|
+
// First, check if the variant is in the prefetched cache
|
|
42
|
+
const cachedVariant = context.getVariant(flagName);
|
|
43
|
+
if (cachedVariant !== null) {
|
|
44
|
+
// Variant is in cache, use it
|
|
45
|
+
setVariant(cachedVariant.variant);
|
|
46
|
+
setPayload(cachedVariant.payload);
|
|
47
|
+
setIsLoading(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Variant not in cache, fetch it individually
|
|
51
|
+
let isMounted = true;
|
|
52
|
+
const fetchVariant = async () => {
|
|
53
|
+
setIsLoading(true);
|
|
54
|
+
try {
|
|
55
|
+
const url = `${gatewayUrl}/feature-flags/${encodeURIComponent(flagName)}/variant`;
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
method: 'GET',
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/json',
|
|
60
|
+
},
|
|
61
|
+
credentials: 'include', // Include cookies for authentication
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
console.warn(`Failed to fetch variant for flag '${flagName}': ${response.status} ${response.statusText}`);
|
|
65
|
+
if (isMounted) {
|
|
66
|
+
setVariant(null);
|
|
67
|
+
setPayload(undefined);
|
|
68
|
+
setIsLoading(false);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const data = await response.json();
|
|
73
|
+
if (isMounted) {
|
|
74
|
+
setVariant(data.variant || null);
|
|
75
|
+
setPayload(data.payload);
|
|
76
|
+
setIsLoading(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(`Error fetching variant for flag '${flagName}':`, error);
|
|
81
|
+
if (isMounted) {
|
|
82
|
+
setVariant(null);
|
|
83
|
+
setPayload(undefined);
|
|
84
|
+
setIsLoading(false);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
fetchVariant();
|
|
89
|
+
return () => {
|
|
90
|
+
isMounted = false;
|
|
91
|
+
};
|
|
92
|
+
}, [flagName, gatewayUrl, context]);
|
|
93
|
+
// Return cached variant if available, otherwise return the fetched variant
|
|
94
|
+
const cachedVariant = context.getVariant(flagName);
|
|
95
|
+
if (cachedVariant !== null) {
|
|
96
|
+
return {
|
|
97
|
+
variant: cachedVariant.variant,
|
|
98
|
+
payload: cachedVariant.payload,
|
|
99
|
+
isLoading: false,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
variant,
|
|
104
|
+
payload,
|
|
105
|
+
isLoading,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=useVariant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVariant.js","sourceRoot":"","sources":["../../src/react/useVariant.ts"],"names":[],"mappings":"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"}
|