Fork of atp.tools as a universal profile for people on the ATmosphere
1/**
2 * TID (Transaction ID) implementation for ATProto
3 * Based on the original Go implementation from github.com/bluesky-social/indigo
4 */
5
6// Base32 alphabet used for sorting
7const BASE32_SORT_ALPHABET = "234567abcdefghijklmnopqrstuvwxyz";
8
9// Constants for bit operations
10const CLOCK_ID_MASK = 0x3ff;
11const MICROS_MASK = 0x1f_ffff_ffff_ffffn;
12const INTEGER_MASK = 0x7fff_ffff_ffff_ffffn;
13
14class TransactionId {
15 private readonly value: string;
16
17 constructor(value: string) {
18 this.value = value;
19 }
20
21 toString(): string {
22 return this.value;
23 }
24
25 static create(unixMicros: bigint, clockId: number): TransactionId {
26 const clockIdBig = BigInt(clockId & CLOCK_ID_MASK);
27 const v = ((unixMicros & MICROS_MASK) << 10n) | clockIdBig;
28 return TransactionId.fromInteger(v);
29 }
30
31 static createNow(clockId: number): TransactionId {
32 const nowMicros = BigInt(Date.now()) * 1000n; // Convert ms to μs
33 return TransactionId.create(nowMicros, clockId);
34 }
35
36 private static fromInteger(value: bigint): TransactionId {
37 value = INTEGER_MASK & value;
38 let result = "";
39
40 for (let i = 0; i < 13; i++) {
41 result = BASE32_SORT_ALPHABET[Number(value & 0x1fn)] + result;
42 value = value >> 5n;
43 }
44
45 return new TransactionId(result);
46 }
47}
48
49/**
50 * Extracts timestamp from a TID string
51 * @param tid - The TID string to parse
52 * @returns Date object representing the timestamp
53 */
54export function tidToTime(tid: string): Date {
55 // Convert TID string to integer
56 let value = 0n;
57 for (let i = 0; i < Math.min(tid.length, 13); i++) {
58 const char = tid[i];
59 const charValue = BASE32_SORT_ALPHABET.indexOf(char);
60 if (charValue === -1) {
61 throw new Error(`Invalid base32 character: ${char}`);
62 }
63 value = (value << 5n) | BigInt(charValue);
64 }
65
66 // Extract timestamp (shift right 10 bits to remove clock ID, mask to get microseconds)
67 const micros = (value >> 10n) & 0x1fff_ffff_ffff_ffffn;
68
69 // Convert microseconds to milliseconds for JavaScript Date
70 const millis = Number(micros / 1000n);
71
72 return new Date(millis);
73}
74
75/**
76 * Generates a new Transaction ID with a random clock ID
77 * @returns TransactionId
78 */
79export function generateTid(): TransactionId {
80 const clockId = Math.floor(Math.random() * 64 + 512);
81 return TransactionId.createNow(clockId);
82}