/** * Encode a key to be safe for use as a filesystem path. * * @param key - The key to encode * @returns Filesystem-safe encoded key * * @remarks * Encodes characters that are problematic in filenames: * - Forward slash (/) → %2F * - Backslash (\) → %5C * - Colon (:) → %3A * - Asterisk (*) → %2A * - Question mark (?) → %3F * - Quote (") → %22 * - Less than (<) → %3C * - Greater than (>) → %3E * - Pipe (|) → %7C * - Percent (%) → %25 * - Null byte → %00 * * @example * ```typescript * const key = 'user:123/profile.json'; * const encoded = encodeKey(key); * // Result: 'user%3A123%2Fprofile.json' * ``` */ export function encodeKey(key: string): string { return key .replace(/%/g, '%25') // Must be first! .replace(/\//g, '%2F') .replace(/\\/g, '%5C') .replace(/:/g, '%3A') .replace(/\*/g, '%2A') .replace(/\?/g, '%3F') .replace(/"/g, '%22') .replace(//g, '%3E') .replace(/\|/g, '%7C') .replace(/\0/g, '%00'); } /** * Decode a filesystem-safe key back to original form. * * @param encoded - The encoded key * @returns Original key * * @example * ```typescript * const encoded = 'user%3A123%2Fprofile.json'; * const key = decodeKey(encoded); * // Result: 'user:123/profile.json' * ``` */ export function decodeKey(encoded: string): string { return encoded .replace(/%2F/g, '/') .replace(/%5C/g, '\\') .replace(/%3A/g, ':') .replace(/%2A/g, '*') .replace(/%3F/g, '?') .replace(/%22/g, '"') .replace(/%3C/g, '<') .replace(/%3E/g, '>') .replace(/%7C/g, '|') .replace(/%00/g, '\0') .replace(/%25/g, '%'); // Must be last! }