normaals-uuid
v1.0.0
Published
Generate human-readable IDs in Latvian with cryptographic randomness and configurable uniqueness
Maintainers
Readme
normaals-uuid
Generate human-readable, unique identifiers using Latvian words with cryptographic security.
Instead of hard-to-remember UUIDs like 550e8400-e29b-41d4-a716-446655440000, get friendly IDs like Zaļš-Gurķis-a3b5c7 or Liela-Sarkana-Māja-1a2b3c4d.
Features
- ✅ Human-readable: Uses real Latvian words instead of random characters
- ✅ Grammatically correct: Adjectives automatically match noun gender (masculine/feminine)
- ✅ Cryptographically secure: Uses Node.js
cryptomodule for uniqueness - ✅ Highly configurable: Multiple formats, separators, and code lengths
- ✅ Comprehensive dictionaries: 100+ nouns, 100+ adjectives, 30+ colors
- ✅ UUID v4-level uniqueness: Low collision probability
- ✅ Zero dependencies: Uses only Node.js built-in modules
- ✅ Lightweight: Small footprint, fast generation
- ✅ Full validation and parsing: Built-in tools to work with IDs
Installation
npm install normaals-uuidQuick Start
const lvUuid = require('normaals-uuid');
// Generate a friendly UUID (with Latvian letters)
const id = lvUuid.generate();
console.log(id); // "Zaļš-Gurķis-a3b5c7"
// Generate URL-friendly UUID (without special letters)
const urlId = lvUuid.generate({ urlFriendly: true });
console.log(urlId); // "Zals-Gurkis-b4c6d8"
// Validate it
console.log(lvUuid.validate(id)); // true
// Parse it
console.log(lvUuid.parse(id));
// {
// full: 'Zaļš-Gurķis-a3b5c7',
// adjective: 'Zaļš',
// noun: 'Gurķis',
// code: 'a3b5c7',
// words: ['Zaļš', 'Gurķis']
// }API Reference
generate(options)
Generate a new human-readable UUID.
Options:
format(string): Format template. Default:'adjective-noun-code''noun-code'- e.g.,"Gurķis-a3b5c7"'adjective-noun-code'- e.g.,"Zaļš-Gurķis-a3b5c7"'color-noun-code'- e.g.,"Sarkana-Māja-x9y2z1"'adjective-color-noun-code'- e.g.,"Liels-Zils-Koks-m4n8p2"
separator(string): Character to separate parts. Default:'-'codeLength(number): Length of the random code (4-32). Default:6urlFriendly(boolean): Convert Latvian special letters to ASCII. Default:falseincludeTimestamp(boolean): Include timestamp for guaranteed uniqueness. Default:false
Returns: string - The generated UUID
Examples:
// Default format
lvUuid.generate();
// "Zaļš-Gurķis-a3b5c7"
// Color-noun format
lvUuid.generate({ format: 'color-noun-code' });
// "Sarkana-Māja-1b2c3d"
// Long format with custom separator
lvUuid.generate({
format: 'adjective-color-noun-code',
separator: '_',
codeLength: 8
});
// "Liels_Zils_Koks_1a2b3c4d"
// Minimal format
lvUuid.generate({ format: 'noun-code' });
// "Kaķis-9f8e7d"
// URL-friendly (no special characters)
lvUuid.generate({ urlFriendly: true });
// "Zals-Gurkis-a3b5c7"
// URL-friendly with custom options
lvUuid.generate({
format: 'color-noun-code',
urlFriendly: true,
separator: '_'
});
// "Sarkana_Maja_1b2c3d" (ā → a)
// Timestamp for guaranteed uniqueness
lvUuid.generate({ includeTimestamp: true });
// "Zaļš-Gurķis-mgyxcnk86733b8"
// Maximum safety (timestamp + longer code)
lvUuid.generate({
includeTimestamp: true,
codeLength: 12
});
// "Zaļš-Gurķis-mgyxcnk86733b8e9f0a1"validate(id, options)
Validate if a string is a valid UUID in the expected format.
Parameters:
id(string): The ID to validateoptions(object, optional): Same options used to generate the ID
Returns: boolean - true if valid, false otherwise
Examples:
lvUuid.validate('Zaļš-Gurķis-a3b5c7'); // true
lvUuid.validate('Invalid-ID'); // false
lvUuid.validate(''); // false
// Validate with specific format
const customId = lvUuid.generate({ format: 'adjective-color-noun-code' });
lvUuid.validate(customId, { format: 'adjective-color-noun-code' }); // trueparse(id, options)
Parse a UUID into its component parts.
Parameters:
id(string): The ID to parseoptions(object, optional): Same options used to generate the ID
Returns: object|null - Parsed components or null if invalid
Examples:
lvUuid.parse('Zaļš-Gurķis-a3b5c7');
// {
// full: 'Zaļš-Gurķis-a3b5c7',
// adjective: 'Zaļš',
// noun: 'Gurķis',
// code: 'a3b5c7',
// words: ['Zaļš', 'Gurķis']
// }
lvUuid.parse('Sarkana-Māja-1b2c3d', { format: 'color-noun-code' });
// {
// full: 'Sarkana-Māja-1b2c3d',
// color: 'Sarkana',
// noun: 'Māja',
// code: '1b2c3d',
// words: ['Sarkana', 'Māja']
// }
lvUuid.parse('invalid-id'); // nullgetDefaultConfig()
Get the default configuration object.
Returns: object - Default configuration
lvUuid.getDefaultConfig();
// {
// format: 'adjective-noun-code',
// separator: '-',
// codeLength: 6,
// wordCount: 2
// }URL-Friendly Option
Latvian has special letters that may not work well in URLs, databases, or APIs. Use urlFriendly: true to convert them to ASCII equivalents:
| Latvian | ASCII | |---------|-------| | ņ, Ņ | n, N | | ķ, Ķ | k, K | | ļ, Ļ | l, L | | ū, Ū | u, U | | ā, Ā | a, A | | ē, Ē | e, E | | č, Č | c, C | | ģ, Ģ | g, G | | ī, Ī | i, I | | š, Š | s, S | | ž, Ž | z, Z |
Examples:
// With special letters (default)
lvUuid.generate();
// "Zaļš-Gurķis-a3b5c7"
// URL-friendly
lvUuid.generate({ urlFriendly: true });
// "Zals-Gurkis-a3b5c7"
// Both are valid and uniqueWhen to use URL-friendly:
- ✅ URLs and routes (
/lobby/Zals-Gurkis-a3b5c7) - ✅ Database keys without UTF-8 support
- ✅ API endpoints
- ✅ File names
- ✅ DNS-safe identifiers
- ✅ Legacy systems
When to use regular (with special letters):
- ✅ Display in UI (more authentic Latvian)
- ✅ Modern databases with UTF-8 support
- ✅ Internal identifiers
- ✅ User-facing reference codes
Formats
1. noun-code (Minimal)
Just a noun and code.
Gurķis-a3b5c7
Māja-1b2c3d
Kaķis-9f8e7d2. adjective-noun-code (Default)
An adjective that matches the noun's gender.
Zaļš-Gurķis-a3b5c7
Sarkana-Māja-1b2c3d
Mazs-Kaķis-9f8e7d3. color-noun-code
A color that matches the noun's gender.
Zaļa-Māja-a3b5c7
Sarkans-Gurķis-1b2c3d
Zils-Kaķis-9f8e7d4. adjective-color-noun-code (Extended)
Both adjective and color, both matching the noun's gender.
Liela-Sarkana-Māja-a3b5c7
Mazs-Zaļš-Gurķis-1b2c3d
Ātrs-Melns-Kaķis-9f8e7dGrammatical Gender
Latvian nouns have gender (masculine or feminine), and adjectives must agree with the noun's gender. This library handles this automatically:
Masculine examples:
Zaļš-Gurķis-a3b5c7(Green cucumber) - masculine adjective + masculine nounLiels-Koks-1b2c3d(Big tree) - masculine adjective + masculine noun
Feminine examples:
Zaļa-Māja-9f8e7d(Green house) - feminine adjective + feminine nounLiela-Zvaigzne-4c5d6e(Big star) - feminine adjective + feminine noun
Multi-word colors/adjectives: Some colors and adjectives consist of multiple words (e.g., "gaiši zaļš" = light green). These are properly formatted with each word capitalized and separated by dashes:
Gaiši-Zaļš-Koks-a3b5c7(Light green tree)Tumši-Zils-Ezers-1b2c3d(Dark blue lake)
The library contains:
- 100+ nouns (both masculine and feminine)
- 100+ adjectives (with both gender forms)
- 30+ colors (with both gender forms, including compound colors)
Uniqueness Guarantees
The library uses Node.js crypto.randomBytes() to generate the alphanumeric suffix, providing cryptographically secure randomness similar to UUID v4.
Entropy calculation:
- 6 hex characters = 24 bits = 16.7 million combinations
- 8 hex characters = 32 bits = 4.3 billion combinations
- Combined with word randomness = billions of unique combinations
Collision probability is extremely low for practical applications. The default 6-character code provides sufficient uniqueness for most use cases.
Use Cases
With Latvian Letters (Default)
- Display in UI:
Zaļš-Kaķis-a3b5c7 - Customer support: Easy-to-communicate reference numbers
- User-facing codes: More authentic and memorable
- Internal identifiers: When UTF-8 is fully supported
URL-Friendly (urlFriendly: true)
- URLs:
/game/Zals-Kakis-a3b5c7 - API endpoints:
/api/lobby/Sarkana-Maja-1b2c3d - Database keys: Compatible with ASCII-only systems
- File names:
upload-Maza-Zvaigzne-5c6d7e.pdf - Email identifiers: Works in all email clients
- QR codes: Better compatibility
General Use Cases
- User session IDs
- Order numbers
- Transaction IDs
- Game lobby IDs
- Temporary passwords
- Test data identifiers
Examples
See examples/usage.js for comprehensive examples:
node examples/usage.jsTesting
Run the test suite:
npm testThe tests include:
- Basic generation
- All format variations
- Custom separators and code lengths
- Validation and parsing
- Uniqueness testing (10,000+ IDs)
- Entropy verification
- Error handling
- Capitalization checks
Security Considerations
✅ What's Secure
- Cryptographically Secure Random Generation: Uses Node.js
crypto.randomBytes()for the code suffix - No Dependencies: Zero external dependencies = no supply chain vulnerabilities
- Input Validation: All user inputs are validated
- No Secrets: No hardcoded credentials or sensitive data
⚠️ Important Security Notes
NOT suitable for:
- Cryptographic keys or secrets
- Authentication tokens (JWT, API keys, etc.)
- Password reset tokens
- Any security-critical application where compromise would be severe
SUITABLE for:
- Human-readable order numbers
- Customer reference IDs
- Non-security-critical session identifiers (with proper session management)
- Tracking numbers
- Test data identifiers
- User-facing reference codes
Entropy Information
The default configuration provides:
- 6 hex characters = 24 bits = ~16.7 million combinations
- 8 hex characters = 32 bits = ~4.3 billion combinations
- 12 hex characters = 48 bits = ~281 trillion combinations
For higher security requirements, increase the codeLength:
lvUuid.generate({ codeLength: 12 }); // 48 bits of entropyNote: The word portion is predictable and contributes minimal entropy. Uniqueness and security come primarily from the cryptographically secure code suffix.
Requirements
- Node.js >= 12.0.0
- No external dependencies
License
MIT
Contributing
Contributions welcome! Feel free to:
- Add more Latvian words to the dictionaries
- Improve grammatical accuracy
- Add new features
- Report bugs
- Submit pull requests
Author
Created for developers who want human-friendly identifiers in Latvian language.
Priecīgu kodēšanu! (Happy coding!)
