(function () { const STORAGE_KEY = "lapp.pendingItemUpdates"; function readQueue() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); } catch (error) { return []; } } function writeQueue(queue) { localStorage.setItem(STORAGE_KEY, JSON.stringify(queue)); } function queueRequest(request) { const queue = readQueue(); const queuedRequest = { url: request.url, method: request.method || "GET", coalesceKey: request.coalesceKey || null, clientUpdatedAt: request.clientUpdatedAt || Date.now() }; if (queuedRequest.coalesceKey) { const existingIndex = queue.findIndex(function (item) { return item.coalesceKey === queuedRequest.coalesceKey; }); if (existingIndex >= 0) { queue[existingIndex] = queuedRequest; } else { queue.push(queuedRequest); } } else { queue.push(queuedRequest); } writeQueue(queue); } async function sendRequest(request) { const url = new URL(request.url, window.location.origin); if (request.clientUpdatedAt) { url.searchParams.set("client_updated_at", request.clientUpdatedAt); } const response = await fetch(url.toString(), { method: request.method || "GET", cache: "no-store", credentials: "same-origin" }); if (response.redirected && new URL(response.url).pathname === "/login") { const error = new Error("Login required"); error.retryable = true; throw error; } if (!response.ok) { const error = new Error("Request failed: " + response.status); error.retryable = response.status >= 500 || response.status === 408 || response.status === 429; throw error; } return response; } async function queueableItemRequest(url, options) { const request = Object.assign({}, options || {}, { url: url, clientUpdatedAt: Date.now() }); try { await sendRequest(request); flushItemUpdateQueue(); return true; } catch (error) { if (error.retryable !== false) { queueRequest(request); } return false; } } async function flushItemUpdateQueue() { if (flushItemUpdateQueue.running) { return; } flushItemUpdateQueue.running = true; const queue = readQueue(); const remaining = []; for (const request of queue) { try { await sendRequest(request); } catch (error) { if (error.retryable !== false) { remaining.push(request); } } } writeQueue(remaining); flushItemUpdateQueue.running = false; } window.lappQueueItemRequest = queueableItemRequest; window.lappFlushItemUpdateQueue = flushItemUpdateQueue; window.addEventListener("online", flushItemUpdateQueue); document.addEventListener("visibilitychange", function () { if (!document.hidden) { flushItemUpdateQueue(); } }); document.addEventListener("DOMContentLoaded", flushItemUpdateQueue); })();