{"id":15031345,"url":"https://github.com/govcraft/mti","last_synced_at":"2026-03-16T07:03:33.674Z","repository":{"id":248187700,"uuid":"827965213","full_name":"Govcraft/mti","owner":"Govcraft","description":"A Rust library that implements type-safe, prefix-enhanced identifiers based on the TypeID Specification","archived":false,"fork":false,"pushed_at":"2024-07-15T20:14:39.000Z","size":39,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-03-12T03:13:39.349Z","etag":null,"topics":["crate","database","distributed-systems","identifier","parsing","rust","rust-lang","rustlang","string-extensions","typeid","typeid-implementation","unique-identifier","web-development","web-identity"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/mti","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Govcraft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-12T19:10:55.000Z","updated_at":"2024-07-15T20:08:51.000Z","dependencies_parsed_at":"2024-09-28T20:41:16.020Z","dependency_job_id":"1ead09ac-0c35-4adc-afdd-77947b13d265","html_url":"https://github.com/Govcraft/mti","commit_stats":null,"previous_names":["govcraft/magic_type_id","govcraft/mti"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Govcraft%2Fmti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Govcraft%2Fmti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Govcraft%2Fmti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Govcraft%2Fmti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Govcraft","download_url":"https://codeload.github.com/Govcraft/mti/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243147107,"owners_count":20243746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crate","database","distributed-systems","identifier","parsing","rust","rust-lang","rustlang","string-extensions","typeid","typeid-implementation","unique-identifier","web-development","web-identity"],"created_at":"2024-09-24T20:15:29.746Z","updated_at":"2026-03-16T07:03:33.659Z","avatar_url":"https://github.com/Govcraft.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TypeID for Rust: Human-Readable, Type-Safe, Globally Unique Identifiers\n\n[![Crates.io](https://img.shields.io/crates/v/mti.svg)](https://crates.io/crates/mti)\n[![Documentation](https://docs.rs/mti/badge.svg)](https://docs.rs/mti)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE)\n\nTransform opaque UUIDs like `f47ac10b-58cc-4372-a567-0e02b2c3d479` into readable identifiers like `user_01h455vb4pex5vsknk084sn02q` that indicate type and remain globally unique.\n\n## Overview\n\nUUIDs provide global uniqueness but obscure entity types. Debugging production issues requires determining whether `f47ac10b-58cc-4372-a567-0e02b2c3d479` represents a user, order, or payment—impossible without database queries or code searches. TypeIDs solve this by prefixing UUIDs with human-readable type information, transforming opaque identifiers into self-documenting ones like `user_01h455vb4pex5vsknk084sn02q` while maintaining global uniqueness and adding time-sortability through UUIDv7.\n\nThis workspace provides three complementary Rust crates for working with TypeIDs:\n\n- **Start in two lines of code** with the high-level `mti` crate\n- **Production-ready**: implements [TypeID Specification v0.3.0](https://github.com/jetify-com/typeid), zero unsafe code, extensively tested\n- **Time-sortable by default**: UUIDv7 provides database-friendly chronological ordering\n- **Modular architecture**: use the full API or just prefix validation or suffix encoding\n\n## Crates\n\n| Crate | Version | Purpose | Use When |\n|-------|---------|---------|----------|\n| [mti](crates/mti) | [![Crates.io](https://img.shields.io/crates/v/mti.svg)](https://crates.io/crates/mti) | High-level TypeID API with ergonomic creation, parsing, and manipulation | You need complete TypeID functionality (most developers start here) |\n| [typeid-prefix](crates/typeid-prefix) | [![Crates.io](https://img.shields.io/crates/v/typeid_prefix.svg)](https://crates.io/crates/typeid_prefix) | Validation and sanitization of TypeID prefixes | You need standalone prefix validation or custom TypeID implementations |\n| [typeid-suffix](crates/typeid-suffix) | [![Crates.io](https://img.shields.io/crates/v/typeid_suffix.svg)](https://crates.io/crates/typeid_suffix) | Base32 encoding/decoding of UUID suffixes (26 URL-safe characters) | You need standalone suffix handling or custom encoding schemes |\n\n## Quick Start\n\nAdd the main crate to your project:\n\n```toml\n[dependencies]\nmti = \"1.1\"\n```\n\nCreate and parse TypeIDs:\n\n```rust\nuse mti::prelude::*;\n\n// Create a new TypeID (defaults to UUIDv7 - IDs sort chronologically)\nlet user_id = \"user\".create_type_id();\nprintln!(\"{}\", user_id); // user_01h455vb4pex5vsknk084sn02q\n\n// Parse existing TypeIDs\nlet order_id = MagicTypeId::from_str(\"order_01h455vb4pex5vsknk084sn02q\")?;\nassert_eq!(order_id.prefix_str(), \"order\");\n```\n\n## Why TypeIDs\n\nTypeIDs address four common problems with traditional UUID-based identifiers:\n\n**Debuggability**: Raw UUIDs provide no context. In a production log showing `Failed to process f47ac10b-58cc-4372-a567-0e02b2c3d479`, you cannot determine the entity type without querying databases or searching code. TypeIDs make this immediate: `Failed to process user_01h455vb4pex5vsknk084sn02q` shows a user identifier at a glance.\n\n**Type Safety**: Accepting all identifiers as raw UUIDs or strings allows passing a `product_id` where a `user_id` is expected. These errors surface only at runtime. TypeIDs embed type information in the identifier, enabling runtime validation of prefix correctness. Combined with Rust newtypes wrapping `MagicTypeId`, you can prevent mixing different ID types (like `UserId` vs `OrderId`) at compile time.\n\n**Sortability**: Traditional UUIDv4 identifiers are random, causing poor database index locality and making chronological ordering impossible without separate timestamp columns. TypeIDs default to UUIDv7, which encodes creation time in the first 48 bits. Records sort naturally by insertion time, improving clustered index performance and simplifying time-based queries.\n\n**Consistency**: Without a standard, teams invent ad-hoc schemes: prefixed strings, composite keys, or UUID columns with separate type fields. TypeIDs provide a specification-backed format that works across services, languages, and systems. The format `prefix_suffix` is simple, unambiguous, and increasingly adopted.\n\n## Architecture\n\nThe three crates compose cleanly:\n\n```\n┌─────────────────────────────────────────────┐\n│             mti (High-Level API)            │\n│  ┌───────────────────────────────────────┐  │\n│  │         MagicTypeId                   │  │\n│  │  - create_type_id()                   │  │\n│  │  - parse from strings                 │  │\n│  │  - string-like operations             │  │\n│  └────────────┬──────────────┬───────────┘  │\n└───────────────┼──────────────┼──────────────┘\n                │              │\n      ┌─────────▼────┐    ┌────▼─────────┐\n      │ typeid-prefix│    │ typeid-suffix│\n      ├──────────────┤    ├──────────────┤\n      │ TypeIdPrefix │    │ TypeIdSuffix │\n      │              │    │              │\n      │ • Validates  │    │ • Base32     │\n      │   prefixes   │    │   encoding   │\n      │ • Sanitizes  │    │ • UUID       │\n      │   input      │    │   versions   │\n      │ • Max 63     │    │ • 26 chars   │\n      │   chars      │    │   (128 bits) │\n      └──────────────┘    └──────────────┘\n```\n\nThis separation allows using `typeid-prefix` for input validation without UUID generation, or `typeid-suffix` for base32 encoding in non-TypeID contexts. Most developers need only `mti`.\n\n## Key Features\n\n**Specification Compliance**: Implements TypeID v0.3.0 from Jetify, ensuring format compatibility with other TypeID implementations across languages and platforms—your Rust services can exchange TypeIDs with TypeScript, Go, or Python services.\n\n**UUID Version Support**: Handles UUIDv1, v3, v4, v5, v6, v7, and Nil. Defaults to v7 for new identifiers, providing time-sortability and global uniqueness. Use v5 for deterministic IDs (same input always produces same ID) and v4 for simple random identifiers. Built-in `NamespaceId` with RFC 4122 constants (DNS, URL, OID, X500) makes creating deterministic IDs ergonomic—no need to add `uuid` as a direct dependency.\n\n**Zero Unsafe Code**: All three crates forbid unsafe code via `#![deny(unsafe_code)]`, eliminating entire classes of memory safety vulnerabilities. Safety is guaranteed by the compiler, not runtime checks—critical for production systems handling sensitive identifiers.\n\n**Optional Serde Support**: Enable the `serde` feature to serialize and deserialize TypeIDs as JSON, YAML, TOML, or any format Serde supports. TypeIDs serialize as their string representation for human-readable output.\n\n**Optional Tracing**: Enable the `instrument` feature to emit trace events for creation, parsing, and validation, making production debugging easier when you need to understand ID generation patterns.\n\n**Comprehensive Testing**: Each crate includes unit tests, property-based tests with `proptest`, specification compliance tests, and fuzz testing. The test suites verify prefix rules, suffix encoding, roundtrip conversions, and edge cases.\n\n## Usage Examples\n\n### Creating TypeIDs with Different UUID Versions\n\n```rust\nuse mti::prelude::*;\n\n// UUIDv7 (time-sortable, recommended for most use cases)\nlet product_id = \"product\".create_type_id(); // v7 is default\nprintln!(\"{}\", product_id); // product_01h455vb4pex5vsknk084sn02q\n\n// UUIDv4 (random, no timestamp - use when creation time shouldn't be inferable)\nlet session_id = \"session\".create_type_id::\u003cV4\u003e();\n\n// UUIDv5 (deterministic - same namespace+name always produces same ID)\n// Use for content-addressable storage or idempotent operations\nlet domain_id = \"domain\".create_type_id_v5(NamespaceId::DNS, b\"example.com\");\nprintln!(\"{}\", domain_id); // Always the same for this namespace+name\n\n// Well-known namespaces: DNS, URL, OID, X500 (RFC 4122)\nlet url_id = \"page\".create_type_id_v5(NamespaceId::URL, b\"https://example.com/about\");\n\n// Custom namespace from UUID string\nlet custom_ns = NamespaceId::from_str(\"6ba7b810-9dad-11d1-80b4-00c04fd430c8\")?;\nlet resource_id = \"resource\".create_type_id_v5(custom_ns, b\"unique_resource_name\");\n```\n\n### Parsing and Extracting Components\n\n```rust\nuse mti::prelude::*;\n\nlet id_str = \"order_01h455vb4pex5vsknk084sn02q\";\nlet order_id = MagicTypeId::from_str(id_str)?;\n\nassert_eq!(order_id.prefix_str(), \"order\");\nassert_eq!(order_id.suffix_str(), \"01h455vb4pex5vsknk084sn02q\");\n\n// Extract the underlying UUID\nlet uuid = order_id.uuid()?;\nprintln!(\"UUID: {}\", uuid);\n```\n\n### Building Type Safety with Newtypes\n\nWrap `MagicTypeId` in domain-specific types to prevent mixing different ID types at compile time:\n\n```rust\nuse mti::prelude::*;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct UserId(MagicTypeId);\n\nimpl UserId {\n    fn new() -\u003e Self {\n        Self(\"user\".create_type_id())\n    }\n\n    fn parse(s: \u0026str) -\u003e Result\u003cSelf, MagicTypeIdError\u003e {\n        let id = MagicTypeId::from_str(s)?;\n        if id.prefix_str() != \"user\" {\n            return Err(MagicTypeIdError::Validation(\n                \"Expected 'user' prefix\".to_string()\n            ));\n        }\n        Ok(Self(id))\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct OrderId(MagicTypeId);\n\nimpl OrderId {\n    fn new() -\u003e Self {\n        Self(\"order\".create_type_id())\n    }\n}\n\nfn process_user(id: UserId) {\n    println!(\"Processing user: {}\", id.0);\n}\n\nlet user_id = UserId::new();\nlet order_id = OrderId::new();\n\nprocess_user(user_id); // Compiles\n// process_user(order_id); // Compile error: expected `UserId`, found `OrderId`\n```\n\n## When to Use Each Crate\n\n| Scenario | Use Crate | Reason |\n|----------|-----------|---------|\n| Building application with TypeID identifiers | `mti` | Complete API handles all common operations |\n| Validating user input for prefix-only fields | `typeid-prefix` | Lightweight validation without UUID dependencies |\n| Custom identifier format using base32 encoding | `typeid-suffix` | Reuse encoding logic in different contexts |\n| Implementing custom TypeID variant | `typeid-prefix` + `typeid-suffix` | Build on validated components with custom logic |\n| Adding TypeIDs to existing UUID-based system | `mti` | Drop-in replacement with migration path |\n\n## Development\n\nBuild all crates:\n\n```bash\ncargo build --workspace\n```\n\nRun tests:\n\n```bash\ncargo nextest run --workspace\n```\n\nCheck with clippy:\n\n```bash\ncargo clippy --workspace --all-features\n```\n\nFormat code:\n\n```bash\ncargo fmt --workspace\n```\n\n## Workspace Structure\n\n```\nmti/\n├── Cargo.toml              # Workspace configuration\n├── README.md               # This file\n└── crates/\n    ├── mti/                # High-level TypeID API\n    │   ├── Cargo.toml\n    │   ├── README.md\n    │   ├── src/\n    │   └── tests/\n    ├── typeid-prefix/      # Prefix validation and sanitization\n    │   ├── Cargo.toml\n    │   ├── README.md\n    │   ├── src/\n    │   ├── tests/\n    │   └── fuzz/\n    └── typeid-suffix/      # Suffix encoding and decoding\n        ├── Cargo.toml\n        ├── README.md\n        ├── src/\n        ├── tests/\n        └── fuzz/\n```\n\n## Contributing\n\nContributions are welcome. This project follows these standards:\n\n- **Conventional Commits**: All commit messages must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.\n- **No Unsafe Code**: The workspace denies unsafe code. Submit safe implementations.\n- **Linting**: Code must pass `cargo clippy` with no warnings. Fix underlying issues rather than suppressing lints.\n- **Testing**: Add tests for new features. Maintain or improve code coverage.\n- **Documentation**: Public APIs require documentation. Add examples for complex features.\n\nSubmit pull requests to the `main` branch. The CI pipeline checks formatting, linting, tests, and documentation builds.\n\n## License\n\nLicensed under either of Apache License, Version 2.0 or MIT license at your option.\n\n## Acknowledgments\n\nThis implementation follows the TypeID Specification v0.3.0 created and maintained by [Jetify](https://www.jetify.com/). The specification defines the format, validation rules, and encoding schemes implemented in these crates.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovcraft%2Fmti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgovcraft%2Fmti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovcraft%2Fmti/lists"}