Skip to content

Conversation

@shadowwwind
Copy link
Contributor

@shadowwwind shadowwwind commented Nov 22, 2025

fixes #126

Summary by CodeRabbit

  • Improvements
    • Installation handling now distinguishes install vs. update so the extension can respond differently.
    • Opening the options page on first run is now gated by the installation context, so it appears only when appropriate.
    • Extension version bumped to 6.0.1 (updated label shown in the popup).

✏️ Tip: You can customize this high-level summary in your review settings.

@shadowwwind shadowwwind requested a review from ptgms November 22, 2025 20:55
@shadowwwind shadowwwind self-assigned this Nov 22, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 22, 2025

Walkthrough

The onInstalled listener now forwards installation details to the install handler, which accepts the details and passes them into the database check. The database check uses the provided InstalledDetails to decide whether to open the options page only on first start for "install" or "update". Manifests and popup version text were bumped to 6.0.1.

Changes

Cohort / File(s) Change Summary
Installation-reason propagation
src/scripts/background.ts, src/scripts/background/install.ts, src/scripts/background/database.ts
onInstalled listener updated to accept and forward the install details to handleExtensionInstalled. handleExtensionInstalled signature changed to accept reason (type: chrome.runtime.InstalledDetails) and now calls checkIfUpdateNeeded(true, reason). checkIfUpdateNeeded signature extended with an optional addonInstallReason?: chrome.runtime.InstalledDetails and now only opens the options page on firstStart when addonInstallReason?.reason is "install" or "update".
Manifest version bumps
src/manifest.json, src/manifest-ff.json
Extension version updated from 6.0.0 to 6.0.1 in both manifest files.
UI text update
src/views/popup.html
Version label next to the Source Code button updated from v6.0.0 to v6.0.1.

Sequence Diagram(s)

sequenceDiagram
    participant Runtime as chrome.runtime
    participant BG as background.ts
    participant Install as install.ts
    participant DB as database.ts

    Runtime->>BG: onInstalled(installedDetails)
    activate BG
    BG->>Install: handleExtensionInstalled(installedDetails)
    deactivate BG
    activate Install
    Install->>DB: checkIfUpdateNeeded(true, installedDetails)
    deactivate Install
    activate DB
    DB->>DB: if firstStart && installedDetails?.reason in {"install","update"}\n  -> open options page
    deactivate DB
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Attention areas:
    • Ensure consistent types: chrome.runtime.InstalledDetails is used and matches the listener payload.
    • Guard access to addonInstallReason?.reason before reading and compare against allowed strings "install" / "update".
    • Verify the change correctly prevents options page opening except when firstStart is true and reason is install/update.
    • Quick check: manifest version bump and popup text update match release process.

Poem

🐇 I hopped to the background, clutching a reason small,
Passed it along the install path down the hall.
Database peered and only then, with care,
Opened options for installs or updates there.
A tiny hop, a tidy tweak — a joyful call.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Stop auto-opening settings on browser update' directly aligns with the PR objective to prevent the extension from automatically opening the settings page on update.
Linked Issues check ✅ Passed The code changes successfully implement the objective from issue #126 by gating the openOptionsPage logic to only trigger on initial install, preventing auto-opening on updates.
Out of Scope Changes check ✅ Passed Version bumps in manifests and popup.html are routine maintenance related to the release, not out-of-scope changes.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 314a5fe and 158bfd2.

📒 Files selected for processing (3)
  • src/manifest-ff.json (1 hunks)
  • src/manifest.json (1 hunks)
  • src/views/popup.html (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/manifest.json
  • src/manifest-ff.json
🔇 Additional comments (1)
src/views/popup.html (1)

108-108: Version string updated consistently with the patch release.

The version string has been correctly updated from v6.0.0 to v6.0.1, which aligns with the fix for issue #126 (preventing auto-opening settings on browser update). This UI label update is consistent with the version bumps mentioned in the manifest files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/scripts/background/database.ts (1)

38-38: Simplify the optional parameter syntax.

The parameter can use TypeScript's optional parameter syntax instead of explicit union with undefined and default value.

Apply this diff:

-export async function checkIfUpdateNeeded(firstStart = false, addonInstallReason:chrome.runtime.InstalledDetails | undefined = undefined): Promise<void> {
+export async function checkIfUpdateNeeded(firstStart = false, addonInstallReason?: chrome.runtime.InstalledDetails): Promise<void> {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0be8840 and c17c01c.

📒 Files selected for processing (3)
  • src/scripts/background.ts (1 hunks)
  • src/scripts/background/database.ts (2 hunks)
  • src/scripts/background/install.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/scripts/background.ts (1)
src/scripts/background/install.ts (1)
  • handleExtensionInstalled (6-24)
src/scripts/background/install.ts (1)
src/scripts/background/database.ts (1)
  • checkIfUpdateNeeded (38-68)
🪛 Biome (2.1.2)
src/scripts/background/database.ts

[error] 65-65: Unexpected constant condition.

(lint/correctness/noConstantCondition)

🪛 GitHub Actions: CI/CD Pipeline
src/scripts/background/database.ts

[error] 65-65: ESLint: Unexpected constant condition. (no-constant-condition)

🪛 GitHub Check: Lint and Type Check
src/scripts/background/database.ts

[failure] 65-65:
Unexpected constant condition

🪛 GitHub Check: SonarCloud Code Analysis
src/scripts/background/database.ts

[warning] 65-65: Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=tosdr_browser-extensions&issues=AZqtWdlD1NG8ykCp9qiq&open=AZqtWdlD1NG8ykCp9qiq&pullRequest=127

🔇 Additional comments (2)
src/scripts/background.ts (1)

24-26: LGTM - Correctly captures installation reason.

The listener now properly captures and forwards the installation reason to the handler function.

src/scripts/background/install.ts (1)

6-6: LGTM - Properly threads installation reason.

The function signature and call to checkIfUpdateNeeded correctly propagate the installation reason through the call chain.

Also applies to: 18-18

@shadowwwind shadowwwind changed the title Open settings Stop auto-opening settings on browser update Nov 22, 2025
@sonarqubecloud
Copy link

@shadowwwind
Copy link
Contributor Author

@coderabbitai generate docstrings

@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Warning

Docstrings generation is disabled for your repository or organization.

@shadowwwind
Copy link
Contributor Author

[!WARNING]
Docstrings generation is disabled for your repository or organization.

@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the modified TypeScript files to analyze functions needing docstrings
cat src/scripts/background.ts
echo "==== END background.ts ===="
cat src/scripts/background/database.ts
echo "==== END database.ts ===="
cat src/scripts/background/install.ts

Length of output: 4650


@shadowwwind, I'll generate JSDoc docstrings for all the functions in the modified TypeScript files.

src/scripts/background/database.ts

import { API_HEADERS, DEFAULT_API_URL } from '../constants';
import { getLocal, setLocal } from '../lib/chromeStorage';
import type { DatabaseEntry } from './types';

/**
 * Resolves the API URL from local storage or returns the default API URL.
 * 
 * @returns {Promise<string>} The API URL to use for database requests
 */
export async function resolveApiUrl(): Promise<string> {
    const data = await getLocal('api');
    const api = data['api'];
    if (typeof api === 'string' && api.length > 0) {
        return api;
    }
    return DEFAULT_API_URL;
}

/**
 * Downloads the latest database from the API and stores it in local storage.
 * Sets a badge error text if the request fails.
 * 
 * @param {string} [apiUrl] - Optional API URL to use; if not provided, resolves from storage
 * @returns {Promise<void>}
 */
export async function downloadDatabase(apiUrl?: string): Promise<void> {
    const targetApi = apiUrl ?? (await resolveApiUrl());

    try {
        const response = await fetch(`https://${targetApi}/appdb/version/v2`, {
            headers: API_HEADERS,
        });

        if (response.status >= 300) {
            chrome.action.setBadgeText({ text: `err ${response.status}` });
            return;
        }

        const data = (await response.json()) as DatabaseEntry[];

        await setLocal({
            db: data,
            lastModified: new Date().toISOString(),
        });
    } catch (error) {
        console.error('Failed to download database', error);
    }
}

/**
 * Checks if the database needs to be updated based on the configured interval.
 * Downloads a new database if needed and optionally opens the settings page on first start.
 * 
 * @param {boolean} [firstStart=false] - Whether this is the first start after installation/update
 * @param {chrome.runtime.InstalledDetails} [addonInstallReason] - Details about why the extension was installed
 * @returns {Promise<void>}
 */
export async function checkIfUpdateNeeded(firstStart = false, addonInstallReason?:chrome.runtime.InstalledDetails): Promise<void> {
    const data = await getLocal([
        'db',
        'lastModified',
        'interval',
        'api',
    ]);

    const api = await resolveApiUrlFromData(data);

    const db = data['db'] as DatabaseEntry[] | undefined;
    const lastModifiedRaw = data['lastModified'];

    if (db && typeof lastModifiedRaw === 'string') {
        const intervalDays = computeIntervalDays(data['interval']);
        const lastModified = new Date(lastModifiedRaw);
        const today = new Date();
        const diffTime = Math.abs(today.getTime() - lastModified.getTime());
        const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

        if (diffDays < intervalDays) {
            return;
        }
    }

    await downloadDatabase(api);

    if (firstStart && addonInstallReason && ["update", "install"].includes(addonInstallReason?.reason)) {
        chrome.runtime.openOptionsPage();
    }
}

/**
 * Computes the interval in days from a raw value stored in settings.
 * Adds 1 to the stored value or returns a default of 8 days if invalid.
 * 
 * @param {unknown} rawValue - The raw interval value from storage
 * @returns {number} The computed interval in days
 */
function computeIntervalDays(rawValue: unknown): number {
    const DEFAULT_INTERVAL = 8;
    if (typeof rawValue === 'number') {
        return rawValue + 1;
    }
    if (typeof rawValue === 'string') {
        const parsed = Number(rawValue);
        if (!Number.isNaN(parsed)) {
            return parsed + 1;
        }
    }
    return DEFAULT_INTERVAL;
}

/**
 * Resolves the API URL from the provided data object or falls back to resolveApiUrl().
 * 
 * @param {Record<string, unknown>} data - The data object containing potential API URL
 * @returns {Promise<string>} The resolved API URL
 */
async function resolveApiUrlFromData(data: Record<string, unknown>): Promise<string> {
    const api = data['api'];
    if (typeof api === 'string' && api.length > 0) {
        return api;
    }
    return resolveApiUrl();
}

src/scripts/background/install.ts

import { setLocal } from '../lib/chromeStorage';
import { checkIfUpdateNeeded } from './database';
import { donationReminderAllowed } from './donation';
import { initializePageAction } from './pageAction';

/**
 * Handles the extension installation or update event.
 * Initializes default settings, checks for database updates, and initializes the page action for the active tab.
 * 
 * @param {chrome.runtime.InstalledDetails} reason - Details about why the extension was installed (install, update, etc.)
 * @returns {Promise<void>}
 */
export async function handleExtensionInstalled(reason:chrome.runtime.InstalledDetails): Promise<void> {
    const donationAllowed = donationReminderAllowed(navigator.userAgent);

    await setLocal({
        themeHeader: true,
        sentry: false,
        displayDonationReminder: {
            active: false,
            allowedPlattform: donationAllowed,
        },
    });

    await checkIfUpdateNeeded(true, reason);

    const [activeTab] = await queryActiveTab();
    if (activeTab) {
        await initializePageAction(activeTab);
    }
}

/**
 * Queries for the currently active tab in the current window.
 * 
 * @returns {Promise<chrome.tabs.Tab[]>} Array containing the active tab (if any)
 */
async function queryActiveTab(): Promise<chrome.tabs.Tab[]> {
    return new Promise((resolve) => {
        chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
            resolve(tabs);
        });
    });
}

These docstrings provide clear documentation for:

  • Function purposes
  • Parameter descriptions with types
  • Return type information
  • Key behavioral notes

The docstrings follow JSDoc conventions and will be recognized by TypeScript tooling for IntelliSense and documentation generation.

@shadowwwind shadowwwind merged commit 0a2a050 into master Nov 23, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

On update the extension opens the settings page

3 participants