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

@w3payments/adapters

v1.2.2

Published

Payment vendor adapters for W3 Payments platform

Readme

@w3payments/adapters

Vendor-specific payment adapter implementations for the W3 Payments Platform. This package provides the integration layer between the W3 Payments core engine and external payment vendors using the adapter pattern for extensibility.

Installation

npm install @w3payments/adapters

Dependencies: Automatically installs @w3payments/common.

Key Features

  • MeshPay integration - Complete Mesh Connect SDK implementation
  • Adapter pattern architecture - Extensible design for adding new vendors
  • Vendor abstraction - Unified interface across different payment providers
  • Error handling - Vendor-specific error mapping and recovery
  • Type safety - Full TypeScript support for all vendor APIs

🚀 Current Integrations

MeshPay Adapter

MeshPay provides crypto-to-crypto payment processing and exchange integrations.

Features

  • Crypto-to-crypto transfers - BTC, ETH, USDC, SOL and more
  • Exchange integrations - Coinbase, Kraken, Binance support
  • Secure authentication - OAuth-based user consent flow
  • Real-time status - Payment tracking and confirmation
  • Multi-network support - Bitcoin, Ethereum, Solana, Polygon

Basic Usage

import { MeshPayAdapter } from '@w3payments/adapters/meshpay';
import type { CreatePaymentOptions } from '@w3payments/common';

// Initialize adapter
const adapter = new MeshPayAdapter({
  clientId: 'your_mesh_client_id',
  clientSecret: 'your_mesh_client_secret',
  environment: 'sandbox' // or 'production'
});

// Create payment session
const paymentOptions: CreatePaymentOptions = {
  amount: '100.00',
  currency: 'USD',
  destinations: [{
    address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
    networkId: 'bitcoin',
    symbol: 'BTC'
  }],
  targetCurrency: 'BTC',
  targetNetwork: 'bitcoin'
};

const session = await adapter.createSession(paymentOptions);
console.log('MeshPay session URL:', session.url);

Supported Payment Methods

// Crypto wallet transfers
const cryptoOptions = {
  amount: '50.00',
  currency: 'USD',
  targetCurrency: 'USDC',
  targetNetwork: 'ethereum',
  // User pays with existing crypto from their wallet
  paymentMethodFilter: {
    walletFilter: ['BTC', 'ETH', 'USDC']
  }
};

// Exchange account transfers  
const exchangeOptions = {
  amount: '100.00', 
  currency: 'USD',
  targetCurrency: 'SOL',
  targetNetwork: 'solana',
  // User pays from exchange account (Coinbase, Kraken, etc.)
  paymentMethodFilter: {
    exchangeFilter: ['coinbase', 'kraken', 'binance']
  }
};

Configuration Options

interface MeshPayConfig {
  clientId: string;           // MeshPay client ID
  clientSecret: string;       // MeshPay client secret  
  environment: 'sandbox' | 'production';
  
  // Optional settings
  settings?: {
    transferFinishTimeout?: number;  // Default: 60000ms
    catalogPageSize?: number;        // Default: 20
    enableTestMode?: boolean;        // Default: false
  };
}

const adapter = new MeshPayAdapter({
  clientId: process.env.MESH_CLIENT_ID!,
  clientSecret: process.env.MESH_CLIENT_SECRET!,
  environment: 'production',
  settings: {
    transferFinishTimeout: 120000,  // 2 minutes
    catalogPageSize: 50,
    enableTestMode: false
  }
});

Session Management

// Create session with specific options
const session = await adapter.createSession({
  amount: '75.00',
  currency: 'USD',
  destinations: [/* ... */],
  // MeshPay specific options
  vendorOptions: {
    userId: 'user_123',              // Optional user identifier
    metadata: {                      // Optional metadata
      orderId: 'order_456',
      merchantId: 'merchant_789'
    }
  }
});

// Check session status
const status = await adapter.getSessionStatus(session.id);
console.log('Payment status:', status.status);
console.log('Transaction ID:', status.transactionId);
console.log('Network fees:', status.networkFees);

🔧 Creating Custom Adapters

Adapter Interface

All adapters must implement the VendorAdapter interface:

import type { 
  VendorAdapter, 
  CreatePaymentOptions, 
  CheckoutSession,
  PaymentResult 
} from '@w3payments/common';

interface VendorAdapter {
  // Create new payment session
  createSession(options: CreatePaymentOptions): Promise<CheckoutSession>;
  
  // Get payment status
  getSessionStatus(sessionId: string): Promise<PaymentResult>;
  
  // Optional: Get supported payment methods
  getSupportedMethods?(): Promise<PaymentMethod[]>;
  
  // Optional: Validate configuration
  validateConfig?(): Promise<boolean>;
}

Example Custom Adapter

import type { 
  VendorAdapter, 
  CreatePaymentOptions, 
  CheckoutSession, 
  PaymentResult 
} from '@w3payments/common';

export class CustomVendorAdapter implements VendorAdapter {
  private apiKey: string;
  private baseUrl: string;
  
  constructor(config: { apiKey: string; environment: string }) {
    this.apiKey = config.apiKey;
    this.baseUrl = config.environment === 'production' 
      ? 'https://api.customvendor.com'
      : 'https://sandbox.customvendor.com';
  }
  
  async createSession(options: CreatePaymentOptions): Promise<CheckoutSession> {
    // Validate input
    if (!options.amount || !options.destinations?.length) {
      throw new Error('Invalid payment options');
    }
    
    // Transform W3 format to vendor format
    const vendorPayload = this.transformPaymentOptions(options);
    
    // Make API call
    const response = await fetch(`${this.baseUrl}/sessions`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(vendorPayload)
    });
    
    if (!response.ok) {
      throw new Error(`Vendor API error: ${response.statusText}`);
    }
    
    const data = await response.json();
    
    // Transform vendor response to W3 format
    return {
      id: data.sessionId,
      vendorId: 'custom-vendor',
      url: data.checkoutUrl,
      status: 'pending',
      expiresAt: new Date(data.expirationTime)
    };
  }
  
  async getSessionStatus(sessionId: string): Promise<PaymentResult> {
    const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`
      }
    });
    
    if (!response.ok) {
      throw new Error(`Failed to get session status: ${response.statusText}`);
    }
    
    const data = await response.json();
    
    return {
      status: this.mapVendorStatus(data.status),
      transactionId: data.transactionHash,
      amount: data.finalAmount,
      currency: data.finalCurrency,
      networkFees: data.fees,
      completedAt: data.completedAt ? new Date(data.completedAt) : undefined
    };
  }
  
  private transformPaymentOptions(options: CreatePaymentOptions) {
    // Transform W3 payment options to vendor API format
    return {
      amount: parseFloat(options.amount),
      sourceCurrency: options.currency,
      targetCurrency: options.targetCurrency,
      destinationAddress: options.destinations[0].address,
      network: options.targetNetwork,
      // Add vendor-specific fields
    };
  }
  
  private mapVendorStatus(vendorStatus: string): PaymentStatus {
    // Map vendor status to standard W3 status
    switch (vendorStatus.toLowerCase()) {
      case 'created':
      case 'pending':
        return 'pending';
      case 'processing':
      case 'confirming':
        return 'processing';
      case 'completed':
      case 'success':
        return 'completed';
      case 'failed':
      case 'error':
      case 'cancelled':
        return 'failed';
      default:
        return 'pending';
    }
  }
}

Registering Custom Adapters

import { AdapterRegistry } from '@w3payments/core';
import { CustomVendorAdapter } from './custom-vendor-adapter';

// Register with core
const registry = new AdapterRegistry();
registry.register('custom-vendor', new CustomVendorAdapter({
  apiKey: process.env.CUSTOM_VENDOR_API_KEY!,
  environment: 'sandbox'
}));

🔒 Security Considerations

API Key Management

// ✅ Good: Use environment variables
const adapter = new MeshPayAdapter({
  clientId: process.env.MESH_CLIENT_ID!,
  clientSecret: process.env.MESH_CLIENT_SECRET!,
  environment: 'production'
});

// ❌ Bad: Hardcoded secrets
const adapter = new MeshPayAdapter({
  clientId: 'mesh_client_123',
  clientSecret: 'mesh_secret_456',  // Never do this!
  environment: 'production'
});

Request Validation

export class SecureAdapter implements VendorAdapter {
  async createSession(options: CreatePaymentOptions): Promise<CheckoutSession> {
    // Validate required fields
    this.validatePaymentOptions(options);
    
    // Sanitize input data
    const sanitizedOptions = this.sanitizeInput(options);
    
    // Proceed with API call
    return this.callVendorAPI(sanitizedOptions);
  }
  
  private validatePaymentOptions(options: CreatePaymentOptions): void {
    if (!options.amount || parseFloat(options.amount) <= 0) {
      throw new Error('Invalid amount');
    }
    
    if (!options.destinations?.length) {
      throw new Error('At least one destination required');
    }
    
    // Validate addresses
    for (const dest of options.destinations) {
      if (!this.isValidAddress(dest.address, dest.networkId)) {
        throw new Error(`Invalid address for network ${dest.networkId}`);
      }
    }
  }
  
  private sanitizeInput(options: CreatePaymentOptions): CreatePaymentOptions {
    return {
      ...options,
      amount: parseFloat(options.amount).toFixed(8), // Normalize precision
      destinations: options.destinations.map(dest => ({
        ...dest,
        address: dest.address.trim(), // Remove whitespace
      }))
    };
  }
}

⚠️ Error Handling

Adapter-Specific Errors

export class AdapterError extends Error {
  constructor(
    message: string,
    public vendorId: string,
    public vendorCode?: string,
    public details?: any
  ) {
    super(message);
    this.name = 'AdapterError';
  }
}

// Usage in adapter
async createSession(options: CreatePaymentOptions): Promise<CheckoutSession> {
  try {
    const response = await this.callVendorAPI(options);
    return this.transformResponse(response);
  } catch (error) {
    // Transform vendor errors to standardized format
    throw new AdapterError(
      'Failed to create payment session',
      'mesh-pay',
      error.code,
      { originalError: error.message }
    );
  }
}

Retry Logic

async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<T> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
      
      // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, delay * attempt));
    }
  }
  
  throw new Error('Max retries exceeded');
}

// Use in adapter
async getSessionStatus(sessionId: string): Promise<PaymentResult> {
  return withRetry(() => this.fetchSessionStatus(sessionId));
}

🧪 Testing Adapters

Mock Implementations

export class MockMeshPayAdapter implements VendorAdapter {
  private sessions = new Map<string, any>();
  
  async createSession(options: CreatePaymentOptions): Promise<CheckoutSession> {
    const sessionId = `mock_session_${Date.now()}`;
    
    this.sessions.set(sessionId, {
      ...options,
      status: 'pending',
      createdAt: new Date()
    });
    
    return {
      id: sessionId,
      vendorId: 'mesh-pay',
      url: `https://mock-meshpay.example.com/session/${sessionId}`,
      status: 'pending'
    };
  }
  
  async getSessionStatus(sessionId: string): Promise<PaymentResult> {
    const session = this.sessions.get(sessionId);
    if (!session) {
      throw new Error('Session not found');
    }
    
    return {
      status: 'completed', // Mock successful payment
      transactionId: `mock_tx_${sessionId}`,
      amount: session.amount,
      currency: session.currency
    };
  }
}

Integration Tests

import { MeshPayAdapter } from '@w3payments/adapters/meshpay';

describe('MeshPayAdapter', () => {
  let adapter: MeshPayAdapter;
  
  beforeEach(() => {
    adapter = new MeshPayAdapter({
      clientId: 'test_client_id',
      clientSecret: 'test_client_secret',
      environment: 'sandbox'
    });
  });
  
  test('creates payment session successfully', async () => {
    const options = {
      amount: '100.00',
      currency: 'USD',
      destinations: [{
        address: 'test_address',
        networkId: 'ethereum',
        symbol: 'USDC'
      }]
    };
    
    const session = await adapter.createSession(options);
    
    expect(session.id).toBeDefined();
    expect(session.vendorId).toBe('mesh-pay');
    expect(session.url).toMatch(/^https:/);
  });
});

📚 Planned Integrations

Coming Soon

  • IronPay - Fiat-to-crypto onramping with ACH support
  • Circle - USDC payment processing and programmable wallets
  • Stripe Crypto - Traditional payment integration with crypto settlement
  • Coinbase Commerce - Direct Coinbase integration for merchants
  • BitPay - Bitcoin payment processing and invoicing

Future Considerations

  • PayPal Crypto - When available for business integration
  • Square Crypto - Point-of-sale crypto payments
  • Shopify Payments - E-commerce platform integration

📄 License

Proprietary - All rights reserved


💡 Pro Tip: When building custom adapters, always implement comprehensive error handling and validate all inputs. The adapter pattern allows you to maintain consistent behavior across different vendors while handling their unique requirements.