v5.3.3
5.3.3 (2026-10-29)
- Ads: Fix unhandled rejections when unloading during an ad (#10842) (144f216)
- Ads: Link SVTA pods and slots carried separately (#10808) (498453b)
- Cast: Reject Opus on the 1st-gen Chromecast (#10844) (89a3439)
- DRM: Close sessions dropped after a failed license request (#10804) (bad01c7)
- HLS: Fall back to redundant variant URIs when a media playlist fails (#10787) (1bcb8c2), closes #10751
- MSE: Fall back to MediaSource reset when changeType fails (#10807) (7602b56)
- MSE: Keep playback position after a MediaSource reset (#10806) (885ded0)
- MSF: Keep the next group when an object of a group completes late (#10856) (cb0c310), closes #10823
- MSF: Set Next Object filter for draft-22 live joins (#10829) (b2023ab), closes #10828
- Preload: Keep Content Steering updating when preloading before the first load (#10826) (a699b1c), closes #10824
- Resolve relative track URIs against the page in add*Track methods (#10786) (541546d), closes #10750
- TTML: Default paragraph line height to normal (#10835) (bdb87eb)
- UI: Avoid compounding caption font size with nested cues (#10820) (6e86254)
- UI: Fix translation of the subtitle style "Default" option (#10805) (2b116d5), closes #10791
v5.2.16
5.2.16 (2026-10-29)
- Ads: Fix unhandled rejections when unloading during an ad (#10842) (3614c15)
- Cast: Reject Opus on the 1st-gen Chromecast (#10844) (0c2ac47)
- DRM: Close sessions dropped after a failed license request (#10804) (2e991c1)
- HLS: Fall back to redundant variant URIs when a media playlist fails (#10787) (44724e2), closes #10751
- MSE: Fall back to MediaSource reset when changeType fails (#10807) (eb729d9)
- MSE: Keep playback position after a MediaSource reset (#10806) (8656096)
- Preload: Keep Content Steering updating when preloading before the first load (#10826) (ffbad76), closes #10824
- Resolve relative track URIs against the page in add*Track methods (#10786) (cb344e5), closes #10750
Release Next v3.0.0-next.18
-
#917 by @bobsingor – Add folders:
folders.create,folders.list,folders.get(with the path above the folder),folders.updateto rename,folders.moveIntoto move documents and folders together, andfolders.deletefor empty folders. The top level is the placeroot. Document records carryfolderId;documents.initanddocuments.importFromtake one, anddocuments.listfilters by it. Folder conflicts answer 409 withdetails.reason. -
#917 by @bobsingor – Documents have a
name: set it withdocuments.initordocuments.import(it defaults to the document id) and change it with the newdocuments.updateoperation, which needs the newdocs.updatetenant scope.documents.listgainsqto search names ignoring case,sort(createdAt,nameorsize) andorder, and no longer lists documents that are being deleted unlessstate=deletingasks for them. -
#917 by @bobsingor –
folders.deletetakesrecursive=trueto delete a folder with everything in it. Without it, a folder that holds anything is still refused. -
#917 by @bobsingor – Document operations accept tenant JWTs, which need the operation's document capabilities exactly as a document JWT does; no tenant scope reaches inside a document. A tenant token's
scopenow takes document capabilities next to tenant scopes, and they hold for every document of the tenant.documents.downloadneedsdoc.downloadanddocuments.thumbnailneedsdoc.renderinstead ofdocs.read.docs.updaterenames and moves, and never changes content.
-
#910 by @bobsingor – The
doc.versions.*operations take the layer: their paths are/v1/docs/:docId/layers/:layerName/versions….doc.versions.listanswersLayerVersions({ baseSha, versions }): the layer's base and its versions, the upload first. -
#909 by @bobsingor – Share links carry
identity(who their visitors are, for a link made for one person) on the link record,shares.createandshares.update.Identityis a named component, shared withtokens.issue, so the SDKs have one type for it. -
#910 by @bobsingor – The signature notes describe the new rule. A signature is made over the layer's own base, and its new version is that layer's own: the document and every other layer stay as they were.
StaleBaseis no longer an error code.
-
#917 by @bobsingor – Add the
foldersclient (create,list,get,update,moveInto,delete), afolderIdoption ondocuments.init,documents.importFrom,documents.listanduploads.create, andfolderIdon document records. -
#917 by @bobsingor – Add
documents.updatefor renaming documents, anameoption ondocuments.init,documents.importFromanduploads.create, and theq,sortandorderoptions ondocuments.list. Document records now carryname. -
#917 by @bobsingor – Add the
recursiveoption tofolders.delete. -
#910 by @bobsingor –
doc.versions.*takes the layer:list,signatures,signatureContents,signatureDigest,analysis,downloadandrevisionread/v1/docs/{docId}/layers/{layerName}/versions….listanswers the layer'sbaseShaand its versions (the upload, then the ones its signatures made), and another layer's version is 404. -
#909 by @bobsingor –
shares.createandshares.updatetakeidentity, and a share record returns it: who a link's visitors are, for a link made for one person.Identityis one shared type, used bytokens.issuetoo. -
#917 by @bobsingor – A tenant token's
scopeintokens.issuetakes document capabilities next to tenant scopes, and the document operations document tenant tokens as a credential.
- #910 by @bobsingor –
StaleBaseis no longer an engine error code, and the signature notes describe the new rule: a signature's new version belongs to its layer, and the document and every other layer stay as they were.
-
#917 by @bobsingor – Organize documents in folders. Folders nest up to 100 levels with names unique among siblings, ignoring case. A move takes documents and folders together or not at all and never makes a loop, even when two moves race; only empty folders delete. Documents are filed at upload and listed per folder, and a document being deleted leaves its folder. Migration 046 adds the
folderstable anddocuments.folder_id. Errors thrown with structured context now return it asdetails. -
#917 by @bobsingor – Store a name for every document, searchable and sortable without regard to case, and rename documents with
PATCH /v1/tenants/:tenantId/documents/:idunder the newdocs.updatescope. The documents list searches by name, sorts by creation time, name or size in either order with stable cursors, and hides documents that are being deleted unless asked for by state. Migration 045 names existing documents frommetadata.namewhen it is a non-empty string, otherwise from their id. -
#917 by @bobsingor – Delete a folder with everything in it via
recursive=true: the folder and every folder under it go in one transaction, and every document in them stops opening, leaves every list and stops answering its share links at once, while their stored files are removed in the background. The sweeper now also finishes deletes left behind, such as one interrupted by a crash, afterdeletingGraceMs(default one minute). The filesystem object store no longer fails a write when a delete elsewhere in the same tenant prunes the directories the write has just made. -
#917 by @bobsingor – Tenant scopes act on records and document capabilities act on what is inside documents, on any token. A tenant JWT is checked inside documents the way a document JWT is, against the document capabilities its scope names, which hold for every document of the tenant;
docs.readlists documents but no longer opens, reads or changes them. Downloading the original file needsdoc.downloadand the thumbnail needsdoc.render. A tenant token whose scope names no document capability is refused on the document routes, andtokens.issuevalidates a tenant token's scope entries.
-
#910 by @bobsingor – A layer's versions are read through the layer. The version routes moved from
/v1/docs/:docId/versions…to/v1/docs/:docId/layers/:layerName/versions…, checked like every other layer route.- The list gives the layer's versions (the upload, then the ones its signatures made) and its
baseSha. - A version's signatures, analysis, download and revisions answer only for the upload or the layer's own versions: another layer's version is 404, and a token for one layer can't use another layer's path.
- Tenant tokens read any layer's versions, through that layer.
- The list gives the layer's versions (the upload, then the ones its signatures made) and its
-
#909 by @bobsingor – A share link can say who its visitors are, for a link made for one person:
identityonshares.createandshares.update, the same shape astokens.issue's (migration 043). Every session the link gives carries it, whoever opens the link: a field it sets is never asked, and a visitor's answer for it is ignored. ItsuserIdreplaces the visitor's ownvisitor_<id>; each visit still gets its own layer on a per-visitor link. A link that asks a field its identity sets is refused (400), on create and on an update checked against the link as it will be. -
#907 by @bobsingor – A share link's visitor is remembered on every link except a per-visitor link that doesn't keep visitors' layers: the exchange answers
visitor.keep: truefor shared links too. A visitor who comes back in the same browser keeps their answers to the link's questions and stays the author of what they added, instead of being asked again on every page load and listed as a new visitor each time. -
#910 by @bobsingor – A signature moves only the layer it was made in. Completing a signature writes the new version as that layer's own: only its
base_shamoves, and the document (documents.base_sha, the upload) and every other layer stay as they were.Before, a signature moved the whole document, so on a per-visitor link the next visitor opened the signer's filled-in, signed copy, and layers still on the old version could no longer sign (
StaleBase).- Every layer can sign, over its own base. A layer that signs again signs over its previous version.
- Versions belong to their layer: a layer's versions are numbered along its own chain and stored under the layer, and they're deleted with it.
/layers/:layerName/headreports the layer's own base.- Migration 044 gives each existing signed version its layer, puts a document a signature moved back on its upload, and starts layers that stored nothing on the upload too.
- No document-wide signal any more: the base-changed bus channel is gone. Other replicas reload the signing layer because its version moved.
- #907 by @bobsingor – A ready document whose share link asks for a passphrase or answers it got after the document opened shows them as
shareRequest, as a document waiting to open does, anddocuments.retry(id, { sharePassword })orretry(id, { visitor })lets it go on as the same visitor instead of opening it again.
-
#909 by @bobsingor –
documents.retry(id, { identity })takes the visitor's answers to what a share link asks (was{ visitor }). They join who the page said the user is, the document'sidentityor else the viewer's, and the document opens again with that identity. -
#910 by @bobsingor – The
StaleBaseengine error is gone, and with it itsconflictmapping: a signature moves only its own layer, so every layer can sign.
-
#911 by @bobsingor – New
runPageFormFieldsConformancesuite checks thatpages.insertandpages.extractbring form fields, keep same-named fields apart, and survive a save in either mode. -
#907 by @bobsingor –
DocumentSharegetsopenRequest,onOpenRequest()andresume(): a passphrase, or questions asked on open, that a share link gets while a document is open are asked of the visitor, andresume({ sharePassword })orresume({ visitor })lets the document go on as the same visitor.ShareOpenRequestandshareOpenRequestOf()move here from@embedpdf/core, which re-exports the type.
-
#910 by @bobsingor – The version wire paths and resources are the layer's:
wirePaths.layerVersions,layerVersionSignatures,layerVersionSignatureContents,layerVersionSignatureDigest,layerVersionAnalysis,layerVersionDownloadandlayerVersionRevisiontake the layer name. The resources are nowlayer-versionsandlayer-version-*, so a layer's CDN grant covers only its own versions.The catalog schema is
LayerVersionsSchema({ baseSha, versions }, wasDocumentVersionsSchemawithhead). -
#909 by @bobsingor –
identityis the one word for who the user is, on both engines.OpenOptions.identityis who your page knows the user is: the local engine's session identity, as before; on the cloud engine a document token decides, and a share link takes it as the visitor's answers to what the link asks. The share input'svisitoris gone (passidentityin the options instead), andDocumentShare.resume()takes{ sharePassword, identity }.doc.security.identitysays who a session acts for.The runtime entry exports
devWarn,isDevandresetDevWarningsfor engines: development-only warnings, once per key. -
#910 by @bobsingor –
EngineErrorCode.StaleBaseis gone. A signature no longer moves the document, so no layer is ever behind it and every layer can sign over its own base.
-
#911 by @bobsingor – New
EPDFDoc_ImportPagescopies pages with the form fields of their widgets, whereFPDF_ImportPagesByIndexleft each copied widget's/Parentnaming an object of the source and wrote no/AcroForm. Each field above the copied widgets is copied once, its/Kidslimited to what was copied, and the copied top-level fields join the destination's/AcroForm /Fields(made when it has none) with the source's/DRresources,/DAand/Q,/NeedAppearances, calculation order andSignaturesExist. A/DRfont is shared only when the destination defines one of that name the same way, key for key (widths and descriptor included, no font program); otherwise it is copied under a free name, and the copied/DAstrings follow, comments and all. A copied pop-up's/Parentnames the copy of its annotation.New
EPDFDoc_GetImportFieldRootslists the top-level fields an import of some pages brings, andEPDFForm_GetFieldPartialNamereads a field's own/Tby object number. -
#913 by @bobsingor – New
EPDFCatalog_GetMetadatareads the document's XMP packet (the catalog's/Metadatastream) decoded, andEPDFCatalog_SetMetadatareplaces it, unfiltered, keeping the stream's object number, or removes it.Saving an encrypted document encrypts its metadata stream, unless the file says
/EncryptMetadata false; it was written in the clear, so readers decrypted the XMP into noise. A metadata stream with a filter is written decoded, where its encoded bytes were written without the filter that decodes them.
-
#911 by @bobsingor –
pages.insertandpages.extractbring the form fields of the copied pages' widgets, written into the document's/AcroForm, so the fields stay fillable after a save and in other PDF apps. An extract brings only the widgets on the extracted pages. An inserted top-level field whose name the document already uses comes in asname_2(or the next free number), with its fields under it, so two copies of a filled-in form keep their own values. -
#913 by @bobsingor –
metadata.updatekeeps a document's XMP packet in step with its/Infofields: a field it sets is written to its XMP property (dc:title,dc:creator,dc:description,pdf:Keywords,xmp:CreatorTool,pdf:Producer,xmp:CreateDate,xmp:ModifyDate,pdf:Trapped), added when the packet doesn't have it, and a field it sets tonullis removed from the packet too. A packet'sdc:subjectkeyword list follows the keywords.metadata.custom.updatechanges or removes thepdfx:property Adobe apps copy a custom key to, and never adds one. Everything else in the packet stays as written; a document without XMP gets none, and XMP that isn't well-formed is left as it is.
-
#910 by @bobsingor – A document's signed bytes (
signatures.getContents,getDigest,downloadRevisionand historyanalyze) are read through its layer's version paths. -
#909 by @bobsingor – A share link takes the page's
identity(theopen()option, or the viewer'sidentity) as the visitor's answers, the same as the visitor typing them: only the fields the link asks, neveruserIdorgroupId. The share input'svisitoris gone.Nothing the page passes is ignored silently: in development the engine warns once when it doesn't use
scope(the document's token says what the session may do), or when the session doesn't act for theidentitypassed, and says why. -
#907 by @bobsingor – A renewal the share link refuses for a passphrase, or for questions asked on open, no longer retries on every request. The document asks once (
doc.share.openRequest,onOpenRequest), reads on with its session until it runs out, then waits forresume(); with nothing listening, a request fails with the refusal. A shared link's visitor is now kept in the visitor store for the next visit, as the server says (visitor.keep).
- #909 by @bobsingor – The viewer takes
identityagain: who your page knows the user is. A document token decides for itself, and a share link takes it as the visitor's answers to what the link asks, so the questions it covers aren't asked.src.visitoris gone;scopestays out, since the token says what the user may do.
-
#905 by @bobsingor – PDF JavaScript runs in Next.js apps again.
- Turbopack, the default bundler in Next 16, failed with "Can't resolve '#quickjs-variant'", because it doesn't follow an
importstarget that names another package.#quickjs-variantnow maps to two files of this package,quickjs-variant/browser.jsandquickjs-variant/wasmfile.js, which re-export QuickJS's browser and wasm-file builds. - Production builds on Next before 16.4.1, webpack or Turbopack, broke QuickJS's browser build, so the sandbox never started. QuickJS 0.32.0 embeds its wasm as raw bytes in a template literal, and Next's minifier turned some of them into octal escapes ("Octal escape sequences are not allowed in template strings"). QuickJS is pinned to 0.31.0, which embeds the wasm as base64.
Browsers still get the browser build, with no
.wasmrequest, and Node the wasm-file one. - Turbopack, the default bundler in Next 16, failed with "Can't resolve '#quickjs-variant'", because it doesn't follow an
-
#908 by @bobsingor – Hide the Measure tab when the session can neither draw measurements nor set a page's scale: the measurement panel, and the Measure bar's scale button that opens it, now follow the same permission checks as the measurement tools. The scale button is drawn like every other bar button, so the Measure bar is as tall as the other mode bars, and it shows pressed while the panel is open; clicking it again closes the panel.
-
#907 by @bobsingor – Where a document allows searching but not copying text, search opens as a find bar over the top corner of the pages instead of a panel of empty result rows. It shows which match you're on and how many there are,
EnterandShift+Enterstep through them, and its options sit behind a button. In the search panel,EnterandShift+Enterstep through the matches too, and a match the engine finds no text around reads "Result 3" instead of an empty row. -
#907 by @bobsingor – When a share link gets a passphrase or questions while its document is open, the viewer shows the same passphrase or questions form over the document, and the document goes on once they're given.
Tabler v1.7.3
- 62faccc: Fixed
Autosizemoving the scroll position of a scrolled ancestor when the textarea is resized. - 21dc7f5: Fixed
.card-tablelosing its rounded corners inside.table-responsive-smto.table-responsive-xxlwrappers. - ec4b184: Fixed
.modal-headervertical padding so multiline and wrapped.modal-titletext no longer touches the header edges. - 8dec6f4: Fixed Tom Select chip
border-radius, optgroup dividers and dropdown corners that read undefined--bs-*variables.
💎 Version 8.6.0
A minor release: ApexCharts stops writing on the element you render into, plus fixes for unit chart updates and destroy timing.
Behaviour changes to check when upgrading:
- ApexCharts no longer sets
min-heighton the element passed tonew ApexCharts(el). The height it reserves (the chart height pluschart.parentHeightOffset) is now amin-heighton its own.apexcharts-canvaswrapper, so amin-heightyou give the element, through a style prop or a class, applies while the chart is mounted and survivesdestroy()(react-apexcharts#751). Rendered heights are otherwise unchanged; code that read the reservation from the element should read it from.apexcharts-canvas. - Unit chart updates follow
chart.animations.dynamicAnimation: 350 ms by default (was 800), and no tween when it is disabled. SetdynamicAnimation: { speed: 800 }for the old pace.
- Updates follow dynamicAnimation, 350 ms by default (was 800).
- Resolve tweened var() colours inside the chart.
- Cancel gesture timers on destroy, start clean on render.
- Finish an update mid piece-morph on the morph's clock.
- Leave the host element's min-height to the user.
Upgrading is npm install apexcharts@8.6.0.
Full changelog, with the detail behind each change: https://github.com/apexcharts/apexcharts.js/compare/v8.5.0...v8.6.0
Tabler v1.7.2
- f251b2f: Fixed
Datepickerthrowing on a click when the start of a range is clicked again to clear it. - 3dba8bc: Let
data-bs-dismiss="offcanvas"close a responsive offcanvas (.offcanvas-lgetc.) withoutdata-bs-target. - 19fc71a: Fixed
.table-primary,.table-warningand other table variants showing light backgrounds in dark mode.
- 40a1a91: Fixed a chart tooltip crash when the
thousandsorsuffix-kaxis formatter gets an empty value.