@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 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"}
@@ -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"}
@@ -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,6 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ /**
3
+ * Injection token for BuildrFlags configuration
4
+ */
5
+ export const BUILDRFLAGS_CONFIG = new InjectionToken('BuildrFlagsConfig');
6
+ //# sourceMappingURL=types.js.map
@@ -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
+ }