nehoid
Version:
NehoID is a high-performance TypeScript library designed for generating, validating, and managing unique identifiers in enterprise-grade applications.
1,465 lines (1,460 loc) • 64.8 kB
TypeScript
import { StruLink } from 'strulink';
/**
* Supported encoding types for data transformation.
*
* These encoding schemes provide various methods for transforming strings,
* including standard encodings, cryptographic preparations, and specialized formats.
* Each type corresponds to a specific encoding algorithm with different properties
* such as reversibility, URL-safety, and security characteristics.
*/
type ENC_TYPE = Parameters<typeof StruLink.encode>[1];
/**
* Core encoding utilities for data transformation and compression.
*
* The Encoder class provides a comprehensive set of encoding and decoding methods
* supporting multiple algorithms including base64, hex, ROT13, compression schemes,
* and specialized encodings. It serves as the foundation for NehoID's transformation
* capabilities and supports both synchronous and asynchronous operations.
*
* @example
* ```typescript
* // Basic encoding and decoding
* const encoded = await Encoder.encode('hello world', 'base64');
* const decoded = Encoder.decode(encoded, 'base64');
*
* // Multiple encodings in sequence
* const multiEncoded = await Encoder.encode('data', ['base64', 'hex']);
* const multiDecoded = Encoder.decode(multiEncoded, ['hex', 'base64']);
*
* // Compression
* const compressed = Encoder.compress('long text to compress', 'gzip');
* const decompressed = Encoder.decompress(compressed, 'gzip');
* ```
*/
declare class Encoder {
/**
* Encode a string using one or more encoding schemes asynchronously.
*
* Applies encoding transformations in sequence, where each encoding
* is applied to the result of the previous encoding. This allows for
* complex encoding pipelines to be built programmatically.
*
* @param input - The string to encode
* @param encodings - Single encoding type or array of encoding types to apply in sequence
* @returns Promise that resolves to the encoded string
*
* @example
* ```typescript
* // Single encoding
* const base64Result = await Encoder.encode('hello', 'base64');
* // Output: 'aGVsbG8='
*
* // Multiple encodings
* const result = await Encoder.encode('data', ['base64', 'hex']);
* // Applies base64 first, then hex to the result
*
* // URL-safe encoding
* const urlSafe = await Encoder.encode('user input', 'urlSafeBase64');
* ```
*/
static encode(input: string, encodings: ENC_TYPE | ENC_TYPE[]): Promise<string>;
/**
* Decode a string using one or more decoding schemes.
*
* Reverses encoding transformations by applying decodings in reverse order.
* Supports both manual specification of decoding types and automatic detection.
*
* @param input - The encoded string to decode
* @param encodings - Single decoding type or array of decoding types to apply in reverse order
* @param opt - Optional decoding configuration
* @param opt.autoDetect - Whether to attempt automatic encoding detection (experimental)
* @returns The decoded string
*
* @example
* ```typescript
* // Single decoding
* const original = Encoder.decode('aGVsbG8=', 'base64');
* // Output: 'hello'
*
* // Multiple decodings (reverse order)
* const result = Encoder.decode(encodedData, ['hex', 'base64']);
* // Decodes hex first, then base64
*
* // With auto-detection
* const decoded = Encoder.decode(encodedStr, 'base64', { autoDetect: true });
* ```
*/
static decode(input: string, encodings: ENC_TYPE | ENC_TYPE[], opt?: {
autoDetect?: boolean;
}): string;
/**
* Compress a string using LZ77 or GZIP-style compression.
*
* Reduces the size of input strings using dictionary-based compression algorithms.
* LZ77 uses sliding window compression, while GZIP uses LZW-style dictionary compression.
* Both methods are lossless and can be reversed using the decompress method.
*
* @param input - The string to compress
* @param method - Compression algorithm to use ('lz77' or 'gzip')
* @returns The compressed and base64-encoded string
*
* @example
* ```typescript
* // LZ77 compression (good for repetitive data)
* const compressed = Encoder.compress('abababababab', 'lz77');
* const decompressed = Encoder.decompress(compressed, 'lz77');
*
* // GZIP compression (good for large texts)
* const text = 'A very long string with lots of repetition and patterns...';
* const gzipped = Encoder.compress(text, 'gzip');
* const original = Encoder.decompress(gzipped, 'gzip');
*
* // Measure compression ratio
* const ratio = gzipped.length / text.length;
* console.log(`Compression ratio: ${ratio.toFixed(2)}`);
* ```
*/
static compress(input: string, method: "lz77" | "gzip"): string;
/**
* Decompress a string that was compressed using the compress method.
*
* Reverses the compression applied by the compress method, restoring the
* original string. Supports both LZ77 and GZIP decompression algorithms.
*
* @param input - The compressed string to decompress
* @param method - Decompression algorithm to use ('lz77' or 'gzip')
* @returns The decompressed original string
*
* @example
* ```typescript
* // Round-trip compression
* const original = 'This is a long string with repetitive patterns...';
* const compressed = Encoder.compress(original, 'lz77');
* const decompressed = Encoder.decompress(compressed, 'lz77');
* // decompressed === original
*
* // Error handling
* try {
* const result = Encoder.decompress('invalid-compressed-data', 'gzip');
* } catch (error) {
* console.error('Decompression failed:', error);
* }
*
* // Check decompression success
* const result = Encoder.decompress(compressedData, 'lz77');
* if (!result) {
* console.error('Decompression returned empty result');
* }
* ```
*/
static decompress(input: string, method: "lz77" | "gzip"): string;
}
/**
* Configuration options for ID generation.
*
* Controls every aspect of how an ID is generated — from its size and encoding
* to advanced features like expiration, checksums, sequential numbering, and
* metadata embedding. All properties are optional; omitting them applies sensible defaults.
*
* @example Basic usage
* ```typescript
* const opts: IdGeneratorOptions = {
* size: 16,
* prefix: 'usr_',
* encoding: 'base62',
* includeTimestamp: true,
* };
* ```
*
* @example Preset format shortcut
* ```typescript
* const opts: IdGeneratorOptions = { format: 'uuid' };
* ```
*
* @example URL-safe ID with high entropy
* ```typescript
* const opts: IdGeneratorOptions = {
* size: 32,
* randomness: 'crypto',
* quality: { urlSafe: true, minEntropy: 'high', avoidPatterns: true },
* };
* ```
*
* @example Pattern-based ID (e.g. licence plate)
* ```typescript
* const opts: IdGeneratorOptions = { pattern: 'AA-9999' };
* // Possible output: "CA-4821"
* ```
*
* @example Expiring token with checksum
* ```typescript
* const opts: IdGeneratorOptions = {
* expiresIn: 60 * 60 * 1000, // 1 hour in ms
* includeChecksum: true,
* domain: 'auth',
* version: 2,
* };
* ```
*/
interface IdGeneratorOptions {
/** Desired total length of the generated ID (excluding affixes). */
size?: number;
/**
* Number of segments when generating a multi-part ID.
* Each segment is separated by {@link separator}.
*
* @default 1
* @example
* ```typescript
* // With segments: 2 and separator: '-' → "aB3x-K9mZ"
* { segments: 2, separator: '-', size: 4 }
* ```
*/
segments?: number;
/**
* Separator character inserted between each segment.
*
* @default '-'
* @example { segments: 3, separator: '_' } // "abc_def_ghi"
*/
separator?: string;
/**
* Encoding scheme(s) to apply during generation.
* Pass a single value or an array to chain multiple encodings.
*
* @example Single encoding
* ```typescript
* { encoding: 'base62' }
* ```
* @example Chained encodings
* ```typescript
* { encoding: ['base62', 'hex'] }
* ```
*/
encoding?: ENC_TYPE | ENC_TYPE[];
/**
* Custom character alphabet used as the source pool for generation.
* Overrides any alphabet implied by {@link encoding} or {@link charset}.
*
* @example
* ```typescript
* { alphabet: '0123456789abcdef' } // hexadecimal only
* ```
*/
alphabet?: string;
/**
* Compression algorithm applied to the raw bytes before encoding.
*
* - `'none'` — no compression (default)
* - `'lz77'` — fast, lightweight compression
* - `'gzip'` — standard gzip compression
*
* @default 'none'
*/
compression?: "none" | "lz77" | "gzip";
/**
* When `true`, the ID can be decoded back to its original form.
* Requires a reversible encoding scheme (e.g. Base64, Base62).
*
* @default false
*/
reversible?: boolean;
/**
* Static string prepended to the generated ID.
*
* @example
* ```typescript
* { prefix: 'usr_' } // "usr_aB3xK9mZ"
* ```
*/
prefix?: string;
/**
* Shortcut to apply a well-known ID format.
* When set, format-specific defaults (size, alphabet, timestamp) are applied automatically.
*
* | Value | Length | Notes |
* |------------|--------|-----------------------------------------|
* | `'uuid'` | 36 | RFC 4122, hyphen-separated |
* | `'nanoid'` | 21 | URL-safe, uses `size` override if set |
* | `'cuid'` | 25 | Collision-resistant, prefixed with `c` |
* | `'ksuid'` | 27 | K-Sortable, timestamp-prefixed |
* | `'xid'` | 20 | Mongo-compatible, base32-encoded |
* | `'pushid'` | 20 | Firebase-style, time-ordered |
*
* @example
* ```typescript
* NehoID.generate({ format: 'ksuid' });
* // Output: "0ujzPyRiIAffKhBux4PvQdDqMHY"
* ```
*/
format?: "uuid" | "nanoid" | "cuid" | "ksuid" | "xid" | "pushid";
/**
* When `true`, a Unix millisecond timestamp is embedded in the ID,
* enabling chronological sorting.
*
* @default false
*/
includeTimestamp?: boolean;
/**
* Embeds an expiration deadline in the ID as `_exp{epoch_ms}`.
* The value is a TTL expressed in **milliseconds** from the moment of generation.
*
* @example
* ```typescript
* { expiresIn: 24 * 60 * 60 * 1000 } // expires in 24 h
* // Output: "aB3xK9mZ_exp1710000000000"
* ```
*/
expiresIn?: number;
/**
* Version tag prepended to the ID as `v{n}_`.
* Accepts a number (auto-prefixed with `v`) or a custom string.
*
* @example
* ```typescript
* { version: 2 } // "v2_aB3xK9mZ"
* { version: 'beta' } // "beta_aB3xK9mZ"
* ```
*/
version?: number | string;
/**
* Domain or service identifier prepended as a namespace: `{domain}_{id}`.
* Useful for distinguishing IDs across microservices.
*
* @example
* ```typescript
* { domain: 'payments' } // "payments_aB3xK9mZ"
* ```
*/
domain?: string;
/**
* Fine-grained control over which character categories are included.
* Each boolean flag defaults to `true` unless explicitly set to `false`.
*
* @example Numbers only
* ```typescript
* { charset: { numbers: true, lowercase: false, uppercase: false } }
* ```
* @example Exclude ambiguous characters
* ```typescript
* { charset: { exclude: ['0', 'O', 'l', 'I'] } }
* ```
*/
charset?: {
/** Include digits `0–9`. @default true */
numbers?: boolean;
/** Include lowercase letters `a–z`. @default true */
lowercase?: boolean;
/** Include uppercase letters `A–Z`. @default true */
uppercase?: boolean;
/** Include printable special characters (`!@#$%^&*…`). @default false */
special?: boolean;
/** Characters to remove from the final pool, applied after all inclusions. */
exclude?: string[];
};
/**
* Case transformation applied to the final ID string.
*
* | Value | Description | Example |
* |------------|------------------------------------------|------------------|
* | `'lower'` | All lowercase | `"abc123def"` |
* | `'upper'` | All uppercase | `"ABC123DEF"` |
* | `'mixed'` | Random per-character casing | `"AbC1d2EF"` |
* | `'camel'` | camelCase (first word lowercase) | `"myOrderId"` |
* | `'pascal'` | PascalCase (every word capitalised) | `"MyOrderId"` |
* | `'snake'` | snake_case (words joined with `_`) | `"my_order_id"` |
*/
case?: "lower" | "upper" | "mixed" | "camel" | "pascal" | "snake";
/**
* Source of randomness used during generation.
*
* - `'fast'` — `Math.random()`, fastest but not cryptographically secure.
* - `'crypto'` — `crypto.getRandomValues()`, cryptographically secure.
* - `'secure'` — Additional entropy hardening on top of crypto.
*
* @default 'fast'
*/
randomness?: "fast" | "crypto" | "secure";
/**
* Quality constraints applied after generation.
*
* @example
* ```typescript
* {
* quality: {
* minEntropy: 'high',
* avoidPatterns: true,
* urlSafe: true,
* }
* }
* ```
*/
quality?: {
/**
* Minimum Shannon entropy level required.
* IDs that do not meet this threshold are regenerated.
*
* - `'low'` — ≥ 2 bits/char
* - `'medium'` — ≥ 3.5 bits/char
* - `'high'` — ≥ 5 bits/char
*/
minEntropy?: "low" | "medium" | "high";
/** Reject IDs that contain common sequences (`123`, `aaa`, etc.). @default false */
avoidPatterns?: boolean;
/** Restrict output to characters safe for use in URLs without encoding. @default false */
urlSafe?: boolean;
};
/**
* Template string where each placeholder is replaced by a random character.
*
* | Placeholder | Replaced with |
* |-------------|----------------------|
* | `X` | Uppercase letter A–Z |
* | `A` | Uppercase letter A–Z |
* | `a` | Lowercase letter a–z |
* | `9` | Digit 0–9 |
* | Other chars | Kept as-is |
*
* @example
* ```typescript
* { pattern: 'XXX-999' } // e.g. "BKT-472"
* { pattern: 'AA-9999' } // e.g. "CA-1834" (licence-plate style)
* ```
*/
pattern?: string;
/**
* Emit deterministic sequential IDs scoped to a named context.
* Useful as a distributed-safe replacement for database auto-increment.
*
* @example
* ```typescript
* { sequential: { context: 'invoices', start: 1000, padLength: 6 } }
* // Output: "invoices001000"
* ```
*/
sequential?: {
/** Named scope that isolates the counter from other sequences. */
context: string;
/** Initial counter value. @default 1 */
start?: number;
/** Zero-pad the counter to this many digits. @default 0 (no padding) */
padLength?: number;
};
/**
* When `true`, a short DJB2 checksum is appended as `_{checksum}`.
* Use {@link NehoID.validate} to verify integrity later.
*
* @default false
* @example
* ```typescript
* { includeChecksum: true }
* // Output: "aB3xK9mZ_3f2a"
* ```
*/
includeChecksum?: boolean;
/**
* Arbitrary key-value pairs serialised as Base64 JSON and appended as `_meta{data}`.
* Keep payloads small — large objects significantly inflate ID length.
*
* @example
* ```typescript
* { metadata: { env: 'prod', source: 'api' } }
* // Output: "aB3xK9mZ_meta eyJlbnYiOiJwcm9kIn0="
* ```
*/
metadata?: Record<string, unknown>;
}
/**
* Strategy configuration for collision-resistant ID generation.
*
* When generating IDs that must be unique within an external store (e.g. a database),
* use this interface with {@link NehoID.safe} to automatically retry on collision.
*
* @example Exponential back-off with database check
* ```typescript
* const id = await NehoID.safe({
* name: 'user-id-check',
* maxAttempts: 10,
* backoffType: 'exponential',
* checkFunction: async (candidate) => {
* const exists = await db.users.exists({ id: candidate });
* return !exists; // return true → candidate is unique and accepted
* },
* });
* ```
*/
interface CollisionStrategy {
/** Human-readable name for logging and debugging purposes. */
name: string;
/**
* Maximum number of generation attempts before throwing an error.
* Raise this value when collision probability is high.
*
* @minimum 1
* @example 50
*/
maxAttempts: number;
/**
* Retry delay strategy applied between consecutive attempts.
*
* - `'linear'` — constant delay between retries.
* - `'exponential'` — delay doubles with each attempt (recommended).
*/
backoffType: "linear" | "exponential";
/**
* Async predicate that returns `true` when the candidate ID is unique
* and safe to use, or `false` to trigger another attempt.
*
* @param id - The candidate ID to validate.
* @returns `Promise<boolean>` — `true` if unique, `false` if collision.
*
* @example
* ```typescript
* checkFunction: async (id) => !(await redis.exists(`session:${id}`))
* ```
*/
checkFunction: (id: string) => Promise<boolean>;
}
/**
* Options for generating IDs that embed environmental context.
*
* Useful for tracing, analytics, and fraud detection — each flag adds a
* fingerprint segment derived from the current runtime environment.
*
* > ⚠️ **Privacy notice**: Enabling `includeLocation` or `includeDevice` may
* > collect personally identifiable information. Ensure compliance with
* > applicable privacy regulations (GDPR, CCPA, etc.) before enabling these flags.
*
* @example
* ```typescript
* const id = NehoID.contextual({
* includeDevice: true,
* includeTimezone: true,
* userBehavior: 'checkout',
* });
* ```
*/
interface ContextOptions {
/** Embed a device fingerprint (OS, CPU, memory) in the ID. @default false */
includeDevice?: boolean;
/** Embed the IANA timezone string (e.g. `"Europe/Paris"`). @default false */
includeTimezone?: boolean;
/** Embed a hash of the browser user-agent string. @default false */
includeBrowser?: boolean;
/** Embed screen resolution and colour depth. @default false */
includeScreen?: boolean;
/**
* Embed a coarse geolocation hash.
* Requires user permission and `navigator.geolocation` availability.
*
* @default false
*/
includeLocation?: boolean;
/**
* Custom string describing the current user interaction (e.g. `'login'`, `'purchase'`).
* Hashed and embedded as a short segment.
*
* @example 'add-to-cart'
*/
userBehavior?: string;
}
/**
* Configuration for generating human-readable, structured semantic IDs.
*
* Semantic IDs encode business context directly in the identifier, making
* them self-documenting while remaining unique.
*
* @example
* ```typescript
* const id = NehoID.semantic({
* prefix: 'ORD',
* region: 'EU-WEST',
* department: 'SALES',
* year: 2025,
* customSegments: { channel: 'web' },
* });
* // Possible output: "ORD-EU-WEST-SALES-2025-web-x7k2"
* ```
*/
interface SemanticOptions {
/** Static business prefix (e.g. `'ORD'`, `'INV'`, `'TKT'`). */
prefix?: string;
/**
* Geographic region code embedded in the ID.
*
* @example 'US-WEST' | 'EU-CENTRAL' | 'APAC'
*/
region?: string;
/**
* Organisational unit or department code.
*
* @example 'SALES' | 'OPS' | 'ENG'
*/
department?: string;
/**
* Four-digit year component for temporal organisation.
*
* @example 2025
*/
year?: number;
/**
* Additional domain-specific segments as key-value pairs.
* Each entry is appended in insertion order.
*
* @example { channel: 'mobile', tier: 'premium' }
*/
customSegments?: Record<string, string | number>;
}
/**
* Options for generating multiple IDs in a single operation.
*
* @example Standard batch
* ```typescript
* const ids = NehoID.batch({ count: 50, format: 'uuid', ensureUnique: true });
* ```
*
* @example High-throughput parallel batch
* ```typescript
* const ids = NehoID.batch({ count: 10_000, format: 'nano', parallel: true });
* ```
*/
interface BatchOptions {
/**
* Number of IDs to produce.
*
* @minimum 1
*/
count: number;
/**
* ID format applied uniformly across the batch.
*
* | Value | Description |
* |--------------|------------------------------------|
* | `'standard'` | Default NehoID format |
* | `'nano'` | NanoID-compatible, 21 chars |
* | `'short'` | Short alphanumeric, 8 chars |
* | `'uuid'` | RFC 4122 UUID, 36 chars |
*
* @default 'standard'
*/
format?: "standard" | "nano" | "short" | "uuid";
/**
* Generate IDs in parallel using worker threads when available.
* Significantly improves throughput for large batches (> 1 000 IDs).
*
* @default false
*/
parallel?: boolean;
/**
* Deduplicate the output so every ID in the batch is distinct.
* Slightly reduces throughput for very large batches.
*
* @default true
*/
ensureUnique?: boolean;
}
/**
* Options controlling what aspects of an ID are validated.
*
* @example Full validation
* ```typescript
* const valid = NehoID.validate(id, {
* checkFormat: true,
* checkCollisions: true,
* repairCorrupted: false,
* });
* ```
*/
interface ValidationOptions {
/**
* Verify that the ID conforms to its declared format (length, alphabet, prefix, checksum).
*
* @default true
*/
checkFormat?: boolean;
/**
* Check whether the ID already exists in the configured store.
* Requires a collision back-end to be registered via `NehoID.configure()`.
*
* @default false
*/
checkCollisions?: boolean;
/**
* Attempt to recover a structurally damaged ID (e.g. truncated, bad checksum).
* Returns the repaired string if possible; `false` otherwise.
*
* @default false
*/
repairCorrupted?: boolean;
}
/**
* Detailed quality assessment of a generated ID.
*
* Returned by {@link NehoID.healthCheck}. A score of `1.0` represents a
* cryptographically ideal ID; `0.0` represents a trivially guessable one.
*
* @example
* ```typescript
* const health = NehoID.healthCheck('usr_aB3xK9mZ');
* // {
* // score: 0.91,
* // entropy: 'high',
* // predictability: 'low',
* // recommendations: [],
* // }
* ```
*/
interface HealthScore {
/**
* Overall quality score in the range `[0.0, 1.0]`.
* Higher values indicate better randomness and uniqueness guarantees.
*/
score: number;
/**
* Shannon entropy classification of the ID's character distribution.
*
* - `'low'` — < 2 bits/char, easily guessable.
* - `'medium'` — 2–4 bits/char, moderate security.
* - `'high'` — > 4 bits/char, suitable for security tokens.
*/
entropy: "low" | "medium" | "high";
/**
* Likelihood that the ID could be predicted or enumerated by an attacker.
*
* - `'high'` — sequential or pattern-based, avoid for sensitive use-cases.
* - `'medium'` — some structure present.
* - `'low'` — effectively random.
*/
predictability: "low" | "medium" | "high";
/**
* Actionable suggestions for improving ID quality.
* Empty array when no improvements are needed.
*
* @example ["Increase size to at least 16", "Use 'crypto' randomness source"]
*/
recommendations: string[];
}
/**
* Runtime performance and health statistics for the ID generation system.
*
* Populated by the internal {@link Monitor} after {@link NehoID.startMonitoring} is called.
*
* @example
* ```typescript
* NehoID.startMonitoring();
* // ... run workload ...
* const stats = NehoID.getStats();
* console.log(`Generated: ${stats.generated} | Avg: ${stats.averageGenerationTime}`);
* ```
*/
interface Stats {
/** Total number of IDs successfully generated during the monitoring session. */
generated: number;
/**
* Number of collision events detected.
* A non-zero value indicates ID space exhaustion or a low-quality generator config.
*/
collisions: number;
/**
* Human-readable average generation latency (e.g. `"0.043 ms"`).
* Computed as a rolling mean over all generation calls.
*/
averageGenerationTime: string;
/**
* Current heap memory consumed by internal caches and counters (e.g. `"4.2 MB"`).
*/
memoryUsage: string;
/**
* Chi-squared distribution quality score in `[0.0, 1.0]`.
* Values close to `1.0` indicate a uniform ID distribution (ideal).
* Values below `0.7` may indicate a biased generator.
*/
distributionScore: number;
}
/**
* Configuration for bulk-migrating IDs between formats.
*
* Use this with {@link NehoID.migrate} to convert legacy IDs (e.g. plain UUIDs)
* to a richer NehoID format without losing referential integrity.
*
* @example Migrate a list of UUIDs to NehoID format
* ```typescript
* const newIds = await NehoID.migrate({
* from: 'uuid',
* to: 'nehoid',
* preserveOrder: true,
* batchSize: 500,
* ids: legacyUuids,
* });
* ```
*
* @example Migrate the first 1 000 records from a store
* ```typescript
* const newIds = await NehoID.migrate({
* from: 'legacy-numeric',
* to: 'ksuid',
* count: 1000,
* batchSize: 100,
* });
* ```
*/
interface MigrationOptions {
/** Format identifier of the source IDs (e.g. `'uuid'`, `'legacy-numeric'`). */
from: string;
/** Format identifier for the output IDs (e.g. `'nehoid'`, `'ksuid'`). */
to: string;
/**
* Preserve the original chronological ordering of IDs in the output array.
* When `false`, output order is not guaranteed (may be faster).
*
* @default true
*/
preserveOrder?: boolean;
/**
* Number of IDs processed per internal batch to limit memory pressure.
* Tune this based on available heap and source record size.
*
* @default 100
* @minimum 1
*/
batchSize?: number;
/**
* Explicit list of source IDs to migrate.
* When provided, takes precedence over {@link count}.
*/
ids?: string[];
/**
* Maximum number of IDs to migrate from the configured source store.
* Ignored when {@link ids} is provided.
*/
count?: number;
}
/**
* Options for generating IDs that are valid across multiple platforms and languages.
*
* Different runtimes impose constraints on string length, character sets, and
* integer overflow. This interface ensures the output ID satisfies all target platforms.
*
* @example
* ```typescript
* const id = NehoID.compatible({
* platform: ['javascript', 'python', 'go'],
* format: 'alphanumeric',
* length: 16,
* });
* ```
*/
interface CompatibilityOptions {
/**
* Target platforms the ID must be usable on without transformation.
* The generator applies the most restrictive constraint set across all listed platforms.
*
* | Platform | Key constraints |
* |----------------|------------------------------------------------|
* | `'javascript'` | UTF-16, `Number.MAX_SAFE_INTEGER` limit |
* | `'python'` | UTF-8, arbitrary precision integers |
* | `'go'` | UTF-8, fixed-size integer types |
*/
platform: Array<"javascript" | "python" | "go">;
/**
* Named character set or format the ID must conform to.
*
* @example 'alphanumeric' | 'hex' | 'base62' | 'uuid'
*/
format: string;
/**
* Exact character length of the generated ID.
*
* @minimum 1
* @example 16
*/
length: number;
}
/**
* Specialized ID generators for NehoID
* Implements hierarchical, temporal, and sequential ID generation
*/
declare class Specialized {
/**
* Generates a hierarchical ID with parent-child relationships
* @param parent Optional parent ID to create a child under
* @param level Hierarchy level (defaults to 1 if no parent, otherwise parent level + 1)
* @param separator Character to separate hierarchy levels
* @returns A hierarchical ID
*/
static hierarchical(options?: {
parent?: string;
level?: number;
separator?: string;
}): string;
/**
* Generates a time-ordered ID for chronological sorting
* @param precision Time precision ('ms', 's', 'm', 'h', 'd')
* @param suffix Whether to add a random suffix for uniqueness
* @returns A temporal ID with timestamp
*/
static temporal(options?: {
precision?: 'ms' | 's' | 'm' | 'h' | 'd';
suffix?: boolean;
format?: 'hex' | 'dec' | 'b36';
}): string;
/**
* Generates a sequential ID suitable for database use
* @param prefix Optional prefix for the ID
* @param counter Current counter value
* @param padLength Length to pad the counter to
* @returns A sequential ID
*/
static sequential(options: {
prefix?: string;
counter: number;
padLength?: number;
suffix?: boolean;
}): string;
/**
* Generates a temporal ID from a specific timestamp
* @param timestamp Unix timestamp in milliseconds
* @param precision Time precision ('ms', 's', 'm', 'h', 'd')
* @param suffix Whether to add a random suffix for uniqueness
* @param format Timestamp format ('hex' | 'dec' | 'b36')
* @returns A temporal ID with the specified timestamp
*/
static fromTemporal(timestamp: number, options?: {
precision?: 'ms' | 's' | 'm' | 'h' | 'd';
suffix?: boolean;
format?: 'hex' | 'dec' | 'b36';
}): string;
/**
* Extracts timestamp from a temporal ID
* @param temporalId The temporal ID to extract timestamp from
* @param precision Time precision used in the temporal ID ('ms', 's', 'm', 'h', 'd')
* @param format Timestamp format used in the temporal ID ('hex' | 'dec' | 'b36')
* @returns Unix timestamp in milliseconds
* @throws Error if the temporal ID format is invalid
*/
static fromTemporalToTimestamp(temporalId: string, options?: {
precision?: 'ms' | 's' | 'm' | 'h' | 'd';
format?: 'hex' | 'dec' | 'b36';
}): number;
}
/**
* Specialized ID generation methods for advanced use cases.
*
* This module provides generators for hierarchical relationships, time-ordered IDs,
* and sequential identifiers. These specialized generators are designed for specific
* architectural patterns and data modeling requirements.
*/
declare class SpecializedGenerators {
/**
* Generates a hierarchical ID with parent-child relationships.
*
* Creates IDs that encode hierarchical structures, making it easy to query
* and navigate tree-like data relationships. The ID format supports efficient
* ancestor and descendant queries in databases.
*
* @param options - Configuration options for hierarchical generation
* @returns A hierarchical ID string with encoded relationship information
*
* @example
* ```typescript
* // Basic hierarchical ID
* const rootId = SpecializedGenerators.hierarchical();
*
* // Child ID with parent reference
* const childId = SpecializedGenerators.hierarchical({
* parentId: rootId,
* level: 1
* });
*
* // Deep hierarchy
* const grandchildId = SpecializedGenerators.hierarchical({
* parentId: childId,
* level: 2,
* maxDepth: 5
* });
* ```
*
* @example
* ```typescript
* // Database queries with hierarchical IDs
* // Find all descendants of a node
* const descendants = await db.collection.find({
* hierarchicalId: { $regex: `^${parentId}` }
* });
*
* // Find direct children
* const children = await db.collection.find({
* parentId: parentId
* });
* ```
*/
static hierarchical(options?: Record<string, any>): string;
/**
* Generates a time-ordered ID for chronological sorting and pagination.
*
* Creates IDs that sort chronologically by embedding timestamp information.
* This enables efficient time-based queries and pagination without requiring
* separate timestamp columns.
*
* @param options - Configuration options for temporal generation
* @returns A temporal ID string with embedded timestamp for natural sorting
*
* @example
* ```typescript
* // Basic temporal ID (current timestamp)
* const eventId = SpecializedGenerators.temporal();
*
* // Custom timestamp
* const pastEventId = SpecializedGenerators.temporal({
* timestamp: new Date('2023-01-01').getTime()
* });
*
* // High precision temporal ID
* const preciseId = SpecializedGenerators.temporal({
* precision: 'nanoseconds',
* includeRandom: true
* });
* ```
*
* @example
* ```typescript
* // Time-based pagination
* const recentEvents = await db.collection.find({
* temporalId: { $gt: lastEventId }
* }).sort({ temporalId: 1 }).limit(50);
*
* // Events from specific time range
* const startTime = SpecializedGenerators.temporal({
* timestamp: Date.now() - (24 * 60 * 60 * 1000) // 24 hours ago
* });
* const todaysEvents = await db.collection.find({
* temporalId: { $gte: startTime }
* });
* ```
*/
static temporal(...options: Parameters<typeof Specialized.temporal>): string;
/**
* Generates a sequential ID suitable for database primary keys.
*
* Creates human-readable sequential identifiers that can replace auto-incrementing
* integers in databases. Supports prefixes, padding, and custom formatting
* for business logic requirements.
*
* @param options - Configuration options for sequential generation
* @returns A formatted sequential ID string
*
* @example
* ```typescript
* // Simple sequential ID
* const id = SpecializedGenerators.sequential({
* counter: 1001
* });
* // Output: '1001'
*
* // With prefix and padding
* const orderId = SpecializedGenerators.sequential({
* prefix: 'ORD',
* counter: 42,
* padLength: 6
* });
* // Output: 'ORD000042'
*
* // With suffix
* const invoiceId = SpecializedGenerators.sequential({
* prefix: 'INV',
* counter: 123,
* suffix: true
* });
* // Output: 'INV123'
* ```
*
* @example
* ```typescript
* // Database schema with sequential IDs
* const userSchema = new mongoose.Schema({
* _id: {
* type: String,
* default: () => SpecializedGenerators.sequential({
* prefix: 'USR',
* counter: await getNextUserCounter()
* })
* },
* name: String
* });
* ```
*/
/**
* Generates a temporal ID from a timestamp.
*
* Converts a Unix timestamp into a temporal ID that can be used for
* chronological sorting and time-based queries. The temporal ID format
* includes encoded timestamp information for efficient database indexing.
*
* @param timestamp - Unix timestamp in milliseconds
* @returns A temporal ID string containing the encoded timestamp
*
* @example
* ```typescript
* // Generate temporal ID from current time
* const temporalId = SpecializedGenerators.fromTemporal(Date.now());
*
* // Generate temporal ID from specific date
* const pastTemporalId = SpecializedGenerators.fromTemporal(
* new Date('2023-01-01').getTime()
* );
*
* // Use in database queries
* const recentEvents = await db.collection.find({
* temporalId: { $gte: SpecializedGenerators.fromTemporal(Date.now() - 86400000) }
* });
* ```
*/
static fromTemporal(timestamp: number, options?: Parameters<typeof Specialized.fromTemporal>[1]): string;
/**
* Extracts timestamp from a temporal ID.
*
* Reverses the temporal ID generation process to recover the original
* Unix timestamp. This is useful for converting temporal IDs back to
* human-readable dates or for time-based calculations.
*
* @param temporalId - Temporal ID string to extract timestamp from
* @returns Unix timestamp in milliseconds
* @throws {Error} If the temporal ID format is invalid
*
* @example
* ```typescript
* // Extract timestamp from temporal ID
* const temporalId = SpecializedGenerators.fromTemporal(Date.now());
* const timestamp = SpecializedGenerators.fromTemporalToTimestamp(temporalId);
*
* // Convert back to Date object
* const date = new Date(timestamp);
* console.log(date.toISOString());
*
* // Calculate time differences
* const age = Date.now() - timestamp;
* const hoursOld = age / (1000 * 60 * 60);
* ```
*
* @example
* ```typescript
* // Error handling
* try {
* const timestamp = SpecializedGenerators.fromTemporalToTimestamp('invalid-id');
* } catch (error) {
* console.error('Invalid temporal ID format');
* }
* ```
*/
static fromTemporalToTimestamp(temporalId: string, options?: Parameters<typeof Specialized.fromTemporalToTimestamp>[1]): number;
static sequential(options: {
prefix?: string;
counter: number;
padLength?: number;
suffix?: boolean;
}): string;
}
/**
* Central facade for all ID generation, validation, monitoring, and migration
* operations provided by the NehoID library.
*
* Every public method is **static** — no instantiation required. Internally the
* class delegates to specialised sub-modules ({@link Generator}, {@link Validators},
* {@link Monitor}, {@link Advanced}, etc.) and adds orchestration, option
* pre-processing, and monitoring instrumentation on top.
*
* ---
*
* ### Quick-start
*
* ```typescript
* import { NehoID } from 'nehoid';
*
* // ── Simple generation ──────────────────────────────────────────────────────
* const id = NehoID.generate(); // default settings
* const uuid = NehoID.generate({ format: 'uuid' }); // RFC 4122 UUID
* const nano = NehoID.nanoid(16); // NanoID, length 16
* const hex = NehoID.hex(32); // 32-char hex string
*
* // ── Collision-safe async generation ───────────────────────────────────────
* const safeId = await NehoID.safe({
* name: 'user-id',
* maxAttempts: 10,
* backoffType: 'exponential',
* checkFunction: async (candidate) => !(await db.exists(candidate)),
* });
*
* // ── Bulk generation ────────────────────────────────────────────────────────
* const ids = NehoID.batch({ count: 500, format: 'uuid', ensureUnique: true });
*
* // ── Validation ─────────────────────────────────────────────────────────────
* const ok = NehoID.validate(id);
* const health = NehoID.healthCheck(id);
*
* // ── Monitoring ─────────────────────────────────────────────────────────────
* NehoID.startMonitoring();
* const stats = NehoID.getStats();
* NehoID.stopMonitoring();
* ```
*/
declare class NehoID {
private constructor();
/**
* Replaces pattern placeholders with random characters.
*
* Recognised placeholders:
* - `X` / `A` → random uppercase letter (A–Z)
* - `a` → random lowercase letter (a–z)
* - `9` → random digit (0–9)
*
* All other characters are kept verbatim.
*
* @param pattern - Template string (e.g. `'XXX-999'`).
* @returns Resolved pattern string (e.g. `'BKT-472'`).
*/
private static generateFromPattern;
/**
* Derives an alphabet string from a {@link IdGeneratorOptions.charset} descriptor.
*
* @param charset - Charset descriptor from caller options.
* @returns Combined alphabet string, or `undefined` if the descriptor is empty.
*/
private static buildAlphabetFromCharset;
/**
* Applies format-specific defaults for preset format shortcuts.
*
* Mutates `processedOptions` in place and may return early with a fully
* formed ID for formats that have their own dedicated generators.
*
* @param format - The requested preset format.
* @param originalOptions - The raw caller options (read-only).
* @param processedOptions - Options object being built for the core generator.
* @returns An early-exit ID string for `'uuid'` and `'nanoid'`, or `undefined`.
*/
private static applyFormatPreset;
/**
* Applies a case transformation to an ID string.
*
* @param id - The raw ID string.
* @param caseMode - Desired case transformation.
* @returns Transformed string.
*/
private static applyCase;
/**
* Generates a unique ID with optional configuration.
*
* This is the primary entry point for ID generation. It supports preset format
* shortcuts, fine-grained character control, case transformations, expiration
* timestamps, versioning, domains, sequential numbering, pattern templates,
* metadata embedding, and checksum appending — all composable in a single call.
*
* > **Performance note**: For bulk generation prefer {@link NehoID.batch}, which
* > avoids per-call monitoring overhead and can run in parallel.
*
* @param options - Generation options. All properties are optional.
* @returns A newly generated unique ID string.
*
* @throws {RangeError} If `options.size` is defined and less than 1.
* @throws {TypeError} If `options.sequential.padLength` is negative.
*
* @example Preset formats
* ```typescript
* NehoID.generate({ format: 'uuid' }); // "550e8400-e29b-41d4-a716-446655440000"
* NehoID.generate({ format: 'nanoid' }); // "V1StGXR8_Z5jdHi6B-myT"
* NehoID.generate({ format: 'ksuid' }); // "0ujzPyRiIAffKhBux4PvQdDqMHY"
* ```
*
* @example Custom size, segments & separator
* ```typescript
* NehoID.generate({ size: 4, segments: 3, separator: '.' });
* // "aB3x.K9mZ.tR8q"
* ```
*
* @example Prefix, case & charset control
* ```typescript
* NehoID.generate({
* prefix: 'USR',
* case: 'lower',
* charset: { numbers: true, uppercase: false }
* });
* // "usr_3f2a9c1b"
* ```
*
* @example Pattern template
* ```typescript
* NehoID.generate({ pattern: 'AA-9999' }); // "CA-1834"
* NehoID.generate({ pattern: 'XXX-XXX' }); // "BKT-ZMP"
* ```
*
* @example Compression & Encoding
* ```typescript
* NehoID.generate({
* encoding: 'base64',
* compression: 'lz77'
* });
* ```
*
* @example Expiring security token
* ```typescript
* NehoID.generate({
* size: 32,
* randomness: 'crypto',
* expiresIn: 15 * 60 * 1000, // 15 minutes
* domain: 'auth',
* includeChecksum: true,
* });
* ```
*
* @example Sequential order IDs
* ```typescript
* NehoID.generate({
* sequential: { context: 'orders', start: 1000, padLength: 6 },
* });
* // "orders001000"
* ```
*
* @example Embedded metadata
* ```typescript
* NehoID.generate({
* metadata: { env: 'prod', source: 'api-v3' },
* includeTimestamp: true,
* });
* ```
*/
static generate(options?: Partial<IdGeneratorOptions>): string;
/**
* Generates a collision-safe ID by validating each candidate against an
* external uniqueness predicate before returning it.
*
* The method retries up to {@link CollisionStrategy.maxAttempts} times with
* the configured back-off strategy. If all attempts fail, it throws an error
* and increments the collision counter in {@link Monitor}.
*
* @param options - Collision strategy including the async uniqueness check.
* @returns A promise that resolves to a guaranteed-unique ID string.
* @throws {Error} When `maxAttempts` is exhausted without finding a unique ID.
*
* @example Database uniqueness check
* ```typescript
* const id = await NehoID.safe({
* name: 'order-id-check',
* maxAttempts: 10,
* backoffType: 'exponential',
* checkFunction: async (candidate) => {
* return !(await db.orders.exists({ id: candidate }));
* },
* });
* ```
*
* @example Redis cache token
* ```typescript
* const token = await NehoID.safe({
* name: 'session-token',
* maxAttempts: 5,
* backoffType: 'linear',
* checkFunction: async (t) => !(await redis.exists(`sess:${t}`)),
* });
* ```
*/
static safe(options: CollisionStrategy): Promise<string>;
/**
* Generates a RFC 4122 v4 UUID.
*
* @returns A hyphen-separated UUID string (36 characters).
*
* @example
* ```typescript
* NehoID.uuid(); // "550e8400-e29b-41d4-a716-446655440000"
* ```
*/
static uuid(): string;
/**
* Generates a NanoID using URL-safe characters.
*
* NanoIDs are compact, URL-safe, and statistically collision-resistant.
* The default length of 21 chars provides ~126 bits of entropy.
*
* @param length - Character length of the output. @default 21
* @returns A NanoID string.
*
* @example
* ```typescript
* NehoID.nanoid(); // "V1StGXR8_Z5jdHi6B-myT" (21 chars)
* NehoID.nanoid(10); // "IRFa-VaY2b" (10 chars)
* ```
*/
static nanoid(length?: number): string;
/**
* Generates a short, compact alphanumeric ID.
*
* Useful for human-readable references (order numbers, share codes, etc.)
* where brevity matters more than maximum entropy.
*
* @param length - Character length of the output. @default 8
* @returns A short alphanumeric string.
*
* @example
* ```typescript
* NehoID.short(); // "aB3xK9mZ" (8 chars)
* NehoID.short(12); // "aB3xK9mZtR8q"
* ```
*/
static short(length?: number): string;
/**
* Generates a random hexadecimal string.
*
* @param length - Character length of the output. @default 16
* @returns A lowercase hexadecimal string.
*
* @example
* ```typescript
* NehoID.hex(); // "3f2a9c1b4e7d8f0a" (16 chars)
* NehoID.hex(32); // "3f2a9c1b4e7d8f0a1c3e5b7d9f2a4c6e"
* ```
*/
static hex(length?: number): string;
/**
* Generates a hierarchical ID encoding a parent-child relationship.
*
* Hierarchical IDs preserve the ancestry chain in the identifier itself,
* enabling efficient tree traversal without additional database joins.
*
* @param options - Hierarchical generation options.
* @returns A hierarchical ID string with encoded relationship segments.
*
* @example
* ```typescript
* const child = NehoID.hierarchical({ parentId: 'root-abc123', depth: 2 });
* // "root-abc123.L2.xK9m"
* ```
*/
static hierarchical(options?: Record<string, unknown>): string;
/**
* Generates a time-ordered ID suitable for chronological sorting.
*
* Temporal IDs embed a timestamp prefix so that lexicographic order matches
* insertion order — ideal for event logs, message queues, and time-series data.
*
* @param options - Temporal generation options (precision, random suffix, etc.).
* @returns A temporal ID string with an embedded timestamp prefix.
*
* @example
* ```typescript
* const id = NehoID.temporal({ precision: 'milliseconds', suffix: true });
* // "01HX3KBPM4-aB3x"
* ```
*/
static temporal(...options: Parameters<typeof SpecializedGenerators.temporal>): string;
/**
* Converts a Unix timestamp (milliseconds) into a temporal ID.
*
* Allows back-dated or future-dated IDs to be generated from arbitrary
* epoch values without going through the standard clock.
*
* @param timestamp - Unix epoch in milliseconds.
* @returns A temporal ID string derived from the given timestamp.
* @throws {RangeError} If `timestamp` is negative.
*
* @example
* ```typescript
* NehoID.fromTemporal(Date.now()); // current-time