Add remote wiki data loading with local cache and BreezeWiki fallback#2
Add remote wiki data loading with local cache and BreezeWiki fallback#2
Conversation
…euristic fallback Agent-Logs-Url: https://github.com/SillyLittleTech/Flean/sessions/e1d6c009-0550-4e30-8402-9f04d1e09994 Co-authored-by: kiyarose <75678535+kiyarose@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Implements on-demand loading of indie-wiki-buddy’s wiki mapping data, caching it locally (compressed) and using it to redirect to independent wikis when available, with fallback to existing BreezeWiki heuristics.
Changes:
- Added a wiki data manager module to fetch, compress, cache, and look up structured wiki mappings.
- Updated background scripts to warm the cache, refresh weekly via alarms, and expose a
findWikimessage API. - Updated content scripts to query the background for structured matches before applying heuristic BreezeWiki redirects; updated overlay copy accordingly.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| mos/Flean Extension/Resources/scripts/wiki-data-manager.js | New module to fetch + cache compressed wiki mapping data and perform URL matching. |
| mos/Flean Extension/Resources/background.js | Initializes/refreshes cached data and exposes lookup via runtime messaging. |
| mos/Flean Extension/Resources/content.js | Uses structured lookup (with timeout) before BreezeWiki heuristic redirect; updates overlay text. |
| mos/Flean Extension/Resources/manifest.json | Adds alarms permission and GitHub raw host permission for data fetches. |
| ios/extention/Resources/scripts/wiki-data-manager.js | iOS copy of the wiki data manager module. |
| ios/extention/Resources/background.js | iOS copy of background initialization/lookup logic. |
| ios/extention/Resources/content.js | iOS copy of structured lookup + overlay updates. |
| ios/extention/Resources/manifest.json | iOS copy of manifest permission updates. |
…, version 2.1.3 Agent-Logs-Url: https://github.com/SillyLittleTech/Flean/sessions/9f48cef1-3648-4c02-9639-a400a683d1db Co-authored-by: kiyarose <75678535+kiyarose@users.noreply.github.com>
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| PHP | Mar 26, 2026 8:18p.m. | Review ↗ | |
| Shell | Mar 26, 2026 8:18p.m. | Review ↗ | |
| JavaScript | Mar 26, 2026 8:18p.m. | Review ↗ | |
| Swift | Mar 26, 2026 8:18p.m. | Review ↗ |
…tives Agent-Logs-Url: https://github.com/SillyLittleTech/Flean/sessions/0fe5a555-523e-412f-b8cc-ca77526e7dad Co-authored-by: kiyarose <75678535+kiyarose@users.noreply.github.com>
Done in commit
Three files were added to wire this up:
|
kiyarose
left a comment
There was a problem hiding this comment.
Details
# DeepSource Code Review ReportRepository: SillyLittleTech/Flean
Branch: copilot/implement-remote-wiki-data-loading
PR: #2 · #2
Commit: abb91d5...8b68900
Run: https://app.deepsource.com/gh/SillyLittleTech/Flean/run/dcdad54b-1d88-4dc4-9eff-1d81968e59c0/
Summary
- PHP: No issues detected- Shell: No issues detected- Swift: No issues detected- JavaScript: 107 issues
Code Review Findings
PHP
Status: Success
Findings: No new issues detected
Shell
Status: Success
Findings: No new issues detected
Swift
Status: Success
Findings: No new issues detected
JavaScript
Status: Failure
Findings: 107 new issues
-
Avoid using console in code that runs on the browser (
JS-0002)
File:ios/extention/Resources/background.js
Line: 23try { await fetchWikiData() invalidateIndex() console.log('Flean: wiki data refreshed') } catch (e) { console.warn('Flean: scheduled wiki data refresh failed', e) }
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:ios/extention/Resources/background.js
Line: 7async function initWikiData () { try { await getWikiData() console.log('Flean: wiki data ready') } catch (e) { console.warn('Flean: wiki data init failed, heuristics will be used', e) }
Category: Bug risk
Severity: major -
use
Boolean(settingsLink)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:ios/extention/Resources/content.js
Line: 65let mirrors = DEFAULTS.mirrors.slice() try { const cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') if (cache && cache.ts && (Date.now() - cache.ts) < 30 * 1000) { allowedSites = cache.allowedSites || allowedSites selectedMirror = normalizeHost(cache.selectedMirror || selectedMirror) askOnVisit = !!cache.askOnVisit
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/content.js
Line: 167const now = Date.now() const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } }
Category: Anti-pattern
Severity: minor -
use
Boolean(cache.askOnVisit)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 68if (cache && cache.ts && (Date.now() - cache.ts) < 30 * 1000) { allowedSites = cache.allowedSites || allowedSites selectedMirror = normalizeHost(cache.selectedMirror || selectedMirror) askOnVisit = !!cache.askOnVisit mirrors = (cache.mirrors || mirrors).map(normalizeHost) } } catch (e) { /* ignore cache parse errors */ }
Category: Anti-pattern
Severity: minor -
use
Boolean(openBtn)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
use
Boolean(s.askOnVisit)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 77(async () => { try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })()
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:ios/extention/Resources/content.js
Line: 151new Promise(resolve => { cancelTimeout = setTimeout(() => resolve(null), 500) }) ]) clearTimeout(cancelTimeout) if (structured && structured.destinationUrl) { finalDestUrl = structured.destinationUrl finalDestLabel = structured.wikiName || new URL(structured.destinationUrl).host isIndieWiki = true
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:ios/extention/Resources/content.js
Line: 83})() // Keep the localStorage cache in sync immediately when preferences change. if (browser && browser.storage && typeof browser.storage.onChanged === 'object') { try { browser.storage.onChanged.addListener((changes, areaName) => { if (areaName !== 'local') return
Category: Anti-pattern
Severity: minor -
use
Boolean(allowBtn)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
Function has a cyclomatic complexity of 57 with "critical" risk (
JS-R1005)
File:ios/extention/Resources/content.js
Line: 3// Content script: intercept fandom/wikia wiki pages and redirect to a selected Breezewiki mirror. (async function () { try { const url = new URL(window.location.href) const host = url.host.toLowerCase()
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/content.js
Line: 54// If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Anti-pattern
Severity: minor -
Variable name is too small (
JS-C1002)
File:ios/extention/Resources/content.js
Line: 76// Background refresh of storage to keep the cache fresh (non-blocking) (async () => { try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ }
Category: Anti-pattern
Severity: minor -
use
Boolean(changes.askOnVisit.newValue)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 92try { cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') || { ts: 0 } } catch (e) { cache = { ts: 0 } } if (changes.allowedSites) { cache.allowedSites = changes.allowedSites.newValue || []; updated = true } if (changes.selectedMirror) { cache.selectedMirror = normalizeHost(changes.selectedMirror.newValue || DEFAULTS.selectedMirror); updated = true } if (changes.askOnVisit) { cache.askOnVisit = !!changes.askOnVisit.newValue; updated = true } if (changes.mirrors) { cache.mirrors = (changes.mirrors.newValue || DEFAULTS.mirrors).map(normalizeHost); updated = true } if (updated) { cache.ts = Date.now()
Category: Anti-pattern
Severity: minor -
use
Boolean(onceBtn)instead (JS-0066)
File:ios/extention/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/content.js
Line: 166const now = Date.now() const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/content.js
Line: 202if (reloadCount >= ATTEMPT_THRESHOLD || recent.length >= ATTEMPT_THRESHOLD) { window.sessionStorage.setItem(suppressKey, String(now + SUPPRESS_COOLDOWN_MS)) console.info('Flean: suppressing redirect for', pageKey, 'for', SUPPRESS_COOLDOWN_MS, 'ms (reloads=' + reloadCount + ', navigations=' + recent.length + ')') showSuppressionBanner() return }
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/content.js
Line: 168const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } }
Category: Anti-pattern
Severity: minor -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 360if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 89if (areaName !== 'local') return let updated = false let cache = null try { cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') || { ts: 0 } } catch (e) { cache = { ts: 0 } } if (changes.allowedSites) { cache.allowedSites = changes.allowedSites.newValue || []; updated = true } if (changes.selectedMirror) { cache.selectedMirror = normalizeHost(changes.selectedMirror.newValue || DEFAULTS.selectedMirror); updated = true } if (changes.askOnVisit) { cache.askOnVisit = !!changes.askOnVisit.newValue; updated = true }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 129// Extract page title let page = path.replace(/^\/wiki\//i, '') try { page = decodeURIComponent(page) } catch (e) { /* ignore */ } // Compute mirror URL (fallback) const pageForMirror = page.replace(/\s+/g, '_').replace(/^\/+|\/+$/g, '')
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 365if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 170const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } } // Detect whether this page load is a browser reload (F5 / Cmd-R)
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 257if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 187try { reloadCount = isReload ? (parseInt(window.sessionStorage.getItem(reloadKey) || '0', 10) + 1) : 0 window.sessionStorage.setItem(reloadKey, String(reloadCount)) } catch (e) { /* ignore */ } const recent = readSessionArray(attemptsKey).filter(ts => (now - ts) <= ATTEMPT_WINDOW_MS) recent.push(now)
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 318console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ } }, { capture: true }) if (openBtn) {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 53try { // If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 156finalDestLabel = structured.wikiName || new URL(structured.destinationUrl).host isIndieWiki = true } } catch (e) { /* background unavailable – fall back to heuristic mirror */ } // Fast-path for askOnVisit=false using sessionStorage-only attempt tracking if (!askOnVisit) {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 178try { const navEntry = performance.getEntriesByType('navigation')[0] isReload = navEntry ? navEntry.type === 'reload' : (performance.navigation && performance.navigation.type === 1) } catch (e) { /* ignore */ } // Track consecutive reloads separately; two in a row bypasses the redirect. // Intentionally resets to 0 on any non-reload navigation so only truly
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 111if (Date.now() <= until) isSessionAllowed = true else window.sessionStorage.removeItem('__flean_allow_until') } } catch (e) { /* ignore */ } if ((allowedSites || []).includes(host) || isSessionAllowed) { console.log('Flean: host is in ignore list or session-allowed, skipping redirection for', host)
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:ios/extention/Resources/content.js
Line: 114} catch (e) { /* ignore */ } if ((allowedSites || []).includes(host) || isSessionAllowed) { console.log('Flean: host is in ignore list or session-allowed, skipping redirection for', host) return }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 79const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })() // Keep the localStorage cache in sync immediately when preferences change.
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 171const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } } // Detect whether this page load is a browser reload (F5 / Cmd-R) let isReload = false
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 71askOnVisit = !!cache.askOnVisit mirrors = (cache.mirrors || mirrors).map(normalizeHost) } } catch (e) { /* ignore cache parse errors */ } // Background refresh of storage to keep the cache fresh (non-blocking) (async () => {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 99try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } }) } catch (e) { /* ignore if onChanged isn't available */ } } // Fast session-scoped allow (for immediate navigation within this tab)
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:ios/extention/Resources/content.js
Line: 208} // Redirect quickly console.log('Flean: askOnVisit=false, redirecting', url.href, '->', finalDestUrl) try { window.location.replace(finalDestUrl) } catch (e) { console.warn('Flean: failed to redirect', e) } return }
Category: Bug risk
Severity: major -
'e2' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 54// If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 78try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })()
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 96if (changes.mirrors) { cache.mirrors = (changes.mirrors.newValue || DEFAULTS.mirrors).map(normalizeHost); updated = true } if (updated) { cache.ts = Date.now() try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } }) } catch (e) { /* ignore if onChanged isn't available */ }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 345try { const SESSION_ALLOW_MS = 5 * 1000 // 5 seconds const until = Date.now() + SESSION_ALLOW_MS try { window.sessionStorage.setItem('__flean_allow_until', String(until)) } catch (e) { /* ignore */ } console.info('Flean: session-allow for host', host, 'until', new Date(until).toISOString()) } catch (err) { console.warn('Flean: failed to set session allow', err) } overlay.remove()
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/content.js
Line: 262if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: major -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 181destPath = '/doku.php?id=' + encodeURIComponent(article.replace(/ /g, '_').toLowerCase()) } else { // Default: MediaWiki-style /wiki/ArticleName destPath = '/wiki/' + encodeURIComponent(article.replace(/ /g, '_')) } const destinationUrl = `https://${destBase}${destPath}${url.search}${url.hash}`
Category: Anti-pattern
Severity: minor -
Variable 'destPath' should be initialized on declaration (
JS-0119)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 172.replace(/^https?:\/\//, '') .replace(/\/$/, '') const platform = (wiki.destination_platform || 'mediawiki').toLowerCase() let destPath if (wiki.destination_content_path) { destPath = wiki.destination_content_path
Category: Anti-pattern
Severity: minor -
Found
asyncfunction without anyawaitexpressions (JS-0116)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 115-128let _wikiIndexPromise = null /** Ensure the in-memory lookup index is built. */ async function ensureIndex () { if (_wikiIndex !== null) return _wikiIndex if (_wikiIndexPromise) return _wikiIndexPromise _wikiIndexPromise = getWikiData().then(data => { _wikiIndex = buildIndex(data) _wikiIndexPromise = null return _wikiIndex }).catch(() => { _wikiIndex = new Map() _wikiIndexPromise = null return _wikiIndex }) return _wikiIndexPromise } /** * Invalidate the in-memory index so it is rebuilt on the next lookup.
Category: Bug risk
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 178destPath = wiki.destination_content_path .replace('$1', encodeURIComponent(article.replace(/ /g, '_'))) } else if (platform === 'dokuwiki') { destPath = '/doku.php?id=' + encodeURIComponent(article.replace(/ /g, '_').toLowerCase()) } else { // Default: MediaWiki-style /wiki/ArticleName destPath = '/wiki/' + encodeURIComponent(article.replace(/ /g, '_'))
Category: Anti-pattern
Severity: minor -
'e2' is defined but never used (
JS-0128)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 54return JSON.parse(new TextDecoder().decode(decompressed)) } catch (e) { // May be plain base64 JSON (written by the fallback path above) try { return JSON.parse(atob(value)) } catch (e2) { throw e } } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 187const destinationUrl = `https://${destBase}${destPath}${url.search}${url.hash}` const wikiName = wiki.destination || wiki.article || destBase return { destinationUrl, wikiName } } catch (e) { return null } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 165if (article.toLowerCase().startsWith(originPathPrefix.toLowerCase())) { article = article.slice(originPathPrefix.length) } try { article = decodeURIComponent(article) } catch (e) { /* keep encoded */ } // Build destination URL based on platform const destBase = wiki.destination_base_url
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:ios/extention/Resources/scripts/wiki-data-manager.js
Line: 30let binary = '' for (let i = 0; i < uint8.length; i++) binary += String.fromCharCode(uint8[i]) return btoa(binary) } catch (e) { return btoa(json) } }
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:mos/Flean Extension/Resources/background.js
Line: 23try { await fetchWikiData() invalidateIndex() console.log('Flean: wiki data refreshed') } catch (e) { console.warn('Flean: scheduled wiki data refresh failed', e) }
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:mos/Flean Extension/Resources/background.js
Line: 7async function initWikiData () { try { await getWikiData() console.log('Flean: wiki data ready') } catch (e) { console.warn('Flean: wiki data init failed, heuristics will be used', e) }
Category: Bug risk
Severity: major -
use
Boolean(changes.askOnVisit.newValue)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 92try { cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') || { ts: 0 } } catch (e) { cache = { ts: 0 } } if (changes.allowedSites) { cache.allowedSites = changes.allowedSites.newValue || []; updated = true } if (changes.selectedMirror) { cache.selectedMirror = normalizeHost(changes.selectedMirror.newValue || DEFAULTS.selectedMirror); updated = true } if (changes.askOnVisit) { cache.askOnVisit = !!changes.askOnVisit.newValue; updated = true } if (changes.mirrors) { cache.mirrors = (changes.mirrors.newValue || DEFAULTS.mirrors).map(normalizeHost); updated = true } if (updated) { cache.ts = Date.now()
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:mos/Flean Extension/Resources/content.js
Line: 65let mirrors = DEFAULTS.mirrors.slice() try { const cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') if (cache && cache.ts && (Date.now() - cache.ts) < 30 * 1000) { allowedSites = cache.allowedSites || allowedSites selectedMirror = normalizeHost(cache.selectedMirror || selectedMirror) askOnVisit = !!cache.askOnVisit
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:mos/Flean Extension/Resources/content.js
Line: 202if (reloadCount >= ATTEMPT_THRESHOLD || recent.length >= ATTEMPT_THRESHOLD) { window.sessionStorage.setItem(suppressKey, String(now + SUPPRESS_COOLDOWN_MS)) console.info('Flean: suppressing redirect for', pageKey, 'for', SUPPRESS_COOLDOWN_MS, 'ms (reloads=' + reloadCount + ', navigations=' + recent.length + ')') showSuppressionBanner() return }
Category: Anti-pattern
Severity: minor -
'e' is already declared in the upper scope on line 251 column 48 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 263browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) } closeBtn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); banner.remove() })
Category: Bug risk
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:mos/Flean Extension/Resources/content.js
Line: 167const now = Date.now() const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } }
Category: Anti-pattern
Severity: minor -
use
Boolean(openBtn)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
Variable name is too small (
JS-C1002)
File:mos/Flean Extension/Resources/content.js
Line: 76// Background refresh of storage to keep the cache fresh (non-blocking) (async () => { try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ }
Category: Anti-pattern
Severity: minor -
'e' is already declared in the upper scope on line 251 column 48 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 257if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: minor -
use
Boolean(onceBtn)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
use
Boolean(settingsLink)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:mos/Flean Extension/Resources/content.js
Line: 54// If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Anti-pattern
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:mos/Flean Extension/Resources/content.js
Line: 168const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } }
Category: Anti-pattern
Severity: minor -
use
Boolean(cache.askOnVisit)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 68if (cache && cache.ts && (Date.now() - cache.ts) < 30 * 1000) { allowedSites = cache.allowedSites || allowedSites selectedMirror = normalizeHost(cache.selectedMirror || selectedMirror) askOnVisit = !!cache.askOnVisit mirrors = (cache.mirrors || mirrors).map(normalizeHost) } } catch (e) { /* ignore cache parse errors */ }
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:mos/Flean Extension/Resources/content.js
Line: 83})() // Keep the localStorage cache in sync immediately when preferences change. if (browser && browser.storage && typeof browser.storage.onChanged === 'object') { try { browser.storage.onChanged.addListener((changes, areaName) => { if (areaName !== 'local') return
Category: Anti-pattern
Severity: minor -
'e' is already declared in the upper scope on line 354 column 53 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 366browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) } } catch (err) {
Category: Bug risk
Severity: minor -
Function has a cyclomatic complexity of 57 with "critical" risk (
JS-R1005)
File:mos/Flean Extension/Resources/content.js
Line: 3// Content script: intercept fandom/wikia wiki pages and redirect to a selected Breezewiki mirror. (async function () { try { const url = new URL(window.location.href) const host = url.host.toLowerCase()
Category: Anti-pattern
Severity: minor -
use
Boolean(allowBtn)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 315const allowBtn = overlay.querySelector('#flean-allow-site') const settingsLink = overlay.querySelector('#flean-open-popup') console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ }
Category: Anti-pattern
Severity: minor -
'e' is already declared in the upper scope on line 339 column 43 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 345try { const SESSION_ALLOW_MS = 5 * 1000 // 5 seconds const until = Date.now() + SESSION_ALLOW_MS try { window.sessionStorage.setItem('__flean_allow_until', String(until)) } catch (e) { /* ignore */ } console.info('Flean: session-allow for host', host, 'until', new Date(until).toISOString()) } catch (err) { console.warn('Flean: failed to set session allow', err) } overlay.remove()
Category: Bug risk
Severity: minor -
use
Boolean(s.askOnVisit)instead (JS-0066)
File:mos/Flean Extension/Resources/content.js
Line: 77(async () => { try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })()
Category: Anti-pattern
Severity: minor -
'e' is already declared in the upper scope on line 354 column 53 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 365if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: minor -
'e' is already declared in the upper scope on line 354 column 53 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 360if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: minor -
'e' is already declared in the upper scope on line 251 column 48 (
JS-0123)
File:mos/Flean Extension/Resources/content.js
Line: 262if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: minor -
Unexpected string concatenation (
JS-0246)
File:mos/Flean Extension/Resources/content.js
Line: 166const now = Date.now() const pageKey = url.href const attemptsKey = '__flean_attempts:' + pageKey const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey
Category: Anti-pattern
Severity: minor -
Prefer using an optional chain expression instead, as it's more concise and easier to read (
JS-W1044)
File:mos/Flean Extension/Resources/content.js
Line: 151new Promise(resolve => { cancelTimeout = setTimeout(() => resolve(null), 500) }) ]) clearTimeout(cancelTimeout) if (structured && structured.destinationUrl) { finalDestUrl = structured.destinationUrl finalDestLabel = structured.wikiName || new URL(structured.destinationUrl).host isIndieWiki = true
Category: Anti-pattern
Severity: minor -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 89if (areaName !== 'local') return let updated = false let cache = null try { cache = JSON.parse(window.localStorage.getItem('__flean_cache') || 'null') || { ts: 0 } } catch (e) { cache = { ts: 0 } } if (changes.allowedSites) { cache.allowedSites = changes.allowedSites.newValue || []; updated = true } if (changes.selectedMirror) { cache.selectedMirror = normalizeHost(changes.selectedMirror.newValue || DEFAULTS.selectedMirror); updated = true } if (changes.askOnVisit) { cache.askOnVisit = !!changes.askOnVisit.newValue; updated = true }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 171const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } } // Detect whether this page load is a browser reload (F5 / Cmd-R) let isReload = false
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:mos/Flean Extension/Resources/content.js
Line: 208} // Redirect quickly console.log('Flean: askOnVisit=false, redirecting', url.href, '->', finalDestUrl) try { window.location.replace(finalDestUrl) } catch (e) { console.warn('Flean: failed to redirect', e) } return }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 53try { // If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 318console.debug('Flean: overlay buttons', { openBtn: !!openBtn, onceBtn: !!onceBtn, allowBtn: !!allowBtn, settingsLink: !!settingsLink }) overlay.addEventListener('click', (ev) => { try { console.debug('Flean: overlay click', ev.target && (ev.target.id || ev.target.className || ev.target.tagName)) } catch (e) { /* ignore */ } }, { capture: true }) if (openBtn) {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 178try { const navEntry = performance.getEntriesByType('navigation')[0] isReload = navEntry ? navEntry.type === 'reload' : (performance.navigation && performance.navigation.type === 1) } catch (e) { /* ignore */ } // Track consecutive reloads separately; two in a row bypasses the redirect. // Intentionally resets to 0 on any non-reload navigation so only truly
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 345try { const SESSION_ALLOW_MS = 5 * 1000 // 5 seconds const until = Date.now() + SESSION_ALLOW_MS try { window.sessionStorage.setItem('__flean_allow_until', String(until)) } catch (e) { /* ignore */ } console.info('Flean: session-allow for host', host, 'until', new Date(until).toISOString()) } catch (err) { console.warn('Flean: failed to set session allow', err) } overlay.remove()
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 365if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 156finalDestLabel = structured.wikiName || new URL(structured.destinationUrl).host isIndieWiki = true } } catch (e) { /* background unavailable – fall back to heuristic mirror */ } // Fast-path for askOnVisit=false using sessionStorage-only attempt tracking if (!askOnVisit) {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 71askOnVisit = !!cache.askOnVisit mirrors = (cache.mirrors || mirrors).map(normalizeHost) } } catch (e) { /* ignore cache parse errors */ } // Background refresh of storage to keep the cache fresh (non-blocking) (async () => {
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 78try { const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })()
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 96if (changes.mirrors) { cache.mirrors = (changes.mirrors.newValue || DEFAULTS.mirrors).map(normalizeHost); updated = true } if (updated) { cache.ts = Date.now() try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } }) } catch (e) { /* ignore if onChanged isn't available */ }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 79const s = await browser.storage.local.get({ allowedSites: [], selectedMirror: DEFAULTS.selectedMirror, askOnVisit: DEFAULTS.askOnVisit, mirrors: DEFAULTS.mirrors }) const cache = { allowedSites: s.allowedSites || [], selectedMirror: normalizeHost(s.selectedMirror || DEFAULTS.selectedMirror), askOnVisit: !!s.askOnVisit, mirrors: (s.mirrors || DEFAULTS.mirrors).map(normalizeHost), ts: Date.now() } try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } catch (e) { /* ignore background refresh errors */ } })() // Keep the localStorage cache in sync immediately when preferences change.
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 262if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return } } catch (e) { /* try next */ } try { await browser.tabs.create({ url: browser.runtime.getURL('popup.html') }) } catch (e) { console.warn('Flean: could not open settings', e) } }) }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 170const suppressKey = '__flean_suppressed:' + pageKey const reloadKey = '__flean_reloads:' + pageKey function readSessionArray (k) { try { return JSON.parse(window.sessionStorage.getItem(k) || '[]') } catch (e) { return [] } } function writeSessionArray (k, arr) { try { window.sessionStorage.setItem(k, JSON.stringify(arr)) } catch (e) { /* ignore */ } } // Detect whether this page load is a browser reload (F5 / Cmd-R)
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 111if (Date.now() <= until) isSessionAllowed = true else window.sessionStorage.removeItem('__flean_allow_until') } } catch (e) { /* ignore */ } if ((allowedSites || []).includes(host) || isSessionAllowed) { console.log('Flean: host is in ignore list or session-allowed, skipping redirection for', host)
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 257if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: major -
'e2' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 54// If it's a full URL, URL() will succeed and we can read host return new URL(str).host.toLowerCase() } catch (e) { try { return new URL('https://' + str).host.toLowerCase() } catch (e2) { return str.toLowerCase() } } }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 129// Extract page title let page = path.replace(/^\/wiki\//i, '') try { page = decodeURIComponent(page) } catch (e) { /* ignore */ } // Compute mirror URL (fallback) const pageForMirror = page.replace(/\s+/g, '_').replace(/^\/+|\/+$/g, '')
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 360if (browser.action && typeof browser.action.openPopup === 'function') { await browser.action.openPopup(); return } } catch (e) { /* try next */ } try { if (browser.runtime && typeof browser.runtime.openOptionsPage === 'function') { browser.runtime.openOptionsPage(); return
Category: Bug risk
Severity: major -
Avoid using console in code that runs on the browser (
JS-0002)
File:mos/Flean Extension/Resources/content.js
Line: 114} catch (e) { /* ignore */ } if ((allowedSites || []).includes(host) || isSessionAllowed) { console.log('Flean: host is in ignore list or session-allowed, skipping redirection for', host) return }
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 187try { reloadCount = isReload ? (parseInt(window.sessionStorage.getItem(reloadKey) || '0', 10) + 1) : 0 window.sessionStorage.setItem(reloadKey, String(reloadCount)) } catch (e) { /* ignore */ } const recent = readSessionArray(attemptsKey).filter(ts => (now - ts) <= ATTEMPT_WINDOW_MS) recent.push(now)
Category: Bug risk
Severity: major -
'e' is defined but never used (
JS-0128)
File:mos/Flean Extension/Resources/content.js
Line: 99try { window.localStorage.setItem('__flean_cache', JSON.stringify(cache)) } catch (e) { /* ignore */ } } }) } catch (e) { /* ignore if onChanged isn't available */ } } // Fast session-scoped allow (for immediate navigation within this tab)
Category: Bug risk
Severity: major -
Found
asyncfunction without anyawaitexpressions (JS-0116)
File:mos/Flean Extension/Resources/scripts/wiki-data-manager.js
Line: 115-128let _wikiIndexPromise = null /** Ensure the in-memory lookup index is built. */ async function ensureIndex () { if (_wikiIndex !== null) return _wikiIndex if (_wikiIndexPromise) return _wikiIndexPromise _wikiIndexPromise = getWikiData().then(data => { _wikiIndex = buildIndex(data) _wikiIndexPromise = null return _wikiIndex }).catch(() => { _wikiIndex = new Map() _wikiIndexPromise = null return _wikiIndex }) return _wikiIndexPromise } /** * Invalidate the in-memory index so it is rebuilt on the next lookup.
Category: Bug risk
Severity: minor
...and 7 more occurrences. See full list on DeepSource.
ATTEMPT_THRESHOLDto flat2(wasfromMirror ? 2 : 3)browser.action.openPopup()→openOptionsPage()→tabs.create(popup.html); always visible"version"bumped to"2.1.3"MARKETING_VERSION = 2.1.3,CURRENT_PROJECT_VERSION = 2(8 occurrences each).swiftfiles pass with zero errorsOriginal prompt
Overview
Implement Option C: Remote wiki data loading with local caching and fallback to heuristics.
Current State
Proposed Solution
Add a system to:
Changes Required
1. New File:
scripts/wiki-data-manager.jsfetchWikiData()- fetch from GitHub + compressgetWikiData()- retrieve from cache with fallbackfindMatchingWiki(url)- lookup with both structured data and fallback heuristicscompressJSON(value)/decompressJSON(value)- gzip compression helpers2. Update
background.js3. Update
content.js4. Update
manifest.jsonwebRequestpermissions (if supported by Safari)raw.githubusercontent.com)Benefits
Testing Checklist
The following is the prior conversation context from the user's chat exploration (may be truncated):
User: Do you think it would be possible to port over to my extention functionality of @KevinPayravi/indie-wiki-buddy, in which it can also redirect to independent wikis, not just breezewiki mirrors, and the fact it also has the option to edit search engine results. What parts of that are possible in macOS/iOS ecosystem, are some parts impossible, would it be easier to port indiewikibuddy from scratch, or is my code a good base.
Assistant: I'll help you assess the possibility of porting indie-wiki-buddy functionality to your Flean extension. Let me first examine your repository and then look at indie-wiki-buddy to understand what we're working with.
Assistant: Now let me get more detailed information about the actual implementations:
Assistant: Based on my analysis of your Flean extension and the indie-wiki-buddy project, here's a detailed assessment:
Summary
Your code is a good base, but porting indie-wiki-buddy's full functionality to macOS/iOS has significant platform-specific limitations. Some features are possible, others would need major adaptation.
Feature Breakdown
✅ Possible to Port (with your current code as a foundation):
Wiki Redirects to Independent Mirrors - This is your core strength
Expanded Wiki Support Beyond BreezeWiki
SettingsStorecan be extended to load indie-wiki-buddy's JSON data formatIgnore/Allow Lists
Search Engine Result Filtering - MAJOR LIMITATION
Multiple Languages - Partial Support
Real-time Data Updates
...
This pull request was created from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.