1const CONTACTS_ENDPOINT = '/v2/contacts'; 2const CONTACT_REQUIRED_INFO_SUFFIX = '/required_info'; 3 4/** 5 * @typedef {object} ContactCountry 6 * @property {number} id 7 * @property {string} countryCode 8 * @property {boolean} inEU 9 * @property {number} callingCode 10 * @property {string} i18n 11 * @property {number} vat_percentage 12 * @property {string} vat_prefix 13 */ 14 15/** 16 * @typedef {object} ContactAddress 17 * @property {ContactCountry} country 18 * @property {number} country_id 19 * @property {string} postal_code 20 * @property {string} city 21 * @property {string} address_line_first 22 */ 23 24/** 25 * @typedef {object} ContactBillingProfile 26 * @property {number} id 27 * @property {number} account_id 28 * @property {number} customer_id 29 */ 30 31/** 32 * @typedef {object} ContactDomainName 33 * @property {number} id 34 * @property {string} domain_name 35 * @property {string} status 36 */ 37 38/** 39 * @typedef {object} Contact 40 * @property {number} id 41 * @property {string} first_name 42 * @property {string} last_name 43 * @property {string} company_name 44 * @property {string} vat_number 45 * @property {string} email 46 * @property {string} phone_number 47 * @property {ContactAddress} address 48 * @property {boolean} is_default 49 * @property {Record<string, unknown>[]} contact_additional_info 50 * @property {ContactBillingProfile[]} billing_profile 51 * @property {ContactDomainName[]} domain_names 52 * @property {number} vat_percentage 53 * @property {string} vat_type 54 */ 55 56const requireMethod = (fetcher, method) => { 57 if (!fetcher || typeof fetcher[method] !== 'function') { 58 throw new Error('Missing fetcher'); 59 } 60 return fetcher[method].bind(fetcher); 61}; 62 63const getContactPath = (contactId, suffix = '') => 64 `${CONTACTS_ENDPOINT}/${encodeURIComponent(String(contactId))}${suffix}`; 65 66const getCollectionItems = (payload) => { 67 if (Array.isArray(payload)) { 68 return payload; 69 } 70 71 for (const key of ['data', 'contacts', 'items', 'results']) { 72 if (Array.isArray(payload?.[key])) { 73 return payload[key]; 74 } 75 } 76 77 return []; 78}; 79 80export const fetchContact = (fetcher, contactId) => 81 requireMethod(fetcher, 'getJson')(getContactPath(contactId), { 82 credentials: 'include', 83 cacheMode: 'no-store', 84 }); 85 86/** 87 * Fetches contacts matching the supplied filters. 88 * 89 * @param {{ getJson: Function }} fetcher 90 * @param {{ userId?: number|string, page?: number, itemsPerPage?: number, pagination?: boolean, timeoutMs?: number, cacheMode?: string, signal?: AbortSignal }} [filters] 91 * @returns {Promise<Contact[]>} 92 */ 93export const fetchContacts = async ( 94 fetcher, 95 { userId, page, itemsPerPage, pagination = false, timeoutMs, cacheMode = 'no-store', signal } = {}, 96) => { 97 const response = await requireMethod(fetcher, 'getJson')(CONTACTS_ENDPOINT, { 98 searchParams: { 99 ...(userId ? { user: userId } : {}), 100 ...(page ? { page } : {}), 101 ...(itemsPerPage ? { itemsPerPage } : {}), 102 pagination, 103 }, 104 cacheMode, 105 credentials: 'include', 106 ...(signal ? { signal } : {}), 107 ...(timeoutMs ? { timeoutMs } : {}), 108 }); 109 return getCollectionItems(response); 110}; 111 112/** 113 * Creates a contact. 114 * 115 * @param {{ postJson: Function }} fetcher 116 * @param {Record<string, unknown>} body 117 * @returns {Promise<Contact>} 118 */ 119export const createContact = (fetcher, body) => 120 requireMethod(fetcher, 'postJson')(CONTACTS_ENDPOINT, { 121 credentials: 'include', 122 body, 123 }); 124 125/** 126 * Updates a contact. 127 * 128 * @param {{ patchJson: Function }} fetcher 129 * @param {number|string} contactId 130 * @param {Record<string, unknown>} body 131 * @returns {Promise<Contact>} 132 */ 133export const updateContact = (fetcher, contactId, body) => 134 requireMethod(fetcher, 'patchJson')(getContactPath(contactId), { 135 credentials: 'include', 136 body, 137 }); 138 139/** 140 * Deletes a contact. 141 * 142 * @param {{ deleteJson: Function }} fetcher 143 * @param {number|string} contactId 144 * @returns {Promise<unknown>} 145 */ 146export const deleteContact = (fetcher, contactId) => 147 requireMethod(fetcher, 'deleteJson')(getContactPath(contactId), { 148 credentials: 'include', 149 }); 150 151/** 152 * Saves registry-specific information for a contact. 153 * 154 * @param {{ patchJson: Function }} fetcher 155 * @param {number|string} contactId 156 * @param {Record<string, unknown>} body 157 * @returns {Promise<unknown>} 158 */ 159export const updateContactRequiredInfo = (fetcher, contactId, body) => 160 requireMethod(fetcher, 'patchJson')(getContactPath(contactId, CONTACT_REQUIRED_INFO_SUFFIX), { 161 credentials: 'include', 162 body, 163 });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.