Scrawn LogoScrawn Docs
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);