import type {Upload} from './Upload.js' const ASCII_SPACE = ' '.codePointAt(0) const ASCII_COMMA = ','.codePointAt(0) const BASE64_REGEX = /^[\d+/A-Za-z]*={0,2}$/ export function validateKey(key: string) { if (key.length === 0) { return false } for (let i = 0; i < key.length; ++i) { const charCodePoint = key.codePointAt(i) as number if ( charCodePoint > 127 || charCodePoint === ASCII_SPACE || charCodePoint === ASCII_COMMA ) { return false } } return true } export function validateValue(value: string) { if (value.length % 4 !== 0) { return false } return BASE64_REGEX.test(value) } export function parse(str?: string) { const meta: Record = {} if (!str || str.trim().length === 0) { throw new Error('Metadata string is not valid') } for (const pair of str.split(',')) { const tokens = pair.split(' ') const [key, value] = tokens if ( ((tokens.length === 1 && validateKey(key)) || (tokens.length === 2 && validateKey(key) && validateValue(value))) && !(key in meta) ) { const decodedValue = value ? Buffer.from(value, 'base64').toString('utf8') : null meta[key] = decodedValue } else { throw new Error('Metadata string is not valid') } } return meta } export function stringify(metadata: NonNullable): string { return Object.entries(metadata) .map(([key, value]) => { if (value === null) { return key } const encodedValue = Buffer.from(value, 'utf8').toString('base64') return `${key} ${encodedValue}` }) .join(',') }