wip library to store cold objects in s3, warm objects on disk, and hot objects in memory
nodejs typescript
at main 2.5 kB view raw
1/** 2 * Encode a key to be safe for use as a filesystem path. 3 * 4 * @param key - The key to encode 5 * @param encodeColons - Whether to encode colons as %3A (default: false) 6 * @returns Filesystem-safe encoded key 7 * 8 * @remarks 9 * Preserves forward slashes to create directory structure. 10 * Encodes characters that are problematic in filenames: 11 * - Backslash (\) → %5C 12 * - Colon (:) → %3A (when encodeColons is true, invalid on Windows) 13 * - Asterisk (*) → %2A 14 * - Question mark (?) → %3F 15 * - Quote (") → %22 16 * - Less than (<) → %3C 17 * - Greater than (>) → %3E 18 * - Pipe (|) → %7C 19 * - Percent (%) → %25 20 * - Null byte → %00 21 * 22 * @example 23 * ```typescript 24 * const key = 'did:plc:abc123/site/index.html'; 25 * 26 * // Encode colons (Windows/cross-platform) 27 * const encoded = encodeKey(key, true); 28 * // Result: 'did%3Aplc%3Aabc123/site/index.html' 29 * // Creates: cache/did%3Aplc%3Aabc123/site/index.html 30 * 31 * // Preserve colons (Unix/macOS with readable paths) 32 * const readable = encodeKey(key, false); 33 * // Result: 'did:plc:abc123/site/index.html' 34 * // Creates: cache/did:plc:abc123/site/index.html 35 * ``` 36 */ 37export function encodeKey(key: string, encodeColons = false): string { 38 let result = key 39 .replace(/%/g, '%25') // Must be first! 40 .replace(/\\/g, '%5C'); 41 42 if (encodeColons) { 43 result = result.replace(/:/g, '%3A'); 44 } 45 46 return result 47 .replace(/\*/g, '%2A') 48 .replace(/\?/g, '%3F') 49 .replace(/"/g, '%22') 50 .replace(/</g, '%3C') 51 .replace(/>/g, '%3E') 52 .replace(/\|/g, '%7C') 53 .replace(/\0/g, '%00'); 54} 55 56/** 57 * Decode a filesystem-safe key back to original form. 58 * 59 * @param encoded - The encoded key 60 * @param decodeColons - Whether to decode %3A to : (default: false) 61 * @returns Original key 62 * 63 * @example 64 * ```typescript 65 * const encoded = 'did%3Aplc%3Aabc123/site/index.html'; 66 * 67 * // Decode with colons 68 * const key = decodeKey(encoded, true); 69 * // Result: 'did:plc:abc123/site/index.html' 70 * 71 * // Decode without colons (already readable) 72 * const readable = decodeKey('did:plc:abc123/site/index.html', false); 73 * // Result: 'did:plc:abc123/site/index.html' 74 * ``` 75 */ 76export function decodeKey(encoded: string, decodeColons = false): string { 77 let result = encoded 78 .replace(/%5C/g, '\\') 79 .replace(/%2A/g, '*') 80 .replace(/%3F/g, '?') 81 .replace(/%22/g, '"') 82 .replace(/%3C/g, '<') 83 .replace(/%3E/g, '>') 84 .replace(/%7C/g, '|') 85 .replace(/%00/g, '\0'); 86 87 if (decodeColons) { 88 result = result.replace(/%3A/g, ':'); 89 } 90 91 return result.replace(/%25/g, '%'); // Must be last! 92}