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

toggleai-sdk

v1.0.2

Published

Universal TypeScript SDK for ToggleAI — feature flags & remote config for Node.js, browsers, NestJS, and edge runtimes

Readme

toggleai-sdk

Universal TypeScript SDK for ToggleAI. Manage feature flags, remote configurations, and logging & error monitoring across Node.js, browsers, NestJS, and edge runtimes (Cloudflare Workers, Vercel Edge, Deno, etc.).

🔗 Quick Links

Features

  • 🌍 Universal: Works anywhere JavaScript runs (isomorphic fetch).
  • Zero Latency: Evaluates flags locally in-memory by default (sub-millisecond).
  • 🔄 Real-Time Polling: Automatic background fetching for live flag updates.
  • 🎯 Advanced Targeting: Full support for targeting rules, user attributes, and percentage rollouts.
  • 🐞 Structured Logging: Built-in batched, buffered logging.
  • 🚨 Error Monitoring: Auto-capture global unhandled errors.
  • 🛡️ Type-Safe: Written in TypeScript with full generic support for config values.
  • 📦 Dual Output: Published as both ESM (import) and CommonJS (require).
  • 🏗️ NestJS Ready: First-class ToggleAIModule with forRoot / forRootAsync.
  • 🖥️ Server-Side Evaluation: Call the backend for real-time flag evaluation when needed.

Installation

npm install toggleai-sdk
# or
yarn add toggleai-sdk
# or
pnpm add toggleai-sdk

Quick Start

1. Initialize the Client

import { ToggleAIClient } from "toggleai-sdk";

const client = new ToggleAIClient({
  clientId: "pk_live_xxxxxxxxxxxxxxxx",
  secret: "sk_live_xxxxxxxxxxxxxxxx",
  pollingInterval: 30000, // refresh every 30s (default)
});

await client.init();

2. Evaluate Feature Flags

Flags are evaluated locally from the cached config payload — zero network latency.

const context = {
  userId: "user_123",
  attributes: {
    plan: "premium",
    country: "US",
  },
};

// Boolean flag
if (client.getFlag("new-checkout", context)) {
  showNewCheckout();
}

// Typed flag value (string, number, JSON)
const buttonColor = client.getFlagValue<string>("buy-button-color", context, "#000000");
const maxItems = client.getFlagValue<number>("max-items", context, 10);

3. Read Remote Configs

Remote configs are key-value pairs that don't depend on user context.

const apiTimeout = client.getConfig<number>("api_timeout_ms", 5000);
const theme = client.getConfig<{ primary: string }>("theme_colors", { primary: "#fff" });

// Check all configs
const allConfigs = client.getAllConfigs();

4. Logging & Error Monitoring

The SDK provides an integrated edge-native logger that automatically batches and flushes events to the backend.

const logger = client.getLogger();
logger.info("User signed in", { userId: "user_123" });

try {
  await riskyOperation();
} catch (err) {
  logger.captureError(err as Error, { userId: "user_123" });
}

5. Cleanup

// Closes the client, stops polling, and flushes any pending logs
client.close();

Server-Side Evaluation

By default, the SDK evaluates flags locally from the cached payload (evaluationMode: "local"). For absolute real-time accuracy, use server-side evaluation which calls the backend directly:

// Local evaluation (instant, from cache)
const localResult = client.evaluateFlag("dark-mode", context);
console.log(localResult.reason); // "TARGETING_MATCH", "ROLLOUT", etc.

// Server-side evaluation (network call to POST /sdk/evaluate/:flagKey)
const remoteResult = await client.evaluateFlagRemote("dark-mode", context);

// Server-side evaluate ALL flags at once (POST /sdk/evaluate)
const allResults = await client.evaluateAllFlagsRemote(context);

NestJS Integration

The SDK ships with a dedicated NestJS module at toggleai-sdk/nestjs.

Setup

// app.module.ts
import { Module } from "@nestjs/common";
import { ToggleAIModule } from "toggleai-sdk/nestjs";

@Module({
  imports: [
    ToggleAIModule.forRoot({
      clientId: "pk_live_xxx",
      secret: "sk_live_xxx",
    }),
  ],
})
export class AppModule {}

Async Configuration (with ConfigService)

import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { ToggleAIModule } from "toggleai-sdk/nestjs";

@Module({
  imports: [
    ConfigModule.forRoot(),
    ToggleAIModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        clientId: config.getOrThrow("TOGGLEAI_CLIENT_ID"),
        secret: config.getOrThrow("TOGGLEAI_SECRET"),
        
      }),
    }),
  ],
})
export class AppModule {}

Injecting the Client

import { Injectable } from "@nestjs/common";
import { InjectToggleAI, ToggleAIClient } from "toggleai-sdk/nestjs";

@Injectable()
export class FeatureService {
  constructor(@InjectToggleAI() private readonly client: ToggleAIClient) {}

  isDarkModeEnabled(userId: string): boolean {
    return this.client.getFlag("dark-mode", { userId });
  }

  getApiTimeout(): number {
    return this.client.getConfig<number>("api_timeout_ms", 5000);
  }

  async evaluateRemote(flagKey: string, userId: string) {
    return this.client.evaluateFlagRemote(flagKey, { userId });
  }
}

You can also inject using the token directly:

import { Inject, Injectable } from "@nestjs/common";
import { ToggleAI_CLIENT, ToggleAIClient } from "toggleai-sdk";

@Injectable()
export class MyService {
  constructor(@Inject(ToggleAI_CLIENT) private client: ToggleAIClient) {}
}

Global Default Context

Provide a default context when creating the client. It will be merged with any per-evaluation context (per-eval takes precedence).

const client = new ToggleAIClient({
  clientId: process.env.TOGGLEAI_CLIENT_ID!,
  secret: process.env.TOGGLEAI_SECRET!,
  defaultContext: {
    attributes: {
      server_region: "us-east-1",
      app_version: "2.5.0",
    },
  },
});

Event Listeners

const client = new ToggleAIClient({
  clientId: "...",
  secret: "...",
  onReady: () => console.log("ToggleAI SDK is ready!"),
  onConfigUpdate: (payload) => console.log("Config refreshed at", payload.generatedAt),
  onError: (error) => console.error("SDK Error:", error.code, error.message),
});

Error Handling

The SDK throws ToggleAIError with structured error codes:

import { ToggleAIError } from "toggleai-sdk";

try {
  await client.init();
} catch (error) {
  if (error instanceof ToggleAIError) {
    switch (error.code) {
      case "INVALID_KEY":
        console.error("Authentication failed. Check your API keys.");
        break;
      case "RATE_LIMITED":
        console.error("Rate limited. Slow down requests.");
        break;
      case "FORBIDDEN":
        console.error("Insufficient API key scope.");
        break;
      case "NETWORK_ERROR":
        console.error("Cannot reach the ToggleAI API.");
        break;
    }
  }
}

Logging & Error Monitoring

The SDK includes ToggleAILogger for edge-native logging and error capture. It automatically batches events and flushes them to the backend in the background.

Attached Logger

Get a pre-configured logger that shares the client's API keys:

const logger = client.getLogger();

// Log with structured context
logger.debug("Debugging query", { queryId: "q_1" });
logger.info("Task completed");
logger.warn("Rate limit approaching");
logger.error(new Error("Database connection failed"));
logger.fatal("System out of memory");

Global Error Capture

You can configure a standalone logger to automatically catch global unhandled errors (window.onerror or process.uncaughtException):

import { ToggleAILogger } from "toggleai-sdk";

const logger = new ToggleAILogger({
  clientId: "pk_live_xxx",
  secret: "sk_live_xxx",
  captureGlobalErrors: true, // auto-captures unhandled errors
  minLevel: "warn",          // only send warnings and above
});

Batching & Flushing

Logs are queued in memory and batched. By default, they flush every 5 seconds or when 50 events are queued. You should manually flush before shutting down your server:

await logger.flush();

A/B Testing & Experiments

The ToggleAI SDK supports powerful A/B testing and experiment tracking, allowing you to measure conversion rates, user exposure, and target metrics natively.

1. Auto-Exposure Tracking

When you evaluate a feature flag that has a running experiment attached to it, the SDK automatically sends an exposure event to the backend in the background (fire-and-forget, with session-level deduplication so we don't spam requests).

// Simply evaluating the flag triggers the exposure event under the hood!
const result = client.evaluateFlag("new-hero-variant", { userId: "user_123" });

2. Zero-Code Event Tracking

Track meaningful business actions globally. The backend automatically attributes these events to any running experiments whose metrics match the metricKey.

// Track a single event
await client.track({
  metricKey: "purchase_completed",
  userIdentifier: "user_123",
  value: 49.99, // Optional revenue or metric value
});

// Track multiple events in batch (up to 100)
await client.trackBatch([
  { metricKey: "page_view", userIdentifier: "user_123" },
  { metricKey: "add_to_cart", userIdentifier: "user_123", value: 1 },
]);

3. Explicit Experiment Conversion Tracking

If you need precision control over when a user converts for a specific A/B experiment, you can resolve the variationId and send a manual conversion:

// 1. Evaluate the flag
const result = client.evaluateFlag("checkout-layout", { userId: "user_123" });

// 2. Resolve the variation's database UUID
const variationId = client.resolveVariationId("checkout-layout", result.variationKey);

// 3. Track conversion when the action occurs
if (variationId) {
  await client.trackConversion({
    experimentId: "exp_checkout_redesign",
    variationId,
    metricKey: "checkout_conversion",
    userId: "user_123",
    value: 1, // Optional value
  });
}

4. Manual Exposure Recording

For special setups (like server-side rendering or non-standard routing), you can also manually register exposures:

await client.recordExposure({
  experimentId: "exp_checkout_redesign",
  variationId: "var_redesign_a",
  userIdentifier: "user_123",
});

API Reference

Client Methods

| Method | Returns | Description | |---|---|---| | init() | Promise<void> | Initialize client, fetch config, start polling | | close() | void | Stop polling, release resources | | refresh() | Promise<void> | Manually refresh config payload | | isReady() | boolean | Check if client is initialized | | waitForReady() | Promise<void> | Wait for initialization | | getState() | ClientState | Current lifecycle state |

Feature Flags (Local)

| Method | Returns | Description | |---|---|---| | getFlag(key, ctx?, default?) | boolean | Get boolean flag value | | getFlagValue<T>(key, ctx?, default?) | T | Get typed flag value | | evaluateFlag(key, ctx?) | FlagEvaluationResult | Get full evaluation result | | evaluateAllFlags(ctx?) | Record<string, FlagEvaluationResult> | Evaluate all flags |

Feature Flags (Server-Side)

| Method | Returns | Description | |---|---|---| | evaluateFlagRemote(key, ctx?) | Promise<FlagEvaluationResult> | Server-side single flag evaluation | | evaluateAllFlagsRemote(ctx?) | Promise<Record<...>> | Server-side all flags evaluation |

Remote Config

| Method | Returns | Description | |---|---|---| | getConfig<T>(key, default?) | T | Get typed config value | | getAllConfigs() | Record<string, unknown> | Get all config values | | hasConfig(key) | boolean | Check if config key exists |

Logging

| Method | Returns | Description | |---|---|---| | getLogger() | ToggleAILogger | Get the attached logger instance | | logger.info(msg, ctx?) | void | Log an info message | | logger.error(err, ctx?) | void | Log an error message or Error object | | logger.captureError(err, ctx?)| void | Capture an Error object with context | | logger.setContext(ctx) | void | Set default context for all subsequent logs | | logger.flush() | Promise<void> | Manually flush queued logs |

A/B Testing & Experiments

| Method | Returns | Description | |---|---|---| | track(event) | Promise<TrackEventResult> | Track a generic event for auto-attribution | | trackBatch(events) | Promise<TrackEventResult> | Track multiple events in a single batch | | trackConversion(opts) | Promise<TrackConversionResult> | Track explicit conversion for an experiment | | resolveVariationId(flagKey, varKey) | string \| null | Convert variation key string to DB variation UUID | | recordExposure(exposure) | Promise<ExposureResult> | Manually record user exposure to a variation | | recordExposures(exposures) | Promise<ExposureResult> | Manually record multiple user exposures | | getActiveExperiments() | ExperimentPayloadItem[] | List all running experiments | | getExperimentForFlag(flagKey) | ExperimentPayloadItem \| null| Get experiment details for a specific flag |

Inspection

| Method | Returns | Description | |---|---|---| | getPayload() | ConfigPayload \| null | Raw config payload | | getFlagDefinition(key) | FlagDefinition \| null | Raw flag definition | | getFlagKeys() | string[] | All flag keys | | getConfigKeys() | string[] | All config keys | | getEnvironment() | { id, slug } \| null | Environment metadata |


Backend Endpoints

This SDK communicates with the following backend endpoints (authenticated via API key pair):

| Endpoint | Method | Description | |---|---|---| | /sdk/config | GET | Fetch full config payload (flags + configs) | | /sdk/evaluate | POST | Server-side evaluate all flags for a user | | /sdk/evaluate/:flagKey | POST | Evaluate a single flag server-side | | /sdk/connect | POST | Register SDK connection (analytics) | | /sdk/logs/ingest | POST | Ingest a single log event | | /sdk/logs/ingest/batch | POST | Ingest a batch of log events |


Support

For issues, questions, or contributions, please contact the ToggleAI team or open an issue in the repository.