Compare commits

...

3 Commits

Author SHA1 Message Date
SethBurkart123 fcc856e798 fix: resolve assessments overview failing to load in production builds
Replace dynamic import of ./ui with static import to prevent Vite from
code-splitting into a separate chunk that CRXJS cannot resolve at runtime.

Bumps version to 3.6.3.
2026-04-21 19:08:30 +10:00
SethBurkart123 a0038ac871 chore: bump version to 3.6.2 2026-04-20 15:53:20 +10:00
SethBurkart123 49824e9eab refactor: remove alarms permission, throttle cloud sync to once per day on page load 2026-04-20 15:47:22 +10:00
7 changed files with 22 additions and 20 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "betterseqtaplus", "name": "betterseqtaplus",
"version": "3.6.1", "version": "3.6.3",
"type": "module", "type": "module",
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development and add heaps more features!", "description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development and add heaps more features!",
"browserslist": "> 0.5%, last 2 versions, not dead", "browserslist": "> 0.5%, last 2 versions, not dead",
+4
View File
@@ -59,6 +59,10 @@ async function init() {
IsSEQTAPage = true; IsSEQTAPage = true;
console.info("[BetterSEQTA+] Verified SEQTA Page"); console.info("[BetterSEQTA+] Verified SEQTA Page");
if (typeof window !== "undefined" && window === window.top) {
void browser.runtime.sendMessage({ type: "cloudSettingsPoll" }).catch(() => {});
}
registerFetchSeqtaAppLinkListener(); registerFetchSeqtaAppLinkListener();
const documentLoadStyle = document.createElement("style"); const documentLoadStyle = document.createElement("style");
+7 -14
View File
@@ -13,9 +13,9 @@ export const CLOUD_SUMMARY_URL = `${ACCOUNTS_BASE}/api/user/cloud-summary`;
const CLOUD_SETTINGS_SYNC_URL = `${ACCOUNTS_BASE}/api/bsplus/settings/sync`; const CLOUD_SETTINGS_SYNC_URL = `${ACCOUNTS_BASE}/api/bsplus/settings/sync`;
const REFRESH_URL = `${ACCOUNTS_BASE}/api/bsplus/refresh`; const REFRESH_URL = `${ACCOUNTS_BASE}/api/bsplus/refresh`;
const ALARM_NAME = "bsplus_cloud_settings_auto_sync";
const PERIOD_MINUTES = 60;
const UPLOAD_DEBOUNCE_MS = 2000; const UPLOAD_DEBOUNCE_MS = 2000;
const POLL_THROTTLE_MS = 24 * 60 * 60 * 1000;
const POLL_THROTTLE_KEY = "bsplus_lastCloudPoll";
type CloudSummaryResponse = { type CloudSummaryResponse = {
desqta?: unknown; desqta?: unknown;
@@ -323,6 +323,9 @@ export function runCloudSettingsPoll(): Promise<void> {
if (pollInFlight) return pollInFlight; if (pollInFlight) return pollInFlight;
pollInFlight = (async () => { pollInFlight = (async () => {
try { try {
const { [POLL_THROTTLE_KEY]: last } = await browser.storage.local.get(POLL_THROTTLE_KEY);
if (Date.now() - (Number(last) || 0) < POLL_THROTTLE_MS) return;
await browser.storage.local.set({ [POLL_THROTTLE_KEY]: Date.now() });
await runCloudSettingsPollInner(); await runCloudSettingsPollInner();
} catch (e) { } catch (e) {
console.error("[BS+ cloud sync] Poll error:", e); console.error("[BS+ cloud sync] Poll error:", e);
@@ -360,14 +363,11 @@ async function runDebouncedUploadJob(): Promise<void> {
} }
} }
async function syncAlarmWithStorage(): Promise<void> { async function syncAutoUploadWithStorage(): Promise<void> {
const all = (await browser.storage.local.get()) as Record<string, unknown>; const all = (await browser.storage.local.get()) as Record<string, unknown>;
if (!isAutoCloudSyncEnabled(all)) { if (!isAutoCloudSyncEnabled(all)) {
await browser.alarms.clear(ALARM_NAME);
clearUploadDebounce(); clearUploadDebounce();
return;
} }
await browser.alarms.create(ALARM_NAME, { periodInMinutes: PERIOD_MINUTES });
} }
function onStorageChanged( function onStorageChanged(
@@ -377,7 +377,7 @@ function onStorageChanged(
if (area !== "local") return; if (area !== "local") return;
if (Object.prototype.hasOwnProperty.call(changes, "autoCloudSettingsSync")) { if (Object.prototype.hasOwnProperty.call(changes, "autoCloudSettingsSync")) {
void syncAlarmWithStorage(); void syncAutoUploadWithStorage();
} }
const keys = Object.keys(changes); const keys = Object.keys(changes);
@@ -392,15 +392,8 @@ function onStorageChanged(
})(); })();
} }
function onAlarm(alarm: browser.Alarms.Alarm): void {
if (alarm.name !== ALARM_NAME) return;
void runCloudSettingsPoll();
}
export function initCloudSettingsAutoSync(deps: { reloadSeqtaPages: () => void }): void { export function initCloudSettingsAutoSync(deps: { reloadSeqtaPages: () => void }): void {
reloadSeqtaPagesFn = deps.reloadSeqtaPages; reloadSeqtaPagesFn = deps.reloadSeqtaPages;
browser.alarms.onAlarm.addListener(onAlarm);
browser.storage.onChanged.addListener(onStorageChanged); browser.storage.onChanged.addListener(onStorageChanged);
void syncAlarmWithStorage();
} }
+1 -1
View File
@@ -15,7 +15,7 @@
"64": "resources/icons/icon-64.png" "64": "resources/icons/icon-64.png"
} }
}, },
"permissions": ["tabs", "notifications", "storage", "alarms"], "permissions": ["tabs", "notifications", "storage"],
"host_permissions": ["https://newsapi.org/", "https://betterseqta.org/", "https://accounts.betterseqta.org/", "*://*/*"], "host_permissions": ["https://newsapi.org/", "https://betterseqta.org/", "https://accounts.betterseqta.org/", "*://*/*"],
"background": { "background": {
"service_worker": "background.ts" "service_worker": "background.ts"
@@ -1,7 +1,7 @@
import type { Plugin } from "../../core/types"; import type { Plugin } from "../../core/types";
import { waitForElm } from "@/seqta/utils/waitForElm"; import { waitForElm } from "@/seqta/utils/waitForElm";
import { getAssessmentsData } from "./api"; import { getAssessmentsData } from "./api";
import { renderErrorState, renderSkeletonLoader } from "./ui"; import { renderErrorState, renderGrid, renderSkeletonLoader } from "./ui";
import styles from "./styles.css?inline"; import styles from "./styles.css?inline";
import { delay } from "@/seqta/utils/delay"; import { delay } from "@/seqta/utils/delay";
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage"; import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
@@ -68,7 +68,6 @@ const assessmentsOverviewPlugin: Plugin<{}> = {
try { try {
const data = await getAssessmentsData(); const data = await getAssessmentsData();
const { renderGrid } = await import("./ui");
renderGrid(container, data); renderGrid(container, data);
} catch (err) { } catch (err) {
console.error("Failed to load assessments:", err); console.error("Failed to load assessments:", err);
+4 -1
View File
@@ -34,7 +34,10 @@ export function OpenWhatsNewPopup(onDismissed?: () => void) {
const text = stringToHTML(/* html */ ` const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;"> <div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;">
<h1>3.6.1 - Cloud backup, various fixes & SEQTA Engage support</h1> <h1>3.6.3 - Assessment overview fix</h1>
<li>Fixed assessments overview failing to load.</li>
<h1>3.6.2 - Cloud backup, various fixes & SEQTA Engage support</h1>
<li>BetterSEQTA Cloud: back up and restore extension settings from your account (General settings).</li> <li>BetterSEQTA Cloud: back up and restore extension settings from your account (General settings).</li>
<li>Optional automatic cloud sync if signed in (on by default).</li> <li>Optional automatic cloud sync if signed in (on by default).</li>
<li>Option to use cloud profile photo as the local SEQTA profile picture</li> <li>Option to use cloud profile photo as the local SEQTA profile picture</li>
+4 -1
View File
@@ -36,7 +36,10 @@ export const SENSITIVE_DEVICE_STORAGE_KEYS_EXACT = [
/** e.g. any future `plugin.global-search.storage.*` keys in chrome.storage */ /** e.g. any future `plugin.global-search.storage.*` keys in chrome.storage */
export const SENSITIVE_DEVICE_STORAGE_KEY_PREFIXES = ["plugin.global-search.storage."] as const; export const SENSITIVE_DEVICE_STORAGE_KEY_PREFIXES = ["plugin.global-search.storage."] as const;
const CLIENT_ONLY_CLOUD_KEYS_EXACT = [BSPLUS_CLOUD_KNOWN_REMOTE_UPDATED_AT_KEY] as const; const CLIENT_ONLY_CLOUD_KEYS_EXACT = [
BSPLUS_CLOUD_KNOWN_REMOTE_UPDATED_AT_KEY,
"bsplus_lastCloudPoll",
] as const;
/** After restoring from cloud, keep local session so the user stays signed in. */ /** After restoring from cloud, keep local session so the user stays signed in. */
const AUTH_KEYS_TO_PRESERVE = [ const AUTH_KEYS_TO_PRESERVE = [