Skip to main content

Overview

The @1stdigital/prism-http package provides middleware for vanilla Node.js HTTP servers, without requiring any framework. Perfect for lightweight APIs or custom HTTP implementations.

Zero Dependencies

Works with raw http/https modules

Framework-Free

No Express, Fastify, or other framework needed

Lightweight

Minimal overhead, maximum performance

Installation

npm install @1stdigital/prism-http

Quick Start

const http = require("http");
const { prismPaymentMiddleware } = require("@1stdigital/prism-http");

// Create middleware
const middleware = prismPaymentMiddleware(
  {
    apiKey: "dev-key-123",
    baseUrl: "https://prism-api.test.1stdigital.tech",
  },
  {
    "/api/premium": {
      price: 0.01, // $0.01 USD
      description: "Premium API",
    },
  }
);

// Create HTTP server
const server = http.createServer((req, res) => {
  // Apply middleware
  middleware(req, res, () => {
    // This runs only if payment verified
    if (req.url === "/api/premium") {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(
        JSON.stringify({
          message: "Premium content",
          payer: req.payer, // Wallet address
        })
      );
    } else {
      res.writeHead(404);
      res.end("Not Found");
    }
  });
});

server.listen(3000);

Configuration

interface PrismMiddlewareConfig {
  apiKey: string;
  baseUrl?: string;
  debug?: boolean;
}

interface RoutePaymentConfig {
  price: number | string; // USD price
  description: string;
  mimeType?: string;
}

Routing

URL-based Routing

const server = http.createServer((req, res) => {
  middleware(req, res, () => {
    const url = new URL(req.url, `http://${req.headers.host}`);

    if (url.pathname === "/api/premium") {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(
        JSON.stringify({
          message: "Premium",
          payer: req.payer,
        })
      );
    } else if (url.pathname === "/api/weather") {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(
        JSON.stringify({
          location: "SF",
          temperature: 72,
          payer: req.payer,
        })
      );
    } else {
      res.writeHead(404);
      res.end("Not Found");
    }
  });
});

Accessing Payment Info

const server = http.createServer((req, res) => {
  middleware(req, res, () => {
    // Access payer address
    const payer = req.payer;
    // '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'

    // Access payment object (in res.locals)
    const payment = res.locals?.payment;

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(
      JSON.stringify({
        message: "Data",
        payer,
        network: payment?.network,
      })
    );
  });
});

Settlement Validation

HTTP middleware intercepts res.end() to validate settlement:
// Internal implementation (automatic!)
const originalEnd = res.end.bind(res);

res.end = async function(chunk, encoding, callback) {
  const settlementResult = await core.settlementCallback(...);

  if (!settlementResult || !settlementResult.success) {
    // ❌ Settlement failed
    res.statusCode = 402;
    res.setHeader('Content-Type', 'application/json');
    return originalEnd(JSON.stringify({
      error: 'Payment settlement failed'
    }));
  }

  // ✅ Settlement succeeded
  res.setHeader('X-PAYMENT-RESPONSE', settlementResult.transaction);
  return originalEnd(chunk, encoding, callback);
};

Testing

const http = require("http");
const { prismPaymentMiddleware } = require("@1stdigital/prism-http");

describe("HTTP Payment Middleware", () => {
  let server;

  beforeAll(() => {
    const middleware = prismPaymentMiddleware(
      { apiKey: "test-key" },
      { "/api/premium": { price: 0.01, description: "Test" } }
    );

    server = http.createServer((req, res) => {
      middleware(req, res, () => {
        res.writeHead(200);
        res.end(JSON.stringify({ message: "OK", payer: req.payer }));
      });
    });

    server.listen(0); // Random port
  });

  afterAll(() => server.close());

  test("returns 402 without payment", async () => {
    const port = server.address().port;
    const response = await fetch(`http://localhost:${port}/api/premium`);

    expect(response.status).toBe(402);
  });
});

Next Steps