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: rustler 0.37 → 0.38 (Elixir + crate), zip 7 → 8, quick-xml 0.39 → 0.40, plus uuid, credo, and ex_doc bumps. The quick-xml Attribute::unescape_value API was deprecated; migrated to normalized_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 iepub crate. All structural data (manifest, spine, metadata, cover, TOC) now comes from a pure zip + quick_xml stack. This removes a large transitive dependency surface and lets us tolerate non-OCF-conformant mimetype files (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_mimetype error kind.

Added

  • LangelicEpub.Error may now have kind: :invalid_mimetype when the mimetype zip entry is missing or its content (after trimming a UTF-8 BOM and whitespace) is not application/epub+zip.
  • OTP 29 support: rustler 0.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's NsReader), so dc:-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-compatible toc.ncx alongside the EPUB 3 nav.xhtml so 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 chapter data to 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, and x86_64-unknown-linux-musl.