| … | … | @@ -24,3 +24,19 @@ export function tidNow (clockId = 0, clock = () => BigInt(Date.now()) * 1000n) { |
| 24 | 24 | export function isValidTid (s) { |
| 25 | 25 | return typeof s === 'string' && s.length === 13 && [...s].every(c => S32.includes(c)) |
| 26 | 26 | } |
| 27 | |
| 28 | // The micros component of a TID (drops the 10-bit clock id). |
| 29 | export function tidMicros (tid) { |
| 30 | let n = 0n |
| 31 | for (const ch of String(tid)) n = (n << 5n) | BigInt(S32.indexOf(ch)) |
| 32 | return n >> 10n |
| 33 | } |
| 34 | |
| 35 | // The DETERMINISTIC next rev after `prevRev` — a pure function of the previous rev, never the |
| 36 | // wall clock. This is what makes the atproto chain indexer-agnostic: two co-owners continuing |
| 37 | // from the SAME head over the SAME finalized record set produce byte-identical commits (RFC6979 |
| 38 | // signing is deterministic), so concurrent signers are idempotent rather than forking. Mirrors |
| 39 | // atproto-base/lib/rev.js byte-for-byte (clockId 0) so both implementations agree exactly. |
| 40 | export function nextRev (prevRev) { |
| 41 | return s32encode((tidMicros(prevRev) + 1n) << 10n) |
| 42 | } |