npm package: @sahilw/dust-express
Description: Express.js middleware for HTTP 402 private payments via Dust Protocol
Author: Dust Protocol
Latest version: 0.1.0
Deprecated: Moved to dust-express (unscoped). Install: npm i dust-express

# @dust/express

[![npm version](https://img.shields.io/npm/v/@dust/express)](https://www.npmjs.com/package/@dust/express)

Express.js middleware for HTTP 402 private payments via the Dust Protocol. Drop a single middleware onto any route to require payment before serving the response.

## Installation

```bash
npm install @dust/express express
```

## Quick Start

```typescript
import express from 'express'
import { dustPaywall } from '@dust/express'

const app = express()

app.get(
  '/api/premium',
  dustPaywall({
    amount: '0.001',
    asset: 'ETH',
    privacy: 'transparent',
    chainId: 11155111,
    facilitator: 'https://facilitator.example.com',
    recipient: '0xYourRecipientAddress',
  }),
  (req, res) => {
    res.json({ data: 'this is gated content' })
  },
)

app.listen(3000)
```

## How It Works

1. A request arrives without a payment proof (`X-Dust-Payment` header absent).
2. The middleware responds `402 Payment Required` with an `X-Dust-402` header containing a base64-encoded `PaymentRequirement`.
3. The client reads the requirement, generates a `PaymentProof`, verifies it with the facilitator, and retries with `X-Dust-Payment` set.
4. The middleware decodes and verifies the proof via the facilitator. If valid, calls `next()`.

## API Reference

### `dustPaywall(config: DustPaywallConfig)`

Returns an Express middleware function `(req, res, next) => void`.

```typescript
import { dustPaywall, type DustPaywallConfig } from '@dust/express'

app.use('/api/premium', dustPaywall(config))
```

#### `DustPaywallConfig`

```typescript
interface DustPaywallConfig {
  /** Payment amount. Can be a fixed string or a function receiving the request. */
  amount: string | ((req: Request) => string)
  /** Token symbol or address (e.g. 'ETH', '0x...'). */
  asset: string
  /** Privacy level: 'transparent' | 'stealth' | 'private'. */
  privacy: PrivacyLevel
  /** Chain ID for payment verification. */
  chainId: number
  /** Facilitator base URL for proof verification. */
  facilitator: string
  /** Address that should receive the payment. */
  recipient: string
  /** Payment requirement TTL in seconds. Default: 300. */
  ttlSeconds?: number
}
```

**Dynamic pricing example:**

```typescript
app.get(
  '/api/data/:tier',
  dustPaywall({
    amount: (req) => req.params.tier === 'premium' ? '0.01' : '0.001',
    asset: 'ETH',
    privacy: 'transparent',
    chainId: 11155111,
    facilitator: 'https://facilitator.example.com',
    recipient: '0xYourAddress',
  }),
  handler,
)
```

---

### Response Format

**402 (no proof):**

```http
HTTP/1.1 402 Payment Required
X-Dust-402: <base64-encoded PaymentRequirement>
Content-Type: application/json

{
  "error": "Payment Required",
  "requirement": { "amount": "0.001", "asset": "ETH", ... }
}
```

**402 (invalid proof):**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json

{ "error": "Payment verification failed" }
```

**200 (valid proof):** Calls `next()` — the route handler responds normally.

---

### Full Server Example

```typescript
import express from 'express'
import { dustPaywall } from '@dust/express'

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

// Free endpoint
app.get('/api/public', (req, res) => {
  res.json({ message: 'Free content' })
})

// Paid endpoint — 0.001 ETH per request
app.get(
  '/api/premium',
  dustPaywall({
    amount: '0.001',
    asset: 'ETH',
    privacy: 'transparent',
    chainId: 11155111,
    facilitator: 'https://facilitator.example.com',
    recipient: '0xYourRecipientAddress',
    ttlSeconds: 300,
  }),
  (req, res) => {
    res.json({
      data: 'Gated response',
      timestamp: Date.now(),
    })
  },
)

// Per-route pricing
const PRICES: Record<string, string> = {
  basic: '0.0001',
  premium: '0.001',
  enterprise: '0.01',
}

app.get(
  '/api/report/:tier',
  dustPaywall({
    amount: (req) => PRICES[req.params.tier] ?? '0.001',
    asset: 'ETH',
    privacy: 'transparent',
    chainId: 11155111,
    facilitator: 'https://facilitator.example.com',
    recipient: '0xYourAddress',
  }),
  (req, res) => {
    res.json({ tier: req.params.tier, report: '...' })
  },
)

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

---

### Client Integration

Use `@dust/http402`'s `createPaymentClient` to call a paywall-protected endpoint:

```typescript
import { createPaymentClient } from '@dust/http402'

const client = createPaymentClient({
  chainId: 11155111,
  signer: {
    signTypedData: async (domain, types, value) => wallet.signTypedData({ domain, types, message: value }),
    getAddress: async () => wallet.account.address,
  },
})

const response = await client.fetchWithPayment('http://localhost:3000/api/premium')
const data = await response.json()
```

## Dependencies

- **`@dust/http402`** — payment protocol types, header encoding, verifier
- **`express`** >=4.17.0 (peer dependency)

## License

MIT