# `UXID`
[🔗](https://github.com/riddler/uxid-ex/blob/v2.9.1/lib/uxid.ex#L1)

Generates UXIDs and acts as an Ecto ParameterizedType

**U**ser e**X**perience focused **ID**entifiers (UXIDs) are identifiers which:

* Describe the resource (aid in debugging and investigation)
* Work well with copy and paste (double clicking selects the entire ID)
* Can be shortened for low cardinality resources
* Are secure against enumeration attacks
* Can be generated by application code (not tied to the datastore)
* Are K-sortable (lexicographically sortable by time - works well with datastore indexing)
* Do not require any coordination (human or automated) at startup, or generation
* Are very unlikely to collide (more likely with less randomness)
* Are easily and accurately transmitted to another human using a telephone
* Can optionally be deterministic (name-based) - the same input always maps to
  the same ID

Many of the concepts of Stripe IDs have been used in this library.

## Deterministic IDs

Passing `from:` to `generate/1`, `generate!/1`, or `new/1` produces a
deterministic (name-based) ID: the same input string always maps to the same
ID (UUIDv5-style), with the prefix acting as the namespace. Deterministic IDs
carry a leading `z`/`Z` marker and sort after time-based IDs. They are a hash
of a *known* input, so they are not unguessable - see `generate/1` and the
Deterministic IDs guide for the full picture.

# `option`

```elixir
@type option() ::
  {:case, atom()}
  | {:time, integer()}
  | {:size, atom() | nil}
  | {:rand_size, integer() | nil}
  | {:prefix, String.t() | nil}
  | {:delimiter, String.t() | nil}
  | {:compact_time, boolean() | nil}
  | {:monotonic, boolean() | [atom()] | nil}
  | {:from, String.t() | nil}
```

Options for generating a UXID

# `options`

```elixir
@type options() :: [option()]
```

# `t`

```elixir
@type t() :: String.t()
```

A UXID represented as a String

# `autogenerate`

Generates a loaded version of the UXID.

Field options are threaded through to `generate!/1`, including `monotonic`
for opt-in monotonic generation:

    field :id, UXID, autogenerate: true, prefix: "evt", size: :small, monotonic: true

Deterministic (`from:`) IDs are intentionally **not** wired here - there is no
per-row input available at autogenerate time. Mint them explicitly in
application code (e.g. in a changeset via `generate!/1`) and store/cast the
result as an ordinary string.

# `cast`

Casts the given input to the UXID ParameterizedType with the given parameters.

By default any binary is accepted unchanged (backwards compatible). When the
field opts in with `validate: true`, the value must be either a structurally
valid UXID carrying the field's configured `:prefix` (see `valid?/2`) or a
legacy bare UUID string; anything else casts to `:error`. UUID coexistence
can be turned off with `allow_uuid: false`.

    field :owner_org_id, UXID, prefix: "org", validate: true

# `compact_small_times`

Returns whether compact time encoding is enabled for small sizes.
When true, :xs/:xsmall and :s/:small use 40 bits for timestamp instead of 48,
adding 8 bits to randomness. This is a global policy that can be overridden
per-call with the `compact_time` option.
This provides perfect 5-bit Crockford Base32 alignment (8 chars vs 10 chars).
K-sortability is maintained until ~mid-2038 for compact mode: value 31 (the
first char `z`/`Z`) is reserved as the deterministic-ID scheme marker, so
compact encoding raises for timestamps at/after that band. Standard 48-bit
timestamps are unaffected.

# `decode`

```elixir
@spec decode(String.t()) :: {:ok, UXID.Codec.t()}
```

Decodes a UXID string and returns a Codec struct with extracted components.

# `default_delimiter`

Returns the delimiter used to separate a prefix from the encoded body.
Defaults to `"_"` and can be overridden globally with the `:delimiter`
application env, or per-call/per-field with the `:delimiter` option.

# `deterministic?`

```elixir
@spec deterministic?(
  term(),
  keyword()
) :: boolean()
```

Returns `true` if the given value is a deterministic (name-based) UXID.

Deterministic IDs carry a leading `z`/`Z` scheme marker (Crockford value 31)
instead of an encoded timestamp, so this only inspects the first body
character - it does not otherwise validate structure (pair it with `valid?/2`
if you need both). Time-based IDs start with a lower value and return `false`.

## Options

  * `:delimiter` - the prefix delimiter (defaults to the configured
    delimiter, see `default_delimiter/0`).

## Examples

    iex> UXID.deterministic?("usr_z9m4k7p2q3r8t5v6w0abcde")
    true

    iex> UXID.deterministic?("cus_01emdgjf0dqxqj8fm78xe97y3h")
    false

    iex> UXID.deterministic?("nope!")
    false

# `dump`

Dumps the given term into an Ecto native type.

# `embed_as`

Dictates how the type should be treated if embedded.
For UXIDs, we use :self since they're already strings.

# `encode_case`

# `equal?`

Checks if two UXIDs are equal.

# `generate`

```elixir
@spec generate(opts :: options()) :: {:ok, t()}
```

Returns an encoded UXID string along with response status.

## Deterministic (name-based) IDs

Passing `from:` switches to deterministic mode: the same input string always
maps to the same ID (UUIDv5-style), across processes and machines, forever. The
prefix is folded in as the namespace, so the same string under two prefixes
yields two different bodies. `from:` must be a string (raises otherwise).

Deterministic IDs are marked with a leading `z`/`Z` and sort *after* every
time-based ID; they are not K-sortable among themselves. They are a hash of a
*known* input, so they are exactly as guessable as that input - do not derive
an ID from a low-entropy secret and treat the ID as unguessable.

    {:ok, id} = UXID.generate(prefix: "usr", from: "alice@example.com")
    # {:ok, "usr_z..."} - identical for this input on every call

# `generate!`

```elixir
@spec generate!(opts :: options()) :: t()
```

Returns an unwrapped encoded UXID string.

Passing `from:` returns a deterministic (name-based) ID: the same input always
maps to the same ID, with the prefix acting as the namespace. See `generate/1`
for the full deterministic-mode notes.

    UXID.generate!(prefix: "usr", from: "alice@example.com")
    # => "usr_z..." (stable for this input, forever)

# `init`

Converts the options specified in the field macro into parameters to be used in other callbacks.

# `load`

Loads the given term into a UXID.

# `min_size`

Returns the minimum size configuration.
When set, any requested size smaller than this will be upgraded.

# `monotonic`

Returns the global monotonic generation policy.

When active, the random field is treated as a big-endian counter: the first
ID in a millisecond is seeded from the CSPRNG and each subsequent same-ms ID
advances it by a random positive step (per process, per prefix). This
guarantees uniqueness and K-sortability within a burst while keeping
consecutive IDs within a bounded window ahead - a mitigation, not cryptographic
unpredictability - which is why it is off by default and opt-in per resource.

Accepts `true`/`false`, or a list of sizes (alias-aware, e.g. `[:small]`
matches both `:small` and `:s`). Overridable per-call/per-field with the
`monotonic` option. See `UXID.Monotonic`.

# `new`

```elixir
@spec new(opts :: options()) :: {:ok, UXID.Codec.t()}
```

Returns a new UXID.Codec struct. This is useful for development.

# `type`

Returns the underlying schema type for a UXID.

# `valid?`

```elixir
@spec valid?(
  term(),
  keyword()
) :: boolean()
```

Returns `true` if the given value is a structurally valid UXID.

A valid UXID is a binary made up of an optional prefix, the delimiter, and a
Crockford Base32 body of at least 8 characters. This checks
*structure*, not authenticity: it cannot distinguish a generated UXID from an
arbitrary Base32 string of the same shape, and it deliberately does **not**
accept a bare UUID (see `cast/2`'s `:validate` mode for UUID coexistence).

## Options

  * `:prefix` - when present, the value must carry exactly this prefix. When
    omitted, any prefix (or none) is accepted.
  * `:delimiter` - the prefix delimiter (defaults to the configured
    delimiter, see `default_delimiter/0`).

## Examples

    iex> UXID.valid?("cus_01emdgjf0dqxqj8fm78xe97y3h")
    true

    iex> UXID.valid?("cus_01emdgjf0dqxqj8fm78xe97y3h", prefix: "cus")
    true

    iex> UXID.valid?("cus_01emdgjf0dqxqj8fm78xe97y3h", prefix: "usr")
    false

    iex> UXID.valid?("nope!")
    false

---

*Consult [api-reference.md](api-reference.md) for complete listing*
