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

@teracrafts/huefy-sdk-react

v2.1.4

Published

React SDK for Huefy - App Mail Templates with hooks and components for dynamic email sending

Readme

Huefy React SDK

The official React SDK for Huefy - App Mail Templates. Provides React hooks, context providers, and components for seamless template-based email integration in React applications.

Installation

Install the SDK using npm or yarn:

npm install @teracrafts/huefy-sdk-react
# or
yarn add @teracrafts/huefy-sdk-react

Quick Start

1. Setup the Provider

Wrap your app with the HuefyProvider:

import React from 'react';
import { HuefyProvider } from '@teracrafts/huefy-sdk-react';
import App from './App';

function Root() {
  return (
    <HuefyProvider apiKey="your-huefy-api-key">
      <App />
    </HuefyProvider>
  );
}

export default Root;

2. Use the Hook

Use the useHuefy hook in your components:

import React, { useState } from 'react';
import { useHuefy, EmailProvider } from '@teracrafts/huefy-sdk-react';

function WelcomeEmailForm() {
  const [email, setEmail] = useState('');
  const [name, setName] = useState('');

  const { sendEmail, loading, error, success } = useHuefy({
    onSuccess: (messageId) => {
      console.log('Email sent:', messageId);
      alert('Welcome email sent successfully!');
    },
    onError: (error) => {
      console.error('Failed to send email:', error);
    }
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    await sendEmail(
      'welcome-email',
      {
        name: name,
        company: 'Your Company',
        activationLink: 'https://app.example.com/activate'
      },
      email,
      {
        provider: EmailProvider.SENDGRID
      }
    );
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Name"
        value={name}
        onChange={(e) => setName(e.target.value)}
        disabled={loading}
        required
      />
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        disabled={loading}
        required
      />
      <button type="submit" disabled={loading || !email || !name}>
        {loading ? 'Sending...' : 'Send Welcome Email'}
      </button>
      {error && <div className="error">Error: {error.message}</div>}
      {success && <div className="success">Email sent successfully!</div>}
    </form>
  );
}

Features

  • React Hooks - useHuefy hook for email operations
  • Context Provider - Global configuration and state management
  • TypeScript Support - Full type safety with TypeScript
  • Loading States - Built-in loading and error state management
  • Multiple Providers - Support for SendGrid, Mailgun, SES, Mailchimp
  • Bulk Operations - Send multiple emails efficiently
  • Health Monitoring - API health check functionality
  • Error Handling - Comprehensive error management
  • Retry Logic - Automatic retries with exponential backoff

API Reference

HuefyProvider

The context provider that wraps your application:

interface HuefyProviderProps {
  apiKey: string;
  config?: HuefyConfig;
  children: React.ReactNode;
}

interface HuefyConfig {
  timeout?: number;
  retryOptions?: {
    maxRetries?: number;
    baseDelay?: number;
    maxDelay?: number;
  };
}

Example:

<HuefyProvider 
  apiKey="your-api-key"
  config={{
    timeout: 30000,
    retryOptions: {
      maxRetries: 3,
      baseDelay: 1000,
      maxDelay: 10000
    }
  }}
>
  <App />
</HuefyProvider>

useHuefy Hook

The main hook for email operations:

interface UseHuefyOptions {
  onSuccess?: (messageId: string) => void;
  onError?: (error: Error) => void;
  onLoadingChange?: (loading: boolean) => void;
}

interface UseHuefyResult {
  sendEmail: (
    templateKey: string,
    data: Record<string, any>,
    recipient: string,
    options?: SendEmailOptions
  ) => Promise<SendEmailResponse>;
  
  sendBulkEmails: (
    emails: BulkEmailRequest[]
  ) => Promise<BulkEmailResponse>;
  
  healthCheck: () => Promise<HealthResponse>;
  
  loading: boolean;
  error: Error | null;
  success: boolean;
  lastResponse: SendEmailResponse | BulkEmailResponse | null;
}

SendEmailOptions

interface SendEmailOptions {
  provider?: EmailProvider;
}

enum EmailProvider {
  SES = 'ses',
  SENDGRID = 'sendgrid',
  MAILGUN = 'mailgun',
  MAILCHIMP = 'mailchimp'
}

Usage Examples

Single Email with Form

import React, { useState } from 'react';
import { useHuefy, EmailProvider } from '@teracrafts/huefy-sdk-react';

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const { sendEmail, loading, error } = useHuefy({
    onSuccess: () => {
      setFormData({ name: '', email: '', message: '' });
      alert('Message sent successfully!');
    }
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    await sendEmail(
      'contact-form',
      {
        senderName: formData.name,
        senderEmail: formData.email,
        message: formData.message,
        timestamp: new Date().toISOString()
      },
      '[email protected]',
      { provider: EmailProvider.MAILGUN }
    );
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Your Name"
        value={formData.name}
        onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
        required
      />
      <input
        type="email"
        placeholder="Your Email"
        value={formData.email}
        onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
        required
      />
      <textarea
        placeholder="Your Message"
        value={formData.message}
        onChange={(e) => setFormData(prev => ({ ...prev, message: e.target.value }))}
        required
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Sending...' : 'Send Message'}
      </button>
      {error && <div className="error">Failed to send: {error.message}</div>}
    </form>
  );
}

Bulk Email Newsletter

import React, { useState } from 'react';
import { useHuefy } from '@teracrafts/huefy-sdk-react';

function NewsletterSender() {
  const [subscribers] = useState([
    { email: '[email protected]', name: 'Alice' },
    { email: '[email protected]', name: 'Bob' },
    { email: '[email protected]', name: 'Carol' }
  ]);

  const { sendBulkEmails, loading, error } = useHuefy({
    onSuccess: (result) => {
      const { successfulEmails, totalEmails } = result;
      alert(`Newsletter sent to ${successfulEmails}/${totalEmails} subscribers`);
    }
  });

  const sendNewsletter = async () => {
    const emails = subscribers.map(subscriber => ({
      templateKey: 'newsletter',
      recipient: subscriber.email,
      data: {
        subscriberName: subscriber.name,
        newsletterTitle: 'Weekly Updates',
        unsubscribeLink: 'https://app.example.com/unsubscribe'
      }
    }));

    await sendBulkEmails(emails);
  };

  return (
    <div>
      <h2>Send Newsletter</h2>
      <p>Recipients: {subscribers.length} subscribers</p>
      <button onClick={sendNewsletter} disabled={loading}>
        {loading ? 'Sending Newsletter...' : 'Send Newsletter'}
      </button>
      {error && <div className="error">Failed to send newsletter: {error.message}</div>}
    </div>
  );
}

Health Check Component

import React, { useEffect, useState } from 'react';
import { useHuefy } from '@teracrafts/huefy-sdk-react';

function ApiHealthStatus() {
  const [healthData, setHealthData] = useState(null);
  const { healthCheck, loading, error } = useHuefy();

  useEffect(() => {
    const checkHealth = async () => {
      try {
        const health = await healthCheck();
        setHealthData(health);
      } catch (err) {
        console.error('Health check failed:', err);
      }
    };

    checkHealth();
    const interval = setInterval(checkHealth, 60000); // Check every minute

    return () => clearInterval(interval);
  }, [healthCheck]);

  if (loading) return <div>Checking API health...</div>;
  if (error) return <div>Health check failed: {error.message}</div>;
  if (!healthData) return <div>No health data available</div>;

  return (
    <div className={`health-status ${healthData.status}`}>
      <h3>API Health Status</h3>
      <div>Status: {healthData.status}</div>
      <div>Version: {healthData.version}</div>
      <div>Uptime: {Math.floor(healthData.uptime / 3600)} hours</div>
    </div>
  );
}

Email Form with Validation

import React, { useState } from 'react';
import { useHuefy, EmailProvider } from '@teracrafts/huefy-sdk-react';

interface FormErrors {
  name?: string;
  email?: string;
  company?: string;
}

function UserRegistrationForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    company: ''
  });
  const [errors, setErrors] = useState<FormErrors>({});

  const { sendEmail, loading, error } = useHuefy({
    onSuccess: () => {
      setFormData({ name: '', email: '', company: '' });
      setErrors({});
      alert('Registration email sent!');
    }
  });

  const validateForm = (): boolean => {
    const newErrors: FormErrors = {};

    if (!formData.name.trim()) {
      newErrors.name = 'Name is required';
    }

    if (!formData.email.trim()) {
      newErrors.email = 'Email is required';
    } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
      newErrors.email = 'Email is invalid';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    if (!validateForm()) return;

    await sendEmail(
      'user-registration',
      {
        userName: formData.name,
        userEmail: formData.email,
        userCompany: formData.company || 'Individual',
        activationLink: `https://app.example.com/activate/${Date.now()}`,
        welcomeMessage: 'Welcome to our platform!'
      },
      formData.email,
      { provider: EmailProvider.SENDGRID }
    );
  };

  return (
    <form onSubmit={handleSubmit} className="registration-form">
      <div className="field">
        <label>Name *</label>
        <input
          type="text"
          value={formData.name}
          onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
          disabled={loading}
          className={errors.name ? 'error' : ''}
        />
        {errors.name && <span className="error-text">{errors.name}</span>}
      </div>

      <div className="field">
        <label>Email *</label>
        <input
          type="email"
          value={formData.email}
          onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
          disabled={loading}
          className={errors.email ? 'error' : ''}
        />
        {errors.email && <span className="error-text">{errors.email}</span>}
      </div>

      <div className="field">
        <label>Company</label>
        <input
          type="text"
          value={formData.company}
          onChange={(e) => setFormData(prev => ({ ...prev, company: e.target.value }))}
          disabled={loading}
        />
      </div>

      <button type="submit" disabled={loading || Object.keys(errors).length > 0}>
        {loading ? 'Sending Registration Email...' : 'Register'}
      </button>

      {error && (
        <div className="error-message">
          Registration failed: {error.message}
        </div>
      )}
    </form>
  );
}

Error Handling

The SDK provides comprehensive error handling:

import { useHuefy } from '@teracrafts/huefy-sdk-react';

function EmailComponent() {
  const { sendEmail, error } = useHuefy({
    onError: (error) => {
      // Handle different error types
      switch (error.name) {
        case 'ValidationError':
          console.error('Validation failed:', error.message);
          break;
        case 'AuthenticationError':
          console.error('Invalid API key');
          break;
        case 'NetworkError':
          console.error('Network issue:', error.message);
          break;
        case 'TimeoutError':
          console.error('Request timed out');
          break;
        default:
          console.error('Unknown error:', error.message);
      }
    }
  });

  // Component implementation...
}

TypeScript Support

The SDK is fully typed. Import types as needed:

import {
  HuefyProvider,
  useHuefy,
  EmailProvider,
  SendEmailResponse,
  BulkEmailResponse,
  HealthResponse,
  HuefyConfig,
  UseHuefyOptions
} from '@teracrafts/huefy-sdk-react';

Testing

The SDK includes comprehensive testing utilities:

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { HuefyProvider } from '@teracrafts/huefy-sdk-react';
import YourComponent from './YourComponent';

// Mock the Huefy client for testing
jest.mock('@teracrafts/huefy-sdk-react', () => ({
  ...jest.requireActual('@teracrafts/huefy-sdk-react'),
  useHuefy: () => ({
    sendEmail: jest.fn().mockResolvedValue({ messageId: 'test-123' }),
    loading: false,
    error: null,
    success: true
  })
}));

test('sends email when form is submitted', async () => {
  render(
    <HuefyProvider apiKey="test-key">
      <YourComponent />
    </HuefyProvider>
  );

  fireEvent.click(screen.getByText('Send Email'));

  await waitFor(() => {
    expect(screen.getByText('Email sent successfully!')).toBeInTheDocument();
  });
});

Performance Tips

  1. Memoize email data to prevent unnecessary re-renders:
const emailData = useMemo(() => ({
  name: user.name,
  email: user.email
}), [user.name, user.email]);
  1. Use callback functions for event handlers:
const handleSendEmail = useCallback(async () => {
  await sendEmail(templateKey, data, recipient);
}, [sendEmail, templateKey, data, recipient]);
  1. Debounce form submissions to prevent accidental double-sends:
import { useDebouncedCallback } from 'use-debounce';

const debouncedSendEmail = useDebouncedCallback(
  (templateKey, data, recipient) => {
    sendEmail(templateKey, data, recipient);
  },
  1000
);

Requirements

  • React 16.8+ (hooks support)
  • TypeScript 4.0+ (optional but recommended)
  • Modern browser with Fetch API support

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Run the test suite: npm test
  6. Submit a pull request

License

This SDK is released under the MIT License. See LICENSE for details.

Support