0
# Base32 Utilities
1
2
Utilities for working with Crockford Base32 encoding, including error correction and string manipulation specifically designed for ULID components.
3
4
## Capabilities
5
6
### Fix ULID Base32
7
8
Corrects common Base32 encoding errors in ULID strings by replacing ambiguous characters with their intended equivalents.
9
10
```typescript { .api }
11
/**
12
* Fix a ULID's Base32 encoding
13
* Replaces i/I and l/L with 1, o/O with 0, and removes hyphens
14
* @param id - The ULID string to fix
15
* @returns The corrected ULID string
16
*/
17
function fixULIDBase32(id: string): string;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import { fixULIDBase32, isValid } from "ulid";
24
25
// Fix common character confusions
26
const malformedId = "01HNZXIJGFACFAl6RBXDHEQN6o";
27
const fixed = fixULIDBase32(malformedId); // "01HNZX1JGFACFA16RBXDHEQN60"
28
29
// Verify the fix worked
30
console.log(isValid(malformedId)); // false
31
console.log(isValid(fixed)); // true
32
33
// Remove hyphens from formatted IDs
34
const hyphenatedId = "01HNZX8J-GFAC-FA36-RBXD-HEQN6E";
35
const clean = fixULIDBase32(hyphenatedId); // "01HNZX8JGFACFA36RBXDHEQN6E"
36
37
// Handle mixed case with corrections
38
const messyId = "01hnzxijgfacfal6rbxdheqno0";
39
const corrected = fixULIDBase32(messyId); // "01hnzx1jgfacfa16rbxdheqn00"
40
41
// Use in input validation pipeline
42
function sanitizeULID(input: string): string {
43
const cleaned = fixULIDBase32(input);
44
if (!isValid(cleaned)) {
45
throw new Error(`Cannot fix malformed ULID: ${input}`);
46
}
47
return cleaned.toUpperCase();
48
}
49
50
// Batch processing
51
const userInputs = [
52
"01HNZXIJGFACFAl6RBXDHEQN6o",
53
"01-HNZX-8JGF-ACFA-36RB-XDHE-QN6E",
54
"01hnzxijgfacfal6rbxdheqno0"
55
];
56
const cleanedIds = userInputs.map(fixULIDBase32);
57
```
58
59
**Character Corrections:**
60
61
- `i` or `I` → `1` (one)
62
- `l` or `L` → `1` (one)
63
- `o` or `O` → `0` (zero)
64
- `-` → `` (removed)
65
66
**Common Error Sources:**
67
68
- **Manual transcription**: Humans often confuse similar-looking characters
69
- **OCR systems**: Optical character recognition may misread characters
70
- **Font rendering**: Some fonts make characters appear similar
71
- **Legacy formatting**: Systems that add hyphens for readability
72
73
### Increment Base32
74
75
Increments a Base32 string by one position, used internally by monotonic factories to ensure lexicographic ordering.
76
77
```typescript { .api }
78
/**
79
* Increment a Base32 string by one
80
* @param str - The Base32 string to increment
81
* @returns The incremented Base32 string
82
* @throws ULIDError if the string contains invalid characters
83
*/
84
function incrementBase32(str: string): string;
85
```
86
87
**Usage Examples:**
88
89
```typescript
90
import { incrementBase32 } from "ulid";
91
92
// Basic increment operations
93
console.log(incrementBase32("0000000000000000")); // "0000000000000001"
94
console.log(incrementBase32("0000000000000001")); // "0000000000000002"
95
console.log(incrementBase32("000000000000000Z")); // "0000000000000010"
96
97
// Handle carry operations
98
console.log(incrementBase32("ZZZZZZZZZZZZZZZZ")); // "10000000000000000"
99
100
// Real-world usage with ULID random portions
101
const randomPortion = "CEN5XA66EMZSRZW";
102
const incremented = incrementBase32(randomPortion); // "CEN5XA66EMZSRZX"
103
104
// Used internally by monotonicFactory
105
// (This is for educational purposes - normally handled automatically)
106
function simulateMonotonicBehavior(baseRandom: string, count: number) {
107
let current = baseRandom;
108
const results = [current];
109
110
for (let i = 1; i < count; i++) {
111
current = incrementBase32(current);
112
results.push(current);
113
}
114
115
return results;
116
}
117
118
const sequence = simulateMonotonicBehavior("YYYYYYYYYYYYYYYY", 5);
119
// ["YYYYYYYYYYYYYYYY", "YYYYYYYYYYYYYYY Z", "YYYYYYYYYYYYYYZ0", ...]
120
```
121
122
**Error Conditions:**
123
124
- Throws `ULIDError` with code `Base32IncorrectEncoding` if string contains invalid Base32 characters
125
- Throws `ULIDError` with code `Base32IncorrectEncoding` if increment operation fails
126
127
**Base32 Arithmetic:**
128
129
The increment operation follows Crockford Base32 rules:
130
131
- **Alphabet**: `0123456789ABCDEFGHJKMNPQRSTVWXYZ` (32 characters)
132
- **Increment order**: `0→1→2→...→9→A→B→...→Z→10→11→...`
133
- **Carry handling**: When a position reaches `Z`, it wraps to `0` and carries to the next position
134
- **String expansion**: If all positions are `Z`, the result expands by one character
135
136
**Performance Characteristics:**
137
138
- **Time complexity**: O(n) where n is string length (worst case: all carries)
139
- **Average case**: O(1) for most increments (no carries required)
140
- **Memory usage**: Creates new string, original unchanged
141
142
**Integration with Monotonic Generation:**
143
144
This function is used internally by `monotonicFactory()` to ensure that ULIDs generated within the same millisecond maintain lexicographic ordering:
145
146
```typescript
147
// Conceptual example of monotonic factory behavior
148
let lastTimestamp = Date.now();
149
let lastRandom = "YYYYYYYYYYYYYYYY";
150
151
function generateMonotonic() {
152
const currentTime = Date.now();
153
154
if (currentTime === lastTimestamp) {
155
// Same timestamp - increment random portion
156
lastRandom = incrementBase32(lastRandom);
157
} else {
158
// New timestamp - generate new random portion
159
lastTimestamp = currentTime;
160
lastRandom = generateNewRandom();
161
}
162
163
return encodeTime(lastTimestamp) + lastRandom;
164
}
165
```