# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [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`.
[Unreleased]: https://github.com/xlabs-hq/langelic-epub/compare/v0.1.1...HEAD
[0.1.1]: https://github.com/xlabs-hq/langelic-epub/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/xlabs-hq/langelic-epub/releases/tag/v0.1.0