Recipe API Invariants
- Load the class with
await createRecipe(); Recipe is an ESM, byte-first API. - The constructor accepts PDF
Uint8ArrayorArrayBufferinput. Awaitblob.arrayBuffer()before constructing from aBloborFile. - Recipe drawing uses a top-left origin.
setPageBox()andrectangle()withuseGivenCoords: trueuse PDF-native bottom-left coordinates. - Recipe page numbers are one-based, including
editPage(),pageInfo(),replaceText(),deletePage(), and composition source pages. OnlyinsertPage()uses zero to mean before the first output page. - Call
endPage()before selecting, creating, or editing another page.endPDF()andappendPage()finish an active page themselves, so a forgottenendPage()does not cost that page. While pages are marked for deletion,endPDF()reports an active page instead of finishing it. pauseContext()andresumeContext()are chainable for valid created-page and edited-page transitions. They throw when there is no matching active or paused page content context.deletePage()applies only to original pages in a byte-backed Recipe, must leave at least one page, and cannot be combined with creating, appending, or inserting pages. Page-tree cycles, retained references to deleted pages, and nonzero-generation rewrites are validated bydeletePage(); a failed call leaves the queued deletions unchanged. A page edited afterdeletePage()is validated again duringendPDF().pruneReferences: trueremoves retained references to deleted pages instead of refusing the deletion. If finalization fails, the Recipe releases its resources and remains ended; create a new Recipe to retry.insertPage()andappendPage()throw synchronously for invalid or missing arguments; neither silently no-ops.endPDF()returns an ownedUint8Array; repeated calls return the cached result. It never writes a path or stream.read()andreadAsync()inspect their argument without replacing Recipe's output state.info()returns the document metadata known to Recipe.getPageInfo()is the native-compatible Info accessor and returns the writable output dictionary during source editing.pageInfo()andgetCurrentPageInfo()return page geometry.- Static font, image, and PDF registrations are shared by Recipe instances in a loaded runtime. Unregister assets only after active documents finish.
dispose()releases one Recipe's Emscripten allocations.disposeAssets()releases registered static assets; JavaScript garbage collection cannot do either job deterministically.- Fixed-height clipping requires
textBox.heightandtextBox.clipIfExceedsBox: true;onClipruns only when text remains. - Synchronous callbacks such as text overflow and table cell renderers cannot await work or use Node streams and plugin loading.
import { createRecipe } from "@muhammara/wasm";
var Recipe = await createRecipe();
var recipe = new Recipe().createPage(200, 120).text("Complete page", 20, 30);
var pdfBytes = recipe.endPage().endPDF();
recipe.dispose();
Recipe.disposeAssets();
console.log(pdfBytes instanceof Uint8Array); // true
Review Differences And Restrictions for composition, encryption, HTML, fonts, filesystem, and plugin boundaries.