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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@savvagent/react

v1.0.1

Published

React SDK for Savvagent feature flags

Readme

@savvagent/react

React SDK for Savvagent - AI-powered feature flags that prevent production incidents.

Installation

npm install @savvagent/react
# or
pnpm add @savvagent/react
# or
yarn add @savvagent/react

Quick Start

1. Wrap your app with SavvagentProvider

import { SavvagentProvider } from '@savvagent/react';

function App() {
  return (
    <SavvagentProvider
      config={{
        apiKey: 'sdk_your_api_key_here',
        applicationId: 'your-app-id', // Optional: for application-scoped flags
        enableRealtime: true, // Enable real-time flag updates
      }}
    >
      <YourApp />
    </SavvagentProvider>
  );
}

2. Use the useFlag hook

import { useFlag } from '@savvagent/react';

function MyFeature() {
  const { value: isEnabled, loading } = useFlag('new-checkout-flow', {
    defaultValue: false,
    realtime: true,
  });

  if (loading) {
    return <div>Loading...</div>;
  }

  return isEnabled ? <NewCheckout /> : <OldCheckout />;
}

API Reference

<SavvagentProvider>

Provider component that initializes the Savvagent client and makes it available to all child components.

Props

interface SavvagentProviderProps {
  config: FlagClientConfig;
  children: React.ReactNode;
}

interface FlagClientConfig {
  /** SDK API key (starts with sdk_) */
  apiKey: string;
  /** Application ID for application-scoped flags */
  applicationId?: string;
  /** Base URL for the Savvagent API */
  baseUrl?: string;
  /** Enable real-time flag updates via SSE (default: true) */
  enableRealtime?: boolean;
  /** Cache TTL in milliseconds (default: 60000) */
  cacheTtl?: number;
  /** Enable telemetry tracking (default: true) */
  enableTelemetry?: boolean;
  /** Default flag values when evaluation fails */
  defaults?: Record<string, boolean>;
  /** Custom error handler */
  onError?: (error: Error) => void;
  /** Default language for targeting */
  defaultLanguage?: string;
  /** Disable automatic browser language detection */
  disableLanguageDetection?: boolean;
}

useFlag(flagKey, options)

Hook to evaluate a feature flag with automatic updates.

Parameters

  • flagKey: string - The feature flag key to evaluate
  • options?: UseFlagOptions - Configuration options
interface UseFlagOptions {
  /** Context for flag evaluation (user_id, attributes, etc.) */
  context?: FlagContext;
  /** Default value to use while loading or on error */
  defaultValue?: boolean;
  /** Enable real-time updates for this flag (default: true) */
  realtime?: boolean;
  /** Custom error handler */
  onError?: (error: Error) => void;
}

Returns

interface UseFlagResult {
  /** Current flag value */
  value: boolean;
  /** Whether the flag is currently being evaluated */
  loading: boolean;
  /** Error if evaluation failed */
  error: Error | null;
  /** Detailed evaluation result */
  result: FlagEvaluationResult | null;
  /** Force re-evaluation of the flag */
  refetch: () => Promise<void>;
}

Example

function MyComponent() {
  const { value, loading, error, refetch } = useFlag('beta-feature', {
    context: {
      user_id: user?.id,
      attributes: {
        plan: user?.plan,
        country: user?.country,
      },
    },
    defaultValue: false,
    realtime: true,
    onError: (err) => console.error('Flag evaluation failed:', err),
  });

  if (loading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return (
    <div>
      {value ? <BetaFeature /> : <StandardFeature />}
      <button onClick={() => refetch()}>Refresh Flag</button>
    </div>
  );
}

useSavvagent()

Hook to access the underlying Savvagent client instance for advanced use cases.

Returns

interface SavvagentContextValue {
  /** The FlagClient instance */
  client: FlagClient | null;
  /** Whether the client is ready */
  isReady: boolean;
}

Example

function AdvancedComponent() {
  const { client, isReady } = useSavvagent();

  useEffect(() => {
    if (!isReady || !client) return;

    // Use client directly
    const checkMultipleFlags = async () => {
      const flag1 = await client.isEnabled('feature-1');
      const flag2 = await client.isEnabled('feature-2');
      console.log({ flag1, flag2 });
    };

    checkMultipleFlags();
  }, [client, isReady]);

  return <div>Content</div>;
}

useWithFlag(flagKey, callback, options)

Hook to execute a callback conditionally based on a flag value.

Example

function AnalyticsComponent() {
  useWithFlag('analytics-enabled', async () => {
    await trackEvent('page_view', {
      page: window.location.pathname,
    });
  });

  return <PageContent />;
}

useUser()

Hook to manage user identification for targeted flag evaluation.

Returns

{
  setUserId: (userId: string | null) => void;
  getUserId: () => string | null;
  getAnonymousId: () => string | null;
  setAnonymousId: (id: string) => void;
}

Example

function AuthHandler() {
  const { setUserId } = useUser();

  useEffect(() => {
    if (user) {
      setUserId(user.id);
    } else {
      setUserId(null); // Clear on logout
    }
  }, [user, setUserId]);

  return null;
}

useTrackError(flagKey, context)

Hook to track errors with flag context for AI-powered error analysis.

Example

function FeatureComponent() {
  const trackError = useTrackError('new-payment-flow');
  const [result, setResult] = useState(null);

  const handlePayment = async () => {
    try {
      const result = await processPayment();
      setResult(result);
    } catch (error) {
      trackError(error as Error);
      toast.error('Payment failed');
    }
  };

  return <button onClick={handlePayment}>Pay Now</button>;
}

Advanced Examples

User Targeting

function UserSpecificFeature() {
  const user = useCurrentUser();
  const { value: showPremium } = useFlag('premium-features', {
    context: {
      user_id: user.id,
      attributes: {
        plan: user.subscription.plan,
        signupDate: user.createdAt,
      },
    },
  });

  return showPremium ? <PremiumDashboard /> : <StandardDashboard />;
}

Language Targeting

function LocalizedFeature() {
  const { i18n } = useTranslation();
  const { value: showLocalFeature } = useFlag('regional-promotion', {
    context: {
      language: i18n.language, // e.g., 'en-US', 'fr-FR'
    },
  });

  return showLocalFeature ? <RegionalPromo /> : null;
}

A/B Testing

function ABTest() {
  const user = useCurrentUser();
  const { value: variantB } = useFlag('checkout-variant-b', {
    context: {
      user_id: user.id, // Consistent assignment per user
    },
  });

  return variantB ? <CheckoutVariantB /> : <CheckoutVariantA />;
}

Error Tracking

function ExperimentalFeature() {
  const trackError = useTrackError('experimental-algorithm');

  const handleComputation = async () => {
    try {
      const result = await experimentalComputation();
      return result;
    } catch (error) {
      // Error is automatically correlated with flag changes
      trackError(error as Error);
      throw error;
    }
  };

  return <ComputationUI onCompute={handleComputation} />;
}

TypeScript Support

This package is written in TypeScript and provides full type definitions.

import type {
  FlagClientConfig,
  FlagContext,
  FlagEvaluationResult,
  UseFlagOptions,
  UseFlagResult,
} from '@savvagent/react';

Best Practices

  1. Place SavvagentProvider high in your component tree to ensure all components have access to the client.

  2. Use the defaultValue option to provide a safe fallback while flags are loading.

  3. Enable real-time updates for flags that change frequently or require immediate propagation.

  4. Track errors in new features to leverage Savvagent's AI-powered error correlation.

  5. Use user context for targeted rollouts based on user attributes, location, or behavior.

  6. Handle loading states gracefully to provide a smooth user experience.

License

MIT