JSPM

@flagoff/ts-sdk

1.0.4
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q78109F
  • License MIT

FlagOff - A comprehensive dual-purpose JavaScript SDK for feature flags with client-side and server-side support

Package Exports

  • @flagoff/ts-sdk
  • @flagoff/ts-sdk/react
  • @flagoff/ts-sdk/server
  • @flagoff/ts-sdk/types

Readme

Flagoff TypeScript SDK

[!WARNING]
This SDK is in the early stages of development and supports our feature flag product, which is currently in a private early access mode.

You will need an account to use this SDK, which is not yet publicly available.

Interested in trying it out? Please email us at hello@flagoff.io to request access!

Flagoff is a powerful and resilient feature flagging SDK for TypeScript applications. It is designed to be framework-agnostic, with first-class support for React, and provides robust offline capabilities to ensure your application remains stable and performant even when network connectivity is lost.

This SDK is designed for both client-side (browser) and server-side (Node.js) environments.

Features

  • Robust Offline Mode: Continue to function seamlessly using a local cache if your services, including the Flagoff service, are unavailable.
  • Automatic Recovery: A smart polling mechanism with exponential backoff automatically reconnects and fetches the latest flags when your services come back online.
  • Framework Agnostic: Use it in any JavaScript or TypeScript project, with a dedicated React package for ease of use.
  • Server-Side & Client-Side Support: Unified API for both browser and Node.js environments.
  • Local Evaluation: Evaluate flags locally without needing a network request every time, keeping your customer data private and secure.
  • Secure: Uses JWKS for verifying the integrity of feature flags.

Installation

npm install @flagoff/ts-sdk

or

yarn add @flagoff/ts-sdk

Quick Start

Here is the quickest way to get started in any client-side JavaScript project. For framework-specific guides and runnable examples, see the sections below.

import { FeatureFlagsClient } from '@flagoff/ts-sdk';
import type { ClientSDKConfig } from '@flagoff/ts-sdk';

const FLAGOFF_CONFIG: ClientSDKConfig = {
  apiKey: 'YOUR_API_KEY_HERE',
  offlineMode: 'cache-only',
};

const client = new FeatureFlagsClient(FLAGOFF_CONFIG);

async function startApp() {
  // The initialise method handles the connection, offline fallback, and auto-recovery.
  await client.initialize();

  // Evaluate a specific flag
  const darkModeFlag = await client.evaluateFlag('dark-mode', 'user-123', {});

  if (darkModeFlag.enabled) {
    document.body.classList.add('dark');
  }
}

startApp();

Real-time updates on flags

import { FeatureFlagsClient } from '@flagoff/ts-sdk';
import type { ClientSDKConfig } from '@flagoff/ts-sdk/types';

const FLAGOFF_CONFIG: ClientSDKConfig = {
  apiKey: 'YOUR_API_KEY_HERE',
  offlineMode: 'cache-only',
};

const client = new FeatureFlagsClient(FLAGOFF_CONFIG);

async function startApp() {
  // The initialise method handles the connection, offline fallback, and auto-recovery.
  await client.initialize();
  // listen on event flagsUpdated, do something with the data...
  client.on('flagsUpdated', (event: FlagsUpdatedEvent) => {
    console.log('Flags updated:', event);
  });
}

Framework & Environment Guides

React

Flagoff provides a dedicated package with hooks to make integration seamless.

1. Wrap Your App with the Provider

In your main application file (e.g., App.tsx), import the FeatureFlagsProvider and wrap your application.

// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {
  FeatureFlagsProvider,
  FeatureFlagsClient,
} from '@flagoff/ts-sdk';
import type { ClientSDKConfig } from '@flagoff/ts-sdk/types';

const FLAGOFF_CONFIG: ClientSDKConfig = {
  apiKey: 'YOUR_API_KEY_HERE',
  offlineMode: 'cache-only',
};


const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <FeatureFlagsProvider config={FLAGOFF_CONFIG}>
      <App />
    </FeatureFlagsProvider>
  </React.StrictMode>,
);

2. Use the useFeatureFlag Hook

In any component, you can now use the useFeatureFlag hook to get the value of a flag.

// src/components/MyComponent.tsx
import { useFeatureFlag } from '@flagoff/ts-sdk/react';

function MyComponent() {
  const { enabled, value } = useFeatureFlag('new-homepage-design', {
    identifier: 'user-123',
    traits: { premium: true }
  });

  if (enabled) {
    return <h1>Welcome to the new {value} design!</h1>;
  }

  return <h1>Welcome to the classic homepage.</h1>;
}

Vue.js

There's no direct support for Vue as of yet. However, here's some steps you could take until Vue is supported!

You can integrate the Flagoff client into your Vue application using the Composition API.

It is best practice to create a single, shared instance of the Flagoff client for your entire application. You can export this from a dedicated file and initialise it when your app starts.

// src/services/flagoffClient.ts
import { FeatureFlagsClient } from '@flagoff/ts-sdk';
import type { ClientSDKConfig } from '@flagoff/ts-sdk';

export const client = new FeatureFlagsClient({
  apiKey: 'YOUR_API_KEY_HERE',
  offlineMode: 'cache-only',
});

// Initialise the client when your app starts.
client.initialize();

2. Use in a Component

Now you can import the client into any Vue component and use it to evaluate flags within the onMounted lifecycle hook.

<!-- src/components/MyComponent.vue -->
<script setup>
import { ref, onMounted } from 'vue';
import { client } from '../services/flagoffClient'; // Import the singleton client

const newDesign = ref({ enabled: false, value: 'classic' });
const loading = ref(true);

onMounted(async () => {
  loading.value = true;
  const flag = await client.evaluateFlag('new-homepage-design', 'user-123', {});
  newDesign.value = flag;
  loading.value = false;
  
  // Optional: Listen for real-time updates to keep the UI fresh
  client.on('flagsUpdated', async () => {
    const updatedFlag = await client.evaluateFlag('new-homepage-design', 'user-123', {});
    newDesign.value = updatedFlag;
  });
});
</script>

<template>
  <div v-if="loading">Loading...</div>
  <div v-else>
    <h1 v-if="newDesign.enabled">Welcome to the new {{ newDesign.value }} design!</h1>
    <h1 v-else>Welcome to the classic homepage.</h1>
  </div>
</template>

Node.js (Server-Side)

The server-side SDK has the same API but is optimised for a Node.js environment.

import { FeatureFlagsServer } from '@flagoff/ts-sdk/server';
import type { ServerSDKConfig } from '@flagoff/ts-sdk/types';

const config: ServerSDKConfig = {
  apiKey: 'YOUR_SERVER_API_KEY_HERE',
  // Server SDK defaults to in-memory storage.
};

const serverClient = new FeatureFlagsServer(config);

async function main() {
  await serverClient.initialize();

  console.log('Flagoff Server SDK is ready.');

  const allFlags = await serverClient.getAllFlags();
  console.log(allFlags);
}

main();

You can find working examples in examples directory.


Configuration

The SDK is initialised with a configuration object. The same base configuration is used for both the client and server SDKs.

Option Type Required Default Description
apiKey string Yes N/A Your unique API key for authenticating with the Flagoff service.
baseUrl string No https://api.flagoff.io The base URL for the feature flag API server.
wsUrl string No wss://api.flagoff.io The URL for the WebSocket server for real-time flag updates.
offlineMode 'fail' | 'cache-only' No 'cache-only' Defines the SDK's behaviour on initial connection failure. See Offline Behaviour for details.
enableCaching boolean No true Whether to cache flags in local storage (or memory for server).
cacheValidityMs number No 300000 (5 minutes) The duration in milliseconds for which the cache is considered valid.
enableWebSocket boolean No true Whether to connect to the WebSocket server for real-time updates.
pollingInterval number No 60000 (1 minute) The base interval in milliseconds for the auto-recovery poller to attempt reconnection after a network failure. The interval increases with each attempt (exponential backoff).
maxPollingAttempts number No 5 The maximum number of times the auto-recovery poller will attempt to reconnect before stopping.
jwksUrl string No /.well-known/jwks.json path on baseUrl The URL to fetch the JSON Web Key Set (JWKS) for verifying flag tokens.
enableLocalEvaluation boolean No true Whether to perform flag evaluation locally based on cached flag rules. If false, a network request is made for every evaluation.
defaultUserId string No anonymous A default user ID to use in evaluations when no identifier is provided.
retryAttempts number No 3 The number of times to retry failed HTTP requests.
webSocketTimeout number No 10000 (10 seconds) The timeout in milliseconds for establishing a WebSocket connection.

Offline Behaviour & Caching

The SDK is designed to be highly resilient to network failures. This behaviour is primarily controlled by the offlineMode configuration option.

offlineMode: 'cache-only' (Default)

  • On Startup: The SDK will first attempt to connect to the Flagoff servers.
  • If Connection Fails:
    1. It will attempt to load flags from its local cache.
    2. If a valid cache exists, the SDK will initialise with these cached flags, and your application will function normally. In the background, it will start the auto-recovery poller to try and reconnect.
    3. If no cache exists, the SDK will initialise in a "dormant" state with no flags. It will not make any further network requests until the application is reloaded.
  • Auto-Recovery: When the poller successfully reconnects, it fetches the latest flags, updates the cache, and re-establishes a WebSocket connection for real-time updates.

offlineMode: 'fail'

  • On Startup: The SDK will attempt to connect to the Flagoff servers.
  • If Connection Fails: The initialize() method will throw an error. Your application is responsible for catching this error and handling the failure state. The SDK will not use any cache or attempt to reconnect.

API Reference

client.initialize(): Promise<void>

The main method to start the SDK. It handles the initial connection, offline fallback logic, and starts the auto-recovery poller if needed. You should always call this before attempting to get flags.

client.evaluateFlag(key: string, defaultValue: any, context?: EvaluationContext): Promise<FeatureFlag>

Evaluates a single flag based on the provided context.

  • key: The name of the flag.
  • defaultValue: The value to return if the flag is disabled, not found, or the SDK is not initialised.
  • context: An optional object containing an identifier (e.g., user ID) and a traits object for evaluation.

client.getFlag(key: string): Promise<FeatureFlag | null>

Retrieves a flag's definition from the cache without performing an evaluation. Returns null if the flag is not found in the cache.

client.getAllFlags(): Promise<Record<string, FeatureFlag>>

Returns all flags currently held in the SDK's memory.

client.on(event: string, callback: (payload: any) => void)

Listen to events emitted by the SDK.

  • connected: Fired when the SDK successfully initialises online.
  • flagsUpdated: Fired when flags are updated (e.g., via WebSocket).

Examples

Runnable examples for both client-side and server-side usage can be found in the /src/examples directory of this repository.

You can run these examples directly using tsx:

# Make sure to add your API key to the example file first
npx tsx src/examples/client/index.ts
npx tsx src/examples/server/index.ts

Licence

This SDK is licenced under the MIT Licence.