@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
package/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# @bluealba/pae-feature-flags
|
|
2
|
+
|
|
3
|
+
Feature flags client library for Blue Alba Platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bluealba/pae-feature-flags
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## NestJS Usage
|
|
12
|
+
|
|
13
|
+
### 1. Import the Module
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Module } from '@nestjs/common';
|
|
17
|
+
import { FeatureFlagsModule } from '@bluealba/pae-feature-flags';
|
|
18
|
+
|
|
19
|
+
@Module({
|
|
20
|
+
imports: [
|
|
21
|
+
FeatureFlagsModule.forRoot('http://gateway:3000'),
|
|
22
|
+
// Or with full configuration
|
|
23
|
+
FeatureFlagsModule.forRoot({
|
|
24
|
+
gatewayUrl: 'http://gateway:3000',
|
|
25
|
+
timeout: 5000,
|
|
26
|
+
maxRedirects: 5,
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
})
|
|
30
|
+
export class MyServiceModule {}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Use the Client
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { Injectable } from '@nestjs/common';
|
|
37
|
+
import { FeatureFlagsClient } from '@bluealba/pae-feature-flags';
|
|
38
|
+
|
|
39
|
+
@Injectable()
|
|
40
|
+
export class MyService {
|
|
41
|
+
constructor(private readonly featureFlagsClient: FeatureFlagsClient) {}
|
|
42
|
+
|
|
43
|
+
async doSomething() {
|
|
44
|
+
// Check if a feature is enabled
|
|
45
|
+
const isEnabled = await this.featureFlagsClient.isEnabled('my-feature');
|
|
46
|
+
|
|
47
|
+
if (isEnabled) {
|
|
48
|
+
// New implementation
|
|
49
|
+
} else {
|
|
50
|
+
// Old implementation
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get variant for A/B testing
|
|
54
|
+
const variant = await this.featureFlagsClient.getVariant('ab-test', {
|
|
55
|
+
userId: '123',
|
|
56
|
+
tenantId: 'tenant-1',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (variant?.name === 'variant-a') {
|
|
60
|
+
// Variant A logic
|
|
61
|
+
} else if (variant?.name === 'variant-b') {
|
|
62
|
+
// Variant B logic
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Evaluate multiple flags at once (more efficient)
|
|
66
|
+
const results = await this.featureFlagsClient.evaluateFlags(
|
|
67
|
+
['feature-a', 'feature-b', 'ab-test'],
|
|
68
|
+
{ userId: '123' }
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const featureAEnabled = results.get('feature-a')?.enabled ?? false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## React Usage
|
|
77
|
+
|
|
78
|
+
### 1. Setup the Provider
|
|
79
|
+
|
|
80
|
+
Wrap your application with the `FeatureFlagsProvider`:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { FeatureFlagsProvider } from '@bluealba/pae-feature-flags';
|
|
84
|
+
|
|
85
|
+
function App() {
|
|
86
|
+
return (
|
|
87
|
+
<FeatureFlagsProvider
|
|
88
|
+
gatewayUrl="/api"
|
|
89
|
+
prefetchFlags={['new-ui', 'beta-feature']}
|
|
90
|
+
refreshInterval={60000}
|
|
91
|
+
>
|
|
92
|
+
<YourApp />
|
|
93
|
+
</FeatureFlagsProvider>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### Provider Props
|
|
99
|
+
|
|
100
|
+
- `gatewayUrl` (string, optional): Base URL for the gateway API. Default: `''`
|
|
101
|
+
- `prefetchFlags` (string[], optional): Array of flag names to prefetch on mount
|
|
102
|
+
- `refreshInterval` (number, optional): Interval in milliseconds for automatic refresh
|
|
103
|
+
- `children` (ReactNode): Child components
|
|
104
|
+
|
|
105
|
+
### 2. Use Feature Flags in Components
|
|
106
|
+
|
|
107
|
+
#### Simple Boolean Check with `useFeatureFlag`
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { useFeatureFlag } from '@bluealba/pae-feature-flags';
|
|
111
|
+
|
|
112
|
+
function MyComponent() {
|
|
113
|
+
const isNewUIEnabled = useFeatureFlag('new-ui', false);
|
|
114
|
+
|
|
115
|
+
return isNewUIEnabled ? <NewUI /> : <OldUI />;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Conditional Rendering with `FeatureFlagGuard`
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { FeatureFlagGuard } from '@bluealba/pae-feature-flags';
|
|
123
|
+
|
|
124
|
+
function MyComponent() {
|
|
125
|
+
return (
|
|
126
|
+
<>
|
|
127
|
+
{/* Show feature if enabled */}
|
|
128
|
+
<FeatureFlagGuard flag="beta-feature">
|
|
129
|
+
<BetaFeature />
|
|
130
|
+
</FeatureFlagGuard>
|
|
131
|
+
|
|
132
|
+
{/* Show feature if enabled, fallback if disabled */}
|
|
133
|
+
<FeatureFlagGuard flag="new-ui" fallback={<OldUI />}>
|
|
134
|
+
<NewUI />
|
|
135
|
+
</FeatureFlagGuard>
|
|
136
|
+
|
|
137
|
+
{/* Inverted logic - show if disabled */}
|
|
138
|
+
<FeatureFlagGuard flag="maintenance-mode" invert>
|
|
139
|
+
<MainApp />
|
|
140
|
+
</FeatureFlagGuard>
|
|
141
|
+
</>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Multivariant Flags with `useVariant`
|
|
147
|
+
|
|
148
|
+
For A/B testing and feature variants:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { useVariant } from '@bluealba/pae-feature-flags';
|
|
152
|
+
|
|
153
|
+
function CheckoutFlow() {
|
|
154
|
+
const { variant, payload, isLoading } = useVariant('checkout-flow');
|
|
155
|
+
|
|
156
|
+
if (isLoading) {
|
|
157
|
+
return <Spinner />;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (variant === 'new-checkout') {
|
|
161
|
+
return <NewCheckout config={payload} />;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (variant === 'express-checkout') {
|
|
165
|
+
return <ExpressCheckout config={payload} />;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return <DefaultCheckout />;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### Access Full Context with `useFeatureFlags`
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { useFeatureFlags } from '@bluealba/pae-feature-flags';
|
|
176
|
+
|
|
177
|
+
function FlagsDebugPanel() {
|
|
178
|
+
const { flags, variants, isLoading, error, refresh } = useFeatureFlags();
|
|
179
|
+
|
|
180
|
+
const handleRefresh = async () => {
|
|
181
|
+
await refresh();
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div>
|
|
186
|
+
<button onClick={handleRefresh} disabled={isLoading}>
|
|
187
|
+
Refresh Flags
|
|
188
|
+
</button>
|
|
189
|
+
{error && <div>Error: {error.message}</div>}
|
|
190
|
+
<div>Total flags loaded: {flags.size}</div>
|
|
191
|
+
<ul>
|
|
192
|
+
{Array.from(flags.entries()).map(([name, enabled]) => (
|
|
193
|
+
<li key={name}>
|
|
194
|
+
{name}: {enabled ? 'enabled' : 'disabled'}
|
|
195
|
+
</li>
|
|
196
|
+
))}
|
|
197
|
+
</ul>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### React Best Practices
|
|
204
|
+
|
|
205
|
+
1. **Prefetch Common Flags**: Add frequently used flags to `prefetchFlags` for better performance
|
|
206
|
+
2. **Use FeatureFlagGuard**: Cleaner than inline conditions for simple toggles
|
|
207
|
+
3. **Handle Loading States**: Always handle `isLoading` when using `useVariant`
|
|
208
|
+
4. **Provide Defaults**: Always provide default values to `useFeatureFlag`
|
|
209
|
+
5. **Minimize Refresh**: Don't set refresh intervals too low to avoid network overhead
|
|
210
|
+
|
|
211
|
+
## API Reference
|
|
212
|
+
|
|
213
|
+
### FeatureFlagsClient
|
|
214
|
+
|
|
215
|
+
#### `isEnabled(flagName, defaultValue?, context?): Promise<boolean>`
|
|
216
|
+
|
|
217
|
+
Evaluates if a feature flag is enabled.
|
|
218
|
+
|
|
219
|
+
- `flagName`: Name of the feature flag
|
|
220
|
+
- `defaultValue`: Default value if evaluation fails (default: false)
|
|
221
|
+
- `context`: Optional evaluation context (userId, tenantId, customProperties)
|
|
222
|
+
|
|
223
|
+
#### `getVariant(flagName, context?): Promise<{name: string, payload: any} | null>`
|
|
224
|
+
|
|
225
|
+
Gets the variant for a multivariant feature flag.
|
|
226
|
+
|
|
227
|
+
- `flagName`: Name of the feature flag
|
|
228
|
+
- `context`: Optional evaluation context
|
|
229
|
+
|
|
230
|
+
#### `evaluateFlags(flagNames, context?): Promise<Map<string, FlagEvaluationResult>>`
|
|
231
|
+
|
|
232
|
+
Evaluates multiple feature flags in a single request.
|
|
233
|
+
|
|
234
|
+
- `flagNames`: Array of feature flag names
|
|
235
|
+
- `context`: Optional evaluation context
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
PolyForm-Noncommercial-1.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* Core types and interfaces for feature flags
|
|
19
|
+
*/
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,0CAAwB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for feature flags system
|
|
3
|
+
* These types are shared across React and NestJS implementations
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Type of feature flag
|
|
7
|
+
*/
|
|
8
|
+
export declare enum FeatureFlagType {
|
|
9
|
+
BOOLEAN = "BOOLEAN",
|
|
10
|
+
MULTIVARIANT = "MULTIVARIANT"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Variant configuration for multivariant flags
|
|
14
|
+
*/
|
|
15
|
+
export interface FeatureFlagVariant {
|
|
16
|
+
name: string;
|
|
17
|
+
weight?: number;
|
|
18
|
+
payload?: any;
|
|
19
|
+
stickiness?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Feature flag evaluation context
|
|
23
|
+
* Used to determine flag values based on user, tenant, or custom properties
|
|
24
|
+
*/
|
|
25
|
+
export interface FeatureFlagContext {
|
|
26
|
+
userId?: string;
|
|
27
|
+
tenantId?: string;
|
|
28
|
+
sessionId?: string;
|
|
29
|
+
customProperties?: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of a feature flag evaluation
|
|
33
|
+
*/
|
|
34
|
+
export interface FlagEvaluationResult {
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
variant?: string;
|
|
37
|
+
payload?: any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Bulk evaluation response
|
|
41
|
+
*/
|
|
42
|
+
export interface BulkEvaluationResult {
|
|
43
|
+
flags: Map<string, FlagEvaluationResult>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Feature flag definition
|
|
47
|
+
*/
|
|
48
|
+
export interface FeatureFlag {
|
|
49
|
+
name: string;
|
|
50
|
+
type: FeatureFlagType;
|
|
51
|
+
enabled: boolean;
|
|
52
|
+
description?: string;
|
|
53
|
+
variants?: FeatureFlagVariant[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Configuration for feature flags client
|
|
57
|
+
*/
|
|
58
|
+
export interface FeatureFlagsConfig {
|
|
59
|
+
gatewayUrl: string;
|
|
60
|
+
timeout?: number;
|
|
61
|
+
retries?: number;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,oBAAY,eAAe;IACzB,OAAO,YAAY;IACnB,YAAY,iBAAiB;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Core types for feature flags system
|
|
4
|
+
* These types are shared across React and NestJS implementations
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.FeatureFlagType = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Type of feature flag
|
|
10
|
+
*/
|
|
11
|
+
var FeatureFlagType;
|
|
12
|
+
(function (FeatureFlagType) {
|
|
13
|
+
FeatureFlagType["BOOLEAN"] = "BOOLEAN";
|
|
14
|
+
FeatureFlagType["MULTIVARIANT"] = "MULTIVARIANT";
|
|
15
|
+
})(FeatureFlagType || (exports.FeatureFlagType = FeatureFlagType = {}));
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;GAEG;AACH,IAAY,eAGX;AAHD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,gDAA6B,CAAA;AAC/B,CAAC,EAHW,eAAe,+BAAf,eAAe,QAG1B"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bluealba/pae-feature-flags
|
|
3
|
+
*
|
|
4
|
+
* Feature flags client library for Blue Alba Platform
|
|
5
|
+
*
|
|
6
|
+
* This library provides both React hooks and NestJS client for consuming
|
|
7
|
+
* feature flags from the gateway service.
|
|
8
|
+
*
|
|
9
|
+
* @example NestJS Usage
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { FeatureFlagsModule, FeatureFlagsClient } from '@bluealba/pae-feature-flags';
|
|
12
|
+
*
|
|
13
|
+
* @Module({
|
|
14
|
+
* imports: [
|
|
15
|
+
* FeatureFlagsModule.forRoot('http://gateway:3000'),
|
|
16
|
+
* ],
|
|
17
|
+
* providers: [MyService],
|
|
18
|
+
* })
|
|
19
|
+
* export class MyServiceModule {}
|
|
20
|
+
*
|
|
21
|
+
* @Injectable()
|
|
22
|
+
* export class MyService {
|
|
23
|
+
* constructor(private readonly featureFlagsClient: FeatureFlagsClient) {}
|
|
24
|
+
*
|
|
25
|
+
* async doSomething() {
|
|
26
|
+
* const isEnabled = await this.featureFlagsClient.isEnabled('my-feature');
|
|
27
|
+
* if (isEnabled) {
|
|
28
|
+
* // New implementation
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example React Usage
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { FeatureFlagsProvider, useFeatureFlag } from '@bluealba/pae-feature-flags';
|
|
37
|
+
*
|
|
38
|
+
* // In your app root
|
|
39
|
+
* <FeatureFlagsProvider gatewayUrl="http://gateway:3000">
|
|
40
|
+
* <App />
|
|
41
|
+
* </FeatureFlagsProvider>
|
|
42
|
+
*
|
|
43
|
+
* // In a component
|
|
44
|
+
* function MyComponent() {
|
|
45
|
+
* const isEnabled = useFeatureFlag('my-feature');
|
|
46
|
+
*
|
|
47
|
+
* return isEnabled ? <NewFeature /> : <OldFeature />;
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export * from './core';
|
|
52
|
+
export * from './nestjs';
|
|
53
|
+
export * from './react';
|
|
54
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAGH,cAAc,QAAQ,CAAC;AAGvB,cAAc,UAAU,CAAC;AAGzB,cAAc,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @bluealba/pae-feature-flags
|
|
4
|
+
*
|
|
5
|
+
* Feature flags client library for Blue Alba Platform
|
|
6
|
+
*
|
|
7
|
+
* This library provides both React hooks and NestJS client for consuming
|
|
8
|
+
* feature flags from the gateway service.
|
|
9
|
+
*
|
|
10
|
+
* @example NestJS Usage
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { FeatureFlagsModule, FeatureFlagsClient } from '@bluealba/pae-feature-flags';
|
|
13
|
+
*
|
|
14
|
+
* @Module({
|
|
15
|
+
* imports: [
|
|
16
|
+
* FeatureFlagsModule.forRoot('http://gateway:3000'),
|
|
17
|
+
* ],
|
|
18
|
+
* providers: [MyService],
|
|
19
|
+
* })
|
|
20
|
+
* export class MyServiceModule {}
|
|
21
|
+
*
|
|
22
|
+
* @Injectable()
|
|
23
|
+
* export class MyService {
|
|
24
|
+
* constructor(private readonly featureFlagsClient: FeatureFlagsClient) {}
|
|
25
|
+
*
|
|
26
|
+
* async doSomething() {
|
|
27
|
+
* const isEnabled = await this.featureFlagsClient.isEnabled('my-feature');
|
|
28
|
+
* if (isEnabled) {
|
|
29
|
+
* // New implementation
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example React Usage
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { FeatureFlagsProvider, useFeatureFlag } from '@bluealba/pae-feature-flags';
|
|
38
|
+
*
|
|
39
|
+
* // In your app root
|
|
40
|
+
* <FeatureFlagsProvider gatewayUrl="http://gateway:3000">
|
|
41
|
+
* <App />
|
|
42
|
+
* </FeatureFlagsProvider>
|
|
43
|
+
*
|
|
44
|
+
* // In a component
|
|
45
|
+
* function MyComponent() {
|
|
46
|
+
* const isEnabled = useFeatureFlag('my-feature');
|
|
47
|
+
*
|
|
48
|
+
* return isEnabled ? <NewFeature /> : <OldFeature />;
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
53
|
+
if (k2 === undefined) k2 = k;
|
|
54
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
55
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
56
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
57
|
+
}
|
|
58
|
+
Object.defineProperty(o, k2, desc);
|
|
59
|
+
}) : (function(o, m, k, k2) {
|
|
60
|
+
if (k2 === undefined) k2 = k;
|
|
61
|
+
o[k2] = m[k];
|
|
62
|
+
}));
|
|
63
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
64
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
65
|
+
};
|
|
66
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
67
|
+
// Core types (shared between React and NestJS)
|
|
68
|
+
__exportStar(require("./core"), exports);
|
|
69
|
+
// NestJS exports
|
|
70
|
+
__exportStar(require("./nestjs"), exports);
|
|
71
|
+
// React exports
|
|
72
|
+
__exportStar(require("./react"), exports);
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;;;;;;;;;;;;;;AAEH,+CAA+C;AAC/C,yCAAuB;AAEvB,iBAAiB;AACjB,2CAAyB;AAEzB,gBAAgB;AAChB,0CAAwB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { HttpService } from '@nestjs/axios';
|
|
2
|
+
import { FeatureFlagContext, FlagEvaluationResult } from '../core/types';
|
|
3
|
+
/**
|
|
4
|
+
* Client for consuming feature flags from the gateway service
|
|
5
|
+
*
|
|
6
|
+
* This service provides methods to evaluate feature flags by calling
|
|
7
|
+
* the gateway API endpoints. It handles errors gracefully by returning
|
|
8
|
+
* default values when the API is unavailable or returns errors.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* @Injectable()
|
|
13
|
+
* export class MyService {
|
|
14
|
+
* constructor(private readonly featureFlagsClient: FeatureFlagsClient) {}
|
|
15
|
+
*
|
|
16
|
+
* async doSomething() {
|
|
17
|
+
* const isEnabled = await this.featureFlagsClient.isEnabled('my-feature');
|
|
18
|
+
* if (isEnabled) {
|
|
19
|
+
* // New implementation
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class FeatureFlagsClient {
|
|
26
|
+
private readonly gatewayUrl;
|
|
27
|
+
private readonly httpService;
|
|
28
|
+
private readonly logger;
|
|
29
|
+
constructor(gatewayUrl: string, httpService: HttpService);
|
|
30
|
+
/**
|
|
31
|
+
* Evaluates if a feature flag is enabled
|
|
32
|
+
*
|
|
33
|
+
* @param flagName - The name of the feature flag to evaluate
|
|
34
|
+
* @param defaultValue - The default value to return if evaluation fails (default: false)
|
|
35
|
+
* @param context - Optional evaluation context (user, tenant, custom properties)
|
|
36
|
+
* @returns Promise resolving to true if flag is enabled, false otherwise
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const isEnabled = await client.isEnabled('new-dashboard', false, {
|
|
41
|
+
* userId: '123',
|
|
42
|
+
* tenantId: 'tenant-1'
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
isEnabled(flagName: string, defaultValue?: boolean, context?: FeatureFlagContext): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Gets the variant for a multivariant feature flag
|
|
49
|
+
*
|
|
50
|
+
* @param flagName - The name of the feature flag
|
|
51
|
+
* @param context - Optional evaluation context
|
|
52
|
+
* @returns Promise resolving to variant object with name and payload, or null if no variant
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const variant = await client.getVariant('ab-test', {
|
|
57
|
+
* userId: '123'
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* if (variant?.name === 'variant-a') {
|
|
61
|
+
* // Variant A logic
|
|
62
|
+
* } else if (variant?.name === 'variant-b') {
|
|
63
|
+
* // Variant B logic
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
getVariant(flagName: string, context?: FeatureFlagContext): Promise<{
|
|
68
|
+
name: string;
|
|
69
|
+
payload: any;
|
|
70
|
+
} | null>;
|
|
71
|
+
/**
|
|
72
|
+
* Evaluates multiple feature flags in a single request
|
|
73
|
+
*
|
|
74
|
+
* This method is more efficient than calling isEnabled multiple times
|
|
75
|
+
* as it reduces the number of HTTP requests.
|
|
76
|
+
*
|
|
77
|
+
* @param flagNames - Array of feature flag names to evaluate
|
|
78
|
+
* @param context - Optional evaluation context
|
|
79
|
+
* @returns Promise resolving to a Map of flag names to evaluation results
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const results = await client.evaluateFlags(
|
|
84
|
+
* ['feature-a', 'feature-b', 'ab-test'],
|
|
85
|
+
* { userId: '123', tenantId: 'tenant-1' }
|
|
86
|
+
* );
|
|
87
|
+
*
|
|
88
|
+
* const featureAEnabled = results.get('feature-a')?.enabled ?? false;
|
|
89
|
+
* const abTestVariant = results.get('ab-test')?.variant;
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
evaluateFlags(flagNames: string[], context?: FeatureFlagContext): Promise<Map<string, FlagEvaluationResult>>;
|
|
93
|
+
/**
|
|
94
|
+
* Gets the configured gateway URL
|
|
95
|
+
* Useful for debugging and logging purposes
|
|
96
|
+
*/
|
|
97
|
+
getGatewayUrl(): string;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=FeatureFlagsClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureFlagsClient.d.ts","sourceRoot":"","sources":["../../src/nestjs/FeatureFlagsClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,kBAAkB;IAIJ,OAAO,CAAC,QAAQ,CAAC,UAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW;IAJ9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;gBAGpB,UAAU,EAAE,MAAM,EACzC,WAAW,EAAE,WAAW;IAG3C;;;;;;;;;;;;;;;OAeG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,OAAe,EAC7B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,OAAO,CAAC;IAmBnB;;;;;;;;;;;;;;;;;;;OAmBG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,GAAG,IAAI,CAAC;IA0BjD;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,aAAa,CACjB,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IA6B7C;;;OAGG;IACH,aAAa,IAAI,MAAM;CAGxB"}
|