Metadata-Version: 2.4
Name: whatamithinking-idlib
Version: 1.0.0
Summary: Generate unique IDs to identify resources in apps
Author-email: Connor Sherwood Maynes <connormaynes@gmail.com>
License: MIT License
        
        Copyright (c) 2026 whatamithinking
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/whatamithinking/idlib
Project-URL: Source, https://github.com/whatamithinking/idlib
Keywords: id,unique-id,uuid,resource-id
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: whatamithinking-hostutil
Provides-Extra: dev
Requires-Dist: black; extra == "dev"
Dynamic: license-file

# idlib

Time-ordered unique IDs for identifying resources in applications.

`idlib` generates unique IDs that are **sequential**: every ID generated will be lexicographically greater than all previously generated IDs. This makes them ideal as primary keys in databases, since they naturally sort in insertion order without a secondary timestamp column.

IDs are encoded with [base32hex](https://www.rfc-editor.org/rfc/rfc4648#section-7), which preserves the sort order of the underlying bytes while remaining safe to use in URLs and filenames.

## Installation

```
pip install whatamithinking-idlib
```

## ID Types

### `UOID` — Unique Ordered ID

**Structure:** `time (10 bytes) + random (6 bytes)` → 16 bytes → **32-character string**

The base type. Encodes a nanosecond-precision timestamp and random bytes.

```python
from whatamithinking.idlib import UOID

id1 = UOID()
id2 = UOID()

print(str(id1))   # e.g. "0O0000CGFS0000ABCDEFGH123456"
print(str(id2))   # always lexicographically greater than id1

assert id1 < id2  # guaranteed ordering
```

**Properties:**

| Property | Description |
|----------|-------------|
| `.time`  | Nanosecond epoch timestamp encoded in the ID (`int`) |
| `.rand`  | Random bytes component (`bytes`) |

**Reconstruction from string or bytes:**

```python
id_str = str(id1)
restored = UOID(id_str)   # from string
restored = UOID(bytes(id1))  # from bytes
```

---

### `UOHID` — Unique Ordered Host ID

**Structure:** `time (10 bytes) + random (6 bytes) + hostname (1–64 bytes)` → 17–80 bytes → **32–128-character string**

Extends `UOID` by encoding the hostname of the machine that generated the ID. Useful for systems where resources need to be routed back to the originating service by hostname.

> **Warning:** This ID leaks the hostname of the generating machine. Do not use it when that information is sensitive.

```python
from whatamithinking.idlib import UOHID

id1 = UOHID()

print(str(id1))       # base32hex-encoded string
print(id1.hostname)   # e.g. "my-server"
```

**Properties:**

| Property    | Description |
|-------------|-------------|
| `.time`     | Nanosecond epoch timestamp (`int`) |
| `.rand`     | Random bytes component (`bytes`) |
| `.hostname` | Hostname of the generating machine (`str`) |

---

### `UOPHID` — Unique Ordered Port-Host ID

**Structure:** `time (10 bytes) + random (6 bytes) + port (2 bytes) + hostname (1–64 bytes)` → 19–82 bytes → **32–136-character string**

Extends `UOHID` by also encoding the port number of the service that created the ID. Useful for systems where resources need to be routed to a specific port on the originating host.

```python
from whatamithinking.idlib import UOPHID

id1 = UOPHID(port=9100)

print(str(id1))       # base32hex-encoded string
print(id1.port)       # 9100
print(id1.hostname)   # e.g. "my-server"
```

**Properties:**

| Property    | Description |
|-------------|-------------|
| `.time`     | Nanosecond epoch timestamp (`int`) |
| `.rand`     | Random bytes component (`bytes`) |
| `.port`     | Service port number (`int`, 0–65535) |
| `.hostname` | Hostname of the generating machine (`str`) |

---

## Common API

All three types share this interface:

```python
# Create new
id1 = UOID()

# Restore from string
id2 = UOID("0O0000CGFS0000ABCDEFGH123456")

# Restore from bytes
id3 = UOID(bytes(id1))

# String representation (base32hex, sortable)
s = str(id1)

# Raw bytes
b = bytes(id1)

# Comparison (all ordering operators supported)
assert id1 < id2
assert id1 == id1

# Replace individual fields and get a new instance
new_id = id1.replace(rand=b"\x00" * 6)
```

## Ordering Guarantees

IDs are guaranteed to be strictly increasing as long as they are generated on the same thread. If multiple IDs are generated within the same nanosecond, the random component is auto-incremented to maintain order. If clock drift is detected (clock moved backwards), generation will retry for up to `timeout` seconds (default: 30 ms) before raising a `RuntimeError`.

## License

MIT
