npm package: @lagarsoft/lgsft-flags
Description: React SDK for lgsft-flags — a self-hosted feature flag system. Wrap your app in FlagProvider and call useFlag() to toggle features per user without redeploying.
Latest version: 0.1.3

# @lagarsoft/lgsft-flags

React SDK for [lgsft-flags](https://github.com/Lagarsoft/lgsft-flags) — a self-hosted feature flag system. Toggle features on or off per user without redeploying.

## How it works

Your React app fetches all flags on mount via `FlagProvider`. The flags are evaluated server-side by the Lagarsoft flags dashboard against targeting rules (user lists, attribute conditions), and returned as a simple `{ flagKey: boolean }` map. No business logic runs in the client.

```
React app  →  FlagProvider mounts
           →  GET {dashboardUrl}/api/flags?userId=alice&attr[plan]=pro
           →  Lagarsoft flags dashboard evaluates rules against DB
           →  returns { 'dark-mode': true, 'new-checkout': false, ... }
           →  useFlag('dark-mode') returns true
```

## Requirements

- React 18 or 19
- A running [Lagarsoft flags dashboard](https://github.com/Lagarsoft/lgsft-flags) with at least one project, environment, and API key

## Installation

```bash
npm install @lagarsoft/lgsft-flags
# or
pnpm add @lagarsoft/lgsft-flags
```

## Quick start

### 1. Wrap your app in `FlagProvider`

```tsx
import { FlagProvider } from '@lagarsoft/lgsft-flags'

export function App() {
  return (
    <FlagProvider
      apiUrl="https://your-Lagarsoft flags dashboard.example.com"
      apiKey="lf_your_api_key_here"
      userContext={{ userId: 'user_123' }}
    >
      <YourApp />
    </FlagProvider>
  )
}
```

### 2. Use flags in any component

```tsx
import { useFlag } from '@lagarsoft/lgsft-flags'

function CheckoutButton() {
  const { value, loading } = useFlag('new-checkout-flow')

  if (loading) return null
  return value ? <NewCheckout /> : <LegacyCheckout />
}
```

## API

### `<FlagProvider>`

Fetches all flags on mount and provides them via React context. Re-fetches when `apiUrl`, `apiKey`, or `userContext.userId` changes.

| Prop | Type | Required | Description |
|---|---|---|---|
| `apiUrl` | `string` | Yes | Base URL of your Lagarsoft flags dashboard |
| `apiKey` | `string` | Yes | API key created in the Lagarsoft flags dashboard |
| `userContext` | `UserContext` | No | User info for targeted flag evaluation |
| `onError` | `(error: Error) => void` | No | Called when the flags fetch fails |
| `children` | `ReactNode` | Yes | Your app tree |

#### `UserContext`

```ts
type UserContext = {
  userId?: string                                    // matched by USER_LIST rules
  attributes?: Record<string, string | number | boolean>  // matched by ATTRIBUTE_MATCH rules
}
```

**Example with attributes:**

```tsx
<FlagProvider
  apiUrl="https://your-Lagarsoft flags dashboard.example.com"
  apiKey="lf_your_api_key_here"
  userContext={{
    userId: currentUser.id,
    attributes: {
      plan: currentUser.plan,        // e.g. 'pro'
      country: currentUser.country,  // e.g. 'US'
      beta: currentUser.isBeta,      // e.g. true
    },
  }}
>
  <App />
</FlagProvider>
```

---

### `useFlag(key, defaultValue?)`

Returns an object with the flag value plus loading and error states.

`defaultValue` (default: `false`) is returned while flags are loading or if the fetch fails.

```tsx
const { value, loading, error } = useFlag('my-feature')
const { value } = useFlag('my-feature', true)  // default to true while loading
```

| Property | Type | Description |
|---|---|---|
| `value` | `boolean` | Flag value, or `defaultValue` while loading / on error |
| `loading` | `boolean` | `true` while the initial fetch is in progress |
| `error` | `Error \| null` | Set if the fetch failed, otherwise `null` |

> **Migration note:** Prior to this version, `useFlag` returned a `boolean` directly. Update existing usages from `const enabled = useFlag('key')` to `const { value: enabled } = useFlag('key')`.

---

### `useFlagContext()`

Returns the full context object, useful when you need loading or error state.

```tsx
const { flags, loading, error } = useFlagContext()

if (loading) return <Spinner />
if (error) return <ErrorBanner />

const isEnabled = flags['my-feature'] ?? false
```

| Property | Type | Description |
|---|---|---|
| `flags` | `Record<string, boolean>` | All flag values for the current user |
| `loading` | `boolean` | `true` while the initial fetch is in progress |
| `error` | `Error \| null` | Set if the fetch failed, otherwise `null` |

## Getting an API key

1. Open your lgsft-flags Lagarsoft flags dashboard
2. Select a project and environment
3. Go to **API Keys** → create a new key
4. Copy the `lf_...` value — it is only shown once

## Targeting rules

The Lagarsoft flags dashboard supports two rule types that are evaluated against the `userContext` you provide:

- **User list** — match specific user IDs or emails (pass `userContext.userId`)
- **Attribute match** — match users based on attribute values (pass `userContext.attributes`)

Rules are evaluated in order; the first match wins. If no rule matches, the flag falls back to its default enabled/disabled state.

## TypeScript

The package ships with full type declarations built with `tsup`. No additional `@types` packages are needed.