An encrypted personal cloud built on the AT Protocol.
1// Base64, fingerprint, and AT-URI encoding utilities.
2
3/** Standard base64 from bytes. */
4export function uint8ArrayToBase64(bytes: Uint8Array): string {
5 let binary = "";
6 for (const byte of bytes) {
7 binary += String.fromCharCode(byte);
8 }
9 return btoa(binary);
10}
11
12/** Base64 to bytes — handles unpadded strings (PDS returns unpadded). */
13export function base64ToUint8Array(b64: string): Uint8Array {
14 // Pad to multiple of 4
15 const padded = b64 + "=".repeat((4 - (b64.length % 4)) % 4);
16 const binary = atob(padded);
17 const bytes = new Uint8Array(binary.length);
18 for (let i = 0; i < binary.length; i++) {
19 bytes[i] = binary.charCodeAt(i);
20 }
21 return bytes;
22}
23
24/** First 8 bytes of a public key as a colon-separated hex fingerprint. */
25export function formatFingerprint(pubkey: Uint8Array): string {
26 return Array.from(pubkey.slice(0, 8))
27 .map((b) => b.toString(16).padStart(2, "0"))
28 .join(":");
29}
30
31/** Extract the rkey from an AT-URI: `at://did/collection/rkey` → `rkey`. */
32export function rkeyFromUri(atUri: string): string {
33 const parts = atUri.split("/");
34 const rkey = parts.at(-1);
35 if (!rkey) throw new Error(`Invalid AT-URI: ${atUri}`);
36 return rkey;
37}