npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rodrigopsasaki/vision-fastify

v0.5.0

Published

High-performance Fastify plugin for seamless Vision context integration

Readme

🎯 @rodrigopsasaki/vision-fastify

High-performance Fastify plugin for seamless Vision context integration. Built for speed, designed for observability.

✨ Features

  • 🚀 Zero-overhead observability - Optimized for Fastify's performance
  • 🎯 Automatic context creation - Every request gets a Vision context
  • Performance tracking - Built-in slow operation detection
  • 🔒 Security-aware - Intelligent sensitive data redaction
  • 🎨 Highly configurable - From minimal to comprehensive tracking
  • 🔌 Plugin ecosystem ready - Works with all Fastify plugins
  • 📊 Rich metadata capture - Headers, body, query, params, and more
  • 🏗️ TypeScript first - Full type safety and IntelliSense

🚀 Quick Start

npm install @rodrigopsasaki/vision @rodrigopsasaki/vision-fastify
import Fastify from "fastify";
import { visionPlugin } from "@rodrigopsasaki/vision-fastify";

const fastify = Fastify();

// Register the Vision plugin
await fastify.register(visionPlugin);

fastify.get("/users/:id", async (request, reply) => {
  // Vision context is automatically available
  vision.set("user_id", request.params.id);
  vision.set("operation", "get_user");

  const user = await getUser(request.params.id);
  return user;
});

await fastify.listen({ port: 3000 });

🎛️ Configuration Options

Basic Configuration

await fastify.register(visionPlugin, {
  // Data capture options
  captureHeaders: true,
  captureBody: false, // Be careful in production
  captureQuery: true,
  captureParams: true,

  // Performance tracking
  performance: {
    trackExecutionTime: true,
    slowOperationThreshold: 1000, // 1 second
    trackMemoryUsage: false,
  },

  // Security & privacy
  redactSensitiveData: true,
  redactHeaders: ["authorization", "cookie"],
  redactQueryParams: ["token", "password"],
  redactBodyFields: ["password", "ssn"],
});

Advanced Configuration

await fastify.register(visionPlugin, {
  // Custom extractors
  extractUser: (request) => ({
    id: request.headers["x-user-id"],
    role: request.headers["x-user-role"],
  }),

  extractCorrelationId: (request) =>
    request.headers["x-correlation-id"] || request.headers["x-request-id"],

  extractMetadata: (request) => ({
    client_version: request.headers["x-client-version"],
    feature_flags: request.headers["x-feature-flags"]?.split(","),
  }),

  // Custom context naming
  contextNameGenerator: (request) =>
    `api.${request.method.toLowerCase()}.${request.routeOptions?.url}`,

  // Route exclusion
  excludeRoutes: ["/health", "/metrics", "/docs/*"],
  shouldExcludeRoute: (request) => request.url.startsWith("/internal/"),
});

🎨 Pre-configured Plugins

Minimal Plugin (Performance Optimized)

import { createMinimalVisionPlugin } from "@rodrigopsasaki/vision-fastify";

await fastify.register(
  createMinimalVisionPlugin({
    performance: { slowOperationThreshold: 100 },
  }),
);

Comprehensive Plugin (Full Observability)

import { createComprehensiveVisionPlugin } from "@rodrigopsasaki/vision-fastify";

await fastify.register(
  createComprehensiveVisionPlugin({
    captureBody: true,
    performance: { trackMemoryUsage: true },
  }),
);

Performance Plugin (Ultra-fast)

import { createPerformanceVisionPlugin } from "@rodrigopsasaki/vision-fastify";

await fastify.register(createPerformanceVisionPlugin());

🏗️ Route-Level Configuration

Override plugin settings for specific routes:

fastify.get(
  "/sensitive-endpoint",
  {
    config: {
      vision: {
        captureBody: false,
        redactHeaders: ["authorization", "x-api-key", "custom-token"],
      },
    },
  },
  async (request, reply) => {
    // Route-specific Vision configuration applies
    return { sensitive: "data" };
  },
);

📊 Vision API Usage

Use the full power of Vision's API within your handlers:

fastify.post("/orders", async (request, reply) => {
  // Set operation context
  vision.set("operation", "create_order");
  vision.set("user_id", request.body.userId);

  // Track business events
  vision.push("events", {
    event: "order_created",
    order_id: newOrder.id,
    amount: newOrder.total,
    timestamp: new Date().toISOString(),
  });

  // Add business context
  vision.merge("business_context", {
    operation: "order_processing",
    customer_tier: user.tier,
    payment_method: request.body.paymentMethod,
  });

  // Track performance of external calls
  const startTime = Date.now();
  const paymentResult = await processPayment(order);

  vision.push("external_api_calls", {
    service: "payment-gateway",
    duration_ms: Date.now() - startTime,
    success: paymentResult.success,
  });

  return { orderId: newOrder.id, status: "created" };
});

🔍 Context Access

Access the Vision context from anywhere in your request lifecycle:

// In route handlers
fastify.get("/users/:id", async (request, reply) => {
  const ctx = request.visionContext;
  console.log("Context ID:", ctx.id);
  console.log("Context Data:", Object.fromEntries(ctx.data.entries()));
});

// In hooks
fastify.addHook("preHandler", async (request, reply) => {
  if (request.visionContext) {
    vision.set("pre_handler_executed", true);
  }
});

// In plugins
fastify.register(async (fastify) => {
  fastify.addHook("onRequest", async (request, reply) => {
    // Add plugin-specific metadata
    vision.set("plugin_name", "my-custom-plugin");
  });
});

⚡ Performance Tracking

Automatic performance insights:

// Slow operations are automatically detected
fastify.get("/slow-analytics", async (request, reply) => {
  await generateComplexAnalytics(); // Takes 2 seconds
  // Vision automatically marks this as slow_operation: true
  return analytics;
});

// Custom performance tracking
fastify.get("/custom-timing", async (request, reply) => {
  const dbStart = Date.now();
  const users = await db.users.findMany();

  vision.push("performance", {
    operation: "database.users.findMany",
    duration_ms: Date.now() - dbStart,
    result_count: users.length,
  });

  return users;
});

🔒 Security & Privacy

Built-in security features:

await fastify.register(visionPlugin, {
  // Automatic sensitive data redaction
  redactSensitiveData: true,
  redactHeaders: ["authorization", "cookie", "x-api-key", "x-auth-token"],
  redactQueryParams: ["token", "password", "secret", "api_key"],
  redactBodyFields: ["password", "ssn", "creditCard", "bankAccount"],

  // Custom error transformation
  errorHandling: {
    transformError: (error, request) => ({
      name: error.name,
      message: process.env.NODE_ENV === "production" ? "Internal server error" : error.message,
      // Never expose stack traces in production
      ...(process.env.NODE_ENV !== "production" && {
        stack: error.stack,
      }),
    }),
  },
});

📋 TypeScript Support

Full TypeScript integration with enhanced request/reply types:

import type { VisionFastifyRequest, VisionFastifyReply } from "@rodrigopsasaki/vision-fastify";

// Enhanced request with Vision context
fastify.get("/users/:id", async (request: VisionFastifyRequest, reply: VisionFastifyReply) => {
  // Full type safety
  const ctx = request.visionContext; // VisionContext | undefined
  const userId = request.params.id; // Fully typed params

  // Vision context is available on both request and reply
  reply.visionContext?.data.set("response_prepared", true);

  return { user: { id: userId } };
});

🧪 Testing

Vision-enabled testing utilities:

import { test } from "tap";
import { build } from "./helper"; // Your Fastify test helper

test("Vision context in tests", async (t) => {
  const app = await build(t);

  const response = await app.inject({
    method: "GET",
    url: "/users/123",
    headers: {
      "x-correlation-id": "test-correlation-123",
    },
  });

  t.equal(response.statusCode, 200);
  t.ok(response.headers["x-request-id"]); // Vision adds request ID

  // Verify Vision context was created
  // (You can add custom test exporters to verify context data)
});

🎯 Best Practices

Production Configuration

const isProduction = process.env.NODE_ENV === "production";

await fastify.register(visionPlugin, {
  // Conservative settings for production
  captureHeaders: true,
  captureBody: false, // Avoid capturing sensitive data
  captureQuery: !isProduction, // Skip in production for performance

  // Stricter performance thresholds
  performance: {
    slowOperationThreshold: isProduction ? 500 : 1000,
    trackMemoryUsage: false, // Disable for performance
  },

  // Enhanced security
  redactSensitiveData: true,
  errorHandling: {
    captureStackTrace: !isProduction,
  },
});

Development Configuration

await fastify.register(
  createComprehensiveVisionPlugin({
    // Capture everything for debugging
    captureBody: true,
    captureHeaders: true,

    // Detailed error information
    errorHandling: {
      captureStackTrace: true,
      captureErrors: true,
    },

    // Sensitive performance tracking
    performance: {
      trackMemoryUsage: true,
      slowOperationThreshold: 100,
    },
  }),
);

Microservices Setup

await fastify.register(visionPlugin, {
  // Propagate correlation IDs across services
  extractCorrelationId: (request) =>
    request.headers["x-correlation-id"] || request.headers["x-request-id"] || generateRequestId(),

  // Service-specific context naming
  contextNameGenerator: (request) =>
    `user-service.${request.method.toLowerCase()}.${request.routeOptions?.url}`,

  // Extract service metadata
  extractMetadata: (request) => ({
    service_name: "user-service",
    service_version: process.env.SERVICE_VERSION,
    deployment_env: process.env.NODE_ENV,
  }),
});

🔧 Advanced Usage

Multiple Vision Instances

// Register multiple plugins with different configurations
await fastify.register(visionPlugin, { name: "main-vision" });
await fastify.register(createMinimalVisionPlugin(), { name: "minimal-vision" });

Custom Hooks Integration

fastify.addHook("preHandler", async (request, reply) => {
  if (request.visionContext) {
    // Add authentication context
    vision.merge("auth", {
      authenticated: !!request.headers.authorization,
      auth_method: getAuthMethod(request),
    });
  }
});

fastify.addHook("onError", async (request, reply, error) => {
  if (request.visionContext) {
    // Add error context
    vision.push("error_events", {
      error_type: error.constructor.name,
      error_code: error.code,
      timestamp: new Date().toISOString(),
    });
  }
});

📦 Package Information

  • Bundle Size: Minimal footprint, optimized for Fastify's performance
  • Dependencies: Only fastify-plugin and micromatch
  • TypeScript: Full type definitions included
  • Fastify Support: v4.x and v5.x
  • Node.js: v18+ recommended

🤝 Integration

Works seamlessly with:

  • @fastify/cors - CORS handling
  • @fastify/helmet - Security headers
  • @fastify/rate-limit - Rate limiting
  • @fastify/jwt - JWT authentication
  • @fastify/swagger - API documentation
  • @fastify/multipart - File uploads
  • All other Fastify plugins

📊 Comparison

| Feature | vision-express | vision-fastify | vision-nestjs | | ------------- | -------------- | ----------------- | ---------------- | | Performance | Good | Excellent | Good | | Plugin System | Middleware | Native Plugin | Decorator | | Type Safety | Good | Excellent | Excellent | | Route Config | Limited | Full Support | Full Support | | Async Hooks | Manual | Automatic | Automatic |

Perfect for high-performance APIs, microservices, and production applications where speed and observability are critical! 🚀