function writeGuard(outcome,current,receipt,originalOperationId){ const reason=outcome?.readyToWrite!==true||outcome.state!=='settled'||outcome.resultState!=='settled'?'result_not_ready': !/^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i.test(originalOperationId||'')||outcome.operationId!==originalOperationId?'operation_changed': !receipt||!['phone','messaging','complete'].includes(receipt.profile)||receipt.operationId!==originalOperationId?'receipt_required': !current||current.locationId!==receipt.locationId||current.id!==receipt.recordId?'contact_or_location_changed': current.revision!==receipt.revision?'source_revision_changed':current.phone!==receipt.phone?'source_phone_changed': (current.country?.toUpperCase()??null)!==receipt.country?'source_country_changed': !receipt.e164||outcome.result?.number?.valid!==true||outcome.result.number.e164!==receipt.e164||outcome.fields?.qp_phone_e164!==receipt.e164?'result_phone_changed': !outcome.result?.requestId||outcome.fields?.qp_phone_request_id!==outcome.result.requestId?'request_id_missing': current.lastRequestId===outcome.result.requestId?'already_written':null; if(reason)return {write:false,reason,operationId:originalOperationId??null}; const owned={phone:['e164','country','type','carrier','ported','sms','sms_basis','reachable','checked_at','request_id'],messaging:['e164','country','whatsapp','telegram','checked_at','request_id'],complete:['e164','country','type','carrier','ported','sms','sms_basis','whatsapp','telegram','reachable','checked_at','request_id']}[receipt.profile]; const fields={}; for(const suffix of owned){const key='qp_phone_'+suffix;if(typeof outcome.fields[key]!=='string')return {write:false,reason:'result_field_missing',operationId:originalOperationId};fields[key]=outcome.fields[key];} return {write:true,reason:null,operationId:originalOperationId,fields}; } function mappedContact(input){ if(!input||typeof input!=='object'||Array.isArray(input))throw Error('Native contact inputs required.'); // HighLevel parses number-like input values, including a leading +. // A fixed text prefix prevents coercion; never reconstruct lost digits. if(typeof input.sourcePhone!=='string'||!input.sourcePhone.startsWith('phone:'))throw Error('Map the source phone with its phone: text prefix.'); const fields={locationId:input.locationId,id:input.contactId,phone:input.sourcePhone.slice(6),revision:input.sourceRevision}; if(Object.values(fields).some(v=>typeof v!=='string'||!v||/\{\{.*\}\}/.test(v)))throw Error('Resolve the native contact fields before running.'); // Empty native fields may arrive as numeric 0. Preserve emptiness with a // literal prefix at the mapping boundary; never infer an ID from a number. const country=typeof input.sourceCountry==='string'&&input.sourceCountry.startsWith('country:')?input.sourceCountry.slice(8):input.sourceCountry; if(country!==undefined&&country!==''&&(typeof country!=='string'||!/^[A-Za-z]{2}$/.test(country)))throw Error('Use a known two-letter country or leave it empty for international input.'); const lastRequestId=typeof input.lastRequestId==='string'&&input.lastRequestId.startsWith('request:')?input.lastRequestId.slice(8):input.lastRequestId; if(lastRequestId!==undefined&&(typeof lastRequestId!=='string'||lastRequestId.length>250||/\{\{.*\}\}/.test(lastRequestId)))throw Error('Request reference must be resolved text.'); return{...fields,...(country?{country:country.toUpperCase()}:{}),lastRequestId:lastRequestId||''}; } function nativeObject(value,name){ let parsed=value; if(typeof value==='string'){ try{parsed=JSON.parse(value);}catch(error){ // Native workflow interpolation HTML-encodes the JSON string. Decode // exactly one layer only when the opening JSON key is visibly encoded. if(!/^\s*\{(?:"|"|")/i.test(value))throw error; const entities={'quot':'"','amp':'&','apos':"'",'lt':'<','gt':'>'}; const decoded=value.replace(/&(#x[0-9a-f]+|#[0-9]+|quot|amp|apos|lt|gt);/gi,(entity,key)=>{ if(key[0]!=='#')return entities[key.toLowerCase()]??entity; const point=key[1].toLowerCase()==='x'?parseInt(key.slice(2),16):parseInt(key.slice(1),10); return point>0&&point<=0x10ffff?String.fromCodePoint(point):entity; }); parsed=JSON.parse(decoded); } } if(!parsed||typeof parsed!=='object'||Array.isArray(parsed))throw Error(name+' must be a JSON object.'); return parsed; } var output = writeGuard(nativeObject(inputData.outcome,'outcome'), mappedContact(inputData), nativeObject(inputData.receipt,'receipt'), inputData.originalOperationId); return output;