UNPKG

@vyckr/ttid

Version:

A lightweight, time-based identifier generator that tracks creation, update, and deletion timestamps using a progressive format.

292 lines (215 loc) 7.28 kB
# TTID (Time-Tagged Identifier) A lightweight, time-based identifier generator that tracks creation, update, and deletion timestamps using a progressive format. ## Overview TTID creates unique identifiers with a progressive structure: - **Created:** `[CREATION_TIMESTAMP]` - **Updated:** `[CREATION_TIMESTAMP]-[UPDATE_TIMESTAMP]` - **Deleted:** `[CREATION_TIMESTAMP]-[UPDATE_TIMESTAMP]-[DELETION_TIMESTAMP]` Each TTID segment contains: - High-resolution timestamps encoded in base-36 - Progressive expansion to track lifecycle states - Compact 11-character timestamps for efficiency - Immutable deletion state (cannot be modified once deleted) ## Installation ```bash npm install ttid ``` ## Usage ### Basic ID Generation ```typescript import TTID from 'ttid'; // Generate a new TTID (creation only) const newId = TTID.generate(); console.log(newId); // Example output: "1A2B3C4D5E6" // Verify if a string is a valid TTID const isValid = TTID.isTTID(newId); console.log(isValid); // Returns Date object if valid, null if invalid ``` ### Progressive Updates ```typescript import TTID from 'ttid'; // Start with a new ID let id = TTID.generate(); console.log(id); // "1A2B3C4D5E6" // Update the ID (adds update timestamp) id = TTID.generate(id); console.log(id); // "1A2B3C4D5E6-F7G8H9I0J1" // Update again (replaces update timestamp) id = TTID.generate(id); console.log(id); // "1A2B3C4D5E6-K2L3M4N5O6" // Mark as deleted (adds deletion timestamp - final state) id = TTID.generate(id, true); console.log(id); // "1A2B3C4D5E6-K2L3M4N5O6-P7Q8R9S0T1" // Attempting to modify a deleted ID throws an error try { TTID.generate(id); // Throws: "This identifier can no longer be modified" } catch (error) { console.error(error.message); } ``` ### Decoding Timestamps ```typescript import TTID from 'ttid'; // Create and update an ID let id = TTID.generate(); setTimeout(() => { id = TTID.generate(id); setTimeout(() => { id = TTID.generate(id, true); // Mark as deleted // Decode all timestamps const times = TTID.decodeTime(id); console.log(times); // Example output: // { // createdAt: 1651234567890, // updatedAt: 1651234572345, // deletedAt: 1651234578901 // } // Convert to readable dates console.log({ created: new Date(times.createdAt), updated: times.updatedAt ? new Date(times.updatedAt) : null, deleted: times.deletedAt ? new Date(times.deletedAt) : null }); }, 2000); }, 1000); ``` ### Working with Different States ```typescript import TTID from 'ttid'; // Check ID states function analyzeId(id: string) { const validation = TTID.isTTID(id); if (!validation) { console.log('Invalid TTID'); return; } const segments = id.split('-'); const times = TTID.decodeTime(id); console.log(`ID State: ${getIdState(segments.length)}`); console.log(`Created: ${new Date(times.createdAt)}`); if (times.updatedAt) { console.log(`Updated: ${new Date(times.updatedAt)}`); } if (times.deletedAt) { console.log(`Deleted: ${new Date(times.deletedAt)}`); } } function getIdState(segmentCount: number) { switch (segmentCount) { case 1: return 'Created'; case 2: return 'Updated'; case 3: return 'Deleted'; default: return 'Unknown'; } } // Examples const createdId = TTID.generate(); analyzeId(createdId); // ID State: Created const updatedId = TTID.generate(createdId); analyzeId(updatedId); // ID State: Updated const deletedId = TTID.generate(updatedId, true); analyzeId(deletedId); // ID State: Deleted ``` ### Error Handling ```typescript import TTID from 'ttid'; // Invalid ID format try { TTID.generate('invalid-id'); } catch (error) { console.error(error.message); // "Invalid TTID!" } // Attempting to modify deleted ID const id = TTID.generate(); const updated = TTID.generate(id); const deleted = TTID.generate(updated, true); try { TTID.generate(deleted); } catch (error) { console.error(error.message); // "This identifier can no longer be modified" } // Invalid format for decoding try { TTID.decodeTime('not-a-ttid'); } catch (error) { console.error(error.message); // "Invalid Format!" } ``` ## API Reference ### `TTID.generate(id?: string, del?: boolean)` Generates a new TTID or updates an existing one. **Parameters:** - `id` (optional) - An existing TTID to update - `del` (optional) - Set to `true` to mark the ID as deleted **Returns:** `_ttid` - A TTID string **Behavior:** - No parameters: Creates new ID `[TIMESTAMP]` - Valid TTID provided: Updates to `[CREATED]-[NEW_TIMESTAMP]` - Valid TTID + `del=true`: Marks as deleted `[CREATED]-[UPDATED]-[DELETED_TIMESTAMP]` **Throws:** - Error if provided ID is invalid - Error if attempting to modify a deleted ID (3 segments) ### `TTID.decodeTime(id: string)` Decodes timestamps from a TTID. **Parameters:** - `id` - A TTID string **Returns:** `_timestamps` object with: - `createdAt` - Creation timestamp in milliseconds - `updatedAt` (optional) - Update timestamp in milliseconds - `deletedAt` (optional) - Deletion timestamp in milliseconds **Throws:** Error if the format is invalid ### `TTID.isTTID(id: string)` Validates a TTID and returns creation date if valid. **Parameters:** - `id` - A string to validate **Returns:** - `Date` object (creation date) if valid - `null` if invalid ### `TTID.isUUID(id: string)` Checks if a string is a valid UUID. **Parameters:** - `id` - A string to check **Returns:** `RegExpMatchArray | null` - Match result or null ## Format Specification TTIDs follow a strict format: - Base-36 encoding (0-9, A-Z) - 11-character timestamps - Hyphen-separated segments - Progressive structure **Valid Patterns:** - `[A-Z0-9]{11}` - Created only - `[A-Z0-9]{11}-[A-Z0-9]{1,11}` - Created + Updated - `[A-Z0-9]{11}-[A-Z0-9]{1,11}-[A-Z0-9]{1,11}` - Created + Updated + Deleted **Special Cases:** - Placeholder 'X' may appear in update position for certain states - Deleted IDs cannot be modified further ## Lifecycle States | State | Format | Segments | Modifiable | |-------|--------|----------|------------| | Created | `TIMESTAMP` | 1 | ✅ | | Updated | `CREATED-UPDATED` | 2 | ✅ | | Deleted | `CREATED-UPDATED-DELETED` | 3 | ❌ | ## Comparison with Other Systems | Feature | TTID | UUID | ULID | |---------|------|------|------| | Progressive states | ✅ | ❌ | ❌ | | Soft delete tracking | ✅ | ❌ | ❌ | | Immutable final state | ✅ | ❌ | ❌ | | Compact encoding | ✅ | ❌ | ✅ | | Time-based | ✅ | ⚠️ | ✅ | | Fixed length | ❌ | ✅ | ✅ | ## Use Cases - **Database Records**: Track entity lifecycle (created → updated → soft deleted) - **Audit Systems**: Maintain chronological history in the ID itself - **Document Management**: Version control with embedded timestamps - **API Resources**: RESTful endpoints with state-aware identifiers - **Event Sourcing**: Compact event identifiers with temporal information ## Performance Considerations - Base-36 encoding provides compact representation - Progressive format minimizes storage for simple states - High-resolution timestamps ensure uniqueness in high-frequency scenarios - Validation includes timestamp parsing for integrity checking ## License MIT