npm package: @switchflag/sdk
Description: Lightweight feature flag SDK for Node.js and edge runtimes. Evaluate flags locally with zero runtime dependencies.
Author: Thomas Blaymire
Latest version: 0.2.0

# @switchflag/sdk

[![npm version](https://img.shields.io/npm/v/@switchflag/sdk)](https://www.npmjs.com/package/@switchflag/sdk)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@switchflag/sdk)](https://bundlephobia.com/package/@switchflag/sdk)
[![license](https://img.shields.io/npm/l/@switchflag/sdk)](https://github.com/thomasblaymire/switchflag/blob/main/LICENSE)

Lightweight feature flag SDK for Node.js and edge runtimes. Evaluate flags locally with **zero runtime dependencies**.

## Install

```bash
npm install @switchflag/sdk
```

```bash
pnpm add @switchflag/sdk
```

```bash
yarn add @switchflag/sdk
```

## Quick Start

### Client API

Create a client instance for full control over flag evaluation.

```typescript
import { createClient } from '@switchflag/sdk'

const client = createClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.switchflag.dev', // optional, this is the default
})

const result = await client.getFlag<boolean>('dark-mode', {
  userId: 'user-123',
  attributes: { plan: 'pro', country: 'US' },
})

if (result.value) {
  // Feature is enabled
}
```

### Convenience API

Use the module-level API for simpler usage. Call `init()` once at startup, then use `getFlag()` anywhere.

```typescript
import { getFlag } from '@switchflag/sdk'
import { init } from '@switchflag/sdk'

// Call once at startup
init('your-api-key')

// Use anywhere
const result = await getFlag<boolean>('dark-mode', {
  userId: 'user-123',
  attributes: { plan: 'pro' },
})
```

### Edge Runtime

For Vercel Edge Functions, Cloudflare Workers, and other edge runtimes:

```typescript
import { evaluateAtEdge } from '@switchflag/sdk/edge'

export default async function middleware(request: Request) {
  const result = await evaluateAtEdge<boolean>({ apiKey: 'your-api-key' }, 'new-landing-page', {
    userId: request.headers.get('x-user-id') ?? 'anonymous',
    attributes: {
      country: request.headers.get('x-country') ?? 'unknown',
    },
  })

  if (result.value) {
    return Response.redirect('/new-landing')
  }
}
```

## API Reference

### `createClient(config)`

Creates a Switchflag client instance with built-in caching.

| Parameter        | Type     | Required | Description                                          |
| ---------------- | -------- | -------- | ---------------------------------------------------- |
| `config.apiKey`  | `string` | Yes      | Your Switchflag API key                              |
| `config.baseUrl` | `string` | No       | API base URL (default: `https://api.switchflag.dev`) |

Returns a `SwitchflagClient` with:

- **`getFlag<T>(key, context)`** — Evaluate a flag. Returns `EvaluationResult<T>`.

### `init(apiKey, baseUrl?)`

Initialize the module-level client. Call once at application startup.

### `getFlag<T>(key, context)`

Evaluate a flag using the module-level client. Throws if `init()` hasn't been called.

### `evaluateAtEdge<T>(config, key, context)`

Evaluate a flag in an edge runtime. Uses `fetch` with edge-optimized caching.

Import from `@switchflag/sdk/edge`.

### `EvaluationContext`

```typescript
interface EvaluationContext {
  userId: string
  attributes?: Record<string, string | number | boolean | string[]>
}
```

### `EvaluationResult<T>`

```typescript
interface EvaluationResult<T> {
  value: T
  reason: 'match' | 'default' | 'disabled' | 'not_found'
}
```

## How Evaluation Works

1. The SDK fetches flag configuration from the Switchflag API
2. Rules are evaluated locally against the provided context
3. The first matching rule determines the returned value
4. If no rules match, the flag's default value is returned

All evaluation logic runs in your application — no user data is sent to Switchflag servers beyond the initial flag configuration fetch.

## License

MIT