diff --git a/src/lib/ae_api/api_get__crud_obj_li_v2.ts b/src/lib/ae_api/api_get__crud_obj_li_v2.ts index 4cd5002c..077e363c 100644 --- a/src/lib/ae_api/api_get__crud_obj_li_v2.ts +++ b/src/lib/ae_api/api_get__crud_obj_li_v2.ts @@ -178,7 +178,8 @@ export async function get_ae_obj_li_for_obj_id_crud_v2( // NOTE: The order_by_li variable is in the "headers" because if is a the URL GET params do not handle multiple values very well. Maybe base64 encore in the future or something? Reminder that GET requests should not have a body (no JSON). // NOTE: The order_by_li should be a key value pair of the property/DB field to sort and how to sort (ASC or DESC) if (order_by_li) { - headers['order_by_li'] = order_by_li; + // headers['order_by_li'] = order_by_li; + headers['order_by_li'] = JSON.stringify(order_by_li); } if (limit >= 0) { diff --git a/src/lib/ae_api/api_get_object.ts b/src/lib/ae_api/api_get_object.ts index 44b5f37f..d6189e09 100644 --- a/src/lib/ae_api/api_get_object.ts +++ b/src/lib/ae_api/api_get_object.ts @@ -1,58 +1,50 @@ -import axios from 'axios'; - import type { key_val } from '$lib/ae_stores'; export let temp_get_blob_percent_completed = 0; -// export let get_blob_percent_completed = readable(temp_get_blob_percent_completed); export let get_blob_percent_completed = temp_get_blob_percent_completed; export let temp_get_object_percent_completed = 0; -// export let get_object_percent_completed = readable(temp_get_object_percent_completed); export let get_object_percent_completed = temp_get_object_percent_completed; -// Updated 2024-05-23 +// This is now a complete re-write without Axios. This is a simple fetch API call. +// Updated 2024-11-20 export let get_object = async function get_object( - { - api_cfg=null, - endpoint='', - headers={}, - params={}, - data={}, - timeout=60000, - return_meta=false, - return_blob=false, - filename='', - auto_download=false, - as_list=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 - }: { - api_cfg: any, - endpoint: string, - headers?: any, - params?: any, - data?: any, - timeout?: number, - return_meta?: boolean, - return_blob?: boolean, - filename?: null|string, - auto_download?: boolean, - as_list?: boolean, - task_id?: string, - log_lvl?: number - } - ) { + { + api_cfg = null, + endpoint = '', + headers = {}, + params = {}, + data = {}, + timeout = 60000, + // return_meta = false, + return_blob = false, + filename = '', + auto_download = false, + as_list = false, // Is this still really needed? + // 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 + }: { + api_cfg: any, + endpoint: string, + headers?: any, + params?: any, + data?: any, + timeout?: number, + // return_meta?: boolean, + return_blob?: boolean, + filename?: null | string, + auto_download?: boolean, + as_list?: boolean, + task_id?: string, + log_lvl?: number + } +) { if (log_lvl) { console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`); console.log('Params:', params); if (log_lvl > 1) { console.log('Data:', data); - console.log(`Base URL: ${api_cfg['base_url']}; Timeout: ${timeout}`); - console.log('API Config:', api_cfg); - } - if (log_lvl > 2) { - console.log(`Return Meta: ${return_meta}; Return Blob: ${return_blob}; Filename: ${filename}; Auto Download: ${auto_download}`); } } @@ -61,15 +53,15 @@ export let get_object = async function get_object( return false; } - let axios_api = axios.create({ - baseURL: api_cfg['base_url'], - timeout: timeout, // in milliseconds; 60000 = 60 seconds - /* other custom settings */ - }); - axios_api.defaults.headers = api_cfg['headers']; - if (log_lvl) { - console.log('axios_api.defaults.headers:', axios_api.defaults.headers); - console.log('Additional headers:', headers); + const url = new URL(endpoint, api_cfg['base_url']); + Object.keys(params).forEach(key => url.searchParams.append(key, params[key])); + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeout); + + // Remove a header parameter if it is set to null + if (api_cfg['headers'].hasOwnProperty('x-no-account-id') && api_cfg['headers']['x-no-account-id'] === null) { + delete api_cfg['headers']['x-no-account-id']; } // console.log('Clean the headers. No _underscores_!') @@ -94,403 +86,101 @@ export let get_object = async function get_object( console.log('All headers cleaned:', headers); } + const fetchOptions: RequestInit = { + method: 'GET', + headers: { + ...api_cfg['headers'], + ...headers + }, + signal: controller.signal + }; + if (log_lvl) { - console.log('URL params:'); - } - for (const prop in params) { - if (log_lvl > 1) { - console.log(`URL param: ${prop}: ${params[prop]}`); - } - if (params[prop] === null ) { - params[prop] = 'null'; - } + console.log('Fetch options:', fetchOptions); } - // Handle the case where there is no Blob expected to be returned. Mainly JSON and text data. - if (!return_blob) { - let response_data_promise = await axios_api.get( - endpoint, - { - headers: headers, - params: params, - onDownloadProgress: (progressEvent) => { - let percent_completed = Math.round( - (progressEvent.loaded * 100) / progressEvent.total - ); - if (log_lvl > 1) { - console.log('GET Data Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); - } + try { + const response = await fetch(url.toString(), fetchOptions); + clearTimeout(timeoutId); - temp_get_object_percent_completed = percent_completed; + if (log_lvl) { + console.log(`Response: status=${response.status} statusText=${response.statusText} url=${response.url}`); + } - // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. - try { - // Check if window is defined. This is to prevent errors in SvelteKit. - if (typeof window !== 'undefined') { - window.postMessage({ - type: 'api_download_data', - status: 'downloading', - task_id: task_id, - endpoint: endpoint, - filename: filename, - size_total: progressEvent.total, - size_loaded: progressEvent.loaded, - percent_completed: percent_completed, - }, - '*' - ); - } - } catch (error) { - console.log('Error posting message to window:', error); - } - } - } - ) - .then(function (response) { - if (log_lvl) { - console.log(`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`); - } - if (log_lvl > 1) { - console.log('GET Response:', response); - } - - // Post file download message - try { - if (typeof window !== 'undefined') { - window.postMessage({ - type: 'api_download_data', - status: 'complete', - task_id: task_id, - endpoint: endpoint, - filename: filename, - size_total: 0, - size_loaded: 0, - percent_completed: 100, - }, - '*' - ); - } - } catch (error) { - console.log('Error posting message to window:', error); - } - - if (!Array.isArray(response.data['data']) && as_list) { - if (log_lvl) { - console.log('Data result is a dictionary/object, not an array/list. Forcing return as an array/list'); - } - let return_data = []; - return_data.push(response.data['data']); - return return_data; - } else if (response.data['data']) { - let return_data = response.data['data']; - if (log_lvl) { - if (Array.isArray(return_data)) { - console.log(`Data result is an array/list. Array length: ${return_data.length}`); - } else { - console.log(`Data result is a dictionary/object, not an array/list.`); - } - } - return return_data; - } else { - let return_data = response.data; - if (log_lvl) { - if (Array.isArray(return_data)) { - console.log(`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`); - } else { - console.log(`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`); - } - } - return return_data; - } - }) - .catch(function (error) { - // Handle the common and expected 404 "error" first - if (error.response && error.response.status === 404) { + if (!response.ok) { + if (response.status === 404) { if (log_lvl) { console.log('The response was a 404 not found "error". Returning null.'); } - if (log_lvl > 1) { - console.log(error.response); - } - if (log_lvl > 2) { - console.log(error); - } - - // Post file download message - try { - if (typeof window !== 'undefined') { - window.postMessage({ - type: 'api_download_data', - status: 'complete', - task_id: task_id, - endpoint: endpoint, - filename: filename, - size_total: 0, - size_loaded: 0, - percent_completed: 0, - }, - '*' - ); - } - } catch (error) { - console.log('Error posting message to window:', error); - } - return null; // Returning null since there were no results + return null; } - - if (log_lvl) { - console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`); - console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion??? - - if (error.response) { - // The request was made and the server responded with a status code that falls out of the range of 2xx - console.log('Error Response Data', error.response.data); - console.log('Error Response Status', error.response.status); - console.log('Error Response Headers', error.response.headers); - } else if (error.request) { - // The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js - if (log_lvl > 1) { - console.log('Error Request', error.request); - } - } else { - // Something happened in setting up the request that triggered an Error - console.log('Error Message', error.message); - } - } - if (log_lvl > 2) { - console.log('Error:', error); - console.log(error.config); - } - - if (error.code === 'ECONNABORTED') { - // Timeout Error (You can implement retry here where suitable) - console.log('Timeout Error: ', error.message); - } - if (log_lvl) { - console.log('The response was an error. Returning false.'); - } - - return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns. - // return error; - }); - - if (log_lvl > 1) { - // console.log(`Response Data: ${response_data_promise}`); - console.log(`Response Data:`, response_data_promise); - // console.log(response_data_promise); + throw new Error(`HTTP error! status: ${response.status}`); } - if (response_data_promise) { - // The most common and expected response. - // console.log('Returning result. This is generally expected.'); - return response_data_promise; - } else if (response_data_promise === null) { - // Less common, but expected response if no results were returned. - if (log_lvl) { - console.log('Returning null. This is expected if no results were found. (404)'); + + if (!return_blob) { + const json = await response.json(); + if (log_lvl > 1) { + console.log('Response JSON:', json); } - return response_data_promise; - } else if (response_data_promise === false) { - // Not common, but expected response if the request to the API had an issue. - console.log('Returning false. There may have been an issue with this request.'); - return response_data_promise; + if (!Array.isArray(json.data) && as_list) { + return [json.data]; + } + return json.data || json; } else { - // This generally should not happen. It likely means the query was bad or an API issue. - console.log('Returning (JSON/text) unknown. This should not happen in most cases.'); - Promise.reject(new Error('fail')).then(resolved, rejected); - } + const reader = response.body?.getReader(); + const contentLength = +response.headers.get('Content-Length')!; + let receivedLength = 0; + const chunks = []; - // Handle the case where a Blob is expected to be returned. - } else { + while (true) { + const { done, value } = await reader!.read(); + if (done) break; + chunks.push(value); + receivedLength += value.length; - // console.log('Expecting a Blob to be returned...'); - - let response_data_promise = await axios_api.get( - endpoint, - { - params: params, - responseType: 'blob', - onDownloadProgress: (progressEvent) => { - let percent_completed = Math.round( - (progressEvent.loaded * 100) / progressEvent.total - ); - console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); - - temp_get_blob_percent_completed = percent_completed; - - // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. - try { - if (typeof window !== 'undefined') { - window.postMessage({ - type: 'api_download_blob', - status: 'downloading', - task_id: task_id, - endpoint: endpoint, - filename: filename, - size_total: progressEvent.total, - size_loaded: progressEvent.loaded, - percent_completed: percent_completed, - }, - '*' - ); - } - } catch (error) { - console.log('Error posting message to window:', error); - } - } - } - ) - .then(function (response) { - if (log_lvl) { - console.log(`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`); - } - if (log_lvl > 1) { - console.log('GET (blob) Response:', response); - } - - const { data, headers } = response; - - // Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it. - if (filename) { - } else if (headers['content-disposition']) { - filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1'); - } else { - filename = 'unknown_file.ext'; - } - - // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. - try { - if (typeof window !== 'undefined') { - window.postMessage({ - type: 'api_download_blob', - status: 'complete', - task_id: task_id, - endpoint: endpoint, - filename: filename, - size_total: 0, - size_loaded: 0, - percent_completed: 100, - }, - '*' - ); - } - } catch (error) { - console.log('Error posting message to window:', error); - } - - if (auto_download) { - if (log_lvl) { - console.log(`Auto Download: ${filename}`); - } - const url = window.URL.createObjectURL(new Blob([response.data])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', filename); - document.body.appendChild(link); - link.click(); - return true; - } else { - return response; - } - }) - .catch(function (error) { - // Handle the common and expected 404 "error" first - if (error.response && error.response.status === 404) { - if (log_lvl) { - console.log('The response was a 404 not found "error". Returning null.'); - } + const percent_completed = Math.round((receivedLength * 100) / contentLength); if (log_lvl > 1) { - console.log(error.response); - } - if (log_lvl > 2) { - console.log(error); + console.log('GET Blob Progress:', percent_completed, 'Total:', contentLength, 'Loaded:', receivedLength, 'Percent Completed', percent_completed); } - // Post file download message + temp_get_blob_percent_completed = percent_completed; + try { if (typeof window !== 'undefined') { window.postMessage({ type: 'api_download_blob', - status: 'complete', + status: 'downloading', task_id: task_id, endpoint: endpoint, filename: filename, - size_total: 0, - size_loaded: 0, - percent_completed: 0, - }, - '*' - ); + size_total: contentLength, + size_loaded: receivedLength, + percent_completed: percent_completed + }, '*'); } - } catch (error) { - console.log('Error posting message to window:', error); - } - return null; // Returning null since there were no results - } - - if (log_lvl) { - console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`); - console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion??? - - if (error.response) { - // The request was made and the server responded with a status code that falls out of the range of 2xx - console.log('Error Response Data', error.response.data); - console.log('Error Response Status', error.response.status); - console.log('Error Response Headers', error.response.headers); - } else if (error.request) { - // The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js - if (log_lvl > 1) { - console.log('Error Request', error.request); - } - } else { - // Something happened in setting up the request that triggered an Error - console.log('Error Message', error.message); + } catch (e) { + console.error('Error posting message:', e); } } - if (error.code === 'ECONNABORTED') { - // Timeout Error (You can implement retry here where suitable) - console.log('Timeout Error: ', error.message); + const blob = new Blob(chunks); + 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; } - - if (log_lvl) { - console.log('The response was an error. Returning false.'); - } - - return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns. - // return error; - }); - - 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 if (response_data_promise === null) { - // Less common, but expected response if no results were returned. - if (log_lvl) { - console.log('Returning null. This is expected if no results were found. (404)'); - } - return response_data_promise; - } else if (response_data_promise === false) { - // Not common, but expected response if the request to the API had an issue. - console.log('Returning false. There may have been an issue with this request.'); - return response_data_promise; - } else { - // This generally should not happen. It likely means the query was bad or an API issue. - console.log('Returning (blob) unknown. This should not happen in most cases.'); - Promise.reject(new Error('fail')).then(resolved, rejected); } + } catch (error) { + if (log_lvl) { + console.log('Fetch error:', error); + } + return false; } -} - - -function resolved(result: any) { - console.log('Resolved'); -} - -function rejected(result: any) { - console.error(result); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/lib/ae_api/api_get_object_v1.ts b/src/lib/ae_api/api_get_object_v1.ts new file mode 100644 index 00000000..44b5f37f --- /dev/null +++ b/src/lib/ae_api/api_get_object_v1.ts @@ -0,0 +1,496 @@ +import axios from 'axios'; + +import type { key_val } from '$lib/ae_stores'; + +export let temp_get_blob_percent_completed = 0; +// export let get_blob_percent_completed = readable(temp_get_blob_percent_completed); +export let get_blob_percent_completed = temp_get_blob_percent_completed; + +export let temp_get_object_percent_completed = 0; +// export let get_object_percent_completed = readable(temp_get_object_percent_completed); +export let get_object_percent_completed = temp_get_object_percent_completed; + +// Updated 2024-05-23 +export let get_object = async function get_object( + { + api_cfg=null, + endpoint='', + headers={}, + params={}, + data={}, + timeout=60000, + return_meta=false, + return_blob=false, + filename='', + auto_download=false, + as_list=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 + }: { + api_cfg: any, + endpoint: string, + headers?: any, + params?: any, + data?: any, + timeout?: number, + return_meta?: boolean, + return_blob?: boolean, + filename?: null|string, + auto_download?: boolean, + as_list?: boolean, + task_id?: string, + log_lvl?: number + } + ) { + if (log_lvl) { + console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`); + console.log('Params:', params); + if (log_lvl > 1) { + console.log('Data:', data); + console.log(`Base URL: ${api_cfg['base_url']}; Timeout: ${timeout}`); + console.log('API Config:', api_cfg); + } + if (log_lvl > 2) { + console.log(`Return Meta: ${return_meta}; Return Blob: ${return_blob}; Filename: ${filename}; Auto Download: ${auto_download}`); + } + } + + if (!api_cfg) { + console.log('No API Config was provided. Returning false.'); + return false; + } + + let axios_api = axios.create({ + baseURL: api_cfg['base_url'], + timeout: timeout, // in milliseconds; 60000 = 60 seconds + /* other custom settings */ + }); + axios_api.defaults.headers = api_cfg['headers']; + if (log_lvl) { + console.log('axios_api.defaults.headers:', axios_api.defaults.headers); + console.log('Additional headers:', headers); + } + + // console.log('Clean the headers. No _underscores_!') + let headers_cleaned: key_val = {}; + for (const prop in headers) { + // No underscores allowed in the header parameters! + let prop_cleaned = prop.replaceAll('_', '-'); + + // The value must be a string for the header! + if (typeof headers[prop] != 'string') { + headers[prop] = JSON.stringify(headers[prop]); + } + + headers_cleaned[prop_cleaned] = headers[prop]; + + if (log_lvl) { + console.log(`${prop_cleaned}: ${headers_cleaned[prop_cleaned]}`); + } + } + headers = headers_cleaned; + if (log_lvl) { + console.log('All headers cleaned:', headers); + } + + if (log_lvl) { + console.log('URL params:'); + } + for (const prop in params) { + if (log_lvl > 1) { + console.log(`URL param: ${prop}: ${params[prop]}`); + } + if (params[prop] === null ) { + params[prop] = 'null'; + } + } + + // Handle the case where there is no Blob expected to be returned. Mainly JSON and text data. + if (!return_blob) { + let response_data_promise = await axios_api.get( + endpoint, + { + headers: headers, + params: params, + onDownloadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + if (log_lvl > 1) { + console.log('GET Data Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + } + + temp_get_object_percent_completed = percent_completed; + + // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. + try { + // Check if window is defined. This is to prevent errors in SvelteKit. + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_data', + status: 'downloading', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + } + } + ) + .then(function (response) { + if (log_lvl) { + console.log(`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`); + } + if (log_lvl > 1) { + console.log('GET Response:', response); + } + + // Post file download message + try { + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_data', + status: 'complete', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: 0, + size_loaded: 0, + percent_completed: 100, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + + if (!Array.isArray(response.data['data']) && as_list) { + if (log_lvl) { + console.log('Data result is a dictionary/object, not an array/list. Forcing return as an array/list'); + } + let return_data = []; + return_data.push(response.data['data']); + return return_data; + } else if (response.data['data']) { + let return_data = response.data['data']; + if (log_lvl) { + if (Array.isArray(return_data)) { + console.log(`Data result is an array/list. Array length: ${return_data.length}`); + } else { + console.log(`Data result is a dictionary/object, not an array/list.`); + } + } + return return_data; + } else { + let return_data = response.data; + if (log_lvl) { + if (Array.isArray(return_data)) { + console.log(`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`); + } else { + console.log(`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`); + } + } + return return_data; + } + }) + .catch(function (error) { + // Handle the common and expected 404 "error" first + if (error.response && error.response.status === 404) { + if (log_lvl) { + console.log('The response was a 404 not found "error". Returning null.'); + } + if (log_lvl > 1) { + console.log(error.response); + } + if (log_lvl > 2) { + console.log(error); + } + + // Post file download message + try { + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_data', + status: 'complete', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: 0, + size_loaded: 0, + percent_completed: 0, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + return null; // Returning null since there were no results + } + + if (log_lvl) { + console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`); + console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion??? + + if (error.response) { + // The request was made and the server responded with a status code that falls out of the range of 2xx + console.log('Error Response Data', error.response.data); + console.log('Error Response Status', error.response.status); + console.log('Error Response Headers', error.response.headers); + } else if (error.request) { + // The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js + if (log_lvl > 1) { + console.log('Error Request', error.request); + } + } else { + // Something happened in setting up the request that triggered an Error + console.log('Error Message', error.message); + } + } + if (log_lvl > 2) { + console.log('Error:', error); + console.log(error.config); + } + + if (error.code === 'ECONNABORTED') { + // Timeout Error (You can implement retry here where suitable) + console.log('Timeout Error: ', error.message); + } + if (log_lvl) { + console.log('The response was an error. Returning false.'); + } + + return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns. + // return error; + }); + + if (log_lvl > 1) { + // console.log(`Response Data: ${response_data_promise}`); + console.log(`Response Data:`, response_data_promise); + // console.log(response_data_promise); + } + if (response_data_promise) { + // The most common and expected response. + // console.log('Returning result. This is generally expected.'); + return response_data_promise; + } else if (response_data_promise === null) { + // Less common, but expected response if no results were returned. + if (log_lvl) { + console.log('Returning null. This is expected if no results were found. (404)'); + } + return response_data_promise; + } else if (response_data_promise === false) { + // Not common, but expected response if the request to the API had an issue. + console.log('Returning false. There may have been an issue with this request.'); + return response_data_promise; + } else { + // This generally should not happen. It likely means the query was bad or an API issue. + console.log('Returning (JSON/text) unknown. This should not happen in most cases.'); + Promise.reject(new Error('fail')).then(resolved, rejected); + } + + // Handle the case where a Blob is expected to be returned. + } else { + + // console.log('Expecting a Blob to be returned...'); + + let response_data_promise = await axios_api.get( + endpoint, + { + params: params, + responseType: 'blob', + onDownloadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_get_blob_percent_completed = percent_completed; + + // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. + try { + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_blob', + status: 'downloading', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + } + } + ) + .then(function (response) { + if (log_lvl) { + console.log(`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`); + } + if (log_lvl > 1) { + console.log('GET (blob) Response:', response); + } + + const { data, headers } = response; + + // Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it. + if (filename) { + } else if (headers['content-disposition']) { + filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1'); + } else { + filename = 'unknown_file.ext'; + } + + // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. + try { + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_blob', + status: 'complete', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: 0, + size_loaded: 0, + percent_completed: 100, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + + if (auto_download) { + if (log_lvl) { + console.log(`Auto Download: ${filename}`); + } + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + return true; + } else { + return response; + } + }) + .catch(function (error) { + // Handle the common and expected 404 "error" first + if (error.response && error.response.status === 404) { + if (log_lvl) { + console.log('The response was a 404 not found "error". Returning null.'); + } + if (log_lvl > 1) { + console.log(error.response); + } + if (log_lvl > 2) { + console.log(error); + } + + // Post file download message + try { + if (typeof window !== 'undefined') { + window.postMessage({ + type: 'api_download_blob', + status: 'complete', + task_id: task_id, + endpoint: endpoint, + filename: filename, + size_total: 0, + size_loaded: 0, + percent_completed: 0, + }, + '*' + ); + } + } catch (error) { + console.log('Error posting message to window:', error); + } + return null; // Returning null since there were no results + } + + if (log_lvl) { + console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`); + console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion??? + + if (error.response) { + // The request was made and the server responded with a status code that falls out of the range of 2xx + console.log('Error Response Data', error.response.data); + console.log('Error Response Status', error.response.status); + console.log('Error Response Headers', error.response.headers); + } else if (error.request) { + // The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js + if (log_lvl > 1) { + console.log('Error Request', error.request); + } + } else { + // Something happened in setting up the request that triggered an Error + console.log('Error Message', error.message); + } + } + + if (error.code === 'ECONNABORTED') { + // Timeout Error (You can implement retry here where suitable) + console.log('Timeout Error: ', error.message); + } + + if (log_lvl) { + console.log('The response was an error. Returning false.'); + } + + return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns. + // return error; + }); + + 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 if (response_data_promise === null) { + // Less common, but expected response if no results were returned. + if (log_lvl) { + console.log('Returning null. This is expected if no results were found. (404)'); + } + return response_data_promise; + } else if (response_data_promise === false) { + // Not common, but expected response if the request to the API had an issue. + console.log('Returning false. There may have been an issue with this request.'); + return response_data_promise; + } else { + // This generally should not happen. It likely means the query was bad or an API issue. + console.log('Returning (blob) 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); +} \ No newline at end of file diff --git a/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte b/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte index b121c490..819cde80 100644 --- a/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte +++ b/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte @@ -58,16 +58,30 @@ $: lq_new__event_obj_li = liveQuery(async () => { if (log_lvl) { console.log(`Trying where: ${link_to_type}; equals: ${link_to_id}`); } - let results = await db_events.events - .where(`${link_to_type}_id`) - .equals(link_to_id) - .and((event) => { - return event.hide == false; - }) - .and((event) => { - return event.enable == true; - }) - .sortBy('name') + let results: any = null; + if ($idaa_loc.recovery_meetings.qry__order_by == 'name') { + results = await db_events.events + .where(`${link_to_type}_id`) + .equals(link_to_id) + .and((event) => { + return event.hide == false; + }) + .and((event) => { + return event.enable == true; + }) + .sortBy('name') + } else { + results = await db_events.events + .where(`${link_to_type}_id`) + .equals(link_to_id) + .and((event) => { + return event.hide == false; + }) + .and((event) => { + return event.enable == true; + }) + .sortBy('updated_on') + } return results; } else { @@ -198,7 +212,7 @@ $: if ($idaa_trig.event_li_qry) { qry_str: $idaa_loc.recovery_meetings.qry__fulltext_str, params: params, try_cache: try_cache, - log_lvl: log_lvl, + log_lvl: 2, }) .then(function (search_results) { // Processing the results from the search.