npm package: @featureflare/sdk-js
Description: JavaScript/TypeScript SDK for FeatureFlare feature flags.
Latest version: 0.0.144

# @featureflare/sdk-js

JavaScript/TypeScript SDK for FeatureFlare feature flags.

## Installation

```bash
npm install @featureflare/sdk-js
# or
pnpm add @featureflare/sdk-js
# or
yarn add @featureflare/sdk-js
```

## Usage

### Basic Example

```typescript
import { FeatureFlareClient } from '@featureflare/sdk-js';

// SDK automatically uses production API URL
// Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey explicitly
const featureflare = new FeatureFlareClient({
  sdkKey: 'your-sdk-key-here'
});

const enabled = await featureflare.bool('new-nav', { id: 'user-123' }, false);
console.log(enabled);

const detailed = await featureflare.evaluate('new-nav', { id: 'user-123' }, false);
console.log(detailed.value, detailed.metadata.reason, detailed.metadata.source);
```

### Environment Variables

The SDK automatically reads from environment variables if `sdkKey` is not provided:

- `FEATUREFLARE_CLIENT_KEY` - Client SDK key (for browser/mobile)
- `FEATUREFLARE_SERVER_KEY` - Server SDK key (for backend)
- `FEATUREFLARE_ENV_KEY` - Expected environment key binding (`development`, `staging`, `production`, etc.)

```typescript
// In Node.js, this will use FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY from env
const featureflare = new FeatureFlareClient();
```

### Resilience options (cache/retry/timeout/bootstrap)

```typescript
const featureflare = new FeatureFlareClient({
  sdkKey: 'featureflare_cli_...',
  timeoutMs: 3000,
  maxRetries: 2,
  backoffMs: 200,
  jitter: 0.25,
  cacheTtlMs: 60_000,
  staleTtlMs: 10_000,
  bootstrap: {
    flags: { 'new-nav': true },
    killSwitches: ['dangerous-flow']
  },
  realtime: {
    // optional: enabled defaults to true (SSE primary, polling fallback)
    // optional: hidden tabs disconnect by default and reconnect on visibility restore
    pollingIntervalMs: 15_000,
    ssePath: '/api/v1/sdk/stream'
  }
});
```

- Cache-first evaluation order: fresh cache → stale cache (+ async revalidate) → bootstrap/persistent cache → default.
- `bool(...)` and `evaluate(...)` are outage-safe and return deterministic defaults for expected network failures.
- Hard kill switches have highest precedence and return `false` even when the API is unreachable.
- Realtime updates are enabled by default: SSE is primary transport; polling is used automatically as fallback when SSE is unavailable.
- In browser runtimes, hidden tabs disconnect the realtime stream by default and reconnect with a fresh authenticated stream request when the tab becomes visible again.

To explicitly disable realtime updates:

```typescript
const featureflare = new FeatureFlareClient({
  sdkKey: 'featureflare_cli_...',
  realtime: { enabled: false }
});
```

### API Base URL

The SDK automatically determines the API base URL:

- **`options.apiBaseUrl`**: Highest priority if provided.
- **Environment variables**: `FEATUREFLARE_API_BASE_URL`, then `SHIPIT_API_BASE_URL`.
- **Default fallback (all runtimes)**: `https://api.featureflare.com`.

Example override:

```typescript
const featureflare = new FeatureFlareClient({
  apiBaseUrl: 'https://flags.your-company.com',
  sdkKey: 'featureflare_cli_...'
});
```

### User Payload

```typescript
import { FeatureFlareClient, type FeatureFlareUserPayload } from '@featureflare/sdk-js';

const user: FeatureFlareUserPayload = {
  id: 'user-123',        // Required: unique user identifier
  email: 'user@example.com',
  name: 'John Doe',
  country: 'US',
  meta: {                // Custom attributes for targeting
    companyId: 'acme',
    plan: 'pro'
  }
};

const enabled = await featureflare.bool('feature-flag', user, false);
```

## API Reference

### `FeatureFlareClient`

#### Constructor

```typescript
new FeatureFlareClient(options?: FeatureFlareClientOptions)
```

**Options:**

- `apiBaseUrl?: string` - Explicit FeatureFlare API base URL.
- `sdkKey?: string` - SDK key (client or server). If not provided, reads from `FEATUREFLARE_CLIENT_KEY` or `FEATUREFLARE_SERVER_KEY` env vars.
- `projectKey?: string` - Legacy: project key (requires `envKey`). Not recommended.
- `envKey?: string` - Environment key (default: `'production'`). Only used with `projectKey`.

When using `sdkKey`, `envKey` is sent as an expected environment binding. The API rejects requests if the key's actual environment does not match `envKey`.

#### Methods

##### `bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<boolean>`

Evaluates a boolean feature flag for a user.

- `flagKey`: The flag key to evaluate
- `user`: User payload with `id` or `key` (required)
- `defaultValue`: Default value if evaluation fails (default: `false`)

Returns `Promise<boolean>` - The flag value for the user.

##### `evaluate(flagKey: string, user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<{ value: boolean; metadata: ... }>`

Evaluates a flag with diagnostics metadata:

- `reason`: `fresh_cache | stale_cache | bootstrap | default | network | kill_switch`
- `isStale`
- `latencyMs`
- `source`, `updatedAt`, `staleAt`, `expiresAt`

**Example:**

```typescript
const enabled = await featureflare.bool('new-nav', { id: 'user-123' }, false);
```

##### `flags(user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<Record<string, boolean>>`

Fetches all boolean flags for the provided user.

- `user`: User payload with `id` or `key` (required)
- `defaultValue`: Default value to apply for missing/offline evaluations (default: `false`)

Returns `Promise<Record<string, boolean>>` - A map of `flagKey -> value`.

**Example:**

```typescript
const allFlags = await featureflare.flags({ id: 'user-123' }, false);
```

## Error Handling

`bool(...)` and `evaluate(...)` are non-throwing for expected outage/network states. If the API request fails, the SDK falls back to stale/bootstrap/persistent/default values deterministically.

```typescript
const enabled = await featureflare.bool('flag', user, false);
```

## SDK Keys

Each environment has two SDK keys:

- **Server key**: Secret. Use only in trusted server environments.
- **Client key**: Not a secret. Intended for browser/mobile SDKs.

Get your SDK keys from your FeatureFlare Console → Environments.

## Security: Client-side flags are not authorization

Client keys can be extracted from your frontend bundle. **Never gate truly sensitive operations solely with client-evaluated flags**—enforce authorization on your backend. Use client keys for non-sensitive UI toggles (e.g. feature visibility, A/B tests). For access control, billing gates, or data protection, always validate on the server.

## License

MIT