# INP Middleware

A TypeScript middleware library for Express.js and Next.js that enables service providers to accept and validate payments using the INP (Internet Native Payments) protocol.

## Features

- **Unified Middleware**: Single middleware function handles both service discovery and payment validation
- **Payment Validation**: Automatic validation of blockchain payments with support for multiple networks
- **Service Discovery**: Automatic discovery of service configuration from INP platform
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Easy Integration**: Simple setup for Express.js and Next.js applications
- **Flexible Configuration**: Support for custom payment networks, currencies, and validation rules

## Installation

```bash
npm install @ronnakamoto/inp-middleware
```

## Quick Start

### Express.js

```typescript
import express from 'express';
import { inpMiddleware } from '@ronnakamoto/inp-middleware';

const app = express();

// Apply INP middleware to your API routes
app.use('/api', inpMiddleware({
  projectId: 'your-project-id',
  logErrors: true
}));

// Your API endpoints - payment validation happens automatically
app.post('/api/payment', (req, res) => {
  // Payment is already validated by middleware
  // Access payment info: req.inpPayment
  // Access service config: req.inpDiscovery
  
  res.json({ 
    success: true, 
    message: 'Payment processed successfully' 
  });
});

app.listen(3000);
```

### Next.js API Routes

```typescript
// pages/api/payment.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { inpMiddleware } from '@ronnakamoto/inp-middleware';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  // Your payment processing logic here
  res.json({ success: true });
};

export default inpMiddleware({
  projectId: 'your-project-id'
})(handler);
```

## How It Works

The unified middleware automatically:

1. **Discovers Service Configuration**: Fetches your service's payment requirements from the INP platform
2. **Validates Payments**: Checks payment amount, currency, network, and transaction proof against your service configuration
3. **Verifies Transactions**: Always validates payments on-chain for security
4. **Enriches Requests**: Adds payment and discovery data to the request object
5. **Handles Errors**: Returns appropriate HTTP status codes for payment issues

### Payment Information Sources

The middleware can extract payment information from:

- **Headers**: `X-INP-Payment` or `X-Payment`
- **Request Body**: `{ payment: { ... } }`
- **Query Parameters**: `?payment={...}`

### Example Payment Object

```typescript
{
  amount: 0.001,
  currency: "USDC",
  network: "algorand",
  walletAddress: "user-wallet-address",
  transactionId: "txn_123456789",
  proof: "optional-payment-proof"
}
```

## Configuration Options

```typescript
interface INPMiddlewareOptions {
  // Required
  projectId: string;         // Your project ID
  
  // Optional
  inpPlatformUrl?: string;   // INP platform base URL (defaults to https://internetnativepayment.org)
  apiKey?: string;           // API key for authentication
  timeout?: number;          // Request timeout (default: 30000ms)
  retries?: number;          // Retry attempts (default: 3)
  
  // Payment Validation
  validatePayment?: (payment: INPPayment, endpointConfig: any) => Promise<INPValidationResult> | INPValidationResult;
  
  // Error Handling
  logErrors?: boolean;       // Enable error logging (default: true)
  
  // Metrics Integration
  metricsIngestUrl?: string; // Metrics ingest API URL (defaults to inpPlatformUrl/api/metrics/events)
  metricsIngestKey?: string; // Bearer token for metrics ingest API authentication
}
```

## Metrics Integration

The middleware automatically publishes metrics events for all payment-related activities. This enables real-time monitoring and analytics of your INP-powered services.

### Metrics Events

The middleware publishes the following events:

- **Payment Required**: When a request is made to a paid endpoint without payment
- **Payment Validation Failed**: When payment validation fails
- **Payment Success**: When payment is successfully validated
- **Free Endpoint**: When a request is made to a free endpoint

### Event Structure

```typescript
{
  projectId: string;
  endpointPath: string;
  paid: boolean;
  status: 'success' | 'failed';
  latencyMs: number;
  timestamp: string;
  amount?: number;
  currency?: string;
  walletAddr?: string;
  userId?: string;
}
```

### Automatic Metrics Publishing

**No configuration required!** The middleware automatically publishes metrics events using the same authentication and configuration as your INP platform connection.

```typescript
app.use('/api', inpMiddleware({
  projectId: 'your-project-id',
  apiKey: 'your-api-key' // Same key used for metrics
}));
```

### Metrics Pipeline

The metrics flow works as follows:

1. **Middleware** → Automatically publishes events to INP platform
2. **INP Platform** → Processes events and stores in database
3. **Dashboard** → Displays real-time metrics and analytics

Events are published asynchronously (fire-and-forget) to ensure they don't impact request performance.

### Benefits of This Design

- **Zero Configuration**: No additional environment variables needed
- **Secure**: Uses existing INP platform authentication
- **Simple**: Services don't need to know about metrics infrastructure
- **Reliable**: Leverages existing INP client with retry logic

## Service Configuration

Your service configuration is defined in the INP platform and includes:

```typescript
{
  "endpoints": {
    "payment": {
      "pricing_model": "fixed",
      "price": {
        "amount": "0.001",
        "currency": "USDC"
      },
      "networks": ["algorand", "ethereum"],
      "guaranteed_response_time": "5s"
    }
  }
}
```

## Error Handling

The middleware returns appropriate HTTP status codes:

- `402 Payment Required`: Payment is required but not provided
- `402 Payment Validation Failed`: Payment validation failed
- `400 Bad Request`: Invalid request or configuration
- `500 Internal Server Error`: Unexpected errors

### Example Error Response

```json
{
  "error": "Payment Required",
  "code": "PAYMENT_REQUIRED",
  "required": {
    "amount": "0.001",
    "currency": "USDC",
    "networks": ["algorand", "ethereum"]
  }
}
```

## Advanced Usage

### Custom Payment Validation

You can implement custom payment validation logic by providing a `validatePayment` function:

```typescript
app.use('/api', inpMiddleware({
  projectId: 'your-project-id',
  validatePayment: async (payment, endpointConfig) => {
    // Your custom validation logic here
    if (payment.amount < 0.001) {
      return {
        isValid: false,
        error: 'Payment amount too small'
      };
    }
    
    // Call your own payment verification service
    const verification = await verifyPaymentWithYourService(payment);
    
    if (!verification.success) {
      return {
        isValid: false,
        error: 'Payment verification failed'
      };
    }
    
    return {
      isValid: true,
      details: {
        transactionVerified: true,
        paymentDetails: {
          amount: payment.amount,
          currency: payment.currency,
          network: payment.network,
          timestamp: new Date().toISOString()
        }
      }
    };
  }
}));
```

The `validatePayment` function receives:
- `payment`: The payment object from the request
- `endpointConfig`: The endpoint configuration from the INP platform

It should return an `INPValidationResult` object with `isValid` boolean and optional `error` and `details` properties.

### Accessing Payment Data

```typescript
app.post('/api/service', (req, res) => {
  // Payment information
  const payment = req.inpPayment;
  console.log('Payment amount:', payment?.amount);
  console.log('Payment network:', payment?.network);
  
  // Service configuration
  const discovery = req.inpDiscovery;
  console.log('Service endpoints:', discovery?.endpoints);
  
  // Validation result
  const validation = req.inpValidation;
  console.log('Payment valid:', validation?.isValid);
  
  res.json({ success: true });
});
```

### Direct API Client Usage

```typescript
import { INPClient } from '@ronnakamoto/inp-middleware';

const client = new INPClient({
  // Uses https://internetnativepayment.org by default
  apiKey: 'your-api-key'
});

// Discover service configuration
const discovery = await client.getDiscoveryEndpoint({
  projectId: 'your-project-id'
});

// Validate payment
const validation = await client.validatePayment({
  endpointId: 'endpoint-id',
  payment: paymentData
});
```

## TypeScript Support

Full TypeScript support with comprehensive type definitions:

```typescript
import type { 
  INPRequest, 
  INPPayment, 
  INPDiscoveryEndpoint,
  INPValidationResult 
} from '@ronnakamoto/inp-middleware';

// Your request handler
function handler(req: INPRequest, res: Response) {
  const payment: INPPayment | undefined = req.inpPayment;
  const discovery: INPDiscoveryEndpoint | undefined = req.inpDiscovery;
  const validation: INPValidationResult | undefined = req.inpValidation;
}
```

### Error Handling

```typescript
import { INPError, INPPaymentError } from '@ronnakamoto/inp-middleware';

app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
  if (error instanceof INPPaymentError) {
    return res.status(402).json({
      error: error.message,
      code: error.code,
      details: error.details
    });
  }
  
  if (error instanceof INPError) {
    return res.status(error.statusCode).json({
      error: error.message,
      code: error.code,
      details: error.details
    });
  }
  
  next(error);
});
```

## API Reference

### Middleware Functions

#### `inpMiddleware(options)`
Main middleware function that handles both service discovery and payment validation for Express.js routes.

#### `clearDiscoveryCache(projectId?)`
Clears the discovery cache for testing or manual invalidation.

#### `getCachedDiscoveryData(projectId?)`
Gets cached discovery data for debugging.

### Client Class

#### `INPClient`
HTTP client for communicating with the INP platform.

- `getDiscoveryEndpoint(request)`: Fetch discovery endpoint
- `validatePayment(request)`: Validate payment
- `invokeService(request)`: Invoke service through platform
- `checkProjectPaymentStatus(projectId)`: Check if project has payment endpoints

### Error Classes

- `INPError`: Base error class
- `INPValidationError`: Validation errors
- `INPPaymentError`: Payment-related errors
- `INPDiscoveryError`: Discovery errors
- `INPClientError`: Client errors
- `INPConfigError`: Configuration errors

## Testing

```bash
# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Run tests in watch mode
npm run test:watch
```

## Development

```bash
# Install dependencies
npm install

# Build the library
npm run build

# Development build with watch
npm run dev

# Lint code
npm run lint
```

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request

## License

MIT License - see LICENSE file for details.

## Support

- [Documentation](https://github.com/inp-protocol/inp)
- [Issues](https://github.com/inp-protocol/inp/issues)
- [Discussions](https://github.com/inp-protocol/inp/discussions) 