import { readFile, stat } from 'node:fs/promises'; import { parseAPI, ParseAPIError } from '@parseapi/sdk'; const sample = [ { number: '(415) 555-2671', country: 'US' }, { number: '020 7946 0958', country: 'GB' }, { number: '+33 1 42 68 53 00' }, { number: '123', country: 'US' } ]; async function readRows() { if (process.argv.length > 3) throw new Error('Use: node normalize-phone-numbers.node.mjs [phones.json]'); if (!process.argv[2]) return sample; if ((await stat(process.argv[2])).size > 65536) throw new Error('Use a JSON file smaller than 64 KiB.'); const rows = JSON.parse(await readFile(process.argv[2], 'utf8')); if (!Array.isArray(rows) || rows.length === 0 || rows.length > 100) { throw new Error('Supply an array containing 1 to 100 phone records.'); } return rows; } // example:result function emptyResult(input) { return { input, valid: null, phone: null, country: null, national: null, international: null, error: null }; } function foldResult(input, data) { if (!data || typeof data.valid !== 'boolean' || (data.valid && (typeof data.phone !== 'string' || !/^\+[1-9]\d{1,14}$/.test(data.phone)))) { return { ...emptyResult(input), error: { code: 'unexpected_response', status: null } }; } const text = (value) => typeof value === 'string' && value.length > 0 ? value : null; return { input, valid: data.valid, phone: data.valid ? data.phone : null, country: text(data.country), national: data.valid ? text(data.national) : null, international: data.valid ? text(data.international) : null, error: null }; } // /example:result async function main() { const rows = await readRows(); // Reads PARSEAPI_KEY. Keep this secret key on the server. const parse = parseAPI(undefined, { timeoutMs: 10000, retries: 0 }); const results = []; let stopped = false; // example:request for (const row of rows) { const result = emptyResult(row); const number = typeof row?.number === 'string' ? row.number.trim() : ''; const country = typeof row?.country === 'string' ? row.country.trim().toUpperCase() : undefined; if (!number || number.length > 100 || (row.country != null && !/^[A-Z]{2}$/.test(country ?? ''))) { result.error = { code: 'invalid_input', status: null }; results.push(result); continue; } if (stopped) { result.error = { code: 'not_attempted', status: null }; results.push(result); continue; } try { const data = await parse.phone(number, country ? { country } : {}); results.push(foldResult(row, data)); } catch (error) { result.error = error instanceof ParseAPIError ? { code: error.code, status: error.status } : { code: 'request_failed', status: null }; results.push(result); // Fix key/access/allowance errors before spending more attempts on this file. if (error instanceof ParseAPIError && [401, 403, 429].includes(error.status)) stopped = true; } } // /example:request process.stdout.write(`${JSON.stringify(results, null, 2)}\n`); // An invalid number is a completed check. A failed check needs attention. if (results.some((row) => row.error !== null)) process.exitCode = 2; } main().catch(() => { console.error('Could not start. Check PARSEAPI_KEY and provide a JSON array of 1 to 100 records (under 64 KiB).'); process.exitCode = 1; });