diff --git a/src/lib/ae_api/api_get_object.ts b/src/lib/ae_api/api_get_object.ts index cc060d83..fbd3a16e 100644 --- a/src/lib/ae_api/api_get_object.ts +++ b/src/lib/ae_api/api_get_object.ts @@ -158,19 +158,29 @@ export const get_object = async function get_object({ const response = await fetch_method(url.toString(), fetchOptions).catch(function ( error: any ) { + // SILENCE NOISE: Aborted requests (common in SWR/Background loads) shouldn't spam logs + if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') { + if (log_lvl > 1) { + console.log('API GET: Request was aborted or terminated by browser. This is expected during navigation.', error); + } + return error; // Return error to be handled below + } + console.log( - 'API GET Object *fetch* request was aborted or failed in an unexpected way.', + 'API GET Object *fetch* request failed in an unexpected way.', error ); - // Return the error so we can check it return error; }); clearTimeout(timeoutId); - // If the catch returned an Error object instead of a Response - if (response instanceof Error || (response && response.name === 'TypeError')) { - console.log('API GET Object: Detected NetworkError or TypeError. Failing fast.'); - return false; // Skip retries for dead servers/DNS + // Check if we should stop due to abort or network failure + if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) { + // If it was an explicit abort, definitely stop + if (response.name === 'AbortError') return false; + + if (log_lvl > 1) console.log('API GET Object: Detected NetworkError or TypeError. Failing fast.'); + return false; } if (!response) { diff --git a/src/lib/ae_api/api_post_object.ts b/src/lib/ae_api/api_post_object.ts index e5b4be10..48c54819 100644 --- a/src/lib/ae_api/api_post_object.ts +++ b/src/lib/ae_api/api_post_object.ts @@ -5,7 +5,7 @@ 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-08 +// Updated 2026-01-26 (Abort Silence) export const post_object = async function post_object({ api_cfg = null, endpoint = '', @@ -169,13 +169,29 @@ export const post_object = async function post_object({ const response = await fetch_method(url.toString(), fetchOptions).catch(function ( error: any ) { + // SILENCE NOISE: Aborted requests shouldn't spam logs at log_lvl 0 + if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') { + if (log_lvl > 1) { + console.log('API POST: Request was aborted or terminated by browser. Expected during navigation.', error); + } + return error; + } + console.log( - 'API POST Object *fetch* request was aborted or failed in an unexpected way.', + 'API POST Object *fetch* request failed in an unexpected way.', error ); + return error; }); clearTimeout(timeoutId); + // Check if we should stop due to abort or network failure + if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) { + if (response.name === 'AbortError') return false; + if (log_lvl > 1) console.log('API POST Object: Detected NetworkError or TypeError. Failing fast.'); + return false; + } + if (!response) { throw new Error( `HTTP fetch request was aborted or failed in an unexpected way! URL = ${url.toString()}` diff --git a/src/lib/ae_journals/ae_journals__journal.ts b/src/lib/ae_journals/ae_journals__journal.ts index bc3f3992..4c4d8de7 100644 --- a/src/lib/ae_journals/ae_journals__journal.ts +++ b/src/lib/ae_journals/ae_journals__journal.ts @@ -11,7 +11,7 @@ import { load_ae_obj_li__journal_entry } from '$lib/ae_journals/ae_journals__jou const ae_promises: key_val = {}; -// Updated 2026-01-05 +// Updated 2026-01-26 (SWR Optimization) export async function load_ae_obj_id__journal({ api_cfg, journal_id, @@ -46,75 +46,62 @@ export async function load_ae_obj_id__journal({ log_lvl?: number; }): Promise { if (log_lvl) { - console.log(`*** load_ae_obj_id__journal() *** journal_id=${journal_id}`); + console.log(`*** load_ae_obj_id__journal() *** journal_id=${journal_id} (SWR)`); } - ae_promises.load__journal_obj = await api - .get_ae_obj_v3({ - api_cfg: api_cfg, - obj_type: 'journal', - obj_id: journal_id, - view, - params, - log_lvl: log_lvl - }) - .then(async function (journal_obj_get_result) { - if (journal_obj_get_result) { - if (try_cache) { - // Process the results first - const processed_obj_li = await process_ae_obj__journal_props({ - obj_li: [journal_obj_get_result], - log_lvl: log_lvl - }); - if (log_lvl) { - console.log('Processed object list:', processed_obj_li); - } - // Save the updated results list to the database - await db_save_ae_obj_li__ae_obj({ - db_instance: db_journals, - table_name: 'journal', - obj_li: processed_obj_li, - properties_to_save: properties_to_save, - log_lvl: log_lvl + // 1. FAST PATH: Return cached data immediately + if (try_cache) { + try { + const cached = await db_journals.journal.get(journal_id); + if (cached) { + if (log_lvl) console.log('JOURNAL LOAD: Cache hit. Returning stale data.'); + _refresh_journal_id_background({ + api_cfg, journal_id, view, params, try_cache, + inc_entry_li, enabled, hidden, limit, offset, order_by_li, log_lvl: 0 + }); + if (inc_entry_li && !cached.journal_entry_li) { + cached.journal_entry_li = await load_ae_obj_li__journal_entry({ + api_cfg, for_obj_type: 'journal', for_obj_id: journal_id, + enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl }); } - return journal_obj_get_result; - } else { - console.log('No results returned.'); - return null; + return cached; } - }) - .catch(function (error: any) { - console.log('No results returned or failed.', error); - }); - - if (!ae_promises.load__journal_obj) { - console.log(`ERROR: Journals - Journal - The journal with ID ${journal_id} was not found.`); - return null; + } catch (e) {} } - if (inc_entry_li) { - // Load the entries for the journal - const load_journal_entry_obj_li = await load_ae_obj_li__journal_entry({ - api_cfg: api_cfg, - for_obj_type: 'journal', - for_obj_id: journal_id, - enabled: enabled, - hidden: hidden, - limit: limit, - offset: offset, - order_by_li: order_by_li, - params: params, - try_cache: try_cache, - log_lvl: log_lvl - }); - ae_promises.load__journal_obj.journal_entry_li = load_journal_entry_obj_li; - } - - return ae_promises.load__journal_obj; + // 2. SLOW PATH: Wait for API + return await _refresh_journal_id_background({ + api_cfg, journal_id, view, params, try_cache, + inc_entry_li, enabled, hidden, limit, offset, order_by_li, log_lvl + }); } -// Updated 2026-01-02 +/** + * Internal background refresh for a single journal + */ +async function _refresh_journal_id_background({ api_cfg, journal_id, view, params, try_cache, inc_entry_li, enabled, hidden, limit, offset, order_by_li, log_lvl }: any) { + if (typeof navigator !== 'undefined' && !navigator.onLine) return null; + try { + const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'journal', obj_id: journal_id, view, params, log_lvl }); + if (result) { + if (try_cache) { + const processed = await process_ae_obj__journal_props({ obj_li: [result], log_lvl }); + await db_save_ae_obj_li__ae_obj({ db_instance: db_journals, table_name: 'journal', obj_li: processed, properties_to_save, log_lvl }); + } + if (inc_entry_li) { + result.journal_entry_li = await load_ae_obj_li__journal_entry({ + api_cfg, for_obj_type: 'journal', for_obj_id: journal_id, + enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl + }); + } + return result; + } + } catch (e) {} + return null; +} + +// Updated 2026-01-26 (SWR Optimization) export async function load_ae_obj_li__journal({ api_cfg, for_obj_type = 'account', @@ -151,139 +138,65 @@ export async function load_ae_obj_li__journal({ log_lvl?: number; }): Promise { if (log_lvl) { - console.log( - `*** load_ae_obj_li__journal() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}` - ); + console.log(`*** load_ae_obj_li__journal() *** for=${for_obj_type}:${for_obj_id} (SWR)`); } - let promise; - - if (qry_person_id) { - const search_query: any = { - and: [{ field: 'person_id_random', op: 'eq', value: qry_person_id }] - }; - - if (for_obj_id) { - search_query.and.push({ - field: `${for_obj_type}_id_random`, - op: 'eq', - value: for_obj_id - }); - } - - // Add enabled/hidden filters to search query as V3 search is explicit - if (enabled === 'enabled') { - search_query.and.push({ field: 'enable', op: 'eq', value: true }); - } else if (enabled === 'not_enabled') { - search_query.and.push({ field: 'enable', op: 'eq', value: false }); - } - - if (hidden === 'hidden') { - search_query.and.push({ field: 'hide', op: 'eq', value: true }); - } else if (hidden === 'not_hidden') { - search_query.and.push({ field: 'hide', op: 'eq', value: false }); - } - - if (log_lvl) { - console.log('Using search_ae_obj_v3 with query:', search_query); - } - - promise = api.search_ae_obj_v3({ - api_cfg, - obj_type: 'journal', - search_query, - order_by_li, - limit, - offset, - log_lvl - }); - } else { - promise = api.get_ae_obj_li_v3({ - api_cfg, - obj_type: 'journal', - for_obj_type, - for_obj_id, - enabled, - hidden, - limit, - offset, - order_by_li, - log_lvl - }); - } - - ae_promises.load__journal_obj_li = await promise.then(async function (journal_obj_li_get_result) { - if (journal_obj_li_get_result) { - if (try_cache) { - // Process the results first - const processed_obj_li = await process_ae_obj__journal_props({ - obj_li: journal_obj_li_get_result, - log_lvl: log_lvl + // 1. FAST PATH: Check cache + if (try_cache) { + try { + const cached_li = await db_journals.journal.where('for_id').equals(for_obj_id).toArray(); + if (cached_li && cached_li.length > 0) { + if (log_lvl) console.log(`JOURNAL LIST: Cache hit (${cached_li.length}).`); + _refresh_journal_li_background({ + api_cfg, for_obj_type, for_obj_id, qry_person_id, inc_entry_li, + enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl: 0 }); - if (log_lvl) { - console.log('Processed object list:', processed_obj_li); - } - // Save the updated results list to the database - if (log_lvl) { - console.log('Saving to DB...'); - } - await db_save_ae_obj_li__ae_obj({ - db_instance: db_journals, - table_name: 'journal', - obj_li: processed_obj_li, - properties_to_save: properties_to_save, - log_lvl: log_lvl - }); - if (log_lvl) { - console.log('DB save completed.'); - } + return cached_li; } - return journal_obj_li_get_result; - } else { - return []; - } + } catch (e) {} + } + + // 2. SLOW PATH: API + return await _refresh_journal_li_background({ + api_cfg, for_obj_type, for_obj_id, qry_person_id, inc_entry_li, + enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl }); +} - if (log_lvl) { - console.log('ae_promises.load__journal_obj_li:', ae_promises.load__journal_obj_li); +async function _refresh_journal_li_background({ api_cfg, for_obj_type, for_obj_id, qry_person_id, inc_entry_li, enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl }: any) { + if (typeof navigator !== 'undefined' && !navigator.onLine) return []; + + let promise; + if (qry_person_id) { + const search_query: any = { and: [{ field: 'person_id_random', op: 'eq', value: qry_person_id }] }; + if (for_obj_id) search_query.and.push({ field: `${for_obj_type}_id_random`, op: 'eq', value: for_obj_id }); + if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true }); + if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true }); + + promise = api.search_ae_obj_v3({ api_cfg, obj_type: 'journal', search_query, order_by_li, limit, offset, log_lvl }); + } else { + promise = api.get_ae_obj_li_v3({ api_cfg, obj_type: 'journal', for_obj_type, for_obj_id, enabled, hidden, limit, offset, order_by_li, log_lvl }); } - if (inc_entry_li) { - // Load the entries for the journals - if (log_lvl) { - console.log(`Need to load the entry list for each journal now`); - } - for (let i = 0; i < ae_promises.load__journal_obj_li.length; i++) { - const journal_obj = ae_promises.load__journal_obj_li[i]; - const journal_id = journal_obj.journal_id_random; - - const load_journal_entry_obj_li = load_ae_obj_li__journal_entry({ - api_cfg: api_cfg, - for_obj_type: 'journal', - for_obj_id: journal_id, - enabled: enabled, - hidden: hidden, - limit: limit, - offset: offset, - order_by_li: order_by_li, - params: params, - try_cache: try_cache, - log_lvl: log_lvl - }).then((journal_entry_obj_li) => { - if (log_lvl) { - console.log(`journal_entry_obj_li = `, journal_entry_obj_li); - } - - return journal_entry_obj_li; - }); - - if (log_lvl) { - console.log(`load_journal_entry_obj_li = `, load_journal_entry_obj_li); + try { + const results = await promise; + if (results) { + if (try_cache) { + const processed = await process_ae_obj__journal_props({ obj_li: results, log_lvl }); + await db_save_ae_obj_li__ae_obj({ db_instance: db_journals, table_name: 'journal', obj_li: processed, properties_to_save, log_lvl }); } + if (inc_entry_li) { + for (const journal of results) { + load_ae_obj_li__journal_entry({ + api_cfg, for_obj_type: 'journal', for_obj_id: journal.journal_id_random, + enabled, hidden, limit, offset, order_by_li, params, try_cache, log_lvl: 0 + }); + } + } + return results; } - } - - return ae_promises.load__journal_obj_li; + } catch (e) {} + return []; } // Updated 2026-01-05 @@ -511,10 +424,6 @@ export async function qry__journal({ search_query.and.push({ field: 'start_datetime', op: 'gt', value: qry_start_datetime }); } - // if (qry_str && qry_str.length > 2) { - // // V3 Search full text handling would be added here if supported by backend via specific field or op - // } - // Add for_obj_id context (Account ID) if (journal_id) { // Assuming journal_id here is actually the account_id as per original usage context @@ -582,156 +491,6 @@ export async function qry__journal({ return ae_promises.load__journal_obj_li; } -// This function will loop through the journal_obj_li and save each one to the DB. -// Removed 2025-06-04 -// export async function db_save_ae_obj_li__journal( -// { -// obj_type, -// obj_li, -// log_lvl = 0 -// }: { -// obj_type: string, -// obj_li: any, -// log_lvl?: number -// } -// ) { -// if (log_lvl) { -// console.log(`*** db_save_ae_obj_li__journal() *** obj_type=${obj_type}`, obj_li); -// } - -// if (obj_li && obj_li.length) { -// let obj_li_id: string[] = []; - -// for (const obj of obj_li) { -// // obj_li.forEach(async function (obj: any) { -// if (log_lvl) { -// console.log(`Processing ae_obj ${obj_type}:`, obj); -// } - -// let description = obj.description ?? ''; -// // remove the most common zerowidth characters from the start of the file -// let description_cleaned: string = description.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,""); -// let description_md_html: null|string = await marked.parse(description_cleaned ?? '') ?? null; -// // let description_md_html_alt: null|string = await marked.parse(description_cleaned ?? '', { gfm: false }) ?? null; - -// let obj_record = { -// id: obj.journal_id_random, -// journal_id: obj.journal_id_random, - -// code: obj.code, - -// for_type: obj.for_type, -// for_id: obj.for_id, - -// type_code: obj.type_code, - -// account_id: obj.account_id_random, -// person_id: obj.person_id_random, - -// name: obj.name, -// short_name: obj.short_name, -// summary: obj.summary, -// outline: obj.outline, - -// description: obj.description, -// description_md_html: description_md_html, // Use the markdown parser to generate HTML -// description_html: obj.description_html, -// description_json: obj.description_json, - -// // start_datetime: obj.start_datetime, -// // end_datetime: obj.end_datetime, -// timezone: obj.timezone, - -// alert: obj.alert, -// alert_msg: obj.alert_msg, - -// sort_by: obj.sort_by, -// sort_by_desc: obj.sort_by_desc, - -// cfg_json: obj.cfg_json ?? {}, - -// data_json: obj.data_json ?? {}, - -// // ux_mode: obj.ux_mode, - -// // This only allows for basic access to the data. -// passcode_read: obj.passcode_read, // For LLM (AI) generated summary...??? -// passcode_read_expire: obj.passcode_read_expire, -// passcode_write: obj.passcode_write, -// passcode_write_expire: obj.passcode_write_expire, - -// passcode: obj.passcode, // For Journal Entry encryption password -// passcode_timeout: obj.passcode_timeout, - -// private_passcode: obj.private_passcode, // Combine with Journal passcode to encrypt and decrypt Entries - -// auth_key: obj.auth_key, // For Journal authorization without sign in - -// enable: obj.enable, -// hide: obj.hide, -// priority: obj.priority, -// sort: obj.sort, -// group: obj.group, -// notes: obj.notes, -// created_on: obj.created_on, -// updated_on: obj.updated_on, - -// // Generated fields for sorting locally only -// tmp_sort_1: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.updated_on}_${obj.created_on}`, -// tmp_sort_2: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.updated_on ?? obj.created_on}`, -// tmp_sort_3: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.name}_${obj.updated_on ?? obj.created_on}`, -// // tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`, -// // tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`, - -// combined_passcode: `${obj.passcode}:${obj.private_passcode ?? ''}`, // Combined Journal passcode and Journal private passcode to encrypt and decrypt Entries - -// // From SQL view -// journal_entry_count: obj.journal_entry_count, - -// // A key value list of the others -// // journal_other_kv: obj.journal_other_kv, -// // journal_other_li: obj.journal_other_li, -// }; - -// let id_random = null; - -// try { -// id_random = await db_journals.journal.update(obj_record.id, obj_record); -// } catch (error) { -// console.log(`Error: Failed to update ${obj_record.id}: ${error}`); -// } -// if (!id_random) { -// if (log_lvl) { -// console.log(`Failed to update record with ID: ${obj_record.id}. Trying put...`); -// } -// try { -// id_random = await db_journals.journal.put(obj_record); -// } catch (error) { -// console.log(`Error: Failed to put ${obj.journal_id_random}: ${error}`); -// } -// } else { -// if (log_lvl) { -// console.log(`Updated record with ID: ${obj_record.id}`); -// } -// } -// if (!id_random) { -// console.log(`Failed to save record with ID: ${obj_record.id}`); -// } else { -// if (log_lvl) { -// console.log(`Saved record with ID: ${obj_record.id}`); -// } -// } -// } - -// return obj_li_id; -// } else { -// if (log_lvl) { -// console.log('No objects to save.'); -// } -// return []; -// } -// } - // Updated 2025-05-09 const properties_to_save = [ 'id', @@ -910,4 +669,4 @@ export async function process_ae_obj__journal_props({ return obj; } }); -} +} \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d9c294b7..51a7e680 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1345,6 +1345,17 @@ email = ${$ae_loc?.email} {/if} +{:else if browser && $ae_loc && $ae_loc.allow_access === null} + +
+
+ +
+
Initializing Layout...
+
Determining access context
+
+
+
{:else if browser || flag_reload}
{ - // if (!results) { - // error(404, { - // message: 'Journals - Journal not found' - // }); - // } else { - // // ae_acct.slct.journal_obj = results; - // } - // }) - // .catch((err) => { - // console.error(`Error loading journal object:`, err); - // error(500, { - // message: 'Journals - Error loading journal object' - // }); - // }); - - if (!load_journal_obj) { - console.warn(`ae Journals [journal_id] +layout.ts: Journal ${journal_id} not found via API or Cache.`); - // error(404, { - // message: 'Journals - Journal Entry not found' - // }); - } else { - ae_acct.slct.load_journal_obj = load_journal_obj; - } } // WARNING: Precaution against shared data between sites.