Scrawn LogoScrawn Docs
Scrawn.js

Framework Integration

Integration guides for popular JavaScript frameworks

Overview

This guide provides detailed integration examples for popular JavaScript frameworks and runtimes.

Framework Compatibility Note: Most examples use sdkCallEventConsumer directly in route handlers rather than the middlewareEventConsumer due to framework-specific middleware patterns. The middlewareEventConsumer is designed for Express-like frameworks with (req, res, next) signatures.

Next.js

app/api/generate/route.ts
import { Scrawn } from '@scrawn/core';
import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth';

const scrawn = new Scrawn({
  apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
  baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
});

export async function POST(req: NextRequest) {
  const session = await auth();
  
  if (!session?.user?.id) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // Start tracking (don't await yet)
  const trackingPromise = scrawn.sdkCallEventConsumer({
    userId: session.user.id,
    debitAmount: 100,
  });

  // Process request
  const result = await generateContent(await req.json());
  
  // Wait for tracking to complete
  await trackingPromise;
  
  return NextResponse.json(result);
}

Express.js

server.ts
import express from 'express';
import { Scrawn, type EventPayload } from '@scrawn/core';

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

const scrawn = new Scrawn({
  apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
  baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
});

// Use middleware to automatically track all API calls
app.use(scrawn.middlewareEventConsumer({
  extractor: (req): EventPayload | null => {
    if (!req.user) return null;
    
    return {
      userId: req.user.id,
      debitAmount: req.body?.cost || 10,
    };
  },
  blacklist: ['/health', '/api/collect-payment'],
}));

app.post('/api/generate', async (req, res) => {
  const result = await generateContent(req.body);
  res.json(result);
});

app.post('/api/collect-payment', async (req, res) => {
  const checkoutLink = await scrawn.collectPayment(req.body.userId);
  res.redirect(checkoutLink);
});

app.listen(3000);

NestJS

scrawn.interceptor.ts
import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { Scrawn } from '@scrawn/core';

@Injectable()
export class ScrawnInterceptor implements NestInterceptor {
  private scrawn: Scrawn;

  constructor() {
    this.scrawn = new Scrawn({
      apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
      baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
    });
  }

  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<any>> {
    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (user) {
      // Track in background, don't block request
      this.scrawn.sdkCallEventConsumer({
        userId: user.id,
        debitAmount: 10,
      }).catch(err => {
        console.error('Failed to track event:', err);
      });
    }

    return next.handle();
  }
}
app.controller.ts
import { Controller, Post, UseInterceptors } from '@nestjs/common';
import { ScrawnInterceptor } from './scrawn.interceptor';

@Controller('api')
@UseInterceptors(ScrawnInterceptor)
export class AppController {
  @Post('generate')
  async generate() {
    return { message: 'Content generated' };
  }
}

tRPC

trpc/middleware.ts
import { TRPCError } from '@trpc/server';
import { Scrawn } from '@scrawn/core';
import { t } from './trpc';

const scrawn = new Scrawn({
  apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
  baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
});

export const trackUsage = t.middleware(async ({ ctx, next }) => {
  if (!ctx.session?.user?.id) {
    throw new TRPCError({ code: 'UNAUTHORIZED' });
  }

  // Start tracking (don't await)
  const trackingPromise = scrawn.sdkCallEventConsumer({
    userId: ctx.session.user.id,
    debitAmount: 10,
  });

  // Execute procedure
  const result = await next();
  
  // Wait for tracking
  await trackingPromise.catch(err => {
    console.error('Failed to track event:', err);
  });

  return result;
});

// Use in procedures
export const protectedProcedure = t.procedure.use(trackUsage);