npm package: @flagged/sdk
Description: Feature flag SDK for React and React Native — by Flagged
Latest version: 0.1.0

# @flagged/sdk

Feature flag SDK for **React** and **React Native** applications.

## Installation

```bash
# npm
npm install @flagged/sdk

# yarn
yarn add @flagged/sdk

# pnpm
pnpm add @flagged/sdk
```

### React Native (additional setup)

Install the required storage dependency:

```bash
npm install @react-native-async-storage/async-storage
# or
yarn add @react-native-async-storage/async-storage
```

For iOS, run `npx pod-install` after installation.

## Quick Start

### React

```tsx
import { FlagProvider, useFlag, useFlagData } from "@flagged/sdk";

function App() {
  return (
    <FlagProvider
      apiKey="your-sdk-key"
      projectId="your-project-id"
      baseUrl="https://api.flagged.dev"
      version="1.0.0"
      attributes={{ user_id: "user-123", plan: "premium" }}
    >
      <MyComponent />
    </FlagProvider>
  );
}

function MyComponent() {
  const isEnabled = useFlag("new-feature");
  const flagData = useFlagData("new-feature");

  return (
    <div>
      <p>Feature enabled: {isEnabled ? "Yes" : "No"}</p>
      {flagData && <pre>{JSON.stringify(flagData, null, 2)}</pre>}
    </div>
  );
}
```

### React Native

The same API works in React Native — the SDK automatically uses `AsyncStorage` for caching:

```tsx
import { FlagProvider, useFlag, useFlags } from "@flagged/sdk";
import { View, Text, TouchableOpacity } from "react-native";

function App() {
  return (
    <FlagProvider
      apiKey="your-sdk-key"
      projectId="your-project-id"
      baseUrl="https://api.flagged.dev"
      version="1.0.0"
      attributes={{ platform: "react-native" }}
    >
      <MyScreen />
    </FlagProvider>
  );
}

function MyScreen() {
  const isEnabled = useFlag("new-feature");
  const { identify, refresh } = useFlags();

  const handleLogin = (userId: string) => {
    identify({
      key: userId,
      attributes: { plan: "pro" },
    });
  };

  return (
    <View>
      <Text>Feature: {isEnabled ? "ON" : "OFF"}</Text>
      <TouchableOpacity onPress={refresh}>
        <Text>Refresh Flags</Text>
      </TouchableOpacity>
    </View>
  );
}
```

## API Reference

### `<FlagProvider>`

Wraps your app and provides flag context to all children.

| Prop              | Type                                 | Default    | Description                         |
| ----------------- | ------------------------------------ | ---------- | ----------------------------------- |
| `apiKey`          | `string`                             | _required_ | Your Flagged SDK key                |
| `projectId`       | `string`                             | _required_ | Your project ID                     |
| `version`         | `string`                             | —          | App version for version-based rules |
| `attributes`      | `Record<string, string \| string[]>` | —          | Context attributes for targeting    |
| `pollingInterval` | `number`                             | `30000`    | Auto-refresh interval (ms)          |
| `enablePolling`   | `boolean`                            | `true`     | Enable automatic polling            |
| `baseUrl`         | `string`                             | —          | API base URL                        |
| `onFlagsLoaded`   | `(flags) => void`                    | —          | Callback when flags load            |
| `onError`         | `(error) => void`                    | —          | Callback on error                   |

### Hooks

| Hook                     | Returns                   | Description                                          |
| ------------------------ | ------------------------- | ---------------------------------------------------- |
| `useFlag(key, default?)` | `boolean`                 | Get a single flag's boolean value                    |
| `useFlagData(key)`       | `FlagData \| null`        | Get full flag data (attributes, version rules, etc.) |
| `useMultipleFlags(keys)` | `Record<string, boolean>` | Get multiple flags at once                           |
| `useFlags()`             | `FlagContextType`         | Access full context (flags, refresh, identify, etc.) |

### `useFlags()` Context

```ts
{
  flags: FlagResults;             // Full flag data map
  booleanFlags: Record<string, boolean>;  // Simple boolean map
  refresh: () => Promise<void>;   // Force refresh from server
  isLoading: boolean;
  error: Error | null;
  getFlagData: (name: string) => FlagData | null;
  identify: (payload: IdentifyPayload) => void;
}
```

### `identify()`

Associate a user for gradual rollout evaluation:

```ts
const { identify } = useFlags();

identify({
  key: "user-42", // Primary user identifier
  identifiers: { orgId: "org-99" }, // Additional identifiers
  attributes: { plan: "pro" }, // Supplemental attributes
});
```

### `FlagClient` (Advanced)

For non-React usage or custom integrations:

```ts
import { FlagClient } from "@flagged/sdk";

const client = new FlagClient("your-sdk-key", "your-project-id", {
  baseUrl: "https://api.flagged.dev",
  version: "1.0.0",
});

const flags = await client.evaluateFlags();
const flag = await client.evaluateFlag("my-flag");
```

## Platform Support

| Platform     | Storage                                         | Resolution              |
| ------------ | ----------------------------------------------- | ----------------------- |
| React (Web)  | `localStorage`                                  | `main` / `module` field |
| React Native | `AsyncStorage` (in-memory sync + async persist) | `react-native` field    |

The SDK automatically detects the platform and uses the appropriate storage backend. No configuration needed.