# 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.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v4.3.0 (10.11.2026)

### Added
* Modules created with `ShortUUID.Builder` define `__shortuuid__/0`, an optional
  `ShortUUID.Behaviour` callback that returns the alphabet, base, encoded length and
  `canonical: true`. Libraries such as ecto_shortuuid can use it to skip re-encoding
  decoded IDs to check them.

### Changed
* Faster decoding for alphabets made only of ASCII characters, including all
  predefined alphabets: they decode with a byte lookup table, about 25-30% faster
  than in 4.2.0. Input with the wrong length is rejected about 2.5x faster. Other
  alphabets are unchanged.
* The README's example of a hand-written `ShortUUID.Behaviour` module is now a
  prefixed ID (`usr_...`) that wraps `ShortUUID` and accepts only the IDs it
  produces. The previous example decoded anything after its prefix. A test
  compiles the example from the README to keep it working.
* `usage-rules.md` covers prefixed IDs and when a hand-written module may report
  `canonical: true`.

## v4.2.0 (09.11.2026)

### Added
* UUIDs can be given as URNs (`urn:uuid:550e8400-e29b-41d4-a716-446655440000`).
* Functions generated by `ShortUUID.Builder` have documentation showing the
  encoded length and alphabet.
* `usage-rules.md` with guidance for coding agents, and markdown docs with an
  `llms.txt` index on hexdocs.
* `ShortUUID.Behaviour` documents the contract implementations must meet.

### Fixed
* Custom alphabets with characters that merge when concatenated (combining marks,
  regional indicators, emoji modifiers, ZWJ, CR/LF, Hangul jamo) failed to encode or
  decode many UUIDs. Encoded strings are now matched by codepoint instead of grapheme.

### Changed
* Requires Elixir 1.8 or later. CI now checks this by compiling the library and
  running smoke tests on Elixir 1.8 to 1.13; the full test suite runs on 1.14 and later.
* Custom alphabets are now rejected at compile time if a character is a prefix of
  another one, a character is not in Unicode NFC form, or Unicode normalization could
  make an encoded ID decode to a different UUID.
* `use ShortUUID.Builder` no longer adds aliases, imports or module attributes
  (`@alphabet`, `@base`, ...) to the calling module, so it no longer overrides
  the caller's own attributes.
* `ShortUUID.Core.format_uuid/1` only accepts integers in the 128-bit range, and
  `ShortUUID.Core.encode_int/5` returns `{:error, "Invalid UUID"}` for other input
  instead of raising.
* Faster decoding.
* Clarified in the docs that alphabets are not required to be URL-safe, that only UUID
  input is case-insensitive, and which predefined alphabets are compatible with the
  Python and JavaScript implementations. Compatibility is now tested against fixtures
  generated with both libraries.
* The changelog is included in the Hex package.

## v4.1.0 (08.04.2025)

### Added
* `ShortUUID.Behaviour` for implementing ShortUUID-compatible modules
* Modules created with `ShortUUID.Builder` declare `@behaviour ShortUUID.Behaviour`

## v4.0.0 (25.12.2024)

Breaking changes:
* Dropped support for binary UUID input

### Added
* Support for custom alphabets
* Predefined alphabets (base32, base58, base62, base64, etc.)
* `ShortUUID.Builder` module for creating custom ShortUUID modules

### Changed
* Moved core functionality to `ShortUUID.Core`
* Simplified main `ShortUUID` module interface
* Improved error messages and validation

```elixir
# Old v3.x code still works, the ShortUUID module uses the same alphabet as in V3
# If you just want to keep using ShortUUID no changes are required
ShortUUID.encode(uuid)

# New in v4.x you can use one of the predefined alphabets or define your own
defmodule MyUUID do
  use ShortUUID.Builder, alphabet: :base58
end

MyUUID.encode(uuid)

defmodule MyCustomUUID do
  use ShortUUID.Builder, alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
end

MyCustomUUID.encode(uuid)
```

## v3.0.0 (15.07.2023)

Breaking change, ShortUUIDs created by `< v3.0.0` will produce bad results when decoded.
The new output of `encode` is the reverse of the previous output.
This follows a change in other languages ShortUUID libraries.

To migrate ShortUUIDs created by `< v3.0.0` reverse them before passing to `decode`.

```elixir
# UUID "00000001-0001-0001-0001-000000000001" encoded using v2.1.2 to "UD6ibhr3V4YXvriP822222"
# reversing the encoded string before decode with v3.0.0 will produce the correct result
iex> "UD6ibhr3V4YXvriP822222" |> String.reverse() |> ShortUUID.decode!()
"00000001-0001-0001-0001-000000000001"
```

### Changed
* move most significant bit to the beginning of the encoded result similar to libraries in other languages (most importantly python shortuuid)
* drop support for decoding of un-padded ShortUUIDs
* drop support for formats other than regular hyphenated and unhyphenated UUIDs, MS format and binary UUIDs like are stored in PostgreSQL uuid type
* refactor code for better readability
* improve encode and decode performance

### Benchmarks
Results are not comparable to previous benchmarks due to them being run on a different system
  ```
  Operating System: macOS
  CPU Information: Apple M2 Max
  Number of Available Cores: 12
  Available memory: 32 GB
  Elixir 1.15.2
  Erlang 25.3.2.3

  Benchmark suite executing with the following configuration:
  warmup: 2 s
  time: 5 s
  memory time: 0 ns
  parallel: 1
  inputs: none specified
  ```

* v3.0.0
  ```
  Name                                        ips        average  deviation         median         99th %
  encode/1 binary uuid                  1212.57 K        0.82 μs  ±1995.67%        0.75 μs        1.00 μs
  encode/1 unhyphenated uuid string      788.79 K        1.27 μs   ±984.70%        1.13 μs        1.63 μs
  encode/1 hyphenated uuid string        753.56 K        1.33 μs  ±1106.96%        1.17 μs        1.67 μs
  encode/1 uuid string with braces       722.36 K        1.38 μs  ±1188.51%        1.21 μs        1.83 μs
  decode/1                                 1.15 M      868.43 ns  ±1506.27%         751 ns        1334 ns
  ```

* v2.1.1
  ```
  Name                                        ips        average  deviation         median         99th %
  encode/1 binary uuid                    1018.43 K        0.98 μs  ±1224.91%        0.88 μs        1.25 μs
  encode/1 unhyphenated uuid string        849.67 K        1.18 μs  ±1171.07%        1.08 μs        1.42 μs
  encode/1 hyphenated uuid string          731.91 K        1.37 μs   ±691.40%        1.29 μs        1.63 μs
  encode/1 uuid string with braces         569.16 K        1.76 μs   ±833.41%        1.63 μs        2.17 μs
  decode/1                                   1.00 M      996.37 ns   ±781.87%         918 ns        1376 ns
  ```

## v2.1.2 (2020-04-25)

* fix endless loop when decoding strings whose value does not fit in 128 bits

## v2.1.1 (2019-02-18)

* speed improvements

  Benchmarked on 2018 Macbook Pro 13 (non-touch), results are just a snapshot
  and not averaged.

  before:

  ```
  ## ShortUUIDBench
  benchmark name                       iterations   average time
  encode/1 uuid binary                     500000   5.93 µs/op
  encode/1 uuid string not hyphenated      100000   10.71 µs/op
  encode/1 uuid string                     100000   15.35 µs/op
  encode/1 uuid string with braces         100000   17.22 µs/op
  decode/1                                 100000   15.05 µs/op
  ```

  after:

  ```
  ## ShortUUIDBench
  benchmark name                       iterations   average time
  encode/1 uuid binary                     500000   3.54 µs/op
  encode/1 uuid string not hyphenated      500000   4.12 µs/op
  encode/1 uuid string                     500000   4.54 µs/op
  encode/1 uuid string with braces         500000   5.84 µs/op
  decode/1                                 500000   7.97 µs/op
  ```

## v2.1.0 (2019-02-08)

* support directly encoding binary UUID

## v2.0.1 (2019-01-31)

* add error fallbacks for encode/decode for the case where input is not string
* update test cases
* update docs

## v2.0.0 (2019-01-29)

* drop support for custom alphabets
* use fixed alphabet _23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz_ as it seems to be by far the most widely used shortuuid alphabet