@buildrflags/angular 1.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 +198 -0
- package/dist/buildrflags.module.d.ts +47 -0
- package/dist/buildrflags.module.d.ts.map +1 -0
- package/dist/buildrflags.module.js +63 -0
- package/dist/buildrflags.module.js.map +1 -0
- package/dist/buildrflags.service.d.ts +70 -0
- package/dist/buildrflags.service.d.ts.map +1 -0
- package/dist/buildrflags.service.js +152 -0
- package/dist/buildrflags.service.js.map +1 -0
- package/dist/flag.pipe.d.ts +40 -0
- package/dist/flag.pipe.d.ts.map +1 -0
- package/dist/flag.pipe.js +50 -0
- package/dist/flag.pipe.js.map +1 -0
- package/dist/if-flag.directive.d.ts +50 -0
- package/dist/if-flag.directive.d.ts.map +1 -0
- package/dist/if-flag.directive.js +94 -0
- package/dist/if-flag.directive.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# @buildrflags/angular
|
|
2
|
+
|
|
3
|
+
Angular SDK for [BuildrFlags](https://flags.buildrlab.com) feature flags.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @buildrflags/angular
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @buildrflags/angular
|
|
11
|
+
# or
|
|
12
|
+
yarn add @buildrflags/angular
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Import `BuildrFlagsModule` in your root AppModule:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { NgModule } from '@angular/core';
|
|
21
|
+
import { BuildrFlagsModule } from '@buildrflags/angular';
|
|
22
|
+
|
|
23
|
+
@NgModule({
|
|
24
|
+
imports: [
|
|
25
|
+
BuildrFlagsModule.forRoot({
|
|
26
|
+
apiKey: 'bf_production_xxx',
|
|
27
|
+
baseUrl: 'https://api.flags.buildrlab.com', // optional
|
|
28
|
+
refreshInterval: 60000, // optional, default 60s
|
|
29
|
+
}),
|
|
30
|
+
],
|
|
31
|
+
})
|
|
32
|
+
export class AppModule {}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Standalone Components
|
|
36
|
+
|
|
37
|
+
For standalone components, import the module directly:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { Component } from '@angular/core';
|
|
41
|
+
import { BuildrFlagsModule } from '@buildrflags/angular';
|
|
42
|
+
|
|
43
|
+
@Component({
|
|
44
|
+
standalone: true,
|
|
45
|
+
imports: [BuildrFlagsModule],
|
|
46
|
+
template: `
|
|
47
|
+
<div *ifFlag="'features.newUI'">
|
|
48
|
+
New UI enabled!
|
|
49
|
+
</div>
|
|
50
|
+
`,
|
|
51
|
+
})
|
|
52
|
+
export class MyComponent {}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Structural Directive
|
|
58
|
+
|
|
59
|
+
Use `*ifFlag` to conditionally render content:
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<!-- Show when flag is enabled -->
|
|
63
|
+
<div *ifFlag="'features.darkMode'">
|
|
64
|
+
Dark mode content
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<!-- With else template -->
|
|
68
|
+
<div *ifFlag="'features.newDashboard'; else oldDashboard">
|
|
69
|
+
New dashboard
|
|
70
|
+
</div>
|
|
71
|
+
<ng-template #oldDashboard>
|
|
72
|
+
Old dashboard
|
|
73
|
+
</ng-template>
|
|
74
|
+
|
|
75
|
+
<!-- Negated (show when flag is OFF) -->
|
|
76
|
+
<div *ifFlag="'features.maintenance'; negate: true">
|
|
77
|
+
Site is operational
|
|
78
|
+
</div>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Pipe
|
|
82
|
+
|
|
83
|
+
Use the `flag` pipe with `async` for reactive flag evaluation:
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<!-- In *ngIf -->
|
|
87
|
+
<div *ngIf="'features.darkMode' | flag | async">
|
|
88
|
+
Dark mode enabled
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!-- In attribute binding -->
|
|
92
|
+
<button [disabled]="!('features.submit' | flag | async)">
|
|
93
|
+
Submit
|
|
94
|
+
</button>
|
|
95
|
+
|
|
96
|
+
<!-- In class binding -->
|
|
97
|
+
<div [class.dark-theme]="'features.darkMode' | flag | async">
|
|
98
|
+
Content
|
|
99
|
+
</div>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Service
|
|
103
|
+
|
|
104
|
+
Inject `BuildrFlagsService` for programmatic access:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { Component } from '@angular/core';
|
|
108
|
+
import { BuildrFlagsService } from '@buildrflags/angular';
|
|
109
|
+
|
|
110
|
+
@Component({
|
|
111
|
+
selector: 'app-example',
|
|
112
|
+
template: `
|
|
113
|
+
<div *ngIf="darkMode$ | async">Dark mode!</div>
|
|
114
|
+
`,
|
|
115
|
+
})
|
|
116
|
+
export class ExampleComponent {
|
|
117
|
+
// Observable for reactive updates
|
|
118
|
+
darkMode$ = this.flags.flag$('features.darkMode');
|
|
119
|
+
|
|
120
|
+
constructor(private flags: BuildrFlagsService) {}
|
|
121
|
+
|
|
122
|
+
// Snapshot value
|
|
123
|
+
checkFlag() {
|
|
124
|
+
const enabled = this.flags.getFlag('features.someFlag');
|
|
125
|
+
console.log('Flag enabled:', enabled);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Manual refresh
|
|
129
|
+
async refreshFlags() {
|
|
130
|
+
await this.flags.refresh();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Service API
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
interface BuildrFlagsService {
|
|
139
|
+
// Observables
|
|
140
|
+
flags$: Observable<BuildrFlagsState>; // Full state
|
|
141
|
+
flag$(key: string, defaultValue?: boolean): Observable<boolean>;
|
|
142
|
+
isLoading$: Observable<boolean>;
|
|
143
|
+
error$: Observable<string | null>;
|
|
144
|
+
|
|
145
|
+
// Snapshots
|
|
146
|
+
snapshot: BuildrFlagsState; // Current state
|
|
147
|
+
getFlag(key: string, defaultValue?: boolean): boolean;
|
|
148
|
+
isLoading: boolean;
|
|
149
|
+
|
|
150
|
+
// Actions
|
|
151
|
+
refresh(): Promise<void>; // Manual refresh
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
| Option | Type | Default | Description |
|
|
158
|
+
|--------|------|---------|-------------|
|
|
159
|
+
| `apiKey` | `string` | *required* | Your BuildrFlags API key |
|
|
160
|
+
| `baseUrl` | `string` | `https://api.flags.buildrlab.com` | API base URL |
|
|
161
|
+
| `refreshInterval` | `number` | `60000` | Auto-refresh interval (ms), 0 to disable |
|
|
162
|
+
| `initialFlags` | `Record<string, boolean>` | `undefined` | Initial flags for SSR |
|
|
163
|
+
|
|
164
|
+
## Server-Side Rendering (SSR)
|
|
165
|
+
|
|
166
|
+
For SSR, provide initial flags to avoid flicker:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// In your SSR bootstrap
|
|
170
|
+
BuildrFlagsModule.forRoot({
|
|
171
|
+
apiKey: 'bf_production_xxx',
|
|
172
|
+
initialFlags: {
|
|
173
|
+
'features.darkMode': true,
|
|
174
|
+
'features.newUI': false,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## TypeScript
|
|
180
|
+
|
|
181
|
+
All types are exported:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import type {
|
|
185
|
+
BuildrFlagsConfig,
|
|
186
|
+
BuildrFlagsState,
|
|
187
|
+
FlagResult,
|
|
188
|
+
} from '@buildrflags/angular';
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Requirements
|
|
192
|
+
|
|
193
|
+
- Angular 17+
|
|
194
|
+
- RxJS 7+
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ModuleWithProviders } from '@angular/core';
|
|
2
|
+
import { BuildrFlagsConfig } from './types.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/common";
|
|
5
|
+
import * as i2 from "./if-flag.directive";
|
|
6
|
+
import * as i3 from "./flag.pipe";
|
|
7
|
+
/**
|
|
8
|
+
* Angular module for BuildrFlags feature flags.
|
|
9
|
+
*
|
|
10
|
+
* Import this module in your root AppModule and call forRoot() with your configuration.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @NgModule({
|
|
15
|
+
* imports: [
|
|
16
|
+
* BuildrFlagsModule.forRoot({
|
|
17
|
+
* apiKey: 'bf_production_xxx',
|
|
18
|
+
* baseUrl: 'https://api.flags.buildrlab.com',
|
|
19
|
+
* refreshInterval: 60000,
|
|
20
|
+
* }),
|
|
21
|
+
* ],
|
|
22
|
+
* })
|
|
23
|
+
* export class AppModule {}
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Then use in components:
|
|
27
|
+
* ```html
|
|
28
|
+
* <div *ifFlag="'features.darkMode'">Dark mode enabled!</div>
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Or with the pipe:
|
|
32
|
+
* ```html
|
|
33
|
+
* <button [disabled]="!('features.submit' | flag | async)">Submit</button>
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class BuildrFlagsModule {
|
|
37
|
+
/**
|
|
38
|
+
* Configure BuildrFlags for the root module
|
|
39
|
+
*
|
|
40
|
+
* @param config - BuildrFlags configuration
|
|
41
|
+
*/
|
|
42
|
+
static forRoot(config: BuildrFlagsConfig): ModuleWithProviders<BuildrFlagsModule>;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BuildrFlagsModule, never>;
|
|
44
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<BuildrFlagsModule, never, [typeof i1.CommonModule, typeof i2.IfFlagDirective, typeof i3.FlagPipe], [typeof i2.IfFlagDirective, typeof i3.FlagPipe]>;
|
|
45
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<BuildrFlagsModule>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=buildrflags.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildrflags.module.d.ts","sourceRoot":"","sources":["../src/buildrflags.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAsB,MAAM,YAAY,CAAC;;;;;AAKnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAIa,iBAAiB;IAC5B;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,CAAC,iBAAiB,CAAC;yCANtE,iBAAiB;0CAAjB,iBAAiB;0CAAjB,iBAAiB;CAe7B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { BUILDRFLAGS_CONFIG } from './types.js';
|
|
4
|
+
import { BuildrFlagsService } from './buildrflags.service.js';
|
|
5
|
+
import { IfFlagDirective } from './if-flag.directive.js';
|
|
6
|
+
import { FlagPipe } from './flag.pipe.js';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
/**
|
|
9
|
+
* Angular module for BuildrFlags feature flags.
|
|
10
|
+
*
|
|
11
|
+
* Import this module in your root AppModule and call forRoot() with your configuration.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* @NgModule({
|
|
16
|
+
* imports: [
|
|
17
|
+
* BuildrFlagsModule.forRoot({
|
|
18
|
+
* apiKey: 'bf_production_xxx',
|
|
19
|
+
* baseUrl: 'https://api.flags.buildrlab.com',
|
|
20
|
+
* refreshInterval: 60000,
|
|
21
|
+
* }),
|
|
22
|
+
* ],
|
|
23
|
+
* })
|
|
24
|
+
* export class AppModule {}
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Then use in components:
|
|
28
|
+
* ```html
|
|
29
|
+
* <div *ifFlag="'features.darkMode'">Dark mode enabled!</div>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* Or with the pipe:
|
|
33
|
+
* ```html
|
|
34
|
+
* <button [disabled]="!('features.submit' | flag | async)">Submit</button>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class BuildrFlagsModule {
|
|
38
|
+
/**
|
|
39
|
+
* Configure BuildrFlags for the root module
|
|
40
|
+
*
|
|
41
|
+
* @param config - BuildrFlags configuration
|
|
42
|
+
*/
|
|
43
|
+
static forRoot(config) {
|
|
44
|
+
return {
|
|
45
|
+
ngModule: BuildrFlagsModule,
|
|
46
|
+
providers: [
|
|
47
|
+
{ provide: BUILDRFLAGS_CONFIG, useValue: config },
|
|
48
|
+
BuildrFlagsService,
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
53
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsModule, imports: [CommonModule, IfFlagDirective, FlagPipe], exports: [IfFlagDirective, FlagPipe] }); }
|
|
54
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsModule, imports: [CommonModule] }); }
|
|
55
|
+
}
|
|
56
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsModule, decorators: [{
|
|
57
|
+
type: NgModule,
|
|
58
|
+
args: [{
|
|
59
|
+
imports: [CommonModule, IfFlagDirective, FlagPipe],
|
|
60
|
+
exports: [IfFlagDirective, FlagPipe],
|
|
61
|
+
}]
|
|
62
|
+
}] });
|
|
63
|
+
//# sourceMappingURL=buildrflags.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildrflags.module.js","sourceRoot":"","sources":["../src/buildrflags.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAqB,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,MAAM,OAAO,iBAAiB;IAC5B;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,MAAyB;QACtC,OAAO;YACL,QAAQ,EAAE,iBAAiB;YAC3B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE;gBACjD,kBAAkB;aACnB;SACF,CAAC;IACJ,CAAC;8GAdU,iBAAiB;+GAAjB,iBAAiB,YAHlB,YAAY,EAAE,eAAe,EAAE,QAAQ,aACvC,eAAe,EAAE,QAAQ;+GAExB,iBAAiB,YAHlB,YAAY;;2FAGX,iBAAiB;kBAJ7B,QAAQ;mBAAC;oBACR,OAAO,EAAE,CAAC,YAAY,EAAE,eAAe,EAAE,QAAQ,CAAC;oBAClD,OAAO,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;iBACrC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { BuildrFlagsConfig, BuildrFlagsState } from './types.js';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Service for evaluating feature flags from BuildrFlags API.
|
|
7
|
+
*
|
|
8
|
+
* Fetches flags on initialization and refreshes periodically.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* @Component({...})
|
|
13
|
+
* export class MyComponent {
|
|
14
|
+
* darkMode$ = this.flags.flag$('features.darkMode');
|
|
15
|
+
*
|
|
16
|
+
* constructor(private flags: BuildrFlagsService) {}
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class BuildrFlagsService implements OnDestroy {
|
|
21
|
+
private readonly state$;
|
|
22
|
+
private readonly baseUrl;
|
|
23
|
+
private readonly apiKey;
|
|
24
|
+
private readonly refreshInterval;
|
|
25
|
+
private refreshSubscription?;
|
|
26
|
+
constructor(config: BuildrFlagsConfig);
|
|
27
|
+
ngOnDestroy(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Observable of all flags state
|
|
30
|
+
*/
|
|
31
|
+
get flags$(): Observable<BuildrFlagsState>;
|
|
32
|
+
/**
|
|
33
|
+
* Current flags state (snapshot)
|
|
34
|
+
*/
|
|
35
|
+
get snapshot(): BuildrFlagsState;
|
|
36
|
+
/**
|
|
37
|
+
* Observable for a single flag's enabled state
|
|
38
|
+
*
|
|
39
|
+
* @param flagKey - The key of the flag to observe
|
|
40
|
+
* @param defaultValue - Value to return while loading or if flag not found (default: false)
|
|
41
|
+
*/
|
|
42
|
+
flag$(flagKey: string, defaultValue?: boolean): Observable<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get a flag's current value (snapshot)
|
|
45
|
+
*
|
|
46
|
+
* @param flagKey - The key of the flag to evaluate
|
|
47
|
+
* @param defaultValue - Value to return if flag not found or loading (default: false)
|
|
48
|
+
*/
|
|
49
|
+
getFlag(flagKey: string, defaultValue?: boolean): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Check if flags are currently loading
|
|
52
|
+
*/
|
|
53
|
+
get isLoading(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Observable of loading state
|
|
56
|
+
*/
|
|
57
|
+
get isLoading$(): Observable<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Observable of error state
|
|
60
|
+
*/
|
|
61
|
+
get error$(): Observable<string | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Manually refresh flags from the API
|
|
64
|
+
*/
|
|
65
|
+
refresh(): Promise<void>;
|
|
66
|
+
private fetchFlags;
|
|
67
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BuildrFlagsService, never>;
|
|
68
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<BuildrFlagsService>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=buildrflags.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildrflags.service.d.ts","sourceRoot":"","sources":["../src/buildrflags.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,SAAS,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAmB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAE3E,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,YAAY,CAAC;;AAKpB;;;;;;;;;;;;;;GAcG;AACH,qBACa,kBAAmB,YAAW,SAAS;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAIpB;IAEH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,mBAAmB,CAAC,CAAe;gBAEH,MAAM,EAAE,iBAAiB;IAyBjE,WAAW,IAAI,IAAI;IAInB;;OAEG;IACH,IAAI,MAAM,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAEzC;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,gBAAgB,CAE/B;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,UAAU,CAAC,OAAO,CAAC;IAOjE;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,OAAO;IAMvD;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,UAAU,CAAC,OAAO,CAAC,CAKpC;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtC;IAED;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAIhB,UAAU;yCAlHb,kBAAkB;6CAAlB,kBAAkB;CAqJ9B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Injectable, Inject } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, interval } from 'rxjs';
|
|
3
|
+
import { map, distinctUntilChanged } from 'rxjs/operators';
|
|
4
|
+
import { BUILDRFLAGS_CONFIG, } from './types.js';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://api.flags.buildrlab.com';
|
|
7
|
+
const DEFAULT_REFRESH_INTERVAL = 60_000; // 1 minute
|
|
8
|
+
/**
|
|
9
|
+
* Service for evaluating feature flags from BuildrFlags API.
|
|
10
|
+
*
|
|
11
|
+
* Fetches flags on initialization and refreshes periodically.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* @Component({...})
|
|
16
|
+
* export class MyComponent {
|
|
17
|
+
* darkMode$ = this.flags.flag$('features.darkMode');
|
|
18
|
+
*
|
|
19
|
+
* constructor(private flags: BuildrFlagsService) {}
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class BuildrFlagsService {
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.state$ = new BehaviorSubject({
|
|
26
|
+
flags: {},
|
|
27
|
+
isLoading: true,
|
|
28
|
+
error: null,
|
|
29
|
+
});
|
|
30
|
+
this.apiKey = config.apiKey;
|
|
31
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
32
|
+
this.refreshInterval = config.refreshInterval ?? DEFAULT_REFRESH_INTERVAL;
|
|
33
|
+
// Set initial flags if provided
|
|
34
|
+
if (config.initialFlags) {
|
|
35
|
+
this.state$.next({
|
|
36
|
+
flags: config.initialFlags,
|
|
37
|
+
isLoading: false,
|
|
38
|
+
error: null,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Fetch flags immediately
|
|
42
|
+
void this.fetchFlags();
|
|
43
|
+
// Set up auto-refresh
|
|
44
|
+
if (this.refreshInterval > 0) {
|
|
45
|
+
this.refreshSubscription = interval(this.refreshInterval).subscribe(() => {
|
|
46
|
+
void this.fetchFlags();
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
ngOnDestroy() {
|
|
51
|
+
this.refreshSubscription?.unsubscribe();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Observable of all flags state
|
|
55
|
+
*/
|
|
56
|
+
get flags$() {
|
|
57
|
+
return this.state$.asObservable();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Current flags state (snapshot)
|
|
61
|
+
*/
|
|
62
|
+
get snapshot() {
|
|
63
|
+
return this.state$.getValue();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Observable for a single flag's enabled state
|
|
67
|
+
*
|
|
68
|
+
* @param flagKey - The key of the flag to observe
|
|
69
|
+
* @param defaultValue - Value to return while loading or if flag not found (default: false)
|
|
70
|
+
*/
|
|
71
|
+
flag$(flagKey, defaultValue = false) {
|
|
72
|
+
return this.state$.pipe(map((state) => (state.isLoading ? defaultValue : (state.flags[flagKey] ?? defaultValue))), distinctUntilChanged());
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get a flag's current value (snapshot)
|
|
76
|
+
*
|
|
77
|
+
* @param flagKey - The key of the flag to evaluate
|
|
78
|
+
* @param defaultValue - Value to return if flag not found or loading (default: false)
|
|
79
|
+
*/
|
|
80
|
+
getFlag(flagKey, defaultValue = false) {
|
|
81
|
+
const state = this.state$.getValue();
|
|
82
|
+
if (state.isLoading)
|
|
83
|
+
return defaultValue;
|
|
84
|
+
return state.flags[flagKey] ?? defaultValue;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if flags are currently loading
|
|
88
|
+
*/
|
|
89
|
+
get isLoading() {
|
|
90
|
+
return this.state$.getValue().isLoading;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Observable of loading state
|
|
94
|
+
*/
|
|
95
|
+
get isLoading$() {
|
|
96
|
+
return this.state$.pipe(map((state) => state.isLoading), distinctUntilChanged());
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Observable of error state
|
|
100
|
+
*/
|
|
101
|
+
get error$() {
|
|
102
|
+
return this.state$.pipe(map((state) => state.error), distinctUntilChanged());
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Manually refresh flags from the API
|
|
106
|
+
*/
|
|
107
|
+
async refresh() {
|
|
108
|
+
await this.fetchFlags();
|
|
109
|
+
}
|
|
110
|
+
async fetchFlags() {
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(`${this.baseUrl}/api/evaluate/all`, {
|
|
113
|
+
method: 'GET',
|
|
114
|
+
headers: {
|
|
115
|
+
'X-API-Key': this.apiKey,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const text = await response.text().catch(() => 'Unknown error');
|
|
120
|
+
throw new Error(`API request failed: ${response.status} ${text}`);
|
|
121
|
+
}
|
|
122
|
+
const data = (await response.json());
|
|
123
|
+
const flagMap = {};
|
|
124
|
+
for (const flag of data.flags) {
|
|
125
|
+
flagMap[flag.flagKey] = flag.enabled;
|
|
126
|
+
}
|
|
127
|
+
this.state$.next({
|
|
128
|
+
flags: flagMap,
|
|
129
|
+
isLoading: false,
|
|
130
|
+
error: null,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
const message = err instanceof Error ? err.message : 'Failed to fetch flags';
|
|
135
|
+
this.state$.next({
|
|
136
|
+
...this.state$.getValue(),
|
|
137
|
+
isLoading: false,
|
|
138
|
+
error: message,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsService, deps: [{ token: BUILDRFLAGS_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
143
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsService, providedIn: 'root' }); }
|
|
144
|
+
}
|
|
145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: BuildrFlagsService, decorators: [{
|
|
146
|
+
type: Injectable,
|
|
147
|
+
args: [{ providedIn: 'root' }]
|
|
148
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
149
|
+
type: Inject,
|
|
150
|
+
args: [BUILDRFLAGS_CONFIG]
|
|
151
|
+
}] }] });
|
|
152
|
+
//# sourceMappingURL=buildrflags.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildrflags.service.js","sourceRoot":"","sources":["../src/buildrflags.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PipeTransform } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { BuildrFlagsService } from './buildrflags.service.js';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Pipe for getting a feature flag's enabled state as an Observable.
|
|
7
|
+
*
|
|
8
|
+
* Use with the async pipe for reactive flag evaluation.
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```html
|
|
12
|
+
* <div *ngIf="'features.darkMode' | flag | async">
|
|
13
|
+
* Dark mode content
|
|
14
|
+
* </div>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example In attribute binding
|
|
18
|
+
* ```html
|
|
19
|
+
* <button [disabled]="!('features.submit' | flag | async)">Submit</button>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example In class binding
|
|
23
|
+
* ```html
|
|
24
|
+
* <div [class.dark-theme]="'features.darkMode' | flag | async">Content</div>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class FlagPipe implements PipeTransform {
|
|
28
|
+
private flagsService;
|
|
29
|
+
constructor(flagsService: BuildrFlagsService);
|
|
30
|
+
/**
|
|
31
|
+
* Transform a flag key into an Observable of its enabled state
|
|
32
|
+
*
|
|
33
|
+
* @param flagKey - The key of the flag to evaluate
|
|
34
|
+
* @param defaultValue - Value to return while loading (default: false)
|
|
35
|
+
*/
|
|
36
|
+
transform(flagKey: string, defaultValue?: boolean): Observable<boolean>;
|
|
37
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FlagPipe, never>;
|
|
38
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<FlagPipe, "flag", true>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=flag.pipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flag.pipe.d.ts","sourceRoot":"","sources":["../src/flag.pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,aAAa,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;;AAE9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAIa,QAAS,YAAW,aAAa;IAChC,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,kBAAkB;IAEpD;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,UAAU,CAAC,OAAO,CAAC;yCAT1D,QAAQ;uCAAR,QAAQ;CAYpB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Pipe } from '@angular/core';
|
|
2
|
+
import { BuildrFlagsService } from './buildrflags.service.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "./buildrflags.service.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pipe for getting a feature flag's enabled state as an Observable.
|
|
7
|
+
*
|
|
8
|
+
* Use with the async pipe for reactive flag evaluation.
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```html
|
|
12
|
+
* <div *ngIf="'features.darkMode' | flag | async">
|
|
13
|
+
* Dark mode content
|
|
14
|
+
* </div>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example In attribute binding
|
|
18
|
+
* ```html
|
|
19
|
+
* <button [disabled]="!('features.submit' | flag | async)">Submit</button>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example In class binding
|
|
23
|
+
* ```html
|
|
24
|
+
* <div [class.dark-theme]="'features.darkMode' | flag | async">Content</div>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class FlagPipe {
|
|
28
|
+
constructor(flagsService) {
|
|
29
|
+
this.flagsService = flagsService;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Transform a flag key into an Observable of its enabled state
|
|
33
|
+
*
|
|
34
|
+
* @param flagKey - The key of the flag to evaluate
|
|
35
|
+
* @param defaultValue - Value to return while loading (default: false)
|
|
36
|
+
*/
|
|
37
|
+
transform(flagKey, defaultValue = false) {
|
|
38
|
+
return this.flagsService.flag$(flagKey, defaultValue);
|
|
39
|
+
}
|
|
40
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FlagPipe, deps: [{ token: i1.BuildrFlagsService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
41
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.4", ngImport: i0, type: FlagPipe, isStandalone: true, name: "flag", pure: false }); }
|
|
42
|
+
}
|
|
43
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: FlagPipe, decorators: [{
|
|
44
|
+
type: Pipe,
|
|
45
|
+
args: [{
|
|
46
|
+
name: 'flag',
|
|
47
|
+
pure: false,
|
|
48
|
+
}]
|
|
49
|
+
}], ctorParameters: () => [{ type: i1.BuildrFlagsService }] });
|
|
50
|
+
//# sourceMappingURL=flag.pipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flag.pipe.js","sourceRoot":"","sources":["../src/flag.pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAiB,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;;;AAE9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,MAAM,OAAO,QAAQ;IACnB,YAAoB,YAAgC;QAAhC,iBAAY,GAAZ,YAAY,CAAoB;IAAG,CAAC;IAExD;;;;;OAKG;IACH,SAAS,CAAC,OAAe,EAAE,YAAY,GAAG,KAAK;QAC7C,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;8GAXU,QAAQ;4GAAR,QAAQ;;2FAAR,QAAQ;kBAJpB,IAAI;mBAAC;oBACJ,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,KAAK;iBACZ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { TemplateRef, ViewContainerRef, OnInit, OnDestroy } from '@angular/core';
|
|
2
|
+
import { BuildrFlagsService } from './buildrflags.service.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Structural directive for conditionally rendering content based on a feature flag.
|
|
6
|
+
*
|
|
7
|
+
* @example Basic usage
|
|
8
|
+
* ```html
|
|
9
|
+
* <div *ifFlag="'features.newDashboard'">
|
|
10
|
+
* New dashboard content
|
|
11
|
+
* </div>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example With else template
|
|
15
|
+
* ```html
|
|
16
|
+
* <div *ifFlag="'features.newDashboard'; else oldDashboard">
|
|
17
|
+
* New dashboard content
|
|
18
|
+
* </div>
|
|
19
|
+
* <ng-template #oldDashboard>
|
|
20
|
+
* Old dashboard content
|
|
21
|
+
* </ng-template>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example Negated (show when flag is OFF)
|
|
25
|
+
* ```html
|
|
26
|
+
* <div *ifFlag="'features.newDashboard'; negate: true">
|
|
27
|
+
* Shown when newDashboard is disabled
|
|
28
|
+
* </div>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class IfFlagDirective implements OnInit, OnDestroy {
|
|
32
|
+
private templateRef;
|
|
33
|
+
private viewContainer;
|
|
34
|
+
private flagsService;
|
|
35
|
+
private flagKey;
|
|
36
|
+
private negate;
|
|
37
|
+
private hasView;
|
|
38
|
+
private subscription?;
|
|
39
|
+
private elseTemplateRef?;
|
|
40
|
+
set ifFlag(flagKey: string);
|
|
41
|
+
set ifFlagNegate(negate: boolean);
|
|
42
|
+
set ifFlagElse(templateRef: TemplateRef<unknown> | null);
|
|
43
|
+
constructor(templateRef: TemplateRef<unknown>, viewContainer: ViewContainerRef, flagsService: BuildrFlagsService);
|
|
44
|
+
ngOnInit(): void;
|
|
45
|
+
ngOnDestroy(): void;
|
|
46
|
+
private updateView;
|
|
47
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<IfFlagDirective, never>;
|
|
48
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<IfFlagDirective, "[ifFlag]", never, { "ifFlag": { "alias": "ifFlag"; "required": false; }; "ifFlagNegate": { "alias": "ifFlagNegate"; "required": false; }; "ifFlagElse": { "alias": "ifFlagElse"; "required": false; }; }, {}, never, never, true, never>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=if-flag.directive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"if-flag.directive.d.ts","sourceRoot":"","sources":["../src/if-flag.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EACX,gBAAgB,EAChB,MAAM,EACN,SAAS,EACV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAGa,eAAgB,YAAW,MAAM,EAAE,SAAS;IA0BrD,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,YAAY;IA3BtB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,eAAe,CAAC,CAAuB;IAE/C,IACI,MAAM,CAAC,OAAO,EAAE,MAAM,EAGzB;IAED,IACI,YAAY,CAAC,MAAM,EAAE,OAAO,EAG/B;IAED,IACI,UAAU,CAAC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,EAGtD;gBAGS,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,EACjC,aAAa,EAAE,gBAAgB,EAC/B,YAAY,EAAE,kBAAkB;IAG1C,QAAQ,IAAI,IAAI;IAMhB,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,UAAU;yCAzCP,eAAe;2CAAf,eAAe;CA2D3B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Directive, Input, TemplateRef, ViewContainerRef, } from '@angular/core';
|
|
2
|
+
import { BuildrFlagsService } from './buildrflags.service.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "./buildrflags.service.js";
|
|
5
|
+
/**
|
|
6
|
+
* Structural directive for conditionally rendering content based on a feature flag.
|
|
7
|
+
*
|
|
8
|
+
* @example Basic usage
|
|
9
|
+
* ```html
|
|
10
|
+
* <div *ifFlag="'features.newDashboard'">
|
|
11
|
+
* New dashboard content
|
|
12
|
+
* </div>
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example With else template
|
|
16
|
+
* ```html
|
|
17
|
+
* <div *ifFlag="'features.newDashboard'; else oldDashboard">
|
|
18
|
+
* New dashboard content
|
|
19
|
+
* </div>
|
|
20
|
+
* <ng-template #oldDashboard>
|
|
21
|
+
* Old dashboard content
|
|
22
|
+
* </ng-template>
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example Negated (show when flag is OFF)
|
|
26
|
+
* ```html
|
|
27
|
+
* <div *ifFlag="'features.newDashboard'; negate: true">
|
|
28
|
+
* Shown when newDashboard is disabled
|
|
29
|
+
* </div>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class IfFlagDirective {
|
|
33
|
+
set ifFlag(flagKey) {
|
|
34
|
+
this.flagKey = flagKey;
|
|
35
|
+
this.updateView();
|
|
36
|
+
}
|
|
37
|
+
set ifFlagNegate(negate) {
|
|
38
|
+
this.negate = negate;
|
|
39
|
+
this.updateView();
|
|
40
|
+
}
|
|
41
|
+
set ifFlagElse(templateRef) {
|
|
42
|
+
this.elseTemplateRef = templateRef ?? undefined;
|
|
43
|
+
this.updateView();
|
|
44
|
+
}
|
|
45
|
+
constructor(templateRef, viewContainer, flagsService) {
|
|
46
|
+
this.templateRef = templateRef;
|
|
47
|
+
this.viewContainer = viewContainer;
|
|
48
|
+
this.flagsService = flagsService;
|
|
49
|
+
this.flagKey = '';
|
|
50
|
+
this.negate = false;
|
|
51
|
+
this.hasView = false;
|
|
52
|
+
}
|
|
53
|
+
ngOnInit() {
|
|
54
|
+
this.subscription = this.flagsService.flag$(this.flagKey).subscribe(() => {
|
|
55
|
+
this.updateView();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
ngOnDestroy() {
|
|
59
|
+
this.subscription?.unsubscribe();
|
|
60
|
+
}
|
|
61
|
+
updateView() {
|
|
62
|
+
if (!this.flagKey)
|
|
63
|
+
return;
|
|
64
|
+
const flagEnabled = this.flagsService.getFlag(this.flagKey);
|
|
65
|
+
const shouldShow = this.negate ? !flagEnabled : flagEnabled;
|
|
66
|
+
if (shouldShow && !this.hasView) {
|
|
67
|
+
this.viewContainer.clear();
|
|
68
|
+
this.viewContainer.createEmbeddedView(this.templateRef);
|
|
69
|
+
this.hasView = true;
|
|
70
|
+
}
|
|
71
|
+
else if (!shouldShow) {
|
|
72
|
+
this.viewContainer.clear();
|
|
73
|
+
if (this.elseTemplateRef) {
|
|
74
|
+
this.viewContainer.createEmbeddedView(this.elseTemplateRef);
|
|
75
|
+
}
|
|
76
|
+
this.hasView = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: IfFlagDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i1.BuildrFlagsService }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
80
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.4", type: IfFlagDirective, isStandalone: true, selector: "[ifFlag]", inputs: { ifFlag: "ifFlag", ifFlagNegate: "ifFlagNegate", ifFlagElse: "ifFlagElse" }, ngImport: i0 }); }
|
|
81
|
+
}
|
|
82
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: IfFlagDirective, decorators: [{
|
|
83
|
+
type: Directive,
|
|
84
|
+
args: [{
|
|
85
|
+
selector: '[ifFlag]',
|
|
86
|
+
}]
|
|
87
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: i1.BuildrFlagsService }], propDecorators: { ifFlag: [{
|
|
88
|
+
type: Input
|
|
89
|
+
}], ifFlagNegate: [{
|
|
90
|
+
type: Input
|
|
91
|
+
}], ifFlagElse: [{
|
|
92
|
+
type: Input
|
|
93
|
+
}] } });
|
|
94
|
+
//# sourceMappingURL=if-flag.directive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"if-flag.directive.js","sourceRoot":"","sources":["../src/if-flag.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,WAAW,EACX,gBAAgB,GAGjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;;;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,MAAM,OAAO,eAAe;IAO1B,IACI,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,IACI,YAAY,CAAC,MAAe;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,IACI,UAAU,CAAC,WAAwC;QACrD,IAAI,CAAC,eAAe,GAAG,WAAW,IAAI,SAAS,CAAC;QAChD,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,YACU,WAAiC,EACjC,aAA+B,EAC/B,YAAgC;QAFhC,gBAAW,GAAX,WAAW,CAAsB;QACjC,kBAAa,GAAb,aAAa,CAAkB;QAC/B,iBAAY,GAAZ,YAAY,CAAoB;QA3BlC,YAAO,GAAG,EAAE,CAAC;QACb,WAAM,GAAG,KAAK,CAAC;QACf,YAAO,GAAG,KAAK,CAAC;IA0BrB,CAAC;IAEJ,QAAQ;QACN,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;YACvE,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW;QACT,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,CAAC;IACnC,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;QAE5D,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;aAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzB,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC9D,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;8GA1DU,eAAe;kGAAf,eAAe;;2FAAf,eAAe;kBAH3B,SAAS;mBAAC;oBACT,QAAQ,EAAE,UAAU;iBACrB;;sBAQE,KAAK;;sBAML,KAAK;;sBAML,KAAK"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BuildrFlags Angular SDK
|
|
3
|
+
*
|
|
4
|
+
* Angular module, service, directive, and pipe for feature flag evaluation.
|
|
5
|
+
*
|
|
6
|
+
* @example Module setup
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { BuildrFlagsModule } from '@buildrflags/angular';
|
|
9
|
+
*
|
|
10
|
+
* @NgModule({
|
|
11
|
+
* imports: [
|
|
12
|
+
* BuildrFlagsModule.forRoot({
|
|
13
|
+
* apiKey: 'bf_production_xxx',
|
|
14
|
+
* }),
|
|
15
|
+
* ],
|
|
16
|
+
* })
|
|
17
|
+
* export class AppModule {}
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example Using the directive
|
|
21
|
+
* ```html
|
|
22
|
+
* <div *ifFlag="'features.darkMode'">
|
|
23
|
+
* Dark mode enabled!
|
|
24
|
+
* </div>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Using the service
|
|
28
|
+
* ```typescript
|
|
29
|
+
* @Component({...})
|
|
30
|
+
* export class MyComponent {
|
|
31
|
+
* darkMode$ = this.flags.flag$('features.darkMode');
|
|
32
|
+
*
|
|
33
|
+
* constructor(private flags: BuildrFlagsService) {}
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Using the pipe
|
|
38
|
+
* ```html
|
|
39
|
+
* <div *ngIf="'features.darkMode' | flag | async">
|
|
40
|
+
* Dark mode enabled!
|
|
41
|
+
* </div>
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @packageDocumentation
|
|
45
|
+
*/
|
|
46
|
+
export { BuildrFlagsModule } from './buildrflags.module.js';
|
|
47
|
+
export { BuildrFlagsService } from './buildrflags.service.js';
|
|
48
|
+
export { IfFlagDirective } from './if-flag.directive.js';
|
|
49
|
+
export { FlagPipe } from './flag.pipe.js';
|
|
50
|
+
export type { BuildrFlagsConfig, BuildrFlagsState, FlagResult, BulkEvaluateResponse, } from './types.js';
|
|
51
|
+
export { BUILDRFLAGS_CONFIG } from './types.js';
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAG9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BuildrFlags Angular SDK
|
|
3
|
+
*
|
|
4
|
+
* Angular module, service, directive, and pipe for feature flag evaluation.
|
|
5
|
+
*
|
|
6
|
+
* @example Module setup
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { BuildrFlagsModule } from '@buildrflags/angular';
|
|
9
|
+
*
|
|
10
|
+
* @NgModule({
|
|
11
|
+
* imports: [
|
|
12
|
+
* BuildrFlagsModule.forRoot({
|
|
13
|
+
* apiKey: 'bf_production_xxx',
|
|
14
|
+
* }),
|
|
15
|
+
* ],
|
|
16
|
+
* })
|
|
17
|
+
* export class AppModule {}
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example Using the directive
|
|
21
|
+
* ```html
|
|
22
|
+
* <div *ifFlag="'features.darkMode'">
|
|
23
|
+
* Dark mode enabled!
|
|
24
|
+
* </div>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Using the service
|
|
28
|
+
* ```typescript
|
|
29
|
+
* @Component({...})
|
|
30
|
+
* export class MyComponent {
|
|
31
|
+
* darkMode$ = this.flags.flag$('features.darkMode');
|
|
32
|
+
*
|
|
33
|
+
* constructor(private flags: BuildrFlagsService) {}
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Using the pipe
|
|
38
|
+
* ```html
|
|
39
|
+
* <div *ngIf="'features.darkMode' | flag | async">
|
|
40
|
+
* Dark mode enabled!
|
|
41
|
+
* </div>
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @packageDocumentation
|
|
45
|
+
*/
|
|
46
|
+
// Module
|
|
47
|
+
export { BuildrFlagsModule } from './buildrflags.module.js';
|
|
48
|
+
// Service
|
|
49
|
+
export { BuildrFlagsService } from './buildrflags.service.js';
|
|
50
|
+
// Directive
|
|
51
|
+
export { IfFlagDirective } from './if-flag.directive.js';
|
|
52
|
+
// Pipe
|
|
53
|
+
export { FlagPipe } from './flag.pipe.js';
|
|
54
|
+
// Injection token
|
|
55
|
+
export { BUILDRFLAGS_CONFIG } from './types.js';
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,UAAU;AACV,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,YAAY;AACZ,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO;AACP,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAU1C,kBAAkB;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the BuildrFlags Angular SDK
|
|
4
|
+
*/
|
|
5
|
+
export interface BuildrFlagsConfig {
|
|
6
|
+
/** API key for authentication */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** Base URL for the BuildrFlags API (defaults to https://api.flags.buildrlab.com) */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/** Refresh interval in milliseconds (defaults to 60000ms / 1 minute) */
|
|
11
|
+
refreshInterval?: number;
|
|
12
|
+
/** Initial flags to use before API fetch completes (for SSR) */
|
|
13
|
+
initialFlags?: Record<string, boolean>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Individual flag evaluation result
|
|
17
|
+
*/
|
|
18
|
+
export interface FlagResult {
|
|
19
|
+
flagKey: string;
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Response from the bulk evaluate endpoint
|
|
24
|
+
*/
|
|
25
|
+
export interface BulkEvaluateResponse {
|
|
26
|
+
flags: FlagResult[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* State of the BuildrFlags service
|
|
30
|
+
*/
|
|
31
|
+
export interface BuildrFlagsState {
|
|
32
|
+
/** Map of flag keys to their enabled state */
|
|
33
|
+
flags: Record<string, boolean>;
|
|
34
|
+
/** True while initial flag fetch is in progress */
|
|
35
|
+
isLoading: boolean;
|
|
36
|
+
/** Error message if flag fetch failed */
|
|
37
|
+
error: string | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Injection token for BuildrFlags configuration
|
|
41
|
+
*/
|
|
42
|
+
export declare const BUILDRFLAGS_CONFIG: InjectionToken<BuildrFlagsConfig>;
|
|
43
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,mCAA6D,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA2C/C;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,cAAc,CAAoB,mBAAmB,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@buildrflags/angular",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Angular SDK for BuildrFlags feature flags",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "ngc",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"typecheck": "tsc --noEmit"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@angular/common": ">=17.0.0",
|
|
27
|
+
"@angular/core": ">=17.0.0",
|
|
28
|
+
"rxjs": ">=7.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@angular/common": "^21.1.4",
|
|
32
|
+
"@angular/compiler": "^21.1.4",
|
|
33
|
+
"@angular/compiler-cli": "^21.1.4",
|
|
34
|
+
"@angular/core": "^21.1.4",
|
|
35
|
+
"rxjs": "^7.8.1",
|
|
36
|
+
"typescript": "^5.7.3",
|
|
37
|
+
"vitest": "^4.0.18",
|
|
38
|
+
"zone.js": "^0.16.0"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"angular",
|
|
42
|
+
"feature-flags",
|
|
43
|
+
"buildrflags",
|
|
44
|
+
"flags",
|
|
45
|
+
"toggles"
|
|
46
|
+
],
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "https://github.com/buildrlab/buildrflags.git",
|
|
50
|
+
"directory": "sdks/angular"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://flags.buildrlab.com"
|
|
53
|
+
}
|