Guide

Basic operations

Install a library from Libraries; each repository has its own install and API docs. Examples are in Rust and TypeScript; the tabs switch every block on the page.

Define a type per name

Each kind of thing you identify gets one TNID type, with its name fixed in that type. The rest of the guide uses this user type.

use tnid::{NameStr, Tnid, TnidName};

struct User;
impl TnidName for User {
    const ID_NAME: NameStr<'static> = NameStr::new_const("user");
}
import { Tnid, type TnidType } from "@tnid/core";

const UserId = Tnid("user");
type UserId = TnidType<typeof UserId>;

Generate

TNIDv0, the time-sortable kind, sorts by creation time within each name and is the default. When creation time must stay secret from whoever sees the TNID, use TNIDv1, or store TNIDv0 and show it encrypted as TNIDv1.

let user_id = Tnid::<User>::new_v0();

println!("{user_id}"); // user.Br2flcNDfF6LYICnT
const userId: UserId = UserId.new_v0();

console.log(userId); // user.Br2flcNDfF6LYICnT

Show and store

Show the TNID string to people and in URLs. Store the UUID form, which is the same 128-bit value.

use tnid::Case;

let uuid = user_id.to_uuid_string(Case::Lower);
println!("{uuid}"); // d6157337-0ebc-8686-83ab-4075a34cdcde
const uuid = UserId.toUuidString(userId);
console.log(uuid); // d6157337-0ebc-8686-83ab-4075a34cdcde

Parse

Parsing accepts either form and checks the name, so a post TNID is rejected where a user TNID is expected.

let from_tnid: Tnid<User> = "user.Br2flcNDfF6LYICnT".parse()?;
let from_uuid: Tnid<User> = "d6157337-0ebc-8686-83ab-4075a34cdcde".parse()?;

let wrong: Result<Tnid<User>, _> = "post.Br2flcNDfF6LYICnT".parse(); // Err
const fromTnid: UserId = UserId.parse("user.Br2flcNDfF6LYICnT");
const fromUuid: UserId = UserId.parse("d6157337-0ebc-8686-83ab-4075a34cdcde");

UserId.parse("post.Br2flcNDfF6LYICnT"); // throws