or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base32-utilities.mdgeneration.mdindex.mdtime-utilities.mduuid-conversion.mdvalidation.md

base32-utilities.mddocs/

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

```