const PREFIX = 'mhu1_'; export function encode(payload) { if (!payload || typeof payload !== 'object') { throw new Error('encode: payload must be an object'); } const json = JSON.stringify(payload); const b64 = Buffer.from(json, 'utf8').toString('base64url'); return PREFIX + b64; } export function decode(code) { if (typeof code !== 'string') { throw new Error('Invalid code: expected a string'); } const trimmed = code.trim(); if (!trimmed.startsWith(PREFIX)) { throw new Error('Invalid code: missing "mhu1_" prefix'); } const b64 = trimmed.slice(PREFIX.length); if (!b64) { throw new Error('Invalid code: empty payload'); } let json; try { json = Buffer.from(b64, 'base64url').toString('utf8'); } catch { throw new Error('Invalid code: not valid base64url'); } let payload; try { payload = JSON.parse(json); } catch { throw new Error('Invalid code: payload is not valid JSON'); } if (!payload || typeof payload !== 'object') { throw new Error('Invalid code: payload is not an object'); } if (payload.v !== 1) { throw new Error(`Invalid code: unsupported version (expected v=1, got ${payload.v})`); } if (typeof payload.port !== 'number' || !Number.isFinite(payload.port)) { throw new Error('Invalid code: "port" must be a number'); } if (typeof payload.token !== 'string' || payload.token.length === 0) { throw new Error('Invalid code: "token" must be a non-empty string'); } if (typeof payload.label !== 'string') { throw new Error('Invalid code: "label" must be a string'); } if (payload.fp !== undefined && typeof payload.fp !== 'string') { throw new Error('Invalid code: "fp" must be a string when present'); } return payload; }