Spreadsheet-UX op een echte relationele engine
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
import { randomBytes } from 'node:crypto';
const ALPHABET = '0123456789abcdefghijkmnpqrstvwxyz'; // Crockford-ish: no i, l, o, u
const BASE = ALPHABET.length;
/** Milliseconds, base-33, fixed width — nine digits reach the year 3400. */
const STAMP_WIDTH = 9;
/**
* Bumped instead of reused when two ids land in one millisecond, so ids sort
* in the order they were made even inside a single import loop.
*/
let lastStamp = 0;
/**
* Collision-resistant, URL-safe, time-ordered row identifier.
*
* Time-ordered is load-bearing: an unsorted grid is `ORDER BY id`, so ids made
* in sequence have to sort in sequence — an imported spreadsheet keeps its
* file order, and a new row lands at the bottom instead of wherever twelve
* random characters happen to fall. The random tail keeps two servers that
* share a millisecond from sharing an id.
*/
export function newId(prefix = ''): string {
const now = Date.now();
lastStamp = now > lastStamp ? now : lastStamp + 1;
let stamp = '';
for (let rest = lastStamp, i = 0; i < STAMP_WIDTH; i++) {
stamp = ALPHABET[rest % BASE] + stamp;
rest = Math.floor(rest / BASE);
}
let out = stamp;
for (const b of randomBytes(7)) out += ALPHABET[b % BASE];
return prefix ? `${prefix}_${out}` : out;
}
/** Row ids are user-visible in the address bar; keep them tightly shaped. */
export function isValidId(id: string): boolean {
return /^[A-Za-z0-9_-]{1,64}$/.test(id);
}