-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackground.js
More file actions
115 lines (95 loc) · 3.2 KB
/
Copy pathbackground.js
File metadata and controls
115 lines (95 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Lapsed - background service worker
const DOMAIN_ERRORS = new Set([
'ERR_NAME_NOT_RESOLVED',
'ERR_CONNECTION_REFUSED',
'ERR_CONNECTION_TIMED_OUT',
'ERR_ADDRESS_UNREACHABLE',
'ERR_INTERNET_DISCONNECTED',
'ERR_NAME_RESOLUTION_FAILED'
]);
const STORAGE_KEY = 'failureHistory';
const HISTORY_LIMIT = 10;
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
chrome.tabs.create({
url: chrome.runtime.getURL('welcome.html')
});
}
});
chrome.webNavigation.onErrorOccurred.addListener((details) => {
handleNavigationError(details).catch(err => console.error('Lapsed error:', err));
});
chrome.commands.onCommand.addListener((command) => {
if (command === 'open-popup') {
chrome.action.openPopup();
}
});
chrome.runtime.onMessage.addListener((message) => {
if (message?.type !== 'lapsedStatus') return;
if (!message.domain) return;
updateFailureHistoryStatus(message.domain, message.status, message.label)
.catch(err => console.error('Failed to sync status from lapsed page:', err));
});
async function handleNavigationError(details) {
if (details.frameId !== 0) return;
if (!isDomainError(details.error)) return;
const domain = extractDomain(details.url);
if (!domain || isLocalhost(domain)) return;
await prependToHistory({
domain,
url: details.url,
ts: Date.now(),
status: 'status-checking',
statusLabel: 'Checking'
});
chrome.tabs.update(details.tabId, {
url: chrome.runtime.getURL(
`lapsed.html?domain=${encodeURIComponent(domain)}&originalUrl=${encodeURIComponent(details.url)}`
)
});
}
async function prependToHistory(entry) {
const stored = await chrome.storage.local.get([STORAGE_KEY]);
const history = stored[STORAGE_KEY] || [];
const filtered = history.filter(item => item.domain !== entry.domain);
filtered.unshift(entry);
await chrome.storage.local.set({ [STORAGE_KEY]: filtered.slice(0, HISTORY_LIMIT) });
}
async function updateFailureHistoryStatus(domain, status, label) {
const normalized = normalizeStatus(status);
if (!normalized) return;
const stored = await chrome.storage.local.get([STORAGE_KEY]);
const history = stored[STORAGE_KEY] || [];
const idx = history.findIndex(item => item.domain === domain);
if (idx === -1) return;
const previous = history[idx];
const nextLabel = label || previous.statusLabel || defaultStatusLabel();
const sameStatus = previous.status === normalized;
const sameLabel = previous.statusLabel === nextLabel;
if (sameStatus && sameLabel) return;
history[idx].status = normalized;
history[idx].statusLabel = nextLabel;
await chrome.storage.local.set({ [STORAGE_KEY]: history });
}
function normalizeStatus(status) {
if (!status || typeof status !== 'string') return null;
return status.trim();
}
function defaultStatusLabel() {
return 'Status unknown';
}
function isDomainError(error) {
if (!error) return false;
return Array.from(DOMAIN_ERRORS).some(code => error.includes(code));
}
function extractDomain(urlString) {
try {
return new URL(urlString).hostname;
} catch {
return null;
}
}
function isLocalhost(hostname) {
if (hostname === 'localhost') return true;
return /^\d{1,3}(\.\d{1,3}){3}$/.test(hostname);
}