// import axios from 'axios'; export const temp_post_blob_percent_completed = 0; export const post_blob_percent_completed = temp_post_blob_percent_completed; export const temp_post_object_percent_completed = 0; export const post_object_percent_completed = temp_post_object_percent_completed; // Updated 2026-01-07 export const post_object = async function post_object({ api_cfg = null, endpoint = '', headers = {}, params = {}, data = {}, form_data = null, return_meta = false, return_blob = false, filename = '', auto_download = false, // The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event. task_id = crypto.randomUUID(), log_lvl = 0, retry_count = 5 }: { api_cfg: any; endpoint: string; headers?: any; params?: any; data?: any; form_data?: any; return_meta?: boolean; return_blob?: boolean; filename?: string; auto_download?: boolean; task_id?: string; log_lvl?: number; retry_count?: number; }) { if (log_lvl) { console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`); console.log('Params:', params); if (log_lvl > 1) { console.log('Data:', data); console.log(typeof data); console.log(`Base URL: ${api_cfg['base_url']}`); console.log('API Config:', api_cfg); } if (log_lvl > 2) { console.log(`Return Meta: ${return_meta}`); console.log(`Return Blob: ${return_blob}`); console.log(`Filename: ${filename}`); console.log(`Auto Download: ${auto_download}`); } } // console.log('HERE!! API POST 0'); if (!api_cfg) { console.error('No API Config was provided. Returning false.'); return false; } // console.log('HERE!! API POST 1'); // Construct the URL with query parameters const url = new URL(endpoint, api_cfg['base_url']); if (params) { Object.keys(params).forEach((key) => url.searchParams.append(key, params[key])); } // console.log('HERE!! API POST 2'); // Clean and merge headers const headers_cleaned: Record = {}; const merged_headers = { ...api_cfg['headers'], ...headers }; for (const prop in merged_headers) { const prop_cleaned = prop.replaceAll('_', '-'); let value = merged_headers[prop]; if (value === null || value === undefined) continue; if (typeof value !== 'string') { value = JSON.stringify(value); } headers_cleaned[prop_cleaned] = value; } // Auto-inject Authorization header if JWT is present but header is missing const jwt = headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt']; if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) { headers_cleaned['Authorization'] = `Bearer ${jwt}`; } if (form_data) { // headers_cleaned['Content-Type'] = 'multipart/form-data'; delete headers_cleaned['content-type']; delete headers_cleaned['Content-Type']; console.log('Form Data:', form_data); } else { headers_cleaned['Content-Type'] = 'application/json'; } if (log_lvl > 1) { console.log('Final cleaned headers:', headers_cleaned); } // console.log('HERE!! API POST 4'); for (let attempt = 1; attempt <= retry_count; attempt++) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => { console.error('API POST request timed out.'); controller.abort(); }, 20000); // 20-second timeout const fetchOptions: RequestInit = { method: 'POST', headers: headers_cleaned, body: form_data ? form_data : JSON.stringify(data), signal: controller.signal }; console.log('Final fetch options for post_object:', fetchOptions); if (log_lvl > 1) { console.log('Fetch Options:', fetchOptions); } const response = await fetch(url.toString(), fetchOptions); clearTimeout(timeoutId); // Clear the timeout if the request completes in time if (log_lvl) { console.log(`Response: status=${response.status} attempt=${attempt}`); } if (!response.ok) { if (response.status === 404) { console.warn('404 Not Found. Returning null.'); return null; // Returning null since there were no results } const errorBody = await response.text(); console.error(`HTTP error! status: ${response.status}`, errorBody); // Don't retry on client errors (400, 401, 403) if (response.status >= 400 && response.status < 404) { return false; } throw new Error(`HTTP error! status: ${response.status} - ${errorBody}`); } if (!return_blob) { const json = await response.json(); if (log_lvl > 1) { console.log('Response JSON:', json); } // Post a message to the window indicating the upload is complete try { if (typeof window !== 'undefined') { window.postMessage( { type: 'api_post_json_form', status: 'complete', task_id: task_id, endpoint: endpoint, size_total: 0, size_loaded: 0, percent_completed: 100, progress: 100, rate: 0 }, '*' ); } } catch (error) { console.error('Error posting message to window:', error); } // Return the response data or metadata return return_meta ? json : json.data; } else { const blob = await response.blob(); if (auto_download) { const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.setAttribute('download', filename || 'download'); document.body.appendChild(link); link.click(); link.remove(); return true; } else { return blob; } } } catch (error) { console.error(`API POST error on attempt ${attempt}:`, error); // If this is the last attempt, return false if (attempt === retry_count) { console.error('Max retry attempts reached. Returning false.'); return false; } // Log retry information if (log_lvl) { console.log(`Retrying... (${attempt}/${retry_count})`); } } } // let axios_api = axios.create({ // baseURL: api_cfg['base_url'], // /* other custom settings */ // }); // axios_api.defaults.headers = api_cfg['headers']; // console.log('Axios API', axios_api); // // console.log('Axios API POST', axios_api.post); // // if (typeof data == 'FormData') { // if (form_data) { // axios_api.defaults.headers['content-type'] = 'multipart/form-data'; // data = form_data; // } else { // axios_api.defaults.headers['content-type'] = 'application/json'; // } // if (!return_blob) { // let response_data = await axios_api.post( // endpoint, // data, // { // params: params, // onUploadProgress: (progressEvent) => { // let percent_completed = Math.round( // (progressEvent.loaded * 100) / progressEvent.total // ); // console.log('POST Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); // temp_post_object_percent_completed = percent_completed; // try { // window.postMessage({ // type: 'api_post_json_form', // status: 'uploading', // task_id: task_id, // endpoint: endpoint, // size_total: progressEvent.total, // size_loaded: progressEvent.loaded, // percent_completed: percent_completed, // progress: progressEvent.progress, // rate: progressEvent.rate, // }, // '*' // ); // } catch (error) { // console.log('Error posting message to window:', error); // } // } // } // ) // .then(function (response) { // console.log('POST Response Data:', response.data); // try { // window.postMessage({ // type: 'api_post_json_form', // status: 'complete', // task_id: task_id, // endpoint: endpoint, // size_total: 0, // size_loaded: 0, // percent_completed: 100, // progress: 100, // rate: 0, // }, // '*' // ); // } catch (error) { // console.log('Error posting message to window:', error); // } // if (response.data['data'].result === null) { // // This should mean that the request was successful, but a result of None/null was returned from Aether API. // // console.log('Returning null after POST'); // return null; // } else { // // This should mean that the request was successful, and a result with data was returned from Aether API. // // console.log('Returning data after POST'); // return response.data['data']; // } // //return response.data; // }) // .catch(function (error: any) { // if (error.response && error.response.status === 404) { // return null; // Returning null since there were no results // } // console.log(error); // return false; // Returning false since something may have gone wrong. Also more in line with what the API returns. // // return error; // }); // if (log_lvl > 1) { // console.log('Response Data:', response_data); // } // axios_api.defaults.headers['content-type'] = 'application/json'; // return response_data; // } else { // // console.log('Expecting a Blob to be returned...'); // let response_data_promise = await axios_api.post( // endpoint, // data, // { // params: params, // responseType: 'blob', // onDownloadProgress: (progressEvent) => { // let percent_completed = Math.round( // (progressEvent.loaded * 100) / progressEvent.total // ); // console.log('POST Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); // temp_post_blob_percent_completed = percent_completed; // } // } // ) // .then(function (response) { // if (log_lvl) { // console.log(response); // } // const { data, headers } = response // console.log(headers); // if (filename) { // } else if (headers['content-disposition']) { // filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1'); // } else { // filename = 'unknown_file.ext'; // } // if (auto_download) { // const url = window.URL.createObjectURL(new Blob([response.data])); // const link = document.createElement('a'); // link.href = url; // // link.setAttribute('download', 'event_exhibit_tracking_export.xlsx'); //or any other extension // link.setAttribute('download', filename); //or any other extension // document.body.appendChild(link); // link.click(); // return true; // } else { // return response; // } // }); // if (response_data_promise) { // // The most common and expected response. // // console.log('Returning result. This is generally expected.'); // // let test_blob = new Blob([response_data_promise.data]); // // console.log(test_blob); // // return test_blob; // // console.log(response_data_promise.blob()); // return response_data_promise; // } else { // // This generally should not happen. It likely means the query was bad or an API issue. // console.log('Returning unknown. This should not happen in most cases.'); // Promise.reject(new Error('fail')).then(resolved, rejected); // } // } }; // function resolved(result: any) { // console.log('Resolved'); // } // function rejected(result: any) { // console.error(result); // }