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

@flagdashio/sdk

v0.1.9

Published

FlagDash client SDK for feature flags, remote config, and AI configs

Readme

@flagdashio/sdk

The official FlagDash client SDK for JavaScript and TypeScript. Evaluate feature flags, fetch remote configs, and access AI config files from any JavaScript environment (browser, Node.js, edge runtimes).

Installation

npm install @flagdashio/sdk
# or
pnpm add @flagdashio/sdk
# or
yarn add @flagdashio/sdk

Quick Start

import { FlagDash } from '@flagdashio/sdk';

const client = FlagDash.init({
  sdkKey: 'sk_...',
});

// Evaluate a feature flag
const enabled = await client.flag('new-checkout', undefined, false);

// Fetch a remote config
const pricing = await client.config<{ tier: string }>('pricing');

// Get an AI config file
const agent = await client.aiConfig('agent.md');

Configuration

const client = FlagDash.init({
  sdkKey: 'sk_...',        // Required. Determines the project AND environment.
  baseUrl: 'https://...',  // Your FlagDash instance. Defaults to https://flagdash.io
  refreshInterval: 30000,  // Poll for updates (ms). Defaults to 0 (no polling).
  timeout: 5000,           // Request timeout (ms). Defaults to 5000.
  realtime: true,          // Live updates over SSE. Defaults to false; falls back to polling.
});

There is no environment option. The key you issue is scoped to one project and one environment, so pointing a build at staging means swapping the key, not passing a different string alongside it.

Feature Flags

// Simple boolean flag
const enabled = await client.flag('my-feature');

// With default value
const variant = await client.flag('experiment', undefined, 'control');

// With targeting context
const value = await client.flag('premium-feature', {
  user: { id: 'user_123', plan: 'pro' },
  country: 'US',
});

// All flags at once
const flags = await client.allFlags();

Remote Config

// One config, with a fallback if it is missing
const settings = await client.config('api-settings', { timeout: 5000 });

// Every config at once
const all = await client.allConfigs();

Translations

// Keys are `namespace.key`
const greeting = await client.translation('common.welcome', {
  locale: 'de',
  defaultValue: 'Welcome',
  variables: { name: 'Ada' },
});

// Which locale actually answered, and why
const detail = await client.translationDetail('common.welcome', { locale: 'de' });
detail.value;        // "Willkommen, Ada"
detail.locale;       // "de"
detail.sourceLocale; // set when the value fell back to another locale
detail.reason;       // "match" | "fallback" | "default"

// A whole catalog, cached in memory
const catalog = await client.translations('de', 'common');

Experiments

const context = { user: { id: user.id } };

// null when the context carries no stable identifier to bucket on
const assignment = await client.experiment('checkout-flow-v2', context);
assignment?.variantKey;
assignment?.parameters;

client.trackExperimentMetric({
  experimentKey: 'checkout-flow-v2',
  eventName: 'checkout_completed',
  context,
  value: 42.5,
  properties: { plan: 'pro' },
});

// Metrics buffer in memory and flush in batches. Flush explicitly before a
// controlled shutdown so the last batch is not lost.
await client.flushExperimentEvents();

AI Configs

// Get a single AI config file
const agent = await client.aiConfig('agent.md');
if (agent) {
  console.log(agent.content); // Markdown content
  console.log(agent.file_type); // 'agent' | 'skill' | 'rule'
  console.log(agent.folder); // string | null
}

// With default content fallback
const skill = await client.aiConfig('missing.md', '# Default');

// List all AI configs
const configs = await client.listAiConfigs();

// Filter by type or folder
const skills = await client.listAiConfigs({ fileType: 'skill' });
const toolConfigs = await client.listAiConfigs({ folder: 'tools' });

// Resolve the released version of a config for one user. Pass the user id so a
// staged rollout returns the version that user is entitled to.
const released = await client.aiConfigRelease('agent.md', user.id);

Events

client.on('ready', () => console.log('Client initialized'));
client.on('flags_updated', (flags) => console.log('Flags changed', flags));
client.on('ai_config_updated', () => console.log('AI configs changed'));
client.on('error', (err) => console.error('Error:', err));

Realtime updates

Set realtime: true at init, or toggle it at runtime. SSE replaces polling while it is on, and falls back to polling by itself if the stream cannot be opened.

client.enableRealtime();
client.disableRealtime();

Session replay

Browser DOM replay ships as a separate entry point, so pages that never record do not pay for it in their bundle.

import { FlagDashSessionReplay } from '@flagdashio/sdk/replay';

const replay = new FlagDashSessionReplay({
  sdkKey: 'sk_...',        // needs the `replays:write` scope
  release: 'checkout-2026-08',
  sampleRate: 10,          // percent of sessions to record. Defaults to 100.
  blockedSelectors: ['.payment-form', '[data-private]'],

  // Optional. Nothing here is inferred: a field you leave out shows as "n/a"
  // on the replay rather than being hidden, so an absent value is always
  // distinguishable from an unsent one.
  user: {
    userId: user.id,        // hashed on arrival; the raw value is discarded
    userLabel: user.handle, // shown as-is, so keep it non-sensitive
    accountId: user.tenantId,
    plan: user.plan,
    attributes: { role: user.role },
  },
});

await replay.start();

replay.addEvent('checkout_step', { step: 'shipping' });
replay.trackAction('coupon_applied', { code: 'SUMMER' });
replay.trackRender('CartDrawer', { items: 3 });

// Correlate your own backend logs with the recording
replay.getReplayId();
const headers = replay.injectReplayHeaders({ 'Content-Type': 'application/json' });

await replay.stop();

redactSensitiveText is exported from the same entry point if you need to scrub a string before attaching it to an event.

Cleanup

// Stop polling, close any SSE stream, and remove all listeners
client.destroy();

TypeScript

Full TypeScript support with exported types:

import type {
  FlagDashConfig,
  EvaluationContext,
  UserContext,
  FlagValues,
  AiConfig,
  AiConfigFileType,
  ListAiConfigsOptions,
} from '@flagdashio/sdk';

License

MIT

AI releases

Create a release in Manage → AI Releases, select the environment, then set a baseline, candidate and rollout. With your initialized client, evaluate it using an environment-bound key with ai_configs:read:

const release = await client.aiConfigRelease("support-agent", "usr_123");

The result includes key, version, config, reason, variation_key, and rollout_percentage (idiomatic field names for typed SDKs). Pass a stable user identity. Decisions are fetched afresh; verify baseline, rollout and paused behavior in development before ramping production. Your backend calls the AI provider. Ordinary evaluation leaves secret references unresolved; never put provider credentials in a configuration delivered to browsers or mobile apps. See the release guide for lifecycle and cleanup.

Remote config value format

Remote config storage and server metadata use exactly one {"value": ...} envelope. Convenience config reads return the inner application value, without recursively unwrapping application fields named value. For example, stored {"value": {"value": 7, "enabled": false}} reads as {"value": 7, "enabled": false}. Metadata methods retain the envelope.

MCP and management writes accept the envelope and automatically wrap bare objects. To store an application object whose only key is value, send {"value": {"value": 7}}. Arrays and scalar values must be inside the envelope. Existing bare stored objects are migrated, preserving secret-reference bindings. Server SDK callers previously receiving the envelope should remove their extra .value access when upgrading. Verify in a development environment first.