mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 15:36:33 +00:00
42 lines
1.7 KiB
TypeScript
42 lines
1.7 KiB
TypeScript
/**
|
|
* Ids for the things a book is made of.
|
|
*
|
|
* Every panel that places an element mints one, and they were four copies of
|
|
* the same line: a prefix, `Math.random().toString(36)` and a slice. Copies of
|
|
* a line drift, and this one had already drifted in its slice length. Moved
|
|
* here from the Studio (client/src/components/Studio/bookIds.ts) so the editor,
|
|
* the layouts and the server's book tools mint them the same way.
|
|
*
|
|
* `getRandomValues` rather than `Math.random`: TREK's own quickstart is plain
|
|
* http on a LAN address, where `crypto.randomUUID` is undefined but
|
|
* `getRandomValues` still works, and every Node TREK supports has it as a
|
|
* global too. A book document is shared over a websocket and merged by whoever
|
|
* saves last, so two editors minting the same id for two different elements is
|
|
* a collision that shows up as one of them losing their work. A runtime without
|
|
* Web Crypto at all (none TREK supports) still gets an id that is unique within
|
|
* its own session, from the clock and a counter.
|
|
*
|
|
* Seven characters, as before: 36^7 is about 78 billion, against a document
|
|
* that holds a few hundred elements.
|
|
*/
|
|
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
|
|
interface RandomSource {
|
|
getRandomValues?: (bytes: Uint8Array) => Uint8Array;
|
|
}
|
|
|
|
let fallbackSeq = 0;
|
|
|
|
export function bookElementId(prefix: string): string {
|
|
const c = (globalThis as { crypto?: RandomSource }).crypto;
|
|
if (c && typeof c.getRandomValues === 'function') {
|
|
const bytes = new Uint8Array(7);
|
|
c.getRandomValues(bytes);
|
|
let out = '';
|
|
for (const b of bytes) out += ALPHABET[b % ALPHABET.length];
|
|
return `${prefix}-${out}`;
|
|
}
|
|
fallbackSeq += 1;
|
|
return `${prefix}-${(Date.now() * 1000 + fallbackSeq).toString(36).slice(-7)}`;
|
|
}
|