Release Next v3.0.0-next.12
Pre-release@embedpdf/default-stamps@1.0.0-next.0
Major Changes
-
#803 by @bobsingor – The default stamp libraries are now self-describing, Acrobat-compatible PDFs. Each
<locale>/stamps.pdfcarries its name as/Title, registers every page in/Names /Pagesasidentifier=label(Approved=Goedgekeurd), and records the library id (embedpdf-standard), the locale, and each stamp's kind in/PieceInfo. Import one withimportLibraryPdffrom@embedpdf/plugin-stampand the title, identifiers, and labels come from the file; drop the same file into Acrobat's Stamps folder and it appears there. The artwork is unchanged from the previous release (every page renders pixel-identical). Locales: en, de, nl, fr, es, zh-CN, sv, ja. A new@embedpdf/default-stamps/libraryentry delivers each locale through the module graph:loadDefaultLibrary(locale)resolves to the library's bytes from a generated, lazily imported module, so the library ships as a chunk of your own build with nothing to copy and no CDN.LOCALESlists the shipped codes.The legacy
<locale>/manifest.jsonfiles remain available for existing v2 viewers that load this package from an unversioned CDN URL. They preserve v2's library and stamp ids, categories, labels, and page indexes, and point to the same adjacentstamps.pdffiles. V3 reads the PDF metadata directly and does not load these manifests.
@cloudpdf/contract@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – Add
doc.annotations.flattenanddoc.annotations.exportAppearanceto the public contract.Add
doc.pages.setNameanddoc.pages.removeNamefor registering, renaming, and removing named pages (/Names /Pagesentries) on a layer.
@cloudpdf/engine@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – The cloud engine implements
page(pon).annotations.flattenoverPOST …/annotations/pages/{pon}/items/flatten(content and annotation planes patched in place,annotations.flattenedpublished) andpage(pon).annotations.exportAppearanceoverPOST …/items/appearance(PDF bytes; a read).It also implements
pages.setNameandpages.removeNameoverPOST …/pages/namesandPOST …/pages/names/delete. Both advance onlydocVersionandlayoutVersion, so the cached manifest is patched in place, per-page render/text/annotation leaves stay valid, and the result carries the fresh layout includingnamedPages.
@cloudpdf/sdk@3.0.0-next.12
Minor Changes
- #803 by @bobsingor – Add typed SDK methods for selective annotation flattening and appearance export through
client.doc.annotations.flattenandclient.doc.annotations.exportAppearance. Addclient.doc.pages.setNameandclient.doc.pages.removeNamefor registering, renaming, and removing named pages.
@cloudpdf/server@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – Add
POST /v1/docs/{docId}/layers/{layerName}/annotations/pages/{pon}/items/flatten(flatten a chosen set of the page's annotations; gated like page flatten and persisted the same way — one page's content and annotation versions advance) andPOST …/items/appearance(the chosen annotations' appearances as one single-page PDF; gated bydoc.download, no-store).Add
POST /v1/docs/{docId}/layers/{layerName}/pages/namesandPOST …/pages/names/deleteto register, rename, or remove a/Names /Pagesentry on a layer. Both are page-structure mutations gated bydoc.pages.assemble: the worker writes a new layer artifact and the doc and layout versions advance, exactly like a page move, with no new resource, version, or cache scope./layoutresponses now includenamedPages.
@embedpdf/core@3.0.0-next.12
Minor Changes
- #803 by @bobsingor –
PluginContext.tryForDocument(token, documentId)—forDocumentfor an OPTIONAL dependency: null when the plugin is not installed or that document is not ready, never a throw (a workspace plugin reaching a sibling's document-scoped lens without requiring it).
@embedpdf/engine-core@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – Selective annotation flatten and appearance export.
page(pon).annotations.flatten(refs, usage?)ispages.flattenfor a chosen set: painted annotations are removed from the page, ineligible ones (hidden for the usage, popups, no appearance) stay and reportskipped, and the result (AnnotationFlattenResult) carries that page's new pins plus anannotations.flattenedevent.page(pon).annotations.exportAppearance(refs)returns the chosen annotations' normal appearances as one single-page PDF sized to their union rect — vector, positions preserved, the source untouched; all-or-nothing. Both are optional service members;runAnnotationFlattenConformanceandrunAnnotationAppearanceExportConformancelock the shared behavior.Named pages join the page list.
PageListSnapshot.namedPagescarries the catalog's/Names /Pagesand/Names /Templatesregistrations in tree order —NamedPageEntryis the decoded key plus a target classified aspage(a page inpages),template(a hidden/Type /Templatepage that is never listed or rendered), ordangling. Because a registration only means something against the page set that contains its target, it is layout data likelabeland shares the layout version rather than a plane of its own.DocumentPagesServicegains two optional page-structure mutations:setName({ name, pageObjectNumber, replace? })registers a key, replaces what an existing key points at, or renames in one job;removeName({ name })drops a registration and keeps the page. Both return the fresh layout asPageNameResult(layout plus the docVersion/layoutVersion pins) and publish apages.namedevent. Deleting a page removes every registration pointing at it.runNamedPagesConformancelocks these invariants for every engine. The engine never interprets key text.Stamp
/Nameaccepts any non-empty name — a standard stamp name or a custom identifier such as an Acrobat library's#…key — and a stamp patch may clear it withname: null.
@embedpdf/engine@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – The local engine implements
page(pon).annotations.flatten(gated likepages.flatten, publishesannotations.flattened) andpage(pon).annotations.exportAppearance(gated bydoc.downloadlikepages.extract).It also implements
pages.setNameandpages.removeName: register, rename, or remove a/Names /Pagesentry as a page-structure mutation gated bydoc.pages.assemble, with the fresh layout returned and apages.namedevent published.pages.list()includesnamedPages.The local engine never contacts a CDN. The zero-config default is the
embedpdf.wasmyour bundler emits beside your code (@embedpdf/engine-runtime-wasm32/wasm-url, which webpack, Vite, Rspack, Parcel, and Turbopack all resolve), and it is now streamed and compiled by the worker as it downloads — the previous fetch-then-fallback path had given up streaming. When a toolchain cannot carry that asset (Angular's application builder, plain esbuild), boot fails with the fix named instead of silently fetching a possibly mismatched binary from jsDelivr:DEFAULT_WASM_URLand the fetch-failure fallback are gone.New
@embedpdf/engine/portable: the samelocalEngine()with the wasm delivered through the module graph — a lazy chunk of your own build, gzipped and inflated in the browser — so it works with every bundler at the same cost over the wire, with no asset to copy.wasmLoaderjoinswasmUrl,assetsUrl, andwasmBinaryas an explicit source (bytes produced on demand at boot). Explicit sources never fall back.Angular needs neither: the package's export map routes the
es2020condition Angular's application builder resolves with to the portable build, so the plain@embedpdf/engineimport is zero-config under Angular too. Other bundlers do not declare that condition and keep the streamed asset.
@embedpdf/engine-runtime@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor –
EPDFPage_FlattenAnnotationsflattens a chosen set of a page's annotations with a per-entry status (applied, skipped, not-on-page), replacing the single-annotationEPDFAnnot_Flatten.EPDFPage_ExportAnnotationsAsDocumentflattens a set's appearances into a new single-page document sized to their union rect, replacingEPDFAnnot_ExportAppearanceAsDocumentandEPDFAnnot_ExportMultipleAppearancesAsDocument, which mishandled rotated appearances and the rect fit. Whole-page flatten, selective flatten, and export now share one candidate plan and one placement writer (ISO 32000-2 12.5.5 fit,/Matrixhonored, no content re-parsing); resources shared between exported appearances are cloned once.New named-page functions:
EPDFDoc_GetNamedPageCount,EPDFDoc_GetNamedPageAt(key as UTF-16 plus the value's object number and kind: page, template, or dangling),EPDFDoc_SetNamedPage(create or replace, pages in the page tree only),EPDFDoc_RemoveNamedPage, andEPDFDoc_RemoveNamedPagesForPage.EPDFDoc_DeletePageByObjectNumbernow removes the/Names /Pagesregistrations of the page it deletes. The name-tree index search reports a pair whose value is a missing object (with a null value) instead of hiding it and desynchronizing later indices.Annotation
/Nameis text:EPDFAnnot_SetNametakes any name, writes a name object (escaping applied by the serializer), and never touches/AP;EPDFAnnot_GetNamefills a text buffer. TheFPDF_ANNOT_NAMEenum, its subtype validation, and the sentinel that removed/Nametogether with/APare removed — remove/NamewithEPDFAnnot_RemoveKey(annot, "Name").
@embedpdf/engine-runtime-wasm32@3.0.0-next.12
Minor Changes
- #803 by @bobsingor – New
@embedpdf/engine-runtime-wasm32/wasm-inline:embedpdf.wasmas a gzipped, base64 ES module (about 3.6 MB on disk, the same bytes as the file over the wire), generated in the same build step as the binary. This is what@embedpdf/engine/portableimports lazily so the wasm can travel through the module graph where a bundler cannot emit it as an asset.
@embedpdf/engine-services@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – New
annotations.flattenandannotations.exportAppearanceworker jobs over the runtime's set-based flatten: resolve refs on the page, hand the set to one candidate plan, and either paint in place (bumping that page's revision and weak-annotation state like a page flatten) or into a scratch document returned as PDF bytes.Every page list now includes the catalog's named-page registrations (
namedPages), read from the runtime with each value classified as page, template, or dangling. Newpages.setNameandpages.removeNameworker jobs register, rename, or remove/Names /Pagesentries and return the fresh layout; page deletion drops the registrations that pointed at the page.Annotation
/Nameis written and read as text: note and file-attachment icons map their ids to PDF names, stamps accept any non-empty name (standard or custom) and report custom names verbatim instead of collapsing them, and a stamp patch withname: nullremoves the entry without touching the appearance.
@embedpdf/react@3.0.0-next.12
Minor Changes
- #803 by @bobsingor – The stamp hover ghost is rendered at the on-screen device pixel size and re-requested when the zoom crosses a size bucket, so large vector stamps stay sharp.
@embedpdf/react/stampadditionally re-exportsindexedDbByteStoreandByteStorefrom@embedpdf/web, the browser store forpersistStampLibraries/restoreStampLibraries.
@embedpdf/web@3.0.0-next.12
Minor Changes
- #803 by @bobsingor –
indexedDbByteStore(dbName, { storeName? })is the browser's bytes-by-id store: one IndexedDB object store withlist,put, anddelete. It is the adapter for any plugin's DOM-free persistence port (structurallyStampLibraryStorefrom@embedpdf/plugin-stamp), written once here so every framework binding shares it.
@embedpdf/plugin-annotation@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – Stamps can be placed without the pointer and ghosted at any zoom.
placeStamp(input, placement)creates a stamp annotation by code — the same validation, fit, page clamp,/Name, and/Subja click afterarmStampproduces — and resolves to the new annotation's ref;StampPlacementnames the page, the anchor point, an optional width, and rotation.StampToolInputgainsname(the placed/Name) andsubject(the placed/Subj), and itspreviewnow also accepts aStampPreviewProvider: a function the hover ghost asks for a render at the device pixel width it is displayed at. Requests are bucketed to powers of two (previewBucket) and cached per bucket for the arm's lifetime, so a zoom gesture never renders per frame. The host capability'sarmedStampPreview(devicePixelWidth?)is now asynchronous and takes that width.armStampno longer clears the payload it just set when activating the built-in stamp tool from another active tool. Armed stamps now place correctly instead of falling through to the tool's source callback, while the legacyannotation-stamptool tag remains supported.
@embedpdf/viewer-chrome@3.0.0-next.12
Minor Changes
-
#803 by @bobsingor – The Insert tab's Stamp action now opens the stamps sidebar instead of a click-then-pick file dialog; the Image action handles arbitrary PNG and JPEG insertion. The sidebar is now the classic picker over real libraries. Its built-in library comes from
@embedpdf/default-stamps— the standard rubber stamps as one Acrobat-compatible PDF per locale — loaded on the panel's first open (never at boot), in the locale negotiated from the viewer's language and the browser's, and swapped when the viewer's locale changes; the canvas-drawn placeholder set is gone. The panel gets a library dropdown ("All stamps" plus one entry per library, shown once there are two), a two-column thumbnail grid with the label as tooltip, a hover×that removes a stamp from a user library, and per-library export as PDF and remove. Custom libraries persist in IndexedDB across reloads."Make stamp" joins the annotation selection strip: with one or more annotations selected on a page, it turns their appearances into a vector stamp in a "My stamps" library and opens the panel on it. Widgets and pending redaction marks are excluded.
New
stampsoption on the viewer customization:stamps: { defaultLibrary: false }ships no built-in library and makes no request (air-gapped);stamps: { defaultLibrary: 'https://your.cdn/{locale}/stamps.pdf' }self-hosts a copy of@embedpdf/default-stamps. The default is the copy that ships with the viewer, loaded as a lazy chunk of your own build; nothing is ever fetched from a third party. English and Spanish strings updated.
@cloudpdf/viewer@3.0.0-next.12
Patch Changes
- #803 by @bobsingor – The
cloudpdf.jsartifact carries the built-in stamp library as lazy sibling chunks in its own folder instead of inlining eight locale PDFs as base64. Nothing is fetched from a third party; setstamps.defaultLibraryto self-host or disable it.
@embedpdf/viewer@3.0.0-next.12
Patch Changes
-
#803 by @bobsingor – The built-in stamp library ships inside the viewer instead of being fetched from a CDN. The npm entry keeps
@embedpdf/default-stamps/libraryexternal, so its locale modules become lazy chunks of your own build; the CDN snippet carries them as sibling chunks in its folder.@embedpdf/default-stampsis now a dependency. Previously a library build could inline the eight PDFs into the JS chunk as base64, a form webpack rejects.The viewer registers
stampPlugin(), exposesStampTokenthrough its drive door, and routes the Insert tab's Stamp action to the stamps sidebar. Arbitrary PNG and JPEG insertion remains available through the Insert tab's Image action.The CDN snippet (
dist/embedpdf.js) once again findsembedpdf.wasmwhen loaded from another origin: the wasm is now an asset Vite emits into the dist folder and references by a URL relative to whichever chunk needs it, instead of a path guessed against the entry file — which had resolved tochunks/embedpdf.wasmand failed. A cross-origin test (pnpm testin the viewer package, Playwright against the built artifact) now guards it: the snippet must render with every sibling fetched from its own folder and no request to any other origin.