Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/dull-kings-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@flags-sdk/flagsmith': major
'flags': minor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to make a new release of the flags package

Suggested change
'flags': minor
-'flags': minor

---

Adds Flagsmith Adapter
4 changes: 4 additions & 0 deletions packages/adapter-flagsmith/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: [require.resolve('@pyra/eslint-config/components')],
};
2 changes: 2 additions & 0 deletions packages/adapter-flagsmith/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.vercel
.env*.local
121 changes: 121 additions & 0 deletions packages/adapter-flagsmith/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Flags SDK - Flagsmith Provider

A provider adapter for the Flags SDK that integrates with [Flagsmith](https://flagsmith.com/), allowing you to use Flagsmith's feature flags and remote configuration in your application.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you work for Flagsmith? If we merge this PR we'd also put up some actual docs on flags-sdk.dev. Would you be wiling to link to our Flags SDK and those docs from https://docs.flagsmith.com?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @dferber90, just jumping in here since Tiago is on vacation - yes, Tiago works for Flagsmith.

In answer to your question, for sure, we'd be happy to link to your docs from https://docs.flagsmith.com - would you be happy with adding reciprocal backlink(s) too?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! We'd add you to https://flags-sdk.dev/providers and create a docs page for FlagSmith


## Installation

```bash
npm install @flags-sdk/flagsmith
```

## Usage

An Environment ID must be provided using the `FLAGSMITH_ENVIRONMENT_ID` environment variable.

```typescript
import { flagsmithAdapter } from '@flags-sdk/flagsmith';
import { flag } from 'flags';

// Boolean flags - returns flagState.enabled
const myBooleanFlag = flag({
key: 'my-boolean-feature',
adapter: flagsmithAdapter.booleanValue(),
});

// String flags - returns flagState.value when enabled
const myStringFlag = flag({
key: 'my-string-feature',
adapter: flagsmithAdapter.stringValue(),
});

// Number flags - returns flagState.value when enabled
const myNumberFlag = flag({
key: 'my-number-feature',
adapter: flagsmithAdapter.numberValue(),
});
```

## API

The adapter provides three methods for different flag types:

### `booleanValue()`

Returns an adapter for boolean flags. Uses `flagState.enabled` directly.

```typescript
const booleanAdapter = flagsmithAdapter.booleanValue();
const value = await booleanAdapter.decide({
key: 'my-flag',
defaultValue: false,
entities: { identifier: 'user-123' },
});
```

### `stringValue()`

Returns an adapter for string flags. Returns `flagState.value` when the flag is enabled, otherwise returns the default value.

```typescript
const stringAdapter = flagsmithAdapter.stringValue();
const value = await stringAdapter.decide({
key: 'my-flag',
defaultValue: 'default',
entities: { identifier: 'user-123' },
});
```

### `numberValue()`

Returns an adapter for number flags. Returns `flagState.value` when the flag is enabled, otherwise returns the default value.

```typescript
const numberAdapter = flagsmithAdapter.numberValue();
const value = await numberAdapter.decide({
key: 'my-flag',
defaultValue: 0,
entities: { identifier: 'user-123' },
});
```

## Identity Handling

The adapter supports Flagsmith identity management. Pass an `IIdentity` object to the `entities` parameter:

```typescript
const identity: IIdentity = {
identifier: 'user-123',
traits: {
email: 'user@example.com',
plan: 'premium',
},
};

const value = await adapter.decide({
key: 'my-flag',
defaultValue: false,
entities: identity,
});
```

## Configuration

The adapter automatically initializes Flagsmith with the following configuration:

- `environmentId`: From `FLAGSMITH_ENVIRONMENT_ID` environment variable

## Features

- **Type-safe flag definitions**: Each method returns a properly typed adapter
- **Automatic initialization**: Flagsmith client can be lazily initialized
- **Identity support**: Full support for Flagsmith identity and traits
- **Default value handling**: Proper fallback to default values when flags are disabled or not found
- **Boolean flag optimization**: Boolean flags use the `enabled` state directly for better performance

## Environment Variables

- `FLAGSMITH_ENVIRONMENT_ID` (required): Your Flagsmith environment ID

## License

MIT
70 changes: 70 additions & 0 deletions packages/adapter-flagsmith/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"name": "@flags-sdk/flagsmith",
"version": "0.1.0",
"description": "Flagsmith provider for the Flags SDK",
"keywords": [
"flags-sdk",
"flagsmith-nodejs",
"vercel",
"feature flags",
"flags"
],
"homepage": "https://flags-sdk.dev",
"bugs": {
"url": "https://github.com/vercel/flags/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vercel/flags.git"
},
"license": "MIT",
"author": "",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.js",
"typesVersions": {
"*": {
".": [
"dist/*.d.ts",
"dist/*.d.cts"
]
}
},
"files": [
"dist",
"CHANGELOG.md"
],
"scripts": {
"build": "rimraf dist && tsup",
"dev": "tsup --watch --clean=false",
"eslint": "eslint-runner",
"eslint:fix": "eslint-runner --fix",
"test": "vitest --run",
"test:watch": "vitest",
"type-check": "tsc --noEmit"
},
"dependencies": {
"flagsmith": "^9.0.5"
},
"devDependencies": {
"@types/node": "20.11.17",
"eslint-config-custom": "workspace:*",
"flags": "workspace:*",
"msw": "2.6.4",
"rimraf": "6.0.1",
"tsconfig": "workspace:*",
"tsup": "8.0.1",
"typescript": "5.6.3",
"vite": "5.1.1",
"vitest": "1.4.0"
},
"publishConfig": {
"access": "public"
}
}
Loading