npm package: @struktos/adapter-fastify
Description: Fastify adapter for Struktos.js - Context propagation and cancellation for Fastify applications
Author: Struktos.js Team
Latest version: 0.1.0

# @struktos/adapter-fastify

Fastify adapter for Struktos.js - Bringing enterprise-grade context propagation and cancellation tokens to Fastify applications.

## 🎯 Features

- **Context Propagation** - Automatic context propagation through async operations
- **Trace ID Generation** - Unique trace ID for each request
- **Cancellation Tokens** - Automatic cancellation on client disconnect
- **Type Safety** - Full TypeScript support with Fastify types
- **Zero Config** - Works out of the box with sensible defaults
- **Fastify Plugin** - Native Fastify plugin architecture
- **Performance** - Minimal overhead with high-performance context management

## 📦 Installation

```bash
npm install @struktos/adapter-fastify @struktos/core fastify
```

## 🚀 Quick Start

### Basic Usage

```typescript
import Fastify from 'fastify';
import { createStruktosPlugin } from '@struktos/adapter-fastify';

const fastify = Fastify();

// Register Struktos plugin
await fastify.register(createStruktosPlugin());

// Access context in routes
fastify.get('/api/user', async (request, reply) => {
  const context = request.getContext();
  
  console.log('TraceID:', context.get('traceId'));
  
  return { user: 'John Doe' };
});

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

### With Options

```typescript
await fastify.register(createStruktosPlugin({
  // Custom trace ID generator
  generateTraceId: () => `trace-${Date.now()}`,
  
  // Enable/disable automatic cancellation
  enableCancellation: true,
  
  // Extract user from request
  extractUser: (request) => {
    const token = request.headers.authorization?.substring(7);
    return token ? { id: 'user-123', token } : undefined;
  },
  
  // Lifecycle callbacks
  onContextCreated: (context, request) => {
    console.log('Context created:', context.get('traceId'));
  },
  onContextDestroyed: (context, request) => {
    console.log('Context destroyed:', context.get('traceId'));
  }
}));
```

## 📖 API

### `createStruktosPlugin(options?)`

Creates a Fastify plugin that integrates Struktos context propagation.

**Options:**

```typescript
interface StruktosPluginOptions {
  // Custom function to generate trace IDs
  generateTraceId?: () => string;
  
  // Custom context key for storing context in request
  contextKey?: string;
  
  // Enable automatic cancellation on client disconnect
  enableCancellation?: boolean;
  
  // Extract user information from request
  extractUser?: (request: FastifyRequest) => Record<string, any> | undefined;
  
  // Callback when context is created
  onContextCreated?: (context: RequestContext<any>, request: FastifyRequest) => void;
  
  // Callback when context is destroyed
  onContextDestroyed?: (context: RequestContext<any>, request: FastifyRequest) => void;
}
```

### Request Extensions

The plugin extends Fastify's `FastifyRequest` with:

```typescript
interface FastifyRequest {
  // Struktos context for this request
  struktosContext?: RequestContext<any>;
  
  // Get the current context (throws if not available)
  getContext(): RequestContext<any>;
}
```

## 🎓 Examples

### Context Propagation

```typescript
import { RequestContext } from '@struktos/core';

// Context automatically propagates through async operations
fastify.get('/api/data', async (request, reply) => {
  const context = request.getContext();
  
  // Context is available in nested functions
  await fetchUserData();
  await fetchOrderData();
  
  return { message: 'Success' };
});

async function fetchUserData() {
  // Access context from anywhere
  const context = RequestContext.current();
  console.log('TraceID:', context?.get('traceId'));
  
  // Simulate async operation
  await new Promise(resolve => setTimeout(resolve, 100));
}
```

### Request Metadata

Context automatically includes request metadata:

```typescript
fastify.get('/api/info', async (request, reply) => {
  const context = request.getContext();
  
  return {
    traceId: context.get('traceId'),
    method: context.get('method'),    // 'GET'
    url: context.get('url'),          // '/api/info'
    ip: context.get('ip'),            // '127.0.0.1'
    userAgent: context.get('userAgent') // 'curl/7.64.1'
  };
});
```

### Cancellation Tokens

```typescript
fastify.get('/api/slow', async (request, reply) => {
  const context = request.getContext();
  
  for (let i = 0; i < 100; i++) {
    // Check if client disconnected
    if (context.isCancelled()) {
      console.log('Client disconnected, stopping operation');
      return { error: 'Cancelled' };
    }
    
    await processChunk(i);
  }
  
  return { message: 'Completed' };
});
```

### Caching with CacheManager

```typescript
import { RequestContext, CacheManager } from '@struktos/core';

const productCache = new CacheManager<string, any>(1000);

async function getProducts() {
  const context = RequestContext.current();
  
  // Check cache first
  const cached = productCache.get('products');
  if (cached) {
    return cached;
  }
  
  // Fetch from database
  const products = await db.products.findAll();
  
  // Store in cache
  productCache.set('products', products, 60000); // TTL: 60 seconds
  
  return products;
}

fastify.get('/api/products', async (request, reply) => {
  const products = await getProducts();
  return { products };
});
```

See [examples/](./examples/) for more complete examples.

## 📄 License

MIT © Struktos.js Team