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

ai-pdf-builder

v0.6.2

Published

AI-powered PDF generator for legal docs, pitch decks, and reports. SAFEs, NDAs, term sheets, whitepapers from Markdown. Works with Claude, Cursor, GPT, Copilot, OpenClaw agents. npx ai-pdf-builder

Readme

ai-pdf-builder

🤖 AI-Powered Professional PDF Generation — Create beautiful business documents with AI or from Markdown. Generate whitepapers, memos, agreements, and term sheets instantly. Perfect for AI agents, chatbots, and automation workflows.

New in v0.4: AI document generation! Just describe what you need and let Claude create professional PDFs automatically.


Works With


Perfect For

  • 🤖 AI Agents & Chatbots — Generate documents on-the-fly from conversational AI
  • ⚖️ Legal Tech — Automate NDA, contract, and agreement generation
  • 💰 Fintech — Create term sheets, SAFEs, and investment documents programmatically
  • 🔄 Automation Workflows — Integrate with n8n, Zapier, Make, or custom pipelines
  • 📱 Messaging Bots — Let users request documents via Telegram, WhatsApp, Discord, Slack, or Signal
  • 🏢 Enterprise — Bulk document generation with consistent branding

Table of Contents

Features

  • 🤖 AI Document Generation: Describe what you need → get a professional PDF (powered by Claude)
  • Company-Aware AI: Use --company to auto-include your company details in generated docs
  • Multiple Document Types: Built-in templates for memos, agreements, term sheets, and whitepapers
  • Custom Styling: Apply custom colors and branding to any template
  • TypeScript Support: Full type definitions included
  • Flexible Output: Get PDF as Buffer or save directly to file
  • Template System: Use built-in templates or register your own
  • Security: Built-in content sanitization for LaTeX safety

🤖 AI Generation (NEW!)

Generate professional documents by describing what you need. No Markdown required!

Quick AI Examples

# Generate a business memo
npx ai-pdf-builder ai "Write a memo about Q1 2026 hiring plans" -o hiring-memo.pdf

# Generate with your company branding (reads from company.json)
npx ai-pdf-builder ai "Create an NDA for a potential partner" --company -o nda.pdf

# Generate a whitepaper
npx ai-pdf-builder ai "Write a technical whitepaper about AI in fintech" --template whitepaper -o whitepaper.pdf

# Generate a term sheet
npx ai-pdf-builder ai "Create a Series A term sheet for a $5M raise at $20M pre-money" --template termsheet -o termsheet.pdf

The --company Flag

Create a company.json file in your project root with your company details:

{
  "name": "Acme Corp",
  "legalName": "Acme Corporation Inc.",
  "address": "123 Main St, San Francisco, CA 94102",
  "website": "https://acme.com",
  "industry": "Enterprise Software",
  "description": "We build productivity tools for modern teams."
}

Then use --company to automatically inject these details:

# AI knows your company context
npx ai-pdf-builder ai "Write an investor update for Q4" --company -o q4-update.pdf
npx ai-pdf-builder ai "Create a partnership proposal" --company -o proposal.pdf

AI CLI Options

| Flag | Description | |------|-------------| | --company, -c | Load company context from company.json | | --template, -t | Use specific template (memo, agreement, termsheet, whitepaper) | | --output, -o | Output file path | | --model | Claude model to use (default: claude-sonnet-4-20250514) | | --verbose, -v | Show AI generation progress |

Programmatic AI Generation

import { generateWithAI } from 'ai-pdf-builder';

// Simple AI generation
const result = await generateWithAI({
  prompt: "Write a professional memo about remote work policy changes",
  template: "memo",
  metadata: {
    title: "Remote Work Policy Update",
    author: "HR Department"
  }
});

// With company context
const result = await generateWithAI({
  prompt: "Create an advisor agreement",
  template: "agreement",
  companyContext: {
    name: "Acme Corp",
    legalName: "Acme Corporation Inc."
  }
});

if (result.success) {
  fs.writeFileSync('output.pdf', result.buffer);
}

Requirements for AI Generation

  • Anthropic API Key: Set ANTHROPIC_API_KEY environment variable
  • Pandoc and LaTeX (same as regular PDF generation)

Prerequisites

This package requires Pandoc and LaTeX to be installed on your system:

macOS

# Install Pandoc
brew install pandoc

# Install BasicTeX (minimal LaTeX)
brew install --cask basictex

# After installing BasicTeX, install required packages
sudo tlmgr update --self
sudo tlmgr install collection-fontsrecommended fancyhdr titlesec enumitem xcolor booktabs longtable geometry hyperref setspace array multirow listings

Ubuntu/Debian

# Install Pandoc and TeX Live
sudo apt-get update
sudo apt-get install -y pandoc texlive-latex-base texlive-latex-extra texlive-fonts-recommended

Windows

  1. Download and install Pandoc
  2. Download and install MiKTeX

Docker

For containerized environments, use a Pandoc/LaTeX image:

FROM pandoc/latex:latest

Installation

npm install ai-pdf-builder

Or with yarn:

yarn add ai-pdf-builder

For AI Generation

Set your Anthropic API key:

export ANTHROPIC_API_KEY="your-api-key"

Or add to .env:

ANTHROPIC_API_KEY=your-api-key

Quick Start

AI Generation (Easiest!)

# One command to generate a professional PDF
npx ai-pdf-builder ai "Write a business proposal for a SaaS product" -o proposal.pdf

From Markdown

import { generatePDF } from 'ai-pdf-builder';
import * as fs from 'fs';

const result = await generatePDF({
  content: '# My Document\n\nThis is the content of my PDF.',
  metadata: {
    title: 'My First PDF',
    author: 'John Doe',
    date: 'January 2026'
  }
});

if (result.success && result.buffer) {
  fs.writeFileSync('output.pdf', result.buffer);
  console.log(`PDF generated! Size: ${result.fileSize} bytes`);
}

Usage Examples

AI-Generated Business Memo

# CLI - Instant memo generation
npx ai-pdf-builder ai "Write an executive memo about launching our new mobile app in Q2. Include timeline, resource needs, and risk factors." --template memo -o app-launch-memo.pdf

# With company context for branded output
npx ai-pdf-builder ai "Create a board update covering our Series A progress, key metrics, and next quarter goals" --company --template memo -o board-update.pdf

AI-Generated Legal Documents

# NDA with your company details
npx ai-pdf-builder ai "Generate an NDA for sharing proprietary technology with a potential partner" --company -o tech-nda.pdf

# Advisor agreement
npx ai-pdf-builder ai "Create an advisor agreement offering 0.5% equity over 2 years with monthly vesting" --company --template agreement -o advisor-agreement.pdf

Basic PDF Generation

import { generatePDF } from 'ai-pdf-builder';

const result = await generatePDF({
  content: `
# Executive Summary

This document outlines our strategic initiatives for Q1 2026.

## Key Objectives

- Increase market share by 15%
- Launch new product line
- Expand to 3 new markets

## Timeline

Implementation begins February 1st, 2026.
  `,
  metadata: {
    title: 'Q1 Strategic Plan',
    subtitle: 'Confidential',
    author: 'Strategy Team',
    date: 'January 2026',
    version: 'v1.0'
  },
  toc: true,
  numberSections: true
});

Generate a Business Memo

import { generateMemo } from 'ai-pdf-builder';

const memo = await generateMemo(
  `
# Executive Summary

Key findings from our market analysis indicate strong growth potential.

## Recommendations

1. Accelerate product development
2. Increase marketing budget by 20%
3. Hire 5 additional engineers
  `,
  {
    title: 'Product Whitepaper',
    subtitle: 'Intelligence Infrastructure for Financial Markets',
    author: 'John Smith',
    date: 'January 2026'
  }
);

Generate a Legal Agreement

import { generateAgreement } from 'ai-pdf-builder';

const agreement = await generateAgreement(
  `
# Advisor Agreement

This Advisor Agreement is entered into as of the Effective Date.

## 1. Services

The Advisor agrees to provide strategic guidance and introductions to potential investors.

## 2. Compensation

In consideration of the Services, the Company shall pay the Advisor:

- 8% of cash raised through Advisor's introductions
- 0.25% equity per $250,000 raised, up to 1% maximum

## 3. Term

This Agreement shall remain in effect for 12 months from the Effective Date.
  `,
  {
    title: 'Capital Introduction Agreement',
    subtitle: 'Acme Corp',
    date: 'January 15, 2026'
  }
);

Generate a Term Sheet

import { generateTermsheet } from 'ai-pdf-builder';

const termsheet = await generateTermsheet(
  `
# Series Seed Term Sheet

## Investment Amount

$2,000,000 (Two Million Dollars)

## Pre-Money Valuation

$8,000,000

## Security Type

Series Seed Preferred Stock

## Investors

Lead Investor: TBD
  `,
  {
    title: 'Series Seed',
    company: 'Acme Corp',
    doctype: 'Term Sheet',
    date: 'January 2026'
  }
);

Generate a Whitepaper

import { generateWhitepaper } from 'ai-pdf-builder';

const whitepaper = await generateWhitepaper(
  `
# Abstract

This paper presents a novel approach to financial market intelligence.

# Introduction

Financial markets generate vast amounts of data...

# Technical Architecture

Our system consists of three main components...

# Conclusion

We have demonstrated a scalable solution for...
  `,
  {
    title: 'Product Whitepaper',
    subtitle: 'A Canonical Asset Resolution System',
    author: 'Research Team',
    version: 'v1.0',
    date: 'January 2026'
  }
);

Custom Colors

import { generatePDF } from 'ai-pdf-builder';

const result = await generatePDF({
  content: '# Branded Document\n\nWith custom colors!',
  metadata: { title: 'Custom Branded PDF' },
  customColors: {
    primary: '#3B82F6',    // Blue
    secondary: '#6B7280',  // Gray
    accent: '#111827'      // Dark
  }
});

Save to File

import { generatePDF } from 'ai-pdf-builder';

const result = await generatePDF({
  content: '# My Document',
  metadata: { title: 'Saved PDF' },
  outputPath: './output/my-document.pdf'
});

if (result.success) {
  console.log(`PDF saved to: ${result.path}`);
}

Custom Templates

import { generatePDF, registerTemplate } from 'ai-pdf-builder';

// Register a custom template
registerTemplate({
  name: 'company-branded',
  path: './templates/company.latex',
  description: 'Company branded template with logo',
  supportedDocTypes: ['memo', 'whitepaper', 'report']
});

// Use the custom template
const result = await generatePDF({
  content: '# Company Report',
  metadata: { title: 'Annual Report' },
  template: 'company-branded'
});

List Available Templates

import { listTemplates } from 'ai-pdf-builder';

const templates = listTemplates();
templates.forEach(t => {
  console.log(`${t.name}: ${t.description}`);
  console.log(`  Supports: ${t.supportedDocTypes.join(', ')}`);
});

Check System Requirements

import { checkSystem } from 'ai-pdf-builder';

const status = checkSystem();
if (status.ready) {
  console.log('System ready:', status.message);
} else {
  console.error('Missing dependencies:', status.message);
  if (!status.pandoc.available) {
    console.error('Pandoc:', status.pandoc.error);
  }
  if (!status.latex.available) {
    console.error('LaTeX:', status.latex.error);
  }
}

Integration with Next.js

API Route Example

// app/api/generate-pdf/route.ts
import { generatePDF } from 'ai-pdf-builder';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const { content, title, type } = await request.json();
  
  const result = await generatePDF({
    content,
    metadata: { title },
    template: type === 'memo' ? 'memo' : 'default'
  });

  if (!result.success) {
    return NextResponse.json({ error: result.error }, { status: 500 });
  }

  return new NextResponse(result.buffer, {
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': `attachment; filename="${title}.pdf"`
    }
  });
}

Server Action Example

// app/actions/pdf.ts
'use server';

import { generateMemo } from 'ai-pdf-builder';

export async function createMemo(content: string, title: string) {
  const result = await generateMemo(content, { title });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  return result.buffer?.toString('base64');
}

API Reference

CLI Commands

ai - AI Document Generation

npx ai-pdf-builder ai <prompt> [options]

| Option | Alias | Description | Default | |--------|-------|-------------|---------| | --output | -o | Output file path | output.pdf | | --template | -t | Template: memo, agreement, termsheet, whitepaper | Auto-detected | | --company | -c | Load company context from company.json | false | | --model | | Claude model | claude-sonnet-4-20250514 | | --verbose | -v | Show progress | false |

generate - Markdown to PDF

npx ai-pdf-builder generate <input.md> [options]

| Option | Alias | Description | Default | |--------|-------|-------------|---------| | --output | -o | Output file path | <input>.pdf | | --template | -t | Template name | default | | --title | | Document title | Filename | | --author | | Document author | | | --toc | | Include table of contents | true |

check - System Check

npx ai-pdf-builder check

Verifies Pandoc and LaTeX are properly installed.

generatePDF(options: PDFOptions): Promise

Main function to generate a PDF from Markdown content.

PDFOptions

| Property | Type | Required | Description | |----------|------|----------|-------------| | content | string | Yes | Markdown content to convert | | metadata | DocumentMetadata | No | Document metadata (title, author, etc.) | | template | string | No | Template name or path (default: 'default') | | customColors | ColorConfig | No | Custom color configuration | | outputPath | string | No | Save PDF to this path instead of returning buffer | | toc | boolean | No | Include table of contents (default: true) | | tocDepth | number | No | Depth of TOC (1-3, default: 2) | | numberSections | boolean | No | Number sections (default: true) | | fontSize | number | No | Font size in points (default: 11) | | margin | string | No | Page margins (default: '1in') | | paperSize | 'letter' \| 'a4' | No | Paper size (default: 'letter') | | timeout | number | No | Timeout in ms (default: 60000) |

PDFResult

| Property | Type | Description | |----------|------|-------------| | success | boolean | Whether generation succeeded | | buffer | Buffer | Generated PDF (if outputPath not specified) | | path | string | Path to saved PDF (if outputPath specified) | | error | string | Error message if failed | | pageCount | number | Estimated page count | | fileSize | number | File size in bytes | | generationTime | number | Generation time in ms |

generateWithAI(options: AIGenerationOptions): Promise

Generate a PDF using AI to create the content.

AIGenerationOptions

| Property | Type | Required | Description | |----------|------|----------|-------------| | prompt | string | Yes | Description of what document to generate | | template | string | No | Template to use (auto-detected if not specified) | | metadata | DocumentMetadata | No | Override document metadata | | companyContext | CompanyContext | No | Company details for context | | model | string | No | Claude model (default: claude-sonnet-4-20250514) |

Example

import { generateWithAI } from 'ai-pdf-builder';

const result = await generateWithAI({
  prompt: "Write an executive summary about our AI product launch",
  template: "memo",
  companyContext: {
    name: "TechCorp",
    industry: "AI/ML Software"
  }
});

Preset Functions

All preset functions have the signature:

function preset(
  content: string,
  metadata: DocumentMetadata,
  options?: Partial<PDFOptions>
): Promise<PDFResult>

Available presets:

  • generateMemo - Business memos
  • generateAgreement - Legal agreements
  • generateTermsheet - Investment term sheets
  • generateWhitepaper - Technical whitepapers
  • generateReport - Business reports
  • generateProposal - Proposals
  • generateCapitalIntroAgreement - Fundraising agreements
  • generateSAFE - SAFE documents
  • generateNDA - Non-disclosure agreements

Template Functions

  • getTemplate(name: string): string | null - Get template content
  • listTemplates(): TemplateConfig[] - List all templates
  • registerTemplate(config: TemplateConfig): void - Register custom template
  • hasTemplate(name: string): boolean - Check if template exists

Utility Functions

  • checkSystem(): SystemCheck - Check Pandoc/LaTeX availability
  • checkPandoc(): PandocCheck - Check Pandoc installation
  • checkLaTeX(): LaTeXCheck - Check LaTeX installation
  • sanitizeContent(content: string): string - Sanitize for LaTeX safety

Built-in Templates

| Template | Description | Best For | |----------|-------------|----------| | default | Clean, professional styling | Whitepapers, reports | | memo | Compact business memo | Executive summaries | | agreement | Formal legal document | Contracts, agreements | | termsheet | Premium dark + gold finance | Term sheets, investment docs |

Troubleshooting

"Pandoc not found"

Install Pandoc:

  • macOS: brew install pandoc
  • Ubuntu: sudo apt-get install pandoc
  • Windows: Download from pandoc.org

"pdflatex not found"

Install LaTeX:

  • macOS: brew install --cask basictex
  • Ubuntu: sudo apt-get install texlive-latex-base texlive-latex-extra
  • Windows: Install MiKTeX

Missing LaTeX packages

sudo tlmgr install <package-name>

Common packages needed:

sudo tlmgr install fancyhdr titlesec enumitem xcolor booktabs longtable geometry hyperref

Timeout errors

Increase the timeout for large documents:

const result = await generatePDF({
  content: longContent,
  timeout: 120000 // 2 minutes
});

Error Handling

Proper error handling is crucial for production applications.

Basic Error Handling

import { generatePDF } from 'ai-pdf-builder';

try {
  const result = await generatePDF({
    content: markdownContent,
    metadata: { title: 'My Document' }
  });
  
  if (!result.success) {
    console.error('PDF generation failed:', result.error);
    
    // Handle specific errors
    if (result.error?.includes('Pandoc')) {
      console.error('Pandoc is not installed. Please install it first.');
      // Guide user to installation instructions
    } else if (result.error?.includes('pdflatex')) {
      console.error('LaTeX is not installed. Please install TeX Live or MiKTeX.');
    } else if (result.error?.includes('timeout')) {
      console.error('Generation timed out. Try increasing the timeout option.');
    }
    
    return;
  }
  
  // Success - use result.buffer or result.path
  console.log(`PDF generated successfully: ${result.fileSize} bytes`);
  
} catch (error) {
  console.error('Unexpected error:', error);
  // Handle system-level errors
}

Retry Logic

async function generateWithRetry(
  options: PDFOptions, 
  maxRetries: number = 3
): Promise<PDFResult> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const result = await generatePDF(options);
    
    if (result.success) {
      return result;
    }
    
    console.warn(`Attempt ${attempt}/${maxRetries} failed:`, result.error);
    
    // Wait before retry (exponential backoff)
    if (attempt < maxRetries) {
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
  
  throw new Error(`PDF generation failed after ${maxRetries} attempts`);
}

Error Handling in Express

app.post('/api/pdf', async (req, res) => {
  try {
    const { content, title } = req.body;
    
    const result = await generatePDF({
      content,
      metadata: { title },
      timeout: 30000
    });
    
    if (!result.success) {
      return res.status(500).json({ 
        error: 'PDF generation failed',
        details: result.error 
      });
    }
    
    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', `attachment; filename="${title}.pdf"`);
    res.send(result.buffer);
    
  } catch (error) {
    console.error('PDF generation error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

TypeScript Best Practices

Get the most out of TypeScript's type system for safer code.

Fully Typed Configuration

import { 
  generatePDF, 
  PDFOptions, 
  PDFResult, 
  DocumentMetadata,
  ColorConfig,
  TemplateConfig 
} from 'ai-pdf-builder';

// Type-safe metadata
const metadata: DocumentMetadata = {
  title: 'Annual Report',
  author: 'Jane Doe',
  date: new Date().toLocaleDateString('en-US'),
  version: 'v2.0',
  subtitle: 'Financial Year 2025'
};

// Type-safe color configuration
const colors: ColorConfig = {
  primary: '59,130,246',    // RGB format
  secondary: '107,114,128',
  accent: '17,24,39'
};

// Complete options with type checking
const options: PDFOptions = {
  content: markdownContent,
  metadata,
  customColors: colors,
  template: 'default',
  toc: true,
  tocDepth: 2,
  numberSections: true,
  fontSize: 11,
  margin: '1in',
  paperSize: 'letter',
  timeout: 60000
};

const result: PDFResult = await generatePDF(options);

// Type-safe result handling
if (result.success && result.buffer) {
  const size: number = result.fileSize || 0;
  const pages: number = result.pageCount || 0;
  console.log(`Generated ${pages} pages (${size} bytes)`);
}

Custom Type Guards

import { PDFResult } from 'ai-pdf-builder';

function isSuccessfulResult(result: PDFResult): result is PDFResult & { 
  success: true; 
  buffer: Buffer 
} {
  return result.success && !!result.buffer;
}

// Use the type guard
const result = await generatePDF(options);
if (isSuccessfulResult(result)) {
  // TypeScript knows result.buffer is defined here
  saveToFile(result.buffer);
}

Extending Types

import { DocumentMetadata } from 'ai-pdf-builder';

// Extend with custom metadata
interface CustomMetadata extends DocumentMetadata {
  department?: string;
  classification?: 'public' | 'internal' | 'confidential';
  reviewers?: string[];
}

const metadata: CustomMetadata = {
  title: 'Security Report',
  author: 'Security Team',
  date: '2026-01-22',
  department: 'IT Security',
  classification: 'confidential',
  reviewers: ['Alice', 'Bob']
};

Advanced Topics

Batch Processing

Generate multiple PDFs concurrently:

import { generatePDF } from 'ai-pdf-builder';
import pLimit from 'p-limit';

async function generateBatch(documents: Array<{ content: string; title: string }>) {
  // Limit concurrent operations to avoid overwhelming the system
  const limit = pLimit(3);
  
  const tasks = documents.map(doc => 
    limit(() => generatePDF({
      content: doc.content,
      metadata: { title: doc.title }
    }))
  );
  
  const results = await Promise.all(tasks);
  
  // Process results
  const successful = results.filter(r => r.success);
  const failed = results.filter(r => !r.success);
  
  console.log(`Generated ${successful.length}/${results.length} PDFs`);
  return { successful, failed };
}

Performance Optimization

Tips for large documents:

// 1. Increase timeout for large documents
const result = await generatePDF({
  content: largeMarkdownContent,
  timeout: 180000 // 3 minutes
});

// 2. Disable TOC for faster generation
const result = await generatePDF({
  content,
  toc: false,  // Skip table of contents
  numberSections: false
});

// 3. Use simpler templates
const result = await generatePDF({
  content,
  template: 'default'  // Simpler than termsheet template
});

// 4. Process in chunks for very large documents
async function generateLargeDocument(sections: string[]) {
  const pdfs = await Promise.all(
    sections.map(section => generatePDF({
      content: section,
      toc: false
    }))
  );
  // Merge PDFs using a library like pdf-lib
}

Memory Management

For high-volume operations:

import { generatePDF } from 'ai-pdf-builder';

// Monitor memory usage
function logMemoryUsage() {
  const used = process.memoryUsage();
  console.log({
    rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
    heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`
  });
}

// Process in batches to avoid memory issues
async function processLargeQueue(queue: any[], batchSize = 10) {
  for (let i = 0; i < queue.length; i += batchSize) {
    const batch = queue.slice(i, i + batchSize);
    await Promise.all(batch.map(item => generatePDF(item)));
    
    // Allow garbage collection between batches
    await new Promise(resolve => setImmediate(resolve));
    logMemoryUsage();
  }
}

Custom Template Creation

Create your own LaTeX templates:

import { registerTemplate, generatePDF } from 'ai-pdf-builder';
import * as path from 'path';

// Register a custom template
registerTemplate({
  name: 'company-branded',
  path: path.join(__dirname, 'templates', 'company.latex'),
  description: 'Company branded template with logo',
  supportedDocTypes: ['memo', 'whitepaper', 'report']
});

// Use the custom template
const result = await generatePDF({
  content: markdownContent,
  template: 'company-branded',
  customColors: {
    primary: '0,102,204',  // Company blue
    secondary: '128,128,128'
  }
});

See TEMPLATE_GUIDE.md for a complete guide to creating custom LaTeX templates.

Production Deployment

Docker Deployment

Dockerfile:

FROM pandoc/latex:latest

# Install Node.js
RUN apk add --no-cache nodejs npm

# Set working directory
WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm ci --only=production

# Copy application
COPY . .

# Install required LaTeX packages
RUN tlmgr update --self && \
    tlmgr install \
    collection-fontsrecommended \
    fancyhdr \
    titlesec \
    enumitem \
    xcolor \
    booktabs \
    longtable \
    geometry \
    hyperref \
    setspace \
    array \
    multirow \
    listings

EXPOSE 3000

CMD ["node", "server.js"]

docker-compose.yml:

version: '3.8'
services:
  pdf-generator:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MAX_CONCURRENT_PDFS=3
    volumes:
      - pdf-cache:/app/cache
    mem_limit: 2g
    mem_reservation: 1g

volumes:
  pdf-cache:

Next.js Production Configuration

// next.config.js
module.exports = {
  experimental: {
    serverComponentsExternalPackages: ['ai-pdf-builder']
  },
  // Increase API route timeout for PDF generation
  api: {
    responseLimit: '8mb'
  }
};

// app/api/pdf/route.ts
import { generatePDF } from 'ai-pdf-builder';
import { NextResponse } from 'next/server';

export const maxDuration = 60; // 60 seconds timeout

export async function POST(request: Request) {
  const { content, title } = await request.json();
  
  const result = await generatePDF({
    content,
    metadata: { title },
    timeout: 50000 // Leave buffer before Next.js timeout
  });
  
  if (!result.success) {
    return NextResponse.json({ error: result.error }, { status: 500 });
  }
  
  return new NextResponse(result.buffer, {
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': `attachment; filename="${title}.pdf"`,
      'Cache-Control': 'no-store'
    }
  });
}

Serverless Considerations

AWS Lambda:

// Lambda function with custom runtime
// NOTE: Lambda has a 512MB /tmp limit and 15min timeout
import { generatePDF } from 'ai-pdf-builder';

export const handler = async (event) => {
  // Use /tmp for working directory
  const result = await generatePDF({
    content: event.content,
    metadata: event.metadata,
    workDir: '/tmp/pdf-work',
    timeout: 840000 // 14 minutes (leave buffer)
  });
  
  if (result.success) {
    // Upload to S3 instead of returning (size limits)
    await uploadToS3(result.buffer, event.key);
    return { statusCode: 200, body: JSON.stringify({ url: s3Url }) };
  }
  
  return { statusCode: 500, body: JSON.stringify({ error: result.error }) };
};

Note: For serverless, consider using the container approach or a dedicated PDF generation service due to Pandoc/LaTeX size requirements.

Error Monitoring

Sentry Integration:

import * as Sentry from '@sentry/node';
import { generatePDF } from 'ai-pdf-builder';

Sentry.init({ dsn: process.env.SENTRY_DSN });

async function generateWithMonitoring(options) {
  const transaction = Sentry.startTransaction({
    op: 'pdf.generate',
    name: 'Generate PDF'
  });
  
  try {
    const result = await generatePDF(options);
    
    if (!result.success) {
      Sentry.captureMessage('PDF generation failed', {
        level: 'error',
        extra: { error: result.error, options }
      });
    }
    
    transaction.setStatus('ok');
    return result;
    
  } catch (error) {
    Sentry.captureException(error);
    transaction.setStatus('internal_error');
    throw error;
  } finally {
    transaction.finish();
  }
}

FAQ

How does AI generation work?

The ai command sends your prompt to Claude (Anthropic's AI), which generates professional Markdown content based on your description. This content is then converted to PDF using Pandoc and LaTeX.

What makes it smart:

  • Automatically detects document type from your prompt
  • Structures content appropriately (headers, sections, formatting)
  • Uses professional language and business conventions
  • With --company, includes your company details naturally

What's the difference between AI and manual generation?

| Aspect | AI Generation | Manual (Markdown) | |--------|--------------|-------------------| | Input | Natural language prompt | Structured Markdown | | Control | AI decides structure | You control everything | | Speed | Fastest for drafts | Better for precise docs | | Best for | First drafts, ideas, quick docs | Final versions, exact specs |

Pro tip: Use AI to generate a first draft, then export the Markdown for manual refinement.

Why is my PDF generation slow?

PDF generation involves multiple steps (Markdown parsing, LaTeX compilation, font rendering). Typical generation times:

  • Simple document (1-5 pages): 1-3 seconds
  • Medium document (10-20 pages): 3-8 seconds
  • Large document (50+ pages): 10-30 seconds

To improve performance:

  • Disable TOC if not needed (toc: false)
  • Use simpler templates (template: 'default')
  • Process documents concurrently for batch operations
  • Cache generated PDFs when possible

Can I use this in a serverless environment?

Yes, but with caveats:

  • Docker-based serverless (AWS Fargate, Cloud Run): ✅ Recommended
  • Traditional Lambda/Functions: ⚠️ Challenging due to Pandoc/LaTeX dependencies (~300MB)

For traditional serverless, consider:

  1. Using a custom Lambda layer with Pandoc/LaTeX
  2. Calling a dedicated PDF generation service
  3. Using AWS Lambda Container Images

How do I debug LaTeX errors?

// Enable detailed error logging
const result = await generatePDF({
  content: markdownContent,
  metadata: { title: 'Debug Test' }
});

if (!result.success) {
  console.error('Full error:', result.error);
  // LaTeX errors typically mention line numbers and commands
  // Example: "LaTeX Error: Environment Shaded undefined"
}

Common LaTeX errors:

  • "pdflatex not found": Install LaTeX (see Prerequisites)
  • "Unicode character not set up": Use ASCII alternatives or configure unicode support
  • "Environment undefined": Missing LaTeX package

What Markdown features are supported?

Supported (via Pandoc):

  • ✅ Headers (H1-H6)
  • ✅ Lists (ordered, unordered, nested)
  • ✅ Bold, italic, code
  • ✅ Links and URLs
  • ✅ Tables (simple and grid)
  • ✅ Code blocks with syntax highlighting
  • ✅ Blockquotes
  • ✅ Horizontal rules
  • ✅ Images (if file paths are accessible)

Limited support:

  • ⚠️ HTML (basic tags only)
  • ⚠️ Complex tables (may need LaTeX syntax)
  • ⚠️ Emojis (depends on LaTeX font support)

Not supported:

  • ❌ GitHub-flavored Markdown task lists
  • ❌ Mermaid diagrams (consider rendering to image first)

How do I add images to my PDFs?

const content = `
# Document with Images

![Company Logo](./assets/logo.png)

Regular text here.

![Chart](./charts/quarterly-results.png){ width=80% }
`;

const result = await generatePDF({
  content,
  metadata: { title: 'Document with Images' }
});

Requirements:

  • Image paths must be accessible from where the code runs
  • Supported formats: PNG, JPG, PDF
  • Use relative or absolute paths
  • Control size with Pandoc syntax: { width=50% } or { height=3in }

Can I generate PDFs from HTML?

Yes, convert HTML to Markdown first or use Pandoc's HTML input:

import { generatePDF } from 'ai-pdf-builder';
import TurndownService from 'turndown';

// Convert HTML to Markdown
const turndown = new TurndownService();
const markdown = turndown.turndown(htmlContent);

const result = await generatePDF({
  content: markdown,
  metadata: { title: 'From HTML' }
});

How do I handle concurrent requests?

Use a queue system to limit concurrent PDF generations:

import Queue from 'bull';
import { generatePDF } from 'ai-pdf-builder';

const pdfQueue = new Queue('pdf-generation', process.env.REDIS_URL);

// Limit to 3 concurrent jobs
pdfQueue.process(3, async (job) => {
  return await generatePDF(job.data.options);
});

// Add jobs
app.post('/api/pdf', async (req, res) => {
  const job = await pdfQueue.add({ options: req.body });
  res.json({ jobId: job.id });
});

Integrations

ai-pdf-builder is designed to work seamlessly with AI agents and automation platforms:

AI Agent Frameworks

| Framework | Integration | |-----------|-------------| | Clawdbot / Moltbot | Native support — generate PDFs from chat commands | | LangChain | Use as a tool in your agent chains | | AutoGPT | Add as a plugin for document generation | | CrewAI | Integrate as an agent capability | | Semantic Kernel | Use via function calling |

Messaging Platforms

Works with any bot framework that can execute Node.js:

  • Telegramnode-telegram-bot-api, telegraf
  • WhatsAppwhatsapp-web.js, @whiskeysockets/baileys
  • Discorddiscord.js
  • Slack@slack/bolt
  • Signalsignal-cli

Automation Tools

  • n8n — Use the Execute Command or Code node
  • Zapier — Via Code by Zapier or webhooks
  • Make (Integromat) — HTTP module + hosted endpoint
  • Pipedream — Native Node.js support

Example: LangChain Tool

import { Tool } from "langchain/tools";
import { generateWithAI } from "ai-pdf-builder";

const pdfTool = new Tool({
  name: "generate_pdf",
  description: "Generate a professional PDF document from a description",
  func: async (prompt: string) => {
    const result = await generateWithAI({ prompt });
    if (result.success) {
      // Save or return the PDF
      return `PDF generated: ${result.fileSize} bytes`;
    }
    return `Error: ${result.error}`;
  }
});

Example: Telegram Bot

import TelegramBot from 'node-telegram-bot-api';
import { generateWithAI } from 'ai-pdf-builder';

const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true });

bot.onText(/\/pdf (.+)/, async (msg, match) => {
  const chatId = msg.chat.id;
  const prompt = match[1];
  
  await bot.sendMessage(chatId, '📄 Generating your PDF...');
  
  const result = await generateWithAI({ prompt });
  
  if (result.success) {
    await bot.sendDocument(chatId, result.buffer, {
      filename: 'document.pdf'
    });
  }
});

Author

Built by @NextXFrontier — Follow for AI tools, automation, and building in public.

License

MIT

Contributing

Contributions welcome! Please read our CONTRIBUTING.md guidelines before submitting PRs.