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

@sparkvault/sdk

v1.1.6

Published

SparkVault JavaScript SDK - Identity, Sparks, Vaults, and RNG

Readme

SparkVault JavaScript SDK

The official SparkVault JavaScript SDK for browser applications. Add passwordless authentication to your app in minutes with zero-config integration or full programmatic control.

npm version License: MIT

Table of Contents

Installation

CDN (Recommended)

<script src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"></script>

npm / yarn

npm install @sparkvault/sdk
# or
yarn add @sparkvault/sdk

Bundle Formats:

  • sparkvault.js — UMD bundle for browsers (recommended)
  • sparkvault.esm.js — ES modules for modern bundlers
  • sparkvault.cjs.js — CommonJS for Node.js

Zero-Config Integration

Add SparkVault authentication to your site with a single script tag — no JavaScript required!

<!-- Add this single script tag -->
<script
  async
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
  data-attach-selector=".login-btn"
  data-success-url="/auth/verify-token"
></script>

<!-- Any element matching the selector becomes a login button -->
<button class="login-btn">Sign In</button>
<a href="#" class="login-btn">Create Account</a>

That's it! The SDK automatically:

  • Initializes with your account ID
  • Attaches click handlers to all matching elements
  • Opens the verification modal when clicked
  • POSTs the result to your success URL
  • Watches for dynamically added elements (MutationObserver)

Data Attributes

| Attribute | Required | Description | |-----------|----------|-------------| | data-account-id | Yes | Your SparkVault account ID (required for auto-init) | | data-attach-selector | No | CSS selector for elements to attach click handlers | | data-success-url | No | URL to POST { token, identity, identityType } on success | | data-success-function | No | Global function name to call on success (e.g., "MyApp.auth.onSuccess") | | data-error-url | No | URL to redirect on error (appends ?error=message) | | data-error-function | No | Global function name to call on error | | data-preload-config | No | Set to "false" to defer config loading. Default: true | | data-timeout | No | Request timeout in milliseconds. Default: 30000 | | data-debug | No | Set to "true" for verbose console logging |

Complete Example

<script
  async
  src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"
  data-account-id="acc_YOUR_ACCOUNT_ID"
  data-attach-selector=".js-sparkvault-auth"
  data-success-url="https://example.com/auth/verify-token"
  data-success-function="onSparkVaultSuccess"
  data-error-function="onSparkVaultError"
  data-debug="true"
></script>

<script>
  // Optional: Define callback functions
  function onSparkVaultSuccess(result) {
    console.log('Verified:', result.identity);
    console.log('Token:', result.token);
    // The SDK will also POST to data-success-url
  }

  function onSparkVaultError(error) {
    console.error('Error:', error.message);
    alert('Authentication failed. Please try again.');
  }
</script>

<!-- Multiple elements can use the same selector -->
<button class="js-sparkvault-auth">Sign In</button>
<a href="#" class="js-sparkvault-auth">Login with SparkVault</a>

Success URL Response

When you specify data-success-url, the SDK POSTs the verification result:

{
  "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
  "identity": "[email protected]",
  "identityType": "email"
}

Your backend can respond with redirect instructions:

// Option 1: Redirect to a URL
{ "redirectUrl": "/dashboard" }
// or
{ "redirect_url": "/dashboard" }

// Option 2: Reload the current page
{ "reload": true }

// Option 3: Return data (no automatic action)
{ "success": true, "user": { "id": 123, "email": "[email protected]" } }

Manual Trigger from JavaScript

You can also trigger authentication programmatically using the SparkVault global:

// Trigger authentication from anywhere in your code
SparkVault.identity.pop();

// This uses your configured success/error handlers
<button onclick="SparkVault.identity.pop()">
  Sign In with SparkVault
</button>

Manual Initialization

For full control over the SDK, initialize it manually in JavaScript:

import SparkVault from '@sparkvault/sdk';

const sparkvault = SparkVault.init({
  accountId: 'acc_YOUR_ACCOUNT_ID'  // Required
});

// The SDK is now ready to use
const result = await sparkvault.identity.pop();

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | accountId | string | required | Your SparkVault account ID (starts with acc_) | | timeout | number | 30000 | HTTP request timeout in milliseconds | | preloadConfig | boolean | true | Preload Identity config for instant modal |

CDN Usage

<script src="https://cdn.sparkvault.com/sdk/v1/sparkvault.js"></script>
<script>
  const sparkvault = SparkVault.init({
    accountId: 'acc_YOUR_ACCOUNT_ID'
  });

  document.getElementById('login-btn').addEventListener('click', async () => {
    const result = await sparkvault.identity.pop();
    console.log('Verified:', result.identity);
  });
</script>

Identity Verification

The Identity module provides passwordless authentication through a beautiful, customizable modal. Users can verify via passkeys, email codes, SMS codes, magic links, or social providers.

Basic Usage

// Open the verification modal
const result = await sparkvault.identity.pop();

// User verified!
console.log(result.identity);      // "[email protected]" or "+14155551234"
console.log(result.identityType);  // "email" or "phone"
console.log(result.token);         // Signed JWT token

// Send the token to your backend for verification
await fetch('/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token: result.token })
});

pop() Options

| Option | Type | Description | |--------|------|-------------| | email | string | Pre-fill email address (mutually exclusive with phone) | | phone | string | Pre-fill phone in E.164 format, e.g. "+14155551234" | | backdropBlur | boolean | Override backdrop blur setting from app config | | onCancel | function | Callback when user closes modal without verifying | | onSuccess | function | Callback on success (before promise resolves) | | onError | function | Callback on error (before promise rejects) |

pop() Result

| Field | Type | Description | |-------|------|-------------| | token | string | Signed JWT token (Ed25519). Verify this on your backend. | | identity | string | The verified email address or phone number | | identityType | "email" \| "phone" | Type of identity that was verified |

Example with Options

try {
  const result = await sparkvault.identity.pop({
    // Pre-fill the email field
    email: '[email protected]',

    // Handle cancellation
    onCancel: () => {
      console.log('User cancelled');
    }
  });

  // Success! Send token to your backend
  await loginWithToken(result.token);

} catch (error) {
  if (error.code === 'user_cancelled') {
    // User closed the modal
  } else {
    // Handle other errors
    console.error('Verification failed:', error.message);
  }
}

Authentication Methods

Authentication methods are configured in your Identity App settings. The SDK automatically shows only the methods you have enabled.

| Method | Description | Identity Type | |--------|-------------|---------------| | passkey | WebAuthn/FIDO2 biometric or security key | Email | | totp_email | 6-digit code sent via email | Email | | totp_sms | 6-digit code sent via SMS | Phone | | totp_voice | 6-digit code sent via voice call | Phone | | magic_link / sparklink | One-click magic link via email | Email | | google | Sign in with Google | Email | | apple | Sign in with Apple | Email | | microsoft | Sign in with Microsoft | Email | | github | Sign in with GitHub | Email | | facebook | Sign in with Facebook | Email | | linkedin | Sign in with LinkedIn | Email |

Backend Token Verification

Security Critical: Always verify tokens on your backend. Never trust the frontend result alone. Tokens are signed with Ed25519 — use the JWKS endpoint to verify the signature.

Node.js

import * as jose from 'jose';

const ACCOUNT_ID = 'acc_YOUR_ACCOUNT_ID';
const IDENTITY_URL = 'https://api.sparkvault.com/v1/apps/identity';

app.post('/api/auth/login', async (req, res) => {
  const { token } = req.body;

  try {
    // Fetch public keys and verify signature
    const jwksUrl = `${IDENTITY_URL}/${ACCOUNT_ID}/.well-known/jwks.json`;
    const JWKS = jose.createRemoteJWKSet(new URL(jwksUrl));

    const { payload } = await jose.jwtVerify(token, JWKS, {
      issuer: `${IDENTITY_URL}/${ACCOUNT_ID}`,
      audience: ACCOUNT_ID
    });

    // Token is valid! Create user session
    const user = await findOrCreateUser(payload.identity, payload.identity_type);
    req.session.userId = user.id;

    res.json({ success: true, user });
  } catch (error) {
    res.status(401).json({ error: 'Invalid token' });
  }
});

Python

import jwt
from jwt import PyJWKClient

ACCOUNT_ID = 'acc_YOUR_ACCOUNT_ID'
IDENTITY_URL = 'https://api.sparkvault.com/v1/apps/identity'

def verify_identity_token(token: str):
    """Verify a SparkVault Identity token and return the claims."""
    jwks_url = f"{IDENTITY_URL}/{ACCOUNT_ID}/.well-known/jwks.json"
    jwks_client = PyJWKClient(jwks_url)

    # Get the signing key
    signing_key = jwks_client.get_signing_key_from_jwt(token)

    # Verify and decode
    claims = jwt.decode(
        token,
        signing_key.key,
        algorithms=["EdDSA"],
        issuer=f"{IDENTITY_URL}/{ACCOUNT_ID}",
        audience=ACCOUNT_ID
    )

    return claims

# Usage in Flask
@app.route('/api/auth/login', methods=['POST'])
def login():
    token = request.json.get('token')

    try:
        claims = verify_identity_token(token)

        # Create session
        user = find_or_create_user(claims['identity'], claims['identity_type'])
        session['user_id'] = user.id

        return jsonify({'success': True, 'user': user.to_dict()})
    except jwt.InvalidTokenError as e:
        return jsonify({'error': 'Invalid token'}), 401

Go

package main

import (
    "github.com/lestrrat-go/jwx/v2/jwk"
    "github.com/lestrrat-go/jwx/v2/jwt"
)

const (
    AccountID   = "acc_YOUR_ACCOUNT_ID"
    IdentityURL = "https://api.sparkvault.com/v1/apps/identity"
)

func verifyToken(tokenString string) (jwt.Token, error) {
    jwksURL := fmt.Sprintf("%s/%s/.well-known/jwks.json", IdentityURL, AccountID)

    // Fetch JWKS
    keySet, err := jwk.Fetch(context.Background(), jwksURL)
    if err != nil {
        return nil, err
    }

    // Parse and verify token
    token, err := jwt.Parse(
        []byte(tokenString),
        jwt.WithKeySet(keySet),
        jwt.WithIssuer(fmt.Sprintf("%s/%s", IdentityURL, AccountID)),
        jwt.WithAudience(AccountID),
    )
    if err != nil {
        return nil, err
    }

    return token, nil
}

// Usage in HTTP handler
func loginHandler(w http.ResponseWriter, r *http.Request) {
    var body struct {
        Token string `json:"token"`
    }
    json.NewDecoder(r.Body).Decode(&body)

    token, err := verifyToken(body.Token)
    if err != nil {
        http.Error(w, "Invalid token", http.StatusUnauthorized)
        return
    }

    identity, _ := token.Get("identity")
    // Create session with identity...
}

Ruby

require 'jwt'
require 'net/http'
require 'json'

ACCOUNT_ID = 'acc_YOUR_ACCOUNT_ID'
IDENTITY_URL = 'https://api.sparkvault.com/v1/apps/identity'

def verify_identity_token(token)
  jwks_url = "#{IDENTITY_URL}/#{ACCOUNT_ID}/.well-known/jwks.json"

  # Fetch JWKS
  uri = URI(jwks_url)
  response = Net::HTTP.get(uri)
  jwks = JSON.parse(response)

  # Decode and verify
  JWT.decode(
    token,
    nil,
    true,
    {
      algorithms: ['EdDSA'],
      iss: "#{IDENTITY_URL}/#{ACCOUNT_ID}",
      aud: ACCOUNT_ID,
      verify_iss: true,
      verify_aud: true,
      jwks: jwks
    }
  ).first
end

# Usage in Rails controller
class AuthController < ApplicationController
  def login
    claims = verify_identity_token(params[:token])

    user = User.find_or_create_by(email: claims['identity'])
    session[:user_id] = user.id

    render json: { success: true, user: user }
  rescue JWT::DecodeError => e
    render json: { error: 'Invalid token' }, status: :unauthorized
  end
end

Token Claims

When decoded, the JWT token contains these claims:

{
  "iss": "https://api.sparkvault.com/v1/apps/identity/acc_xxx",
  "sub": "identity:a1b2c3d4e5f67890",
  "aud": "acc_xxx",
  "identity": "[email protected]",
  "identity_type": "email",
  "method": "totp_email",
  "verified_at": 1703977195,
  "iat": 1703977200,
  "exp": 1703980800,
  "jti": "tok_unique_id"
}

| Claim | Type | Description | |-------|------|-------------| | iss | string | Issuer URL — always verify this matches expected value | | sub | string | Subject — hashed identity for consistent user identification | | aud | string | Audience — your account ID | | identity | string | The verified email address or phone number | | identity_type | string | "email" or "phone" | | method | string | Authentication method used (e.g., "totp_email", "passkey") | | verified_at | number | Unix timestamp when identity was verified | | iat | number | Issued at timestamp | | exp | number | Expiration timestamp | | jti | string | Unique token ID for replay protection |

React Integration

import { useState, useCallback } from 'react';
import SparkVault from '@sparkvault/sdk';

// Initialize once, outside component
const sparkvault = SparkVault.init({
  accountId: 'acc_YOUR_ACCOUNT_ID'
});

function useSparkVaultAuth() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const login = useCallback(async (options = {}) => {
    setLoading(true);
    setError(null);

    try {
      // Open verification modal
      const result = await sparkvault.identity.pop(options);

      // Send token to backend
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token: result.token })
      });

      if (!response.ok) throw new Error('Login failed');

      const data = await response.json();
      setUser(data.user);
      return data.user;

    } catch (err) {
      if (err.code !== 'user_cancelled') {
        setError(err.message);
      }
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  const logout = useCallback(async () => {
    await fetch('/api/auth/logout', { method: 'POST' });
    setUser(null);
  }, []);

  return { user, loading, error, login, logout };
}

// Usage in component
function LoginPage() {
  const { user, loading, error, login, logout } = useSparkVaultAuth();

  if (user) {
    return (
      <div>
        <p>Welcome, {user.email}!</p>
        <button onClick={logout}>Sign out</button>
      </div>
    );
  }

  return (
    <div>
      <button onClick={() => login()} disabled={loading}>
        {loading ? 'Verifying...' : 'Sign in'}
      </button>
      {error && <p className="error">{error}</p>}
    </div>
  );
}

Error Handling

The SDK throws typed errors that you can catch and handle appropriately.

import SparkVault, {
  UserCancelledError,
  ValidationError,
  NetworkError,
  TimeoutError
} from '@sparkvault/sdk';

try {
  const result = await sparkvault.identity.pop();
} catch (error) {
  switch (error.code) {
    case 'user_cancelled':
      // User closed the modal — not necessarily an error
      console.log('User cancelled verification');
      break;

    case 'validation_error':
      // Invalid input (e.g., malformed email)
      console.error('Validation error:', error.message);
      break;

    case 'network_error':
      // Network connectivity issue
      console.error('Network error — please check your connection');
      break;

    case 'timeout_error':
      // Request timed out
      console.error('Request timed out — please try again');
      break;

    case 'popup_blocked':
      // Browser blocked the popup
      console.error('Please allow popups for this site');
      break;

    default:
      console.error('Unexpected error:', error.message);
  }
}

Error Types

| Error Class | Code | Description | |-------------|------|-------------| | UserCancelledError | user_cancelled | User closed the modal without completing verification | | ValidationError | validation_error | Invalid input or configuration | | NetworkError | network_error | Network connectivity failure | | TimeoutError | timeout_error | Request exceeded timeout limit | | PopupBlockedError | popup_blocked | Browser blocked the popup window | | AuthenticationError | authentication_error | Authentication failed (e.g., expired token) |

TypeScript Support

The SDK is written in TypeScript and includes full type definitions.

import SparkVault, {
  // Configuration
  SparkVaultConfig,

  // Identity types
  VerifyOptions,
  VerifyResult,
  TokenClaims,

  // Error types
  SparkVaultError,
  UserCancelledError,
  ValidationError,
  NetworkError,
  TimeoutError,
  PopupBlockedError,
} from '@sparkvault/sdk';

// Fully typed configuration
const config: SparkVaultConfig = {
  accountId: 'acc_YOUR_ACCOUNT_ID',
  timeout: 30000,
};

const sparkvault = SparkVault.init(config);

// Fully typed options and result
const options: VerifyOptions = {
  email: '[email protected]',
  onCancel: () => console.log('Cancelled'),
};

const result: VerifyResult = await sparkvault.identity.pop(options);
// result.token: string
// result.identity: string
// result.identityType: 'email' | 'phone'

Best Practices

  1. Initialize Once — Create the SparkVault instance once when your app loads, not on every login attempt. The SDK preloads configuration for instant modal opening.

  2. Always Verify Server-Side — Never trust client-side token validation in production. Always verify the JWT signature on your backend using the JWKS endpoint before creating a session.

  3. Handle Cancellation Gracefully — Users may close the modal without completing verification. This throws a UserCancelledError — handle it gracefully rather than showing an error message.

  4. Cache JWKS Keys — The JWKS endpoint returns public keys with caching headers. Use a library like jose that handles caching automatically, or cache keys for 5-10 minutes.

Browser Support

The SDK supports all modern browsers:

  • Chrome 80+
  • Firefox 75+
  • Safari 13.1+
  • Edge 80+

Note: Passkey authentication requires WebAuthn support. On unsupported browsers, passkey will not appear as an option — other methods will still work.

Development

Setup

git clone https://github.com/Spark-Vault/sdk-js.git
cd sdk-js
npm install

Scripts

npm run build        # Build all bundles
npm run build:watch  # Build with watch mode
npm run typecheck    # Run TypeScript type checking
npm run lint         # Run ESLint
npm run test         # Run tests
npm run test:watch   # Run tests in watch mode

Project Structure

sdk-js/
├── src/
│   ├── index.ts           # Main entry point
│   ├── config.ts          # Configuration management
│   ├── http.ts            # HTTP client
│   ├── errors.ts          # Error types
│   └── identity/          # Identity module
├── dist/                  # Built bundles
├── tests/                 # Test files
├── .github/workflows/     # CI/CD workflows
├── rollup.config.js       # Rollup bundler config
├── tsconfig.json          # TypeScript config
└── package.json

License

MIT License - see LICENSE for details.

Links