⚠️ This system does not provide medical advice.
📦 Package Documentation
core
Middleware

Middleware

Runtime validation middleware for Express, Next.js, and other frameworks


Overview

Middleware automatically validates AI responses before they reach users, providing a hard safety gate in production APIs.

Request → AI → Validator Middleware → Response


Express.js Middleware

Basic Usage

import express from 'express';
import { governorValidator } from '@the-governor-hq/constitution-core';
 
const app = express();
 
app.use(express.json());
 
// Apply validator middleware
app.post('/api/chat',
  governorValidator({ domain: 'wearables', onViolation: 'block' }),
  async (req, res) => {
    const aiResponse = await callLLM(req.body.message);
    
    // Response auto-validated by middleware
    res.json({ message: aiResponse });
  }
);
 
app.listen(3000);

What happens:

  1. User sends request
  2. Your handler generates AI response
  3. Middleware validates before sending
  4. Unsafe content blocked automatically

Configuration

app.post('/api/insights',
  governorValidator({
    domain: 'wearables',
    onViolation: 'block',        // Block unsafe content
    strictMode: true,            // Use LLM judge
    useLLMJudge: true,           // For edge cases
    apiKey: process.env.OPENAI_API_KEY,
    defaultSafeMessage: 'Unable to generate safe insight.'
  }),
  async (req, res) => {
    // Your handler
  }
);

Custom Violation Handler

app.post('/api/chat',
  governorValidator({
    domain: 'wearables',
    onViolation: (violations, original) => {
      // Log violations to monitoring
      logger.error('Safety violation', { violations, original });
      
      // Return custom safe message
      return {
        message: 'I can help with general wellness questions.',
        violations: violations.map(v => v.id)
      };
    }
  }),
  async (req, res) => {
    // Handler
  }
);

Next.js API Routes

App Router (Next.js 13+)

// app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({
  domain: 'wearables',
  onViolation: 'block'
});
 
export async function POST(request: NextRequest) {
  const { message } = await request.json();
  
  const aiResponse = await callLLM(message);
  
  // Validate before returning
  const result = await validator.validate(aiResponse);
  
  if (!result.safe) {
    return NextResponse.json({
      message: result.safeAlternative,
      blocked: true,
      violations: result.violations.map(v => v.id)
    }, { status: 200 });
  }
  
  return NextResponse.json({ message: result.output });
}

Pages Router (Next.js 12)

// pages/api/chat.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({ domain: 'wearables' });
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { message } = req.body;
  
  const aiResponse = await callLLM(message);
  const result = await validator.validate(aiResponse);
  
  if (!result.safe) {
    return res.json({
      message: result.safeAlternative,
      blocked: true
    });
  }
  
  res.json({ message: result.output });
}

tRPC Middleware

import { TRPCError } from '@trpc/server';
import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({ domain: 'wearables' });
 
const governorMiddleware = t.middleware(async ({ next }) => {
  const result = await next();
  
  if (typeof result.data === 'string') {
    const validation = await validator.validate(result.data);
    
    if (!validation.safe) {
      throw new TRPCError({
        code: 'BAD_REQUEST',
        message: validation.safeAlternative
      });
    }
  }
  
  return result;
});
 
export const protectedProcedure = t.procedure.use(governorMiddleware);

GraphQL Middleware

import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({ domain: 'wearables' });
 
const resolvers = {
  Query: {
    getInsight: async (_, { userId }) => {
      const insight = await generateInsight(userId);
      
      const result = await validator.validate(insight);
      
      return {
        content: result.safe ? result.output : result.safeAlternative,
        safe: result.safe,
        violations: result.violations
      };
    }
  }
};

Streaming Responses

For Server-Sent Events or streaming AI responses:

import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({ domain: 'wearables' });
 
app.post('/api/stream', async (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  
  const stream = await callStreamingLLM(req.body.message);
  
  let buffer = '';
  
  for await (const chunk of stream) {
    buffer += chunk;
    
    // Validate accumulated buffer periodically
    if (buffer.length % 100 === 0) {
      const result = await validator.validate(buffer);
      
      if (!result.safe) {
        // Abort stream
        res.write(`data: ${JSON.stringify({ error: 'Content blocked' })}\n\n`);
        res.end();
        return;
      }
    }
    
    res.write(`data: ${chunk}\n\n`);
  }
  
  // Final validation
  const final = await validator.validate(buffer);
  
  if (!final.safe) {
    res.write(`data: ${JSON.stringify({ blocked: true })}\n\n`);
  }
  
  res.end();
});

WebSocket Middleware

import { Server } from 'socket.io';
import { createValidator } from '@the-governor-hq/constitution-core';
 
const io = new Server(server);
const validator = createValidator({ domain: 'wearables' });
 
io.on('connection', (socket) => {
  socket.on('message', async (data) => {
    const aiResponse = await callLLM(data.message);
    
    const result = await validator.validate(aiResponse);
    
    socket.emit('response', {
      message: result.safe ? result.output : result.safeAlternative,
      safe: result.safe,
      violations: result.safe ? [] : result.violations.map(v => v.id)
    });
  });
});

Custom Middleware Factory

Create reusable middleware for your stack:

import { createValidator, type ValidatorConfig } from '@the-governor-hq/constitution-core';
 
export function createGovernorMiddleware(config: ValidatorConfig) {
  const validator = createValidator(config);
  
  return async (req: any, res: any, next: any) => {
    // Store original json method
    const originalJson = res.json.bind(res);
    
    // Override json method to validate responses
    res.json = async (data: any) => {
      if (data.message) {
        const result = await validator.validate(data.message);
        
        if (!result.safe) {
          data.message = result.safeAlternative;
          data.blocked = true;
          data.violations = result.violations.map(v => v.id);
        }
      }
      
      return originalJson(data);
    };
    
    next();
  };
}
 
// Usage
app.use(createGovernorMiddleware({ domain: 'wearables' }));

Error Handling

app.post('/api/chat',
  governorValidator({ domain: 'wearables' }),
  async (req, res, next) => {
    try {
      const aiResponse = await callLLM(req.body.message);
      res.json({ message: aiResponse });
    } catch (error) {
      // Middleware catches validation errors
      next(error);
    }
  }
);
 
// Error handler
app.use((err, req, res, next) => {
  if (err.type === 'GOVERNOR_VALIDATION') {
    return res.status(200).json({
      message: err.safeAlternative,
      blocked: true,
      violations: err.violations
    });
  }
  
  next(err);
});

Performance Optimization

Caching

import { createValidator } from '@the-governor-hq/constitution-core';
import NodeCache from 'node-cache';
 
const cache = new NodeCache({ stdTTL: 3600 });
const validator = createValidator({ domain: 'wearables' });
 
async function validateWithCache(text: string) {
  const cached = cache.get(text);
  if (cached) return cached;
  
  const result = await validator.validate(text);
  cache.set(text, result);
  
  return result;
}

Async Validation (Log Only)

For analytics without blocking:

app.post('/api/chat', async (req, res) => {
  const aiResponse = await callLLM(req.body.message);
  
  // Send response immediately
  res.json({ message: aiResponse });
  
  // Validate asynchronously for logging
  validator.validate(aiResponse).then(result => {
    if (!result.safe) {
      logger.warn('Unsafe content sent', {
        violations: result.violations,
        message: aiResponse
      });
    }
  });
});

Monitoring & Metrics

import { createValidator } from '@the-governor-hq/constitution-core';
 
const validator = createValidator({
  domain: 'wearables',
  onViolation: (violations, original) => {
    // Send to monitoring
    metrics.increment('governor.violations', {
      count: violations.length,
      rules: violations.map(v => v.id).join(',')
    });
    
    // Log for debugging
    logger.warn('Validation failed', {
      violations,
      original,
      timestamp: new Date()
    });
    
    // Return safe alternative
    return 'Unable to generate safe response.';
  }
});

Testing Middleware

import request from 'supertest';
import app from './app';
 
describe('Governor Middleware', () => {
  it('blocks medical diagnosis', async () => {
    const response = await request(app)
      .post('/api/chat')
      .send({ message: 'What does my HRV mean?' });
    
    expect(response.body.message).not.toContain('disease');
    expect(response.body.message).not.toContain('diagnosis');
  });
  
  it('allows safe observations', async () => {
    const response = await request(app)
      .post('/api/chat')
      .send({ message: 'Tell me about my sleep patterns' });
    
    expect(response.status).toBe(200);
    expect(response.body.blocked).toBeUndefined();
  });
});

Summary

Middleware provides:

  • ✅ Automatic validation in API responses
  • ✅ Framework integration (Express, Next.js, tRPC, GraphQL)
  • ✅ Streaming support
  • ✅ Custom error handling
  • ✅ Performance optimization
  • ✅ Monitoring integration

Best practices:

  • Use block mode in production
  • Cache validation results
  • Monitor violations
  • Test edge cases
  • Handle errors gracefully

Next: CLI Tools for development-time validation