npm package: @pl4yzonellc/valar-ui-connector
Description: Reusable Angular library for loading and reading feature flags (`boolean`, `string`, `number`) with: - Strictly typed flag models per app - Startup loading via `APP_INITIALIZER` - Default fallback behavior on HTTP errors
Latest version: 0.0.2

# valar-ui-connector

Reusable Angular library for loading and reading feature flags (`boolean`, `string`, `number`) with:
- Strictly typed flag models per app
- Startup loading via `APP_INITIALIZER`
- Default fallback behavior on HTTP errors

## Public API

```ts
import {
  FeatureFlagsService,
  FeatureFlagsConfig,
  FEATURE_FLAGS_CONFIG,
  provideFeatureFlags
} from '@pl4yzonellc/valar-ui-connector';
```

## Consumer Setup

1. Define app-specific flags and defaults:

```ts
// app-feature-flags.model.ts
export interface AppFeatureFlags {
  showConsultationForm: boolean;
  uiTheme: string;
  maxItems: number;
}

export const APP_DEFAULT_FEATURE_FLAGS: AppFeatureFlags = {
  showConsultationForm: false,
  uiTheme: 'light',
  maxItems: 20,
};
```

2. Register providers in `AppModule`:

```ts
import { NgModule } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideFeatureFlags } from '@pl4yzonellc/valar-ui-connector';
import { environment } from '../environments/environment';
import { AppFeatureFlags, APP_DEFAULT_FEATURE_FLAGS } from './app-feature-flags.model';

@NgModule({
  providers: [
    provideHttpClient(),
    ...provideFeatureFlags<AppFeatureFlags>({
      endpoint: `${environment.baseURL}/feature-flags/tenant_${environment.tenantId}`,
      defaults: APP_DEFAULT_FEATURE_FLAGS,
      // optional:
      // httpOptions: { withCredentials: true, headers: { ... } }
      // map nested payloads, e.g. { uiOptions: {...} }:
      // mapResponse: (response) => (response as { uiOptions?: Partial<AppFeatureFlags> })?.uiOptions
    }),
  ],
})
export class AppModule {}
```

3. Use the service anywhere:

```ts
import { Injectable } from '@angular/core';
import { FeatureFlagsService } from '@pl4yzonellc/valar-ui-connector';
import { AppFeatureFlags } from './app-feature-flags.model';

@Injectable({ providedIn: 'root' })
export class ExampleService {
  constructor(private readonly flags: FeatureFlagsService<AppFeatureFlags>) {}

  canShowConsultationForm(): boolean {
    return this.flags.isEnabled('showConsultationForm');
  }
}
```

Use `isEnabled(...)` for boolean keys and `getFlag(...)` for any typed value:

```ts
const enabled = this.flags.isEnabled('showConsultationForm'); // boolean
const theme = this.flags.getFlag('uiTheme'); // string
const maxItems = this.flags.getFlag('maxItems'); // number
```

## Migration from local `FeatureFlagService`

Use this when an app already has a local service such as
`src/app/tenant/backend-services/feature-flag.service.ts`.

1. Create a typed model and defaults:

```ts
// src/app/feature-flags.model.ts
export interface AppFeatureFlags {
  showConsultationForm: boolean;
}

export const APP_DEFAULT_FEATURE_FLAGS: AppFeatureFlags = {
  showConsultationForm: false,
};
```

2. Replace local `APP_INITIALIZER` wiring with library provider:

Before:
```ts
providers: [
  {
    provide: APP_INITIALIZER,
    useFactory: initializeFeatureFlags,
    deps: [FeatureFlagService],
    multi: true,
  }
]
```

After:
```ts
import { provideFeatureFlags } from '@pl4yzonellc/valar-ui-connector';
import { APP_DEFAULT_FEATURE_FLAGS, AppFeatureFlags } from './feature-flags.model';
import { environment } from '../environments/environment';

providers: [
  ...provideFeatureFlags<AppFeatureFlags>({
    endpoint: `${environment.baseURL}/feature-flags/tenant_${environment.tenantId}`,
    defaults: APP_DEFAULT_FEATURE_FLAGS,
  }),
]
```

3. Replace service imports and injection:

Before:
```ts
import { FeatureFlagService } from 'src/app/tenant/backend-services/feature-flag.service';
```

After:
```ts
import { FeatureFlagsService } from '@pl4yzonellc/valar-ui-connector';
import { AppFeatureFlags } from 'src/app/feature-flags.model';
```

Inject:
```ts
constructor(private readonly flags: FeatureFlagsService<AppFeatureFlags>) {}
```

4. Replace old method calls:
- `getFlags()` -> `getAll()`
- `getFlagByKey('showConsultationForm')` -> `getFlag('showConsultationForm')`
- `isEnabled('showConsultationForm')` remains supported

5. Remove local `FeatureFlagService` and initializer factory after app compiles.

## Behavior

- On app startup, `loadFlags()` is called once through `APP_INITIALIZER`.
- Successful response values are merged with defaults.
- If the HTTP request fails, defaults are kept and a warning is logged.

## Endpoint Contract

`GET <endpoint>` should return a partial flag object. Example:

```json
{
  "showConsultationForm": true
}
```

Unknown keys are ignored by your app if they are not part of the typed flag model.

## Build

```bash
ng build valar-ui-connector
```

## Test

```bash
ng test valar-ui-connector
```