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

@signup-storm/sdk

v1.0.0

Published

TypeScript SDK for Signup Storm API integration

Readme

Signup Storm TypeScript SDK

npm version TypeScript

A comprehensive TypeScript SDK for integrating Signup Storm email signup functionality into your applications and landing pages.

Features

  • 🚀 Easy Integration - Simple API for email signups and management
  • 🎯 Attribution Tracking - Automatic UTM parameter capture
  • 📱 Browser Utilities - Form integration and widget creation
  • 🔒 Type Safety - Full TypeScript support with comprehensive types
  • 🎨 Customizable - Flexible styling and behavior options
  • 📊 Event System - Listen to signup events and responses
  • 🌐 Universal - Works in browser and Node.js environments
  • Lightweight - Zero dependencies, small bundle size

Installation

npm install @signup-storm/sdk
yarn add @signup-storm/sdk
pnpm add @signup-storm/sdk

Quick Start

Basic Usage

import { SignupStorm } from '@signup-storm/sdk';

const client = new SignupStorm({
  apiKey: 'your-api-key',
  baseUrl: 'https://your-signup-samurai-instance.com'
});

// Subscribe an email
const response = await client.signup({
  email: '[email protected]',
  list: 'newsletter',
  tags: ['landing-page', 'early-access']
});

console.log('Signup successful:', response);

Browser Integration

import { createBrowserClient } from '@signup-storm/sdk';

const { client, browser } = createBrowserClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://your-signup-samurai-instance.com'
});

// Integrate with existing form
browser.integrateForm({
  form: '#signup-form',
  list: 'newsletter',
  onSuccess: (response) => {
    console.log('User subscribed:', response.email);
  },
  onError: (error) => {
    console.error('Signup failed:', error.message);
  }
});

API Reference

SignupStorm Client

Constructor

new SignupStorm(config: SignupStormConfig)

Config Options:

  • apiKey (string, required) - Your API key
  • baseUrl (string, required) - Your Signup Storm instance URL
  • timeout (number, optional) - Request timeout in milliseconds (default: 10000)
  • headers (object, optional) - Custom headers to include with requests
  • debug (boolean, optional) - Enable debug logging (default: false)

Methods

signup(request: SignupRequest): Promise<SignupResponse>

Subscribe an email address to a list.

const response = await client.signup({
  email: '[email protected]',
  list: 'newsletter',
  tags: ['blog', 'early-access'],
  utm: {
    source: 'twitter',
    medium: 'social',
    campaign: 'launch'
  },
  customFields: {
    firstName: 'John',
    company: 'Acme Corp'
  }
});

SignupRequest Properties:

  • email (string, required) - Email address to subscribe
  • list (string, optional) - List slug to subscribe to
  • tags (string[], optional) - Tags to apply to the subscriber
  • utm (UTMParameters, optional) - UTM parameters for attribution
  • pageUrl (string, optional) - URL where signup occurred (auto-detected in browser)
  • referrer (string, optional) - Referrer URL (auto-detected in browser)
  • customFields (object, optional) - Custom fields to store with subscriber
  • ipAddress (string, optional) - IP address (auto-detected if not provided)
  • userAgent (string, optional) - User agent (auto-detected in browser)
  • consentTimestamp (string, optional) - GDPR consent timestamp
  • gdprConsent (boolean, optional) - GDPR consent status
unsubscribe(request: UnsubscribeRequest): Promise<UnsubscribeResponse>

Unsubscribe an email address from a list or globally.

const response = await client.unsubscribe({
  email: '[email protected]',
  list: 'newsletter', // Optional - omit for global unsubscribe
  reason: 'No longer interested'
});
getSubscriberStatus(email: string): Promise<SubscriberStatus>

Check the subscription status of an email address.

const status = await client.getSubscriberStatus('[email protected]');
console.log('Status:', status.status); // 'subscribed', 'unsubscribed', etc.
console.log('Lists:', status.lists);
console.log('Tags:', status.tags);

Event System

Listen to SDK events:

client.on('signup:success', (event) => {
  console.log('Signup successful:', event.data);
});

client.on('signup:error', (event) => {
  console.error('Signup failed:', event.data);
});

client.on('request:start', (event) => {
  console.log('Request started:', event.data.type);
});

Available Events:

  • signup:success - Successful signup
  • signup:error - Signup error
  • unsubscribe:success - Successful unsubscribe
  • unsubscribe:error - Unsubscribe error
  • request:start - Request started
  • request:complete - Request completed

Browser Utilities

Form Integration

Integrate with existing HTML forms:

const cleanup = browser.integrateForm({
  form: '#my-form', // Form selector or element
  emailField: 'email', // Email input name/selector (default: 'email')
  list: 'newsletter',
  tags: ['website'],
  customFields: {
    firstName: '[name="first_name"]',
    company: '[name="company"]'
  },
  onSuccess: (response) => {
    // Handle success
    showSuccessMessage('Thanks for subscribing!');
  },
  onError: (error) => {
    // Handle error
    showErrorMessage(error.message);
  },
  onLoading: (loading) => {
    // Handle loading state
    toggleLoadingSpinner(loading);
  },
  preventDefault: true, // Prevent default form submission
  showLoadingState: true, // Show loading on submit button
  disableFormDuringSubmission: true // Disable form during submission
});

// Call cleanup when done
cleanup();

Widget Creation

Create embedded signup widgets:

const widget = browser.createWidget({
  container: '#signup-container',
  list: 'newsletter',
  tags: ['widget'],
  placeholder: 'Enter your email address',
  buttonText: 'Subscribe Now',
  successMessage: 'Thanks for subscribing!',
  cssClasses: {
    container: 'my-signup-widget',
    form: 'signup-form',
    input: 'email-input',
    button: 'subscribe-btn',
    success: 'success-message',
    error: 'error-message'
  },
  styles: {
    container: {
      padding: '20px',
      borderRadius: '8px',
      backgroundColor: '#f5f5f5'
    },
    input: {
      padding: '12px',
      fontSize: '16px',
      border: '1px solid #ddd',
      borderRadius: '4px'
    },
    button: {
      padding: '12px 24px',
      backgroundColor: '#007bff',
      color: 'white',
      border: 'none',
      borderRadius: '4px',
      cursor: 'pointer'
    }
  }
});

Auto-Capture

Automatically capture emails from forms on the page:

const cleanup = browser.autoCapture({
  selector: 'input[type="email"]', // Email input selector
  lists: ['newsletter'], // Auto-subscribe to these lists
  tags: ['auto-capture'],
  onCapture: (email) => {
    console.log('Email captured:', email);
  }
});

// Call cleanup when done
cleanup();

Utilities

Email Validation

import { validateEmail } from '@signup-storm/sdk';

if (validateEmail('[email protected]')) {
  console.log('Valid email');
}

UTM Parameter Extraction

import { extractUTMFromURL, extractUTMFromCurrentPage } from '@signup-storm/sdk';

// Extract from specific URL
const utm = extractUTMFromURL('https://example.com?utm_source=twitter&utm_medium=social');

// Extract from current page (browser only)
const currentUTM = extractUTMFromCurrentPage();

Browser Detection

import { isBrowser } from '@signup-storm/sdk';

if (isBrowser()) {
  // Browser-specific code
  console.log('Running in browser');
}

Examples

React Integration

import React, { useEffect, useRef } from 'react';
import { createBrowserClient } from '@signup-storm/sdk';

const SignupForm: React.FC = () => {
  const formRef = useRef<HTMLFormElement>(null);
  const [message, setMessage] = useState('');
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const { browser } = createBrowserClient({
      apiKey: process.env.REACT_APP_SIGNUP_SAMURAI_API_KEY!,
      baseUrl: process.env.REACT_APP_SIGNUP_SAMURAI_URL!
    });

    const cleanup = browser.integrateForm({
      form: formRef.current!,
      list: 'newsletter',
      onSuccess: () => {
        setMessage('Thanks for subscribing!');
        setLoading(false);
      },
      onError: (error) => {
        setMessage(error.message);
        setLoading(false);
      },
      onLoading: setLoading
    });

    return cleanup;
  }, []);

  return (
    <div>
      <form ref={formRef}>
        <input
          type="email"
          name="email"
          placeholder="Enter your email"
          required
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Subscribing...' : 'Subscribe'}
        </button>
      </form>
      {message && <p>{message}</p>}
    </div>
  );
};

Vue.js Integration

<template>
  <form ref="signupForm" @submit.prevent>
    <input
      type="email"
      name="email"
      placeholder="Enter your email"
      required
    />
    <button type="submit" :disabled="loading">
      {{ loading ? 'Subscribing...' : 'Subscribe' }}
    </button>
    <p v-if="message">{{ message }}</p>
  </form>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { createBrowserClient } from '@signup-storm/sdk';

const signupForm = ref<HTMLFormElement>();
const message = ref('');
const loading = ref(false);
let cleanup: (() => void) | null = null;

onMounted(() => {
  const { browser } = createBrowserClient({
    apiKey: import.meta.env.VITE_SIGNUP_SAMURAI_API_KEY,
    baseUrl: import.meta.env.VITE_SIGNUP_SAMURAI_URL
  });

  cleanup = browser.integrateForm({
    form: signupForm.value!,
    list: 'newsletter',
    onSuccess: () => {
      message.value = 'Thanks for subscribing!';
      loading.value = false;
    },
    onError: (error) => {
      message.value = error.message;
      loading.value = false;
    },
    onLoading: (isLoading) => {
      loading.value = isLoading;
    }
  });
});

onUnmounted(() => {
  cleanup?.();
});
</script>

Node.js Server Usage

import { SignupStorm } from '@signup-storm/sdk';

const client = new SignupStorm({
  apiKey: process.env.SIGNUP_SAMURAI_API_KEY!,
  baseUrl: process.env.SIGNUP_SAMURAI_URL!
});

// API endpoint for server-side signups
app.post('/api/signup', async (req, res) => {
  try {
    const { email, list, tags } = req.body;
    
    const response = await client.signup({
      email,
      list,
      tags,
      ipAddress: req.ip,
      userAgent: req.get('User-Agent'),
      pageUrl: req.get('Referer')
    });

    res.json({ success: true, data: response });
  } catch (error) {
    res.status(400).json({ 
      success: false, 
      error: error.message 
    });
  }
});

Error Handling

The SDK throws SignupStormError for API-related errors:

import { SignupStormError } from '@signup-storm/sdk';

try {
  await client.signup({ email: 'invalid-email' });
} catch (error) {
  if (error instanceof SignupStormError) {
    console.log('Error code:', error.code);
    console.log('HTTP status:', error.status);
    console.log('Message:', error.message);
    console.log('Details:', error.details);
  }
}

TypeScript Support

The SDK is written in TypeScript and provides comprehensive type definitions:

import type { 
  SignupRequest, 
  SignupResponse, 
  UTMParameters,
  SubscriberStatus 
} from '@signup-storm/sdk';

const request: SignupRequest = {
  email: '[email protected]',
  list: 'newsletter',
  utm: {
    source: 'twitter',
    medium: 'social'
  }
};

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/yourusername/signup-samurai.git
cd signup-samurai/packages/sdk

# Install dependencies
pnpm install

# Start development mode
pnpm dev

# Run tests
pnpm test

# Run linting
pnpm lint

Publishing (Maintainers Only)

The SDK is published to npm as @signup-storm/sdk. To publish a new version:

# Using the publish script (recommended)
./scripts/publish.sh

# Or manually
pnpm version patch  # or minor/major
pnpm prepublishOnly  # runs tests, linting, and build
npm publish

The package follows semantic versioning and includes automated checks before publishing.

License

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

Support


Made with ❤️ by Applied Designs, LLC