A universally-unique, lexicographically-sortable, identifier generator
78
Utilities for working with Crockford Base32 encoding, including error correction and string manipulation specifically designed for ULID components.
Corrects common Base32 encoding errors in ULID strings by replacing ambiguous characters with their intended equivalents.
/**
* Fix a ULID's Base32 encoding
* Replaces i/I and l/L with 1, o/O with 0, and removes hyphens
* @param id - The ULID string to fix
* @returns The corrected ULID string
*/
function fixULIDBase32(id: string): string;Usage Examples:
import { fixULIDBase32, isValid } from "ulid";
// Fix common character confusions
const malformedId = "01HNZXIJGFACFAl6RBXDHEQN6o";
const fixed = fixULIDBase32(malformedId); // "01HNZX1JGFACFA16RBXDHEQN60"
// Verify the fix worked
console.log(isValid(malformedId)); // false
console.log(isValid(fixed)); // true
// Remove hyphens from formatted IDs
const hyphenatedId = "01HNZX8J-GFAC-FA36-RBXD-HEQN6E";
const clean = fixULIDBase32(hyphenatedId); // "01HNZX8JGFACFA36RBXDHEQN6E"
// Handle mixed case with corrections
const messyId = "01hnzxijgfacfal6rbxdheqno0";
const corrected = fixULIDBase32(messyId); // "01hnzx1jgfacfa16rbxdheqn00"
// Use in input validation pipeline
function sanitizeULID(input: string): string {
const cleaned = fixULIDBase32(input);
if (!isValid(cleaned)) {
throw new Error(`Cannot fix malformed ULID: ${input}`);
}
return cleaned.toUpperCase();
}
// Batch processing
const userInputs = [
"01HNZXIJGFACFAl6RBXDHEQN6o",
"01-HNZX-8JGF-ACFA-36RB-XDHE-QN6E",
"01hnzxijgfacfal6rbxdheqno0"
];
const cleanedIds = userInputs.map(fixULIDBase32);Character Corrections:
i or I → 1 (one)l or L → 1 (one)o or O → 0 (zero)- → `` (removed)Common Error Sources:
Increments a Base32 string by one position, used internally by monotonic factories to ensure lexicographic ordering.
/**
* Increment a Base32 string by one
* @param str - The Base32 string to increment
* @returns The incremented Base32 string
* @throws ULIDError if the string contains invalid characters
*/
function incrementBase32(str: string): string;Usage Examples:
import { incrementBase32 } from "ulid";
// Basic increment operations
console.log(incrementBase32("0000000000000000")); // "0000000000000001"
console.log(incrementBase32("0000000000000001")); // "0000000000000002"
console.log(incrementBase32("000000000000000Z")); // "0000000000000010"
// Handle carry operations
console.log(incrementBase32("ZZZZZZZZZZZZZZZZ")); // "10000000000000000"
// Real-world usage with ULID random portions
const randomPortion = "CEN5XA66EMZSRZW";
const incremented = incrementBase32(randomPortion); // "CEN5XA66EMZSRZX"
// Used internally by monotonicFactory
// (This is for educational purposes - normally handled automatically)
function simulateMonotonicBehavior(baseRandom: string, count: number) {
let current = baseRandom;
const results = [current];
for (let i = 1; i < count; i++) {
current = incrementBase32(current);
results.push(current);
}
return results;
}
const sequence = simulateMonotonicBehavior("YYYYYYYYYYYYYYYY", 5);
// ["YYYYYYYYYYYYYYYY", "YYYYYYYYYYYYYYY Z", "YYYYYYYYYYYYYYZ0", ...]Error Conditions:
ULIDError with code Base32IncorrectEncoding if string contains invalid Base32 charactersULIDError with code Base32IncorrectEncoding if increment operation failsBase32 Arithmetic:
The increment operation follows Crockford Base32 rules:
0123456789ABCDEFGHJKMNPQRSTVWXYZ (32 characters)0→1→2→...→9→A→B→...→Z→10→11→...Z, it wraps to 0 and carries to the next positionZ, the result expands by one characterPerformance Characteristics:
Integration with Monotonic Generation:
This function is used internally by monotonicFactory() to ensure that ULIDs generated within the same millisecond maintain lexicographic ordering:
// Conceptual example of monotonic factory behavior
let lastTimestamp = Date.now();
let lastRandom = "YYYYYYYYYYYYYYYY";
function generateMonotonic() {
const currentTime = Date.now();
if (currentTime === lastTimestamp) {
// Same timestamp - increment random portion
lastRandom = incrementBase32(lastRandom);
} else {
// New timestamp - generate new random portion
lastTimestamp = currentTime;
lastRandom = generateNewRandom();
}
return encodeTime(lastTimestamp) + lastRandom;
}Install with Tessl CLI
npx tessl i tessl/npm-ulidevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10