@datocms/cma-client
Version:
JS client for DatoCMS REST Content Management API
89 lines (68 loc) • 2.39 kB
text/typescript
import { v4 } from 'uuid';
function fromUint8ArrayToUrlSafeBase64(bytes: Uint8Array) {
const base64 =
typeof Buffer === 'undefined'
? btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(''))
: Buffer.from(bytes).toString('base64');
// Convert to URL-safe format (see RFC 4648, sec. 5)
return (
base64
// Replace + with -
.replace(/\+/g, '-')
// Replace / with _
.replace(/\//g, '_')
// Drop '==' padding
.substring(0, 22)
);
}
function fromUrlSafeBase64toUint8Array(urlSafeBase64: string): Uint8Array {
// Convert from URL-safe format (see RFC 4648, sec. 5)
const base64 = urlSafeBase64
// Replace - with +
.replace(/-/g, '+')
// Replace _ with /
.replace(/_/g, '/');
return typeof Buffer === 'undefined'
? Uint8Array.from(atob(base64), (c) => c.charCodeAt(0))
: new Uint8Array(Buffer.from(base64, 'base64'));
}
export function isValidId(id: string) {
// For backward compatibility, first check to see if this is an older-style integer ID formerly used by Dato
if (/^\d+$/.test(id)) {
const intId = BigInt(id);
const maxDatoIntegerId = 281474976710655; // Max 6-byte/48-bit unsigned int
return intId <= maxDatoIntegerId;
}
const bytes = fromUrlSafeBase64toUint8Array(id);
// UUIDs are 16 bytes
if (bytes.length !== 16) {
return false;
}
// The variant field determines the layout of the UUID
// (see RFC 4122, sec. 4.1.1)
const variant = bytes.at(8)!;
// Variant must be the one described in RFC 4122
if ((variant & 0b11000000) !== 0b10000000) {
return false;
}
// The version number is in the most significant 4 bits
// of the time stamp (see RFC 4122, sec. 4.1.3)
const version = bytes.at(6)! >> 4;
// Version number must be 4 (randomly generated)
if (version !== 0x4) {
return false;
}
return true;
}
export function generateId() {
const bytes = v4(null, new Uint8Array(16));
// Here we unset the first bit to ensure [A-Za-f] as the first char.
//
// If we didn't do this, we would generate IDs that, once encoded
// in base64, could start with a '+' or a '/'. This makes them less
// easy to copy/paste, with bad DX.
// This choice is purely aesthetic: definitely non-mandatory!
bytes[0] = bytes[0]! & 0x7f;
const base64 = fromUint8ArrayToUrlSafeBase64(bytes);
return base64;
}