// BizGaze user-directory search (cross-tenant). The auth token is kept SERVER-SIDE only — the // browser calls /api/directory/search and never sees the token. Configure via env in production: // BIZGAZE_DIRECTORY_URL (base, the search term is appended url-encoded) // BIZGAZE_DIRECTORY_TOKEN (the "stat ..." Authorization header value) const DEFAULT_URL = 'https://app.bizgaze.com/apis/v4/bizgaze/integrations/users_chatsearch/get_usersforchatsearch/searchterm/'; const DEFAULT_TOKEN = 'stat 3cd2e190b4db448496ae316b155d2441'; function baseUrl() { return process.env.BIZGAZE_DIRECTORY_URL || DEFAULT_URL; } function token() { return process.env.BIZGAZE_DIRECTORY_TOKEN || DEFAULT_TOKEN; } function enabled() { return !!(baseUrl() && token()); } // Pull a field from an object by any of several case-insensitive key names. function field(o, names) { const keys = Object.keys(o || {}); for (const want of names) { for (const k of keys) { if (k.toLowerCase() === want) { const v = o[k]; if (v != null && v !== '') return String(v); } } } return ''; } // BizGaze responses vary (raw array, or wrapped in Result/data, sometimes a JSON string). Normalize. function toArray(data) { let d = data; if (typeof d === 'string') { try { d = JSON.parse(d); } catch (_) { return []; } } if (Array.isArray(d)) return d; if (d && typeof d === 'object') { for (const key of ['Result', 'result', 'data', 'Data', 'records', 'Records', 'items', 'Items']) { if (d[key] != null) { let v = d[key]; if (typeof v === 'string') { try { v = JSON.parse(v); } catch (_) {} } if (Array.isArray(v)) return v; } } } return []; } function pick(o) { return { id: field(o, ['userid', 'id', 'contactid', 'partyid', 'recordid']), name: field(o, ['fullname', 'name', 'displayname', 'username', 'contactname', 'firstname']), email: field(o, ['email', 'emailaddress', 'emailid', 'mail']), phone: field(o, ['mobile', 'mobilenumber', 'phone', 'phonenumber', 'contactno', 'contactnumber']), avatar: field(o, ['photourl', 'photo', 'avatar', 'imageurl', 'profilepic', 'profileimage']), org: field(o, ['organization', 'organisation', 'company', 'tenantname', 'orgname']), }; } async function search(term) { if (!enabled() || !term || term.trim().length < 2) return []; const url = baseUrl() + encodeURIComponent(term.trim()); const ctrl = new AbortController(); const to = setTimeout(() => ctrl.abort(), 8000); try { const r = await fetch(url, { headers: { Authorization: token(), Accept: 'application/json' }, signal: ctrl.signal }); if (!r.ok) return []; const data = await r.json().catch(() => null); return toArray(data).map(pick).filter((x) => x.name || x.email || x.phone).slice(0, 25); } catch (_) { return []; } finally { clearTimeout(to); } } module.exports = { search, enabled };