Current section
Files
Jump to
Current section
Files
CHANGELOG.md
# Changelog
## Upcoming
## 2.6.0 / 2026-07-17
* Adds runtime prefix → schema routing for **layered apps**, so a `UXID.Registry` can live at an app's base layer without a `schema:` literal inverting the dependency direction:
- New `UXID.Registered` mixin (`use UXID.Registered, key: :contact`) marks a schema under a registry key; the reference points *down* (schema names a key), so the base-layer registry never references an upper-layer module — `Boundary`/`xref` stay clean
- `MyApp.IDs.verify!(otp_apps: [...])` / `build_routes!/1` assemble the routing table at boot by scanning the given apps for the marker (via reflection, no compile-visible module reference) and store it in `:persistent_term`; `verify!/1` also validates it — raising on a marker that names an unregistered key, two modules claiming one key, or a `route: true` key left unmapped
- Call `verify!/1` from your top app's `start/2` so every boot (prod, dev, CI's `mix test`) re-verifies — no bespoke CI job needed
- `schema_for/1` now resolves a compile-time `schema:` literal first, then the self-registration table, so flat apps are unchanged and layered apps opt in per entry with `route: true`
- Adds `prefixes/0` (convenience for app-side "every schema draws from the registry" conformance tests) and `routes/0`
* Restructures the documentation: a slimmed README plus dedicated guides (Sizes & Encoding, Ecto Integration, Monotonic IDs, Prefix Registry, Configuration) that render on both GitHub and HexDocs
## 2.5.0 / 2026-07-16
* Adds `UXID.Registry`, an opt-in compile-time DSL for an app's prefixes via `use UXID.Registry` with `defid`/`retired`:
- Compile-time uniqueness (active and `retired` prefixes) and prefix-format checks, replacing per-app CI tests
- By-key API: `generate!/1`, `generate/1`, `prefix/1`, `size/1`, `schema/1`, `category/1`, `field_opts/1`, `all/0`, `keys/0`, `reserved/0`
- By-ID-string routing (prefix → schema): `known?/1`, `key_for/1`, `schema_for/1`, `resolve/1`; parsing splits on the last delimiter (unambiguous because a Base32 body never contains it), and the configurable delimiter is validated as Base32-disjoint (defaults to `_`)
- JSON manifest export (`manifest/0`, `manifest_json/0`) so database functions and mobile/JS clients mint prefixes from the same source of truth, with no added dependency
- Registers `defid`/`retired` as paren-free locals and exports the rule for consuming apps
* Adds opt-in monotonic generation via the `monotonic` option (per-call/per-field) or `config :uxid, :monotonic` global policy:
- Accepts `true`/`false`, or a list of sizes (alias-aware, e.g. `[:small]` matches both `:small` and `:s`)
- Within a millisecond the random field is seeded once then advanced by a random positive step (uniform over `[1, 2^(bits/2)]`, drawn from the CSPRNG), guaranteeing uniqueness and K-sortability for a burst — process-local, `async: true` safe, no GenServer/ETS
- Per-call option takes precedence over the global policy; off by default (consecutive IDs stay in a bounded window — a mitigation, not cryptographic unpredictability — weakening enumeration resistance)
- `:xs`/`:xsmall` auto-enable `compact_time` so there is a field to increment; explicit `compact_time: false` on those sizes with monotonic on raises
- Wire format is byte-identical to a random UXID — no decoder changes
## 2.4.0 / 2026-07-09
* Adds `UXID.valid?/2` for structural validation of a UXID string (optional `:prefix` and `:delimiter`)
* Adds opt-in strict casting for the Ecto type via `validate: true` on a field:
- Accepts a well-formed UXID carrying the field's configured `:prefix`, or a legacy bare UUID string
- Rejects malformed values (empty, wrong prefix, non–Base32) with `:error`
- UUID coexistence is on by default (eases `uuid` → `text` column migrations); disable with `allow_uuid: false`
- Default casting is unchanged (any binary passes) when `validate` is not set — fully backwards compatible
* Adds default_delimiter config accessor
## 2.3.0 / 2026-01-16
* Adds min_size config option to enforce minimum UXID sizes (useful for test environments)
* Adds compact_time feature for improved collision resistance in small UXIDs:
- Global policy via `compact_small_times` config automatically compacts :xs/:xsmall/:s/:small sizes
- Per-call override via `compact_time: true/false` option works for any size
- Uses 40-bit timestamps (8 chars) instead of 48-bit (10 chars), freeing 8 bits for randomness
- Example: :small gains 50% more randomness (24 bits vs 16 bits)
- Decoder automatically detects compact format from length and reconstructs full timestamp
- K-sortability maintained until ~September 2039
## 2.2.0 / 2025-09-12
* Adds UXID.Decoder module with full pipeline processing and uppercase/lowercase support
## 2.1.0 / 2025-09-10
* Adds delimiter option (default is '_')
* Adds UXID.Codec with encoding struct and type
* Fixes Dialyzer issues
* Changes UXID type to String.t() to work better with TypedEctoSchema
* Changes how Ecto.Paramaterized type is implemented to work in projects without Ecto
## 2.0.0 / 2025-04-27
### Breaking Changes
* Adds case config and functionality
* Makes lowercase the default
* Removes deprecated Ecto.UXID
## 1.0.0 / 2025-04-13
* Fixes compiler warnings
## 0.2.3 / 2020-11-29
* Uses new project URL
## 0.2.2 / 2020-11-26
* Passes options cleanly down for autogenerate
## 0.2.1 / 2020-11-24
* Updates Mix project description
## 0.2.0 / 2020-11-22
* Deprecates Ecto.UXID
* Removes Decoder and CrockfordBase32
* Adds size option (T-Shirt sizes)
## 0.1.2 / 2020-11-07
* Updates description and README
## 0.1.1 / 2020-11-07
* Updates description and README
## 0.1.0 / 2020-11-06
* Updates description and README
* Has enough usable functionality and documentation for 0.1.0!
## 0.0.6 / 2020-10-30
* Marks Ecto as optional dependency and excludes xref
## 0.0.5 / 2020-10-19
* Adds Ecto.UXID
## 0.0.4 / 2020-10-19
* Includes Erlang crypto application
## 0.0.3 / 2020-10-12
* Fixes documentation
## 0.0.2 / 2020-10-11
* Adds generation of UXIDs
## 0.0.1 / 2020-06-17
* Birthday!