SPB Git

spb/khaelor Public

KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.

TypeScript 82.9% HTML 14.9% CSS 1.1% JavaScript 0.7%
2.4 KB · 84 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: src/shared/ids.ts4 * Description: Monotonic ULID generation — globally unique, time-ordered identifiers.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { randomBytes } from "node:crypto";1112/** Crockford base32 alphabet (no I, L, O, U). */13const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";14const TIME_LENGTH = 10;15const RANDOM_LENGTH = 16;1617let lastTime = -1;18/** Random part as 16 base32 digits (0–31 each) — incremented within the same millisecond. */19let lastRandom: number[] = [];2021function encodeTime(time: number): string {22  let t = time;23  const chars = new Array<string>(TIME_LENGTH);24  for (let i = TIME_LENGTH - 1; i >= 0; i--) {25    chars[i] = ENCODING[t % 32] as string;26    t = Math.floor(t / 32);27  }28  return chars.join("");29}3031function freshRandomDigits(): number[] {32  const bytes = randomBytes(RANDOM_LENGTH);33  const digits = new Array<number>(RANDOM_LENGTH);34  for (let i = 0; i < RANDOM_LENGTH; i++) {35    digits[i] = (bytes[i] as number) % 32;36  }37  return digits;38}3940function incrementDigits(digits: number[]): void {41  for (let i = RANDOM_LENGTH - 1; i >= 0; i--) {42    const d = digits[i] as number;43    if (d < 31) {44      digits[i] = d + 1;45      return;46    }47    digits[i] = 0;48  }49  // Full overflow within one millisecond is practically unreachable; restart randomly.50  const fresh = freshRandomDigits();51  for (let i = 0; i < RANDOM_LENGTH; i++) digits[i] = fresh[i] as number;52}5354/**55 * Generate a ULID: 10 chars of 48-bit epoch-millisecond time + 16 chars of randomness.56 * Monotonic within a process: two calls in the same millisecond produce57 * lexicographically increasing ids.58 */59export function ulid(time: number = Date.now()): string {60  if (!Number.isInteger(time) || time < 0 || time > 2 ** 48 - 1) {61    throw new RangeError(`ulid: time out of range: ${time}`);62  }63  if (time === lastTime) {64    incrementDigits(lastRandom);65  } else {66    lastTime = time;67    lastRandom = freshRandomDigits();68  }69  let random = "";70  for (let i = 0; i < RANDOM_LENGTH; i++) {71    random += ENCODING[lastRandom[i] as number] as string;72  }73  return encodeTime(time) + random;74}7576/** Structural check for a ULID string. */77export function isUlid(value: string): boolean {78  if (value.length !== TIME_LENGTH + RANDOM_LENGTH) return false;79  for (const ch of value) {80    if (!ENCODING.includes(ch)) return false;81  }82  return true;83}84