← Back to the editor

Dastavej Core, for developers

The same headless PDF engine that powers the app — embed it in yours.

Every panel in Dastavej — compress, convert, forms, OCR, watermark — is backed by a plain async function that takes and returns Uint8Array bytes, with zero dependency on React or Dastavej's UI. That whole layer lives in lib/ and is re-exported from a single entry point, lib/publicApi.ts, so you can pull it into your own app.

No AI included. AI-powered features (topic → PDF generation, AI form fill) are deliberately left out of this API while we build a local, on-device AI story — see the AI tab in the app for status.

Installing

Option A — copy the source (simplest, works anywhere)

Copy the lib/ and workers/ folders from the repository into your project and import from ./lib/publicApi. No build-step surprises since it's just TypeScript you compile with your own toolchain.

Option B — git dependency

npm install github:prabhassaas/dastavej

Then import { compressPdf } from 'dastavej'. This package ships TypeScript source (not precompiled JS) via its exports field — works out of the box with bundlers that transpile dependencies (Vite, esbuild-based setups); with Next.js/webpack you may need to add it to transpilePackages. A precompiled npm package is on the roadmap.

Some functions need a Web Worker file

compressPdf loads workers/compress.worker.ts via new URL(..., import.meta.url) — make sure your bundler supports that pattern (Next.js, Vite and webpack 5 all do) and that the file is included wherever you copy lib/ to.

Quick examples

Merge PDFs

import { mergePdfs } from 'dastavej';

const merged = await mergePdfs([bytesA, bytesB, bytesC]);

Compress

import { compressPdf } from 'dastavej';

const { bytes, imagesRecompressed } = await compressPdf(pdfBytes, {
  quality: 0.6,
  maxDimension: 1600,
  onProgress: (done, total) => console.log(`${done}/${total}`),
});

Build a fillable form

import { buildFormPdf, FORM_TEMPLATES } from 'dastavej';

const template = FORM_TEMPLATES.find((t) => t.id === 'job-application')!;
const pdf = await buildFormPdf({
  title: template.title,
  fields: template.fields.map((f) => ({ ...f, id: crypto.randomUUID() })),
  pageSize: 'A4',
  orientation: 'portrait',
  photoBox: template.photoBox,
});

Convert to Word

import { openForConversion, convertToWord } from 'dastavej';

const doc = await openForConversion(pdfBytes);
const docxBytes = await convertToWord(doc, (p) => console.log(p));

Collect filled forms into Excel

import { extractFormData, exportRowsToXlsx } from 'dastavej';

const rows = await Promise.all(
  files.map((f) => f.arrayBuffer().then((buf) => extractFormData(f.name, new Uint8Array(buf)))),
);
await exportRowsToXlsx(rows, 'responses.xlsx');

OCR a scanned PDF

import { ocrPdfBytes } from 'dastavej';

const results = await ocrPdfBytes(pdfBytes, (p) => console.log(p.phase, p.progress), {
  enhance: true, // grayscale + auto-threshold for faded scans
});
console.log(results.map((r) => r.text).join('\n\n'));

Function reference

FunctionModuleWhat it does
mergePdfs(files)lib/pdfOps.tsMerge PDF byte arrays, in order, into one document.
reorderPages(bytes, order)lib/pdfOps.tsRebuild a PDF with a new page order/subset and per-page rotation.
extractPage(bytes, index)lib/pdfOps.tsPull one page out as its own standalone PDF.
splitPdfByRanges(bytes, ranges)lib/pdfOps.tsSplit a PDF into multiple PDFs by 0-based [start, end] page ranges.
splitPdfEveryNPages(bytes, n)lib/pdfOps.tsSplit a PDF into fixed-size chunks of N pages each.
parsePageRanges(spec, totalPages)lib/pdfOps.tsParse a human range spec like "1-3, 5, 8-9" into 0-based ranges.
compressPdf(bytes, opts)lib/compress.tsDownsample & re-encode embedded JPEGs in a Web Worker.
assemblePdf(sources, pages, edits, extras)lib/export.tsBuild a document from sources + apply text edits, annotations, watermark/header/footer.
printPdf(bytes)lib/print.tsOpen the browser print dialog with a date/time-stamped copy.
imagesToPdf(images, options)lib/imageToPdf.tsCombine PNG/JPEG images into a new PDF, one per page, with page size/orientation/fit options.
pdfToImages(bytes, options)lib/pdfToImages.tsRender every page of a PDF to a PNG/JPEG image.
flattenFormPdf(bytes)lib/flatten.tsBurn AcroForm field values permanently into the page content.
openForConversion(bytes)lib/convert.tsParse bytes into a pdf.js document for the convert* functions.
convertToWord(doc, onProgress)lib/convert.tsPDF → .docx (paragraphs, page breaks, heading sizes); OCRs scanned pages automatically.
convertToExcel(doc, onProgress)lib/convert.tsPDF → .xlsx — infers real table columns from text position, all pages in one sheet.
convertToCsv(doc, onProgress)lib/convert.tsSame table extraction as convertToExcel, written as plain-text CSV.
convertToPowerPoint(doc, onProgress)lib/convert.tsPDF → .pptx (each page as a full-bleed slide image).
buildWordFromPages(pages)lib/convert.tsBuild a .docx straight from an array of extracted/OCR'd page text strings.
buildFormPdf(options)lib/formBuilder.tsGenerate a fillable AcroForm PDF from a field spec, with logo/photo box.
FORM_TEMPLATESlib/formTemplates.ts10 ready-made professional form field sets.
extractFormData(name, bytes)lib/formData.tsRead AcroForm field values out of a filled PDF.
exportRowsToXlsx(rows)lib/formData.tsWrite form responses to a real .xlsx (SheetJS).
exportRowsToCsv(rows)lib/formData.tsWrite form responses to a plain CSV file.
ocrPdfBytes(bytes, onProgress, opts)lib/ocr.tsRun Tesseract.js OCR over a PDF's pages, fully client-side.
ocrImages(images, onProgress, opts)lib/ocr.tsRun OCR over standalone image files (photos/screenshots), no PDF needed.
createOcrEngine(onProgress)lib/ocr.tsLow-level: spin up one tesseract.js worker to reuse across multiple recognize() calls.
buildPdfFromMarkdown(title, markdown)lib/mdPdf.tsRender Markdown into a clean, styled PDF report.
createZip(entries)lib/zip.tsZero-dependency ZIP writer for bundling multiple output files.

Ask about the API

RAG over this exact reference and the examples above — answers quote real function signatures instead of a paraphrase from memory, and stay correct as the API evolves.

Uses whatever AI provider is configured in the app's AI tab (shared browser storage) — needs a provider with an embeddings endpoint, e.g. Ollama with ollama pull nomic-embed-text.