From e744bdda5136fff69802806a90e41d8e74462788 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Jul 2026 00:58:52 +0000 Subject: [PATCH] fix: capture OnTrack data on first install without a manual reload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two gaps left a brand-new install silently empty: - Chrome never runs content_scripts in a tab that was already open before install/update, so a student who had OnTrack open (likely, since that's why they installed the extension) got no capture until they reloaded. Backfill content.js/injected.js into any already-open matching tab from onInstalled via chrome.scripting.executeScript. - The ingest dedup cache marked a payload as "sent" on any resolved JSON response, including a 404 "not subscribed" (ingest fires the moment the content script loads, before the popup's /link-ontrack has created the backend user row) or a `skipped` rejection. Once cached, the identical task data never retried until it changed or the ephemeral service worker restarted. Only cache on genuine success now (2xx + ok:true + no skipped). Bump to 1.13.0 — the scripting permission addition changes what's shown on install/update. --- extension/package.json | 2 +- extension/public/background.js | 34 +++++++++++++++++++++++++++------- extension/public/manifest.json | 4 ++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/extension/package.json b/extension/package.json index ea442ca..42233b8 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { "name": "ontracker", "private": true, - "version": "1.12.1", + "version": "1.13.0", "type": "module", "scripts": { "dev": "vite", diff --git a/extension/public/background.js b/extension/public/background.js index d8d3e59..e63eaf9 100644 --- a/extension/public/background.js +++ b/extension/public/background.js @@ -3,7 +3,25 @@ importScripts("config.js"); const ONTRACK_URL = "https://ontrack.deakin.edu.au"; -chrome.runtime.onInstalled.addListener(() => { +// Chrome only runs content_scripts on NEW navigations after install/update — a +// tab that was already open on OnTrack (very likely, since checking tasks is +// why a student would have it open) never gets content.js/injected.js without +// a manual reload. Backfill it into any already-open matching tab so a fresh +// install captures data immediately instead of silently doing nothing until +// the student happens to reload or renavigate. +chrome.runtime.onInstalled.addListener(async () => { + let tabs; + try { + tabs = await chrome.tabs.query({ url: "https://ontrack.deakin.edu.au/*" }); + } catch { + return; // host permission not yet granted or tabs API unavailable + } + for (const tab of tabs) { + if (!tab.id) continue; + chrome.scripting + .executeScript({ target: { tabId: tab.id }, files: ["config.js", "content.js"] }) + .catch(() => {}); // e.g. a chrome:// or restricted tab matched unexpectedly + } }); // Read the durable refresh_token cookie (HttpOnly — only chrome.cookies can see @@ -114,12 +132,14 @@ chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => { payload: msg.payload, }), }) - .then((r) => r.json()) - .then((d) => { - // Only cache once the server actually stored it — a `skipped` response - // (e.g. rejected as an inactive project) must not be treated as sent, or - // this dedup would permanently suppress a push that never landed. - if (!d || !d.skipped) lastIngestHash.set(dedupKey, hash); + .then((r) => r.json().then((d) => ({ httpOk: r.ok, d }))) + .then(({ httpOk, d }) => { + // Only cache once the server actually stored it. fetch() doesn't reject on + // HTTP error status (e.g. 404 "not subscribed" while the account is still + // being linked), and a `skipped` response (e.g. rejected as an inactive + // project) isn't a store either — either one must not be treated as sent, + // or this dedup would permanently suppress a push that never landed. + if (httpOk && d && d.ok && !d.skipped) lastIngestHash.set(dedupKey, hash); sendResponse({ ok: true }); }) .catch(() => { diff --git a/extension/public/manifest.json b/extension/public/manifest.json index 0b547aa..64eb7b7 100644 --- a/extension/public/manifest.json +++ b/extension/public/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdNZfW6IzfrG6mYRZiKk5nmeWybcEmfSAkn4pCkfjY5KMkei/sBeXgwXCb2wjpsAVg9y8nlYIBHVhv7WgEKQasmQ5r4kXe0aiX/tiiZpOu2ha8PIG9GK0jszmWieAeVMSA2mcd/SDYzDDDl2iStxas9LRjOQSE6znZHkQbGLw6GjcH3oFg7in0dV3YgGhxmjlUtdJFKr/5vVCrVHJ7t+91uwGtWeT8wDtGlLNWiWV9iD4leidCcMRvcwHWDIduDDbU9d/BHGEPf8i7+Hf318exjOtJ6j89ISKSB36xmQgcvXMVRgh4APHXw7LejzjfVYwwCmFturkS0miMYnq/mIZwIDAQAB", "name": "Ontracker", - "version": "1.12.1", + "version": "1.13.0", "description": "Keeps your OnTrack Brief token fresh automatically.", "icons": { "16": "icons/icon16.png", @@ -10,7 +10,7 @@ "48": "icons/icon48.png", "128": "icons/icon128.png" }, - "permissions": ["storage", "cookies"], + "permissions": ["storage", "cookies", "scripting"], "host_permissions": [ "https://ontrack.deakin.edu.au/*", "https://on-tracker.com/*",