npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flagforge/sdk-js

v0.3.0

Published

FlagForge JavaScript/TypeScript SDK — local evaluation + real-time streaming

Readme

@flagforge/sdk-js

JavaScript/TypeScript SDK for FlagForge — feature flag evaluation with local (server) or remote (client) modes and real-time config streaming.

For React apps, use @flagforge/sdk-react instead.

Install

npm install @flagforge/sdk-js
# or
pnpm add @flagforge/sdk-js
# or
yarn add @flagforge/sdk-js

You need a running FlagForge server and an SDK key for your environment.

Quick start

Server-side (Node.js) — local evaluation

Use a server key (srv_...). The SDK downloads flag config and evaluates locally (fast, no per-flag HTTP calls).

import { FlagForgeClient } from "@flagforge/sdk-js";

const client = new FlagForgeClient({
  serverKey: process.env.FLAGFORGE_SERVER_KEY!,
  baseUrl: "http://localhost:8080",
  context: { targetingKey: "user-123" },
  streaming: true, // SSE updates (default for server keys)
});

await client.init();

const result = await client.evaluate("new-checkout", {
  targetingKey: "user-123",
  attributes: { plan: "pro" },
});

console.log(result.value);  // true | false | string | number | object
console.log(result.reason); // why that value was chosen

Client-side (browser) — remote evaluation

Use a client key (cli_...). Evaluation runs on the FlagForge server; rules are not shipped to the client.

import { FlagForgeClient } from "@flagforge/sdk-js";

const client = new FlagForgeClient({
  clientKey: "cli_your_key_here",
  baseUrl: "http://localhost:8080",
});

await client.init();

const enabled = await client.getBooleanValue("new-checkout", false, {
  targetingKey: "user-123",
});

Configuration

interface FlagForgeConfig {
  serverKey?: string;           // srv_... — Node.js / trusted servers only
  clientKey?: string;           // cli_... — browsers / untrusted clients
  baseUrl?: string;             // default: http://localhost:8080
  context?: EvaluationContext;  // default context for all evaluations
  streaming?: boolean;          // SSE updates (default: true for server keys)
  pollingInterval?: number;     // fallback poll interval in ms (default: 30000)
  heartbeatIntervalMs?: number; // SDK heartbeat (default: 30000)
  sdkInstanceId?: string;       // stable instance id for connection tracking
  runtime?: string;             // e.g. node, browser, edge
  sdkVersion?: string;          // sent with heartbeat (default: package version)
  rateLimitMaxRetries?: number; // retries on HTTP 429 (default: 3)
  onRateLimited?: (info: { retryAfterMs: number; attempt: number }) => void;
  onReady?: () => void;
  onError?: (error: Error) => void;
  onUpdate?: (config: FlagsConfig) => void;
}

Evaluation

// Single flag
const result = await client.evaluate("flag-key", context, defaultValue);

// Typed helpers
const bool = await client.getBooleanValue("flag-key", false, context);
const str = await client.getStringValue("flag-key", "default", context);
const num = await client.getNumberValue("flag-key", 0, context);

// Batch
const results = await client.evaluateBatch(
  [
    { flagKey: "feature-a", defaultValue: false },
    { flagKey: "feature-b", defaultValue: "control" },
  ],
  context,
);

Evaluation context:

interface EvaluationContext {
  targetingKey?: string;              // user id for overrides / rollouts
  attributes?: Record<string, unknown>;
}

Evaluation result:

interface EvaluationResult {
  flagKey: string;
  value: unknown;
  variantKey?: string;
  reason: EvaluationReason;
}

Real-time updates (server keys)

With streaming: true, the client subscribes to SSE config changes and re-evaluates automatically when flags change.

The server sends delta updates (config_delta events) when only a few flags changed, and falls back to a full config event when needed (e.g. subscriber lag or version mismatch). The SDK:

  • Validates from_version against the local snapshot; fetches full config on mismatch
  • Deduplicates events using monotonic seq numbers
  • Resets sequence tracking after a full config reload
const client = new FlagForgeClient({
  serverKey: "srv_...",
  baseUrl: "http://localhost:8080",
  streaming: true,
  sdkInstanceId: "my-service-pod-1", // optional — for heartbeat visibility
  runtime: "node",
  onUpdate: (config) => {
    console.log("Config version:", config.version);
  },
});

await client.init();

Heartbeat (connection visibility)

All SDK keys send periodic heartbeats to POST /api/v1/heartbeat so the control plane can show active SDK instances. Heartbeats are best-effort and never block evaluation.

Rate limiting

Evaluation and config endpoints may return HTTP 429 when per-SDK-key limits are exceeded. The SDK retries with backoff (honoring Retry-After when present):

const client = new FlagForgeClient({
  serverKey: "srv_...",
  rateLimitMaxRetries: 3,
  onRateLimited: ({ retryAfterMs, attempt }) => {
    console.warn(`Rate limited, retry ${attempt} in ${retryAfterMs}ms`);
  },
});

Next.js

| Environment | Key | Package | |-------------|-----|---------| | Client components | cli_... | @flagforge/sdk-react (recommended) or this package | | Server Components / API routes | srv_... | @flagforge/sdk-js with server-only env vars |

Never put srv_... keys in NEXT_PUBLIC_* variables.

API endpoints used

| Method | Path | Auth | |--------|------|------| | GET | /api/v1/flags-config | SDK key | | POST | /api/v1/evaluate | SDK key | | POST | /api/v1/evaluate/batch | SDK key | | GET | /api/v1/stream | SDK key (server keys) — config + config_delta SSE events | | POST | /api/v1/heartbeat | SDK key |

Standalone evaluator

For testing or offline evaluation with a config snapshot:

import { Evaluator } from "@flagforge/sdk-js";

const evaluator = new Evaluator();
evaluator.update(flagsConfig);

const result = evaluator.evaluate("my-flag", { targetingKey: "user-1" });

Related

License

MIT