npm package: @shade402/express
Description: Express.js middleware and decorators for X402 payment protocol
Author: shade402
Latest version: 0.0.1

# @shade402/express

Express.js middleware and utilities for implementing the X402 payment protocol in your web applications.

## Overview

The Express package provides middleware and helper functions to easily add X402 payment requirements to your Express.js routes. It handles payment verification, 402 response generation, and integrates seamlessly with Solana blockchain payments.

## Features

* Payment middleware for protecting routes with automatic verification
* Centralized error handling middleware for X402 payment errors
* Automatic payment verification using Solana blockchain
* Flexible configuration with global or per-route options
* 402 response builder for creating proper payment requests
* Full TypeScript support with Express request extensions
* Integration with Express error handling

## Installation

```bash
npm install @shade402/express
# or
pnpm add @shade402/express
# or
yarn add @shade402/express
```

## Dependencies

* `@shade402/core`: Core X402 protocol implementation
* `express`: Express.js web framework

## Usage

### Basic Setup with Global Configuration

```typescript
import express from 'express';
import { initX402, paymentRequired } from '@shade402/express';

const app = express();
app.use(express.json());

// Initialize X402 with global configuration
initX402({
  paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
  tokenMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
  network: 'solana-devnet',
  rpcUrl: process.env.SOLANA_RPC_URL,
  autoVerify: true
});

// Protect a route with payment requirement
app.get('/premium-content',
  paymentRequired({
    amount: '1000000', // 1 USDC (6 decimals)
    description: 'Access to premium content'
  }),
  (req, res) => {
    // This code only runs after payment is verified
    res.json({
      content: 'Premium content here',
      paidBy: req.payment?.publicKey
    });
  }
);

app.listen(3000, () => console.log('Server running on port 3000'));
```

### Per-Route Configuration

You can override global configuration for specific routes:

```typescript
import { paymentRequired } from '@shade402/express';

// Override global config for specific routes
app.get('/api/data',
  paymentRequired({
    amount: '500000',
    paymentAddress: 'SpecificWalletAddress',
    tokenMint: 'So11111111111111111111111111111111111111112', // Native SOL
    network: 'solana-mainnet',
    description: 'API data access',
    expiresIn: 300, // 5 minutes
    autoVerify: true
  }),
  (req, res) => {
    res.json({ data: 'Your data here' });
  }
);
```

### Error Handling Middleware

Add the error middleware at the end of your middleware stack to handle X402 payment errors:

```typescript
import express from 'express';
import { x402ErrorMiddleware } from '@shade402/express';

const app = express();

// ... your routes ...

// Add error middleware at the end (after all routes)
app.use(x402ErrorMiddleware({
  logErrors: true,
  includeStack: process.env.NODE_ENV === 'development'
}));
```

The error middleware automatically handles:

* `PaymentRequiredError`: Returns 402 status with payment request
* `PaymentExpiredError`: Returns 410 Gone status
* `InsufficientFundsError`: Returns 402 status
* `PaymentVerificationError`: Returns 403 Forbidden status
* `TransactionBroadcastError`: Returns 502 Bad Gateway status
* `InvalidPaymentRequestError`: Returns 400 Bad Request status
* Generic errors: Returns 500 Internal Server Error

### Manual Payment Verification

For custom verification logic, disable automatic verification:

```typescript
import { paymentRequired } from '@shade402/express';
import { X402Request } from '@shade402/express';

app.post('/custom-endpoint',
  paymentRequired({
    amount: '2000000',
    autoVerify: false // Disable automatic verification
  }),
  (req: X402Request, res) => {
    // Payment authorization is available but not verified
    const payment = req.payment;

    // Do custom verification logic
    if (payment && customVerificationLogic(payment)) {
      res.json({ success: true });
    } else {
      res.status(403).json({ error: 'Payment verification failed' });
    }
  }
);
```

### Building 402 Responses Manually

For custom payment flow control, build 402 responses manually:

```typescript
import { build402Response } from '@shade402/express';

app.get('/custom-protected', (req, res) => {
  // Check some condition
  if (!userHasPaid) {
    const response = build402Response({
      amount: '1000000',
      paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
      tokenMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
      network: 'solana-devnet',
      resource: req.path,
      description: 'Custom payment required'
    });

    // Optional: Set X402 headers for better client compatibility
    return res
      .status(402)
      .set({
        'X-Payment-Required': 'true',
        'X-Payment-Protocol': 'x402',
        'X-Payment-Amount': '1000000',
        'X-Payment-Asset': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
      })
      .json(response);
  }

  res.json({ content: 'Protected content' });
});
```

### Configuration Options

```typescript
import { initX402, X402ConfigOptions } from '@shade402/express';

const config: X402ConfigOptions = {
  paymentAddress: string;      // Your Solana wallet address
  tokenMint: string;            // Token mint address (SPL token or SOL)
  network: string;              // 'solana-devnet' or 'solana-mainnet'
  rpcUrl?: string;              // Optional custom RPC endpoint
  autoVerify?: boolean;         // Auto-verify payments (default: true)
  expiresIn?: number;           // Payment expiration in seconds (default: 600)
};

initX402(config);
```

### Accessing Payment Information

Payment information is available on the request object after verification:

```typescript
import { X402Request } from '@shade402/express';

app.get('/payment-info',
  paymentRequired({ amount: '1000000' }),
  (req: X402Request, res) => {
    const payment = req.payment;

    if (!payment) {
      return res.status(402).json({ error: 'Payment required' });
    }

    res.json({
      paymentId: payment.paymentId,
      amount: payment.actualAmount,
      payer: payment.publicKey,
      transactionHash: payment.transactionHash,
      timestamp: payment.timestamp
    });
  }
);
```

### Multiple Payment Tiers

You can implement different payment tiers for different routes:

```typescript
// Basic tier
app.get('/basic',
  paymentRequired({ amount: '100000', description: 'Basic access' }),
  handler
);

// Premium tier
app.get('/premium',
  paymentRequired({ amount: '1000000', description: 'Premium access' }),
  handler
);

// Enterprise tier
app.get('/enterprise',
  paymentRequired({ amount: '10000000', description: 'Enterprise access' }),
  handler
);
```

## API Reference

### Middleware

#### `paymentRequired(options: PaymentRequiredOptions)`

Express middleware that requires payment to access a route.

**Options:**

```typescript
interface PaymentRequiredOptions {
  amount: string;                    // Required payment amount in token base units
  paymentAddress?: string;           // Override global payment address
  tokenMint?: string;                // Override global token mint
  network?: string;                  // Override global network
  description?: string;              // Payment description
  expiresIn?: number;                // Payment expiration in seconds
  autoVerify?: boolean;              // Enable automatic verification
}
```

**Returns:** Express middleware function

### Configuration

#### `initX402(config: X402ConfigOptions)`

Initialize global X402 configuration. Must be called before using payment middleware.

#### `getConfig()`

Get current global configuration.

**Returns:** `X402ConfigOptions | undefined`

#### `isInitialized()`

Check if X402 is initialized.

**Returns:** `boolean`

### Error Middleware

#### `x402ErrorMiddleware(options?: X402ErrorMiddlewareOptions)`

Error handling middleware for X402 payment errors and general application errors.

**Options:**

```typescript
interface X402ErrorMiddlewareOptions {
  includeStack?: boolean;  // Include stack traces (default: NODE_ENV === 'development')
  logErrors?: boolean;     // Log errors to console (default: true)
  onError?: (error: Error, req: Request, res: Response) => void; // Custom error handler
}
```

**Note:** This middleware should be added after all your routes and middleware.

### Response Builders

#### `build402Response(options: Build402ResponseOptions)`

Build a 402 Payment Required response object.

**Options:**

```typescript
interface Build402ResponseOptions {
  amount: string;
  paymentAddress: string;
  tokenMint: string;
  network: string;
  resource: string;
  description?: string;
  expiresIn?: number;
}
```

**Returns:** Payment request object that should be sent with status 402.

### Type Definitions

#### `X402Request`

Extended Express Request interface with payment information:

```typescript
interface X402Request extends Request {
  payment?: PaymentAuthorization;
}
```

## TypeScript Support

The package includes full TypeScript definitions. Use the `X402Request` type for request objects in protected routes:

```typescript
import { X402Request } from '@shade402/express';

app.get('/protected',
  paymentRequired({ amount: '1000000' }),
  (req: X402Request, res: Response) => {
    // req.payment is available here
    const payment = req.payment;
    // ...
  }
);
```

## Error Responses

The error middleware returns standardized error responses:

### 402 Payment Required

```json
{
  "error": "Payment required",
  "code": "PAYMENT_REQUIRED",
  "payment_request": { ... }
}
```

### 403 Forbidden (Payment Verification Failed)

```json
{
  "error": "Payment verification failed",
  "code": "PAYMENT_VERIFICATION_FAILED"
}
```

### 410 Gone (Payment Expired)

```json
{
  "error": "Payment request expired",
  "code": "PAYMENT_EXPIRED"
}
```

## Best Practices

1. Initialize X402 configuration once at application startup
2. Store sensitive configuration in environment variables
3. Use appropriate payment amounts for different tiers
4. Set reasonable expiration times for payment requests
5. Enable automatic verification in production
6. Add error middleware after all routes
7. Use TypeScript types for better type safety
8. Monitor payment verification failures
9. Consider rate limiting for payment-protected endpoints
10. Log payment transactions for audit purposes

## Examples

### Complete Express Server

```typescript
import express from 'express';
import { initX402, paymentRequired, x402ErrorMiddleware } from '@shade402/express';

const app = express();
app.use(express.json());

// Initialize X402
initX402({
  paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
  tokenMint: process.env.TOKEN_MINT!,
  network: 'solana-devnet',
  rpcUrl: process.env.SOLANA_RPC_URL,
  autoVerify: true,
  expiresIn: 600
});

// Public route
app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

// Protected route
app.get('/api/data',
  paymentRequired({
    amount: '1000000',
    description: 'API data access'
  }),
  (req, res) => {
    res.json({ data: 'Protected data' });
  }
);

// Error handling
app.use(x402ErrorMiddleware({
  logErrors: true,
  includeStack: process.env.NODE_ENV === 'development'
}));

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
```

### Custom Payment Verification

```typescript
import { paymentRequired, X402Request } from '@shade402/express';
import { verifyPaymentInDatabase } from './database';

app.post('/api/process',
  paymentRequired({
    amount: '1000000',
    autoVerify: false
  }),
  async (req: X402Request, res) => {
    const payment = req.payment;
    
    if (!payment) {
      return res.status(402).json({ error: 'Payment required' });
    }

    // Custom verification against database
    const isVerified = await verifyPaymentInDatabase(payment.transactionHash);
    
    if (!isVerified) {
      return res.status(403).json({ error: 'Payment not verified' });
    }

    // Process request
    res.json({ success: true });
  }
);
```

## Testing

```bash
pnpm test
```

## Contributing

See [CONTRIBUTING.md](../../CONTRIBUTING.md)

## License

MIT - See [LICENSE](../../LICENSE/)