All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.1.1 - 2026-06-27
Changed
- Dependency updates:
rustler0.37 → 0.38 (Elixir + crate),zip7 → 8,quick-xml0.39 → 0.40, plusuuid,credo, andex_docbumps. The quick-xmlAttribute::unescape_valueAPI was deprecated; migrated tonormalized_value(XmlVersion::Implicit1_0), which is behavior-identical (same XML 1.0 implicit version, depth, and predefined-entity resolver). No user-facing API change. - Reader no longer depends on the
iepubcrate. All structural data (manifest, spine, metadata, cover, TOC) now comes from a purezip+quick_xmlstack. This removes a large transitive dependency surface and lets us tolerate non-OCF-conformantmimetypefiles (trailing\n,\r\n, space, or a leading UTF-8 BOM) — common in Calibre exports and other real-world EPUBs that other readers accept silently. Genuine non-EPUB content is still rejected with a new:invalid_mimetypeerror kind.
Added
LangelicEpub.Errormay now havekind: :invalid_mimetypewhen themimetypezip entry is missing or its content (after trimming a UTF-8 BOM and whitespace) is notapplication/epub+zip.- OTP 29 support:
rustler0.38 builds against OTP 29's NIF interface, and CI now tests on OTP 29 / Elixir 1.20 in addition to OTP 26/27. The precompiled NIF 2.16 artifact forward-loads on OTP 29's newer NIF ABI, so no new artifact is shipped (a 2.17 artifact would needlessly drop OTP 26 compatibility).
Fixed
- Dublin Core metadata is now matched by its namespace URI rather than a
hard-coded
dc:prefix (the OPF is parsed with quick-xml'sNsReader), sodc:-equivalent elements bound to a non-standard prefix or a default namespace are recovered instead of silently dropped. Parsing the OPF also now rejects elements that declare more than 256 namespace bindings, bounding a malformed or hostile package.
0.1.0 - 2026-04-20
Added
LangelicEpub.parse/1— parse EPUB 2 and EPUB 3 bytes into a%LangelicEpub.Document{}with spine, assets, table of contents, and metadata (including fields like<dc:language>,<dc:rights>, and multiple<dc:creator>entries that the underlying iepub crate does not expose natively).LangelicEpub.build/1— emit EPUB 3 bytes from a%LangelicEpub.Document{}, with a backward-compatibletoc.ncxalongside the EPUB 3nav.xhtmlso EPUB 2-only readers still navigate correctly.- Validation of required fields (
title,identifier,language) and spine/asset ID uniqueness at build time. UTF-8 is enforced on chapterdatato prevent silent corruption in downstream readers. - Rust panics inside the NIF are caught (
std::panic::catch_unwind) and returned as{:error, %LangelicEpub.Error{kind: :panic, ...}}so a malformed input cannot crash the BEAM scheduler. - Precompiled NIFs published via GitHub Releases for
aarch64-apple-darwin,x86_64-apple-darwin,aarch64-unknown-linux-gnu,x86_64-unknown-linux-gnu, andx86_64-unknown-linux-musl.