fix: cache webmention API responses in sessionStorage to persist across refreshes
The old sessionStorage rate limiter prevented re-fetching on page refresh, causing webmentions to disappear since they weren't in the build-time HTML. Now caches the actual API response data with a 5-minute TTL so webmentions render instantly from cache on refresh, while still fetching fresh data in the background. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+61
-21
@@ -13,11 +13,6 @@
|
||||
|
||||
if (!target || !domain) return;
|
||||
|
||||
// Rate limit: only fetch once per page load
|
||||
const cacheKey = `wm-fetched-${target}`;
|
||||
if (sessionStorage.getItem(cacheKey)) return;
|
||||
sessionStorage.setItem(cacheKey, '1');
|
||||
|
||||
// Use server-side proxy to keep webmention.io token secure
|
||||
// Fetch both with and without trailing slash since webmention.io
|
||||
// stores targets inconsistently (Bridgy sends different formats)
|
||||
@@ -29,33 +24,47 @@
|
||||
// Check if build-time webmentions section exists
|
||||
const hasBuildTimeSection = document.getElementById('webmentions') !== null;
|
||||
|
||||
Promise.all([
|
||||
fetch(apiUrl1).then((res) => res.json()).catch(() => ({ children: [] })),
|
||||
fetch(apiUrl2).then((res) => res.json()).catch(() => ({ children: [] })),
|
||||
])
|
||||
.then(([data1, data2]) => {
|
||||
// Merge and deduplicate by wm-id
|
||||
const seen = new Set();
|
||||
const allChildren = [];
|
||||
for (const wm of [...(data1.children || []), ...(data2.children || [])]) {
|
||||
if (!seen.has(wm['wm-id'])) {
|
||||
seen.add(wm['wm-id']);
|
||||
allChildren.push(wm);
|
||||
// Cache API responses in sessionStorage (5 min TTL) so webmentions
|
||||
// persist across page refreshes without re-fetching every time
|
||||
const cacheKey = `wm-data-${target}`;
|
||||
const cacheTTL = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
function getCachedData() {
|
||||
try {
|
||||
const cached = sessionStorage.getItem(cacheKey);
|
||||
if (!cached) return null;
|
||||
const parsed = JSON.parse(cached);
|
||||
if (Date.now() - parsed.ts > cacheTTL) {
|
||||
sessionStorage.removeItem(cacheKey);
|
||||
return null;
|
||||
}
|
||||
return parsed.children;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const data = { children: allChildren };
|
||||
if (!data.children || !data.children.length) return;
|
||||
|
||||
function setCachedData(children) {
|
||||
try {
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify({ ts: Date.now(), children: children }));
|
||||
} catch {
|
||||
// sessionStorage full or unavailable - no problem
|
||||
}
|
||||
}
|
||||
|
||||
function processWebmentions(allChildren) {
|
||||
if (!allChildren || !allChildren.length) return;
|
||||
|
||||
let mentionsToShow;
|
||||
if (hasBuildTimeSection) {
|
||||
// Build-time section exists - only show NEW webmentions to avoid duplicates
|
||||
mentionsToShow = data.children.filter((wm) => {
|
||||
mentionsToShow = allChildren.filter((wm) => {
|
||||
const wmTime = new Date(wm['wm-received']).getTime();
|
||||
return wmTime > buildTime;
|
||||
});
|
||||
} else {
|
||||
// No build-time section - show ALL webmentions from API
|
||||
mentionsToShow = data.children;
|
||||
mentionsToShow = allChildren;
|
||||
}
|
||||
|
||||
if (!mentionsToShow.length) return;
|
||||
@@ -92,6 +101,37 @@
|
||||
|
||||
// Update total count in main header
|
||||
updateTotalCount(mentionsToShow.length);
|
||||
}
|
||||
|
||||
// Try cached data first (renders instantly on refresh)
|
||||
const cached = getCachedData();
|
||||
if (cached) {
|
||||
processWebmentions(cached);
|
||||
}
|
||||
|
||||
// Always fetch fresh data (updates cache for next refresh)
|
||||
Promise.all([
|
||||
fetch(apiUrl1).then((res) => res.json()).catch(() => ({ children: [] })),
|
||||
fetch(apiUrl2).then((res) => res.json()).catch(() => ({ children: [] })),
|
||||
])
|
||||
.then(([data1, data2]) => {
|
||||
// Merge and deduplicate by wm-id
|
||||
const seen = new Set();
|
||||
const allChildren = [];
|
||||
for (const wm of [...(data1.children || []), ...(data2.children || [])]) {
|
||||
if (!seen.has(wm['wm-id'])) {
|
||||
seen.add(wm['wm-id']);
|
||||
allChildren.push(wm);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the merged results
|
||||
setCachedData(allChildren);
|
||||
|
||||
// Only render if we didn't already render from cache
|
||||
if (!cached) {
|
||||
processWebmentions(allChildren);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.debug('[Webmentions] Error fetching:', err.message);
|
||||
|
||||
Reference in New Issue
Block a user