mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-07 20:24:39 +00:00
release build and other CI
This commit is contained in:
+21
-22
@@ -5,31 +5,30 @@
|
|||||||
"es2021": true,
|
"es2021": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": ["eslint:recommended"],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": "latest",
|
"ecmaVersion": "latest",
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"rules": {
|
"plugins": ["@typescript-eslint", "import"],
|
||||||
// allow importing ts extensions
|
"ignorePatterns": ["**/*.d.ts"],
|
||||||
"sort-imports": [
|
"globals": {
|
||||||
"error",
|
"__ENABLE_GH_RELEASE_UPDATE_CHECK__": "readonly",
|
||||||
{
|
"__GH_RELEASE_REPO__": "readonly",
|
||||||
"ignoreCase": true,
|
"__UPDATE_CHANNEL__": "readonly",
|
||||||
"ignoreDeclarationSort": true,
|
"__BUILD_LABEL__": "readonly"
|
||||||
"ignoreMemberSort": false,
|
|
||||||
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"import/extensions": [
|
|
||||||
"error",
|
|
||||||
"ignorePackages",
|
|
||||||
{
|
|
||||||
"js": "never",
|
|
||||||
"ts": "never",
|
|
||||||
"tsx": "never"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"plugins": ["import"]
|
"rules": {
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"no-undef": "off",
|
||||||
|
"no-useless-escape": "off",
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"no-empty": "off",
|
||||||
|
"no-case-declarations": "off",
|
||||||
|
"no-irregular-whitespace": "off",
|
||||||
|
"sort-imports": "off",
|
||||||
|
"import/extensions": "off",
|
||||||
|
"no-async-promise-executor": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
name: Build Extension
|
||||||
|
description: Install dependencies, build Chrome and Firefox extensions, and package zips.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
gh_release_update_check:
|
||||||
|
description: Enable GitHub release update checker in the built extension.
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
update_channel:
|
||||||
|
description: Update channel baked into the build (stable or nightly).
|
||||||
|
required: false
|
||||||
|
default: stable
|
||||||
|
build_label:
|
||||||
|
description: Optional build label for nightly display (e.g. run number).
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
release_repo:
|
||||||
|
description: GitHub repo slug for the update checker (owner/name).
|
||||||
|
required: false
|
||||||
|
default: BetterSEQTA/BetterSEQTA-Plus
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
version:
|
||||||
|
description: Version from package.json
|
||||||
|
value: ${{ steps.version.outputs.version }}
|
||||||
|
chrome_zip:
|
||||||
|
description: Path to the Chrome extension zip
|
||||||
|
value: ${{ steps.zip.outputs.chrome_zip }}
|
||||||
|
firefox_zip:
|
||||||
|
description: Path to the Firefox extension zip
|
||||||
|
value: ${{ steps.zip.outputs.firefox_zip }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Use Node.js 20.x
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Read version
|
||||||
|
id: version
|
||||||
|
shell: bash
|
||||||
|
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build extension
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GH_RELEASE_UPDATE_CHECK: ${{ inputs.gh_release_update_check }}
|
||||||
|
UPDATE_CHANNEL: ${{ inputs.update_channel }}
|
||||||
|
GH_RELEASE_REPO: ${{ inputs.release_repo }}
|
||||||
|
BUILD_LABEL: ${{ inputs.build_label }}
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Package zips
|
||||||
|
id: zip
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
(cd dist/chrome && zip -r "../betterseqtaplus-${VERSION}-chrome.zip" .)
|
||||||
|
(cd dist/firefox && zip -r "../betterseqtaplus-${VERSION}-firefox.zip" .)
|
||||||
|
echo "chrome_zip=dist/betterseqtaplus-${VERSION}-chrome.zip" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "firefox_zip=dist/betterseqtaplus-${VERSION}-firefox.zip" >> "$GITHUB_OUTPUT"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Experimental nightly build from `main`. May break. **Do not upload to Chrome Web Store or Firefox Add-ons.** Download, replace your sideloaded copy, and reload the extension.
|
||||||
@@ -3,8 +3,6 @@ name: NodeJS Build
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Nightly release workflow — updates the same "nightly" release with fresh builds from main.
|
||||||
|
# Runs only on BetterSEQTA/BetterSEQTA-Plus. Uses the default GITHUB_TOKEN.
|
||||||
|
|
||||||
|
name: Nightly Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 3 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
NIGHTLY_TAG: nightly
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightly:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build extension
|
||||||
|
id: build
|
||||||
|
uses: ./.github/actions/build-extension
|
||||||
|
with:
|
||||||
|
gh_release_update_check: "true"
|
||||||
|
update_channel: nightly
|
||||||
|
build_label: ${{ github.run_number }}
|
||||||
|
release_repo: ${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Ensure nightly release exists
|
||||||
|
run: |
|
||||||
|
if ! gh release view "${{ env.NIGHTLY_TAG }}" 2>/dev/null; then
|
||||||
|
gh release create "${{ env.NIGHTLY_TAG }}" \
|
||||||
|
--prerelease \
|
||||||
|
--title "Nightly" \
|
||||||
|
--notes-file .github/nightly-release-notes.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload nightly assets
|
||||||
|
run: |
|
||||||
|
gh release upload "${{ env.NIGHTLY_TAG }}" \
|
||||||
|
--clobber \
|
||||||
|
"${{ steps.build.outputs.chrome_zip }}" \
|
||||||
|
"${{ steps.build.outputs.firefox_zip }}"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: PR CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Use Node.js 20.x
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
env:
|
||||||
|
ESLINT_USE_FLAT_CONFIG: "false"
|
||||||
|
|
||||||
|
- name: Build extension
|
||||||
|
uses: ./.github/actions/build-extension
|
||||||
|
with:
|
||||||
|
gh_release_update_check: "false"
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Manual release workflow only — runs on BetterSEQTA/BetterSEQTA-Plus via workflow_dispatch.
|
||||||
|
# Bump package.json version on main, confirm when dispatching, then run.
|
||||||
|
# Uses the default GITHUB_TOKEN (contents: write).
|
||||||
|
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version_updated:
|
||||||
|
description: I have already updated the version in package.json
|
||||||
|
type: boolean
|
||||||
|
required: true
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Confirm version was updated
|
||||||
|
if: inputs.version_updated != true
|
||||||
|
run: |
|
||||||
|
echo "Check the confirmation box: you must update package.json version before releasing."
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Read version
|
||||||
|
id: version
|
||||||
|
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build extension
|
||||||
|
id: build
|
||||||
|
uses: ./.github/actions/build-extension
|
||||||
|
with:
|
||||||
|
gh_release_update_check: "true"
|
||||||
|
update_channel: stable
|
||||||
|
release_repo: ${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Create release if missing
|
||||||
|
run: |
|
||||||
|
if ! gh release view "${{ steps.version.outputs.version }}" 2>/dev/null; then
|
||||||
|
gh release create "${{ steps.version.outputs.version }}" \
|
||||||
|
--title "${{ steps.version.outputs.version }}" \
|
||||||
|
--notes "Edit this release description on GitHub."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload release assets
|
||||||
|
run: |
|
||||||
|
gh release upload "${{ steps.version.outputs.version }}" \
|
||||||
|
--clobber \
|
||||||
|
"${{ steps.build.outputs.chrome_zip }}" \
|
||||||
|
"${{ steps.build.outputs.firefox_zip }}"
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
- [Documentation home](https://docs.betterseqta.org/)
|
- [Documentation home](https://docs.betterseqta.org/)
|
||||||
- [Installation](https://docs.betterseqta.org/install/)
|
- [Installation](https://docs.betterseqta.org/install/)
|
||||||
- [Contributing](https://docs.betterseqta.org/contributing/)
|
- [Contributing](https://docs.betterseqta.org/contributing/)
|
||||||
|
- [GitHub releases & CI](RELEASES.md) — workflows, nightly builds, update detector
|
||||||
- [Architecture](https://docs.betterseqta.org/architecture/)
|
- [Architecture](https://docs.betterseqta.org/architecture/)
|
||||||
- [Contribution guidelines (repository)](../CONTRIBUTING.md)
|
- [Contribution guidelines (repository)](../CONTRIBUTING.md)
|
||||||
- [Troubleshooting](https://docs.betterseqta.org/troubleshooting/)
|
- [Troubleshooting](https://docs.betterseqta.org/troubleshooting/)
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# GitHub releases, CI, and the update detector
|
||||||
|
|
||||||
|
BetterSEQTA+ is distributed on the Chrome Web Store and Firefox Add-ons, but some users sideload builds from GitHub. This document explains how automated builds, releases, and the in-extension update badge work.
|
||||||
|
|
||||||
|
All published releases target the upstream repository: **[BetterSEQTA/BetterSEQTA-Plus](https://github.com/BetterSEQTA/BetterSEQTA-Plus)**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph ci [Continuous integration]
|
||||||
|
PrCi[pr-ci.yml — every PR]
|
||||||
|
Mvp[mvp.yml — push to main]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph releases [GitHub releases]
|
||||||
|
Manual[release.yml — manual stable]
|
||||||
|
Nightly[nightly.yml — daily cron]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph output [Outputs]
|
||||||
|
Zips["betterseqtaplus-VERSION-chrome.zip\nbetterseqtaplus-VERSION-firefox.zip"]
|
||||||
|
GhStable["Release tag: 3.7.0"]
|
||||||
|
GhNightly["Release tag: nightly"]
|
||||||
|
Badge[Update badge in settings]
|
||||||
|
end
|
||||||
|
|
||||||
|
PrCi -->|build only| NoRelease[No release]
|
||||||
|
Mvp -->|artifact| DistZip[dist.zip artifact]
|
||||||
|
|
||||||
|
Manual --> Zips
|
||||||
|
Manual --> GhStable
|
||||||
|
Manual --> Badge
|
||||||
|
|
||||||
|
Nightly --> Zips
|
||||||
|
Nightly --> GhNightly
|
||||||
|
Nightly --> Badge
|
||||||
|
```
|
||||||
|
|
||||||
|
| Workflow | Trigger | Creates a release? | Update detector in build? |
|
||||||
|
|----------|---------|------------------|---------------------------|
|
||||||
|
| `pr-ci.yml` | Every pull request to `main` | No | No |
|
||||||
|
| `mvp.yml` | Every push to `main` | No | No |
|
||||||
|
| `release.yml` | Manual (`workflow_dispatch`) | Yes — stable version tag | Yes — stable channel |
|
||||||
|
| `nightly.yml` | Daily at 03:00 UTC + manual | Yes — reuses `nightly` tag | Yes — nightly channel |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Shared build action
|
||||||
|
|
||||||
|
All release and CI builds that need packaged extensions use the composite action at [`.github/actions/build-extension/action.yml`](../.github/actions/build-extension/action.yml).
|
||||||
|
|
||||||
|
It:
|
||||||
|
|
||||||
|
1. Installs dependencies (`npm install --legacy-peer-deps`)
|
||||||
|
2. Runs `npm run build` (Chrome then Firefox via Vite)
|
||||||
|
3. Zips each unpacked folder into sideload-ready archives:
|
||||||
|
- `dist/betterseqtaplus-{version}-chrome.zip`
|
||||||
|
- `dist/betterseqtaplus-{version}-firefox.zip`
|
||||||
|
|
||||||
|
The `{version}` comes from `package.json`.
|
||||||
|
|
||||||
|
### Build-time flags (release builds only)
|
||||||
|
|
||||||
|
Release and nightly workflows pass environment variables into Vite, which bakes them into the extension at compile time via `define` in [`vite.config.ts`](../vite.config.ts):
|
||||||
|
|
||||||
|
| Variable | Stable release | Nightly | PR / local dev |
|
||||||
|
|----------|----------------|---------|----------------|
|
||||||
|
| `GH_RELEASE_UPDATE_CHECK` | `true` | `true` | `false` / unset |
|
||||||
|
| `UPDATE_CHANNEL` | `stable` | `nightly` | `stable` (unused) |
|
||||||
|
| `GH_RELEASE_REPO` | `BetterSEQTA/BetterSEQTA-Plus` | same | same |
|
||||||
|
| `BUILD_LABEL` | empty | GitHub run number | empty |
|
||||||
|
|
||||||
|
When `GH_RELEASE_UPDATE_CHECK` is not `true`, the update-checker code is tree-shaken out of the bundle. PR CI builds and local `npm run build` do **not** include the update badge.
|
||||||
|
|
||||||
|
To test a release-style build locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PowerShell
|
||||||
|
$env:GH_RELEASE_UPDATE_CHECK="true"
|
||||||
|
$env:UPDATE_CHANNEL="stable"
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# bash
|
||||||
|
GH_RELEASE_UPDATE_CHECK=true UPDATE_CHANNEL=stable npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stable release (`release.yml`)
|
||||||
|
|
||||||
|
**Purpose:** A safe, manual way to publish versioned builds that users can download from GitHub.
|
||||||
|
|
||||||
|
**Trigger:** Manual only — Actions → **Release** → **Run workflow**. There is no schedule or automatic trigger.
|
||||||
|
|
||||||
|
When dispatching, check **“I have already updated the version in package.json”**. The workflow will not run without that confirmation.
|
||||||
|
|
||||||
|
### Before you run it
|
||||||
|
|
||||||
|
1. Merge your changes to `main`.
|
||||||
|
2. Bump `version` in [`package.json`](../package.json) (e.g. `3.7.0` → `3.8.0`).
|
||||||
|
3. Commit and push that bump.
|
||||||
|
|
||||||
|
### What the workflow does
|
||||||
|
|
||||||
|
1. Aborts if the version confirmation was not checked.
|
||||||
|
2. Reads the version from `package.json`.
|
||||||
|
3. Builds Chrome and Firefox with the update detector enabled (stable channel).
|
||||||
|
4. If no release exists for that tag: creates one (e.g. `3.8.0`) with a placeholder description.
|
||||||
|
5. If a release already exists for that tag: **only replaces the zip assets** (`--clobber`). Title and body are left unchanged.
|
||||||
|
6. Uploads `betterseqtaplus-{version}-chrome.zip` and `-firefox.zip`.
|
||||||
|
|
||||||
|
On first publish, edit the **title** and **release notes** on GitHub afterward. Re-running for the same version refreshes the files only.
|
||||||
|
|
||||||
|
### Downloading and installing
|
||||||
|
|
||||||
|
1. Open [github.com/BetterSEQTA/BetterSEQTA-Plus/releases](https://github.com/BetterSEQTA/BetterSEQTA-Plus/releases).
|
||||||
|
2. Pick the version you want.
|
||||||
|
3. Download `betterseqtaplus-{version}-chrome.zip` or `-firefox.zip`.
|
||||||
|
4. Unzip and load the unpacked folder as a temporary extension (Chrome: Extensions → Load unpacked; Firefox: `about:debugging` → Load Temporary Add-on).
|
||||||
|
|
||||||
|
**These GitHub builds are for sideloading only. Do not upload them to the Chrome Web Store or Firefox Add-ons.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nightly release (`nightly.yml`)
|
||||||
|
|
||||||
|
**Purpose:** Continuous experimental builds from `main` so testers always have a single place to get the latest code.
|
||||||
|
|
||||||
|
**Trigger:**
|
||||||
|
|
||||||
|
- Automatically every day at **03:00 UTC**
|
||||||
|
- Manually via Actions → **Nightly Release** → **Run workflow**
|
||||||
|
|
||||||
|
### What the workflow does
|
||||||
|
|
||||||
|
1. Builds from the current `main` branch with the update detector enabled (nightly channel).
|
||||||
|
2. Uses a fixed release tag: **`nightly`** (marked as prerelease).
|
||||||
|
3. On first run: creates the `nightly` release with the text in [`.github/nightly-release-notes.md`](../.github/nightly-release-notes.md).
|
||||||
|
4. On every subsequent run: **replaces** the zip assets on the same release (`--clobber`). The release title and body are not rewritten.
|
||||||
|
|
||||||
|
The nightly release body warns that builds are experimental and must not be uploaded to extension stores.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PR CI (`pr-ci.yml`)
|
||||||
|
|
||||||
|
**Purpose:** Verify that every pull request builds cleanly in a fresh environment.
|
||||||
|
|
||||||
|
**Trigger:** Every pull request targeting `main`.
|
||||||
|
|
||||||
|
**Steps:**
|
||||||
|
|
||||||
|
1. `npm install --legacy-peer-deps`
|
||||||
|
2. `npm run lint` (ESLint on `src/**/*.{js,ts}`)
|
||||||
|
3. Build via the shared action with **no** update detector
|
||||||
|
|
||||||
|
No release is created and no artifacts are published for end users.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Push CI (`mvp.yml`)
|
||||||
|
|
||||||
|
**Purpose:** Build verification when code lands on `main`.
|
||||||
|
|
||||||
|
**Trigger:** Push to `main` only (not pull requests — those use `pr-ci.yml`).
|
||||||
|
|
||||||
|
Uploads a `dist.zip` artifact containing the full `dist/` folder for debugging. No release, no update detector.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Release workflows run **only on [BetterSEQTA/BetterSEQTA-Plus](https://github.com/BetterSEQTA/BetterSEQTA-Plus)**. They use the default `GITHUB_TOKEN` with `contents: write` — no extra secrets or PATs required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update detector (in-extension)
|
||||||
|
|
||||||
|
GitHub release builds include a small feature that tells sideload users when a newer build is available, so they do not have to check GitHub manually.
|
||||||
|
|
||||||
|
### Where it appears
|
||||||
|
|
||||||
|
In the **settings popup** header (top-right): an amber **“Update available — X.X.X”** pill when an update exists, plus a muted line:
|
||||||
|
|
||||||
|
> GitHub release build — do not upload to extension stores.
|
||||||
|
|
||||||
|
Clicking the badge opens the relevant GitHub releases page.
|
||||||
|
|
||||||
|
### How it checks for updates
|
||||||
|
|
||||||
|
Implementation: [`src/utils/githubReleaseUpdate.ts`](../src/utils/githubReleaseUpdate.ts)
|
||||||
|
|
||||||
|
**Stable channel** (from `release.yml` builds):
|
||||||
|
|
||||||
|
1. Fetches releases from the GitHub API for `BetterSEQTA/BetterSEQTA-Plus`.
|
||||||
|
2. Ignores the `nightly` tag and any non-semver tags.
|
||||||
|
3. Finds the highest semver tag.
|
||||||
|
4. Compares it to `browser.runtime.getManifest().version`.
|
||||||
|
5. Shows the badge if the remote version is newer.
|
||||||
|
|
||||||
|
**Nightly channel** (from `nightly.yml` builds):
|
||||||
|
|
||||||
|
1. Fetches the `nightly` release.
|
||||||
|
2. Compares its `published_at` timestamp to `lastSeenNightlyPublishedAt` in extension storage.
|
||||||
|
3. On first install, records the current publish time without showing a badge.
|
||||||
|
4. Shows **“Update available — nightly #123”** (run number) when a newer nightly has been published.
|
||||||
|
|
||||||
|
Checks are throttled to once every **6 hours** per browser profile (`localStorage` key `bsplus_lastGhReleaseCheck`). Recent results are cached in memory for the session.
|
||||||
|
|
||||||
|
### Dev override (testing)
|
||||||
|
|
||||||
|
To test the badge without publishing a real release:
|
||||||
|
|
||||||
|
1. Open settings and unlock **dev mode** (click the logo, type `dev`).
|
||||||
|
2. In the developer section, set **GitHub latest version override** to a version higher than your installed one (e.g. `9.9.9`).
|
||||||
|
3. Reopen settings — the badge should appear.
|
||||||
|
|
||||||
|
This only applies when dev mode is on. Clear the field to return to normal API checks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File reference
|
||||||
|
|
||||||
|
| Path | Role |
|
||||||
|
|------|------|
|
||||||
|
| `.github/actions/build-extension/action.yml` | Shared install, build, zip |
|
||||||
|
| `.github/workflows/release.yml` | Manual stable releases |
|
||||||
|
| `.github/workflows/nightly.yml` | Nightly releases |
|
||||||
|
| `.github/workflows/pr-ci.yml` | PR lint + build |
|
||||||
|
| `.github/workflows/mvp.yml` | Push-to-main build artifact |
|
||||||
|
| `.github/nightly-release-notes.md` | Static body for the `nightly` release |
|
||||||
|
| `vite.config.ts` | Injects build-time `define` flags |
|
||||||
|
| `src/env.d.ts` | TypeScript declarations for those flags |
|
||||||
|
| `src/utils/githubReleaseUpdate.ts` | Update check logic |
|
||||||
|
| `src/interface/pages/settings.svelte` | Badge and disclaimer UI |
|
||||||
|
| `src/interface/pages/settings/general.svelte` | Dev override input |
|
||||||
|
| `src/types/storage.ts` | `devGhReleaseVersionOverride`, `lastSeenNightlyPublishedAt` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick reference
|
||||||
|
|
||||||
|
### Publish a stable release
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. Bump version in package.json on main
|
||||||
|
2. Actions → Release → Run workflow → confirm version checkbox
|
||||||
|
3. Edit release title/notes on GitHub (first time only)
|
||||||
|
4. Re-run with same version to refresh zips without changing release text
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get the latest nightly
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://github.com/BetterSEQTA/BetterSEQTA-Plus/releases/tag/nightly
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify a PR locally
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run lint
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
+23
-3
@@ -119,12 +119,13 @@ git checkout -b feature/my-new-feature
|
|||||||
|
|
||||||
If your changes require documentation updates, include them in the same PR.
|
If your changes require documentation updates, include them in the same PR.
|
||||||
|
|
||||||
4. **Run Tests**
|
4. **Run CI checks locally**
|
||||||
|
|
||||||
Make sure all tests pass before submitting your PR:
|
Pull requests trigger **PR CI**, which lints and builds in a clean environment:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm test
|
npm run lint
|
||||||
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Submit Your PR**
|
5. **Submit Your PR**
|
||||||
@@ -139,6 +140,25 @@ git checkout -b feature/my-new-feature
|
|||||||
|
|
||||||
Once approved, a maintainer will merge your PR.
|
Once approved, a maintainer will merge your PR.
|
||||||
|
|
||||||
|
### GitHub Actions workflows
|
||||||
|
|
||||||
|
See [RELEASES.md](RELEASES.md) for a full guide (workflows, sideload installs, and update detector).
|
||||||
|
|
||||||
|
| Workflow | Trigger | Purpose |
|
||||||
|
|----------|---------|---------|
|
||||||
|
| `pr-ci.yml` | Every PR to `main` | Typecheck, lint, and build (no release) |
|
||||||
|
| `mvp.yml` | Push to `main` | Build and upload `dist.zip` artifact |
|
||||||
|
| `release.yml` | Manual (`workflow_dispatch`) | Stable release on [BetterSEQTA/BetterSEQTA-Plus](https://github.com/BetterSEQTA/BetterSEQTA-Plus) tagged with `package.json` version |
|
||||||
|
| `nightly.yml` | Daily cron + manual | Updates the fixed `nightly` prerelease with latest `main` builds |
|
||||||
|
|
||||||
|
**Releasing a stable version:** bump `version` in `package.json` on `main`, then manually run the **Release** workflow and confirm the version checkbox. Edit the release title and notes on GitHub after the first publish. Re-running for the same tag only updates the zip files. Assets are `betterseqtaplus-{version}-chrome.zip` and `-firefox.zip`.
|
||||||
|
|
||||||
|
**Nightly builds** replace assets on the same `nightly` release. The release body warns that builds are experimental and must not be uploaded to extension stores.
|
||||||
|
|
||||||
|
**GitHub release builds** include an in-extension update checker (settings header badge). **PR CI and local dev builds do not.**
|
||||||
|
|
||||||
|
Release workflows are dispatched only on the main **BetterSEQTA/BetterSEQTA-Plus** repository and use the default `GITHUB_TOKEN`.
|
||||||
|
|
||||||
### Coding Standards
|
### Coding Standards
|
||||||
|
|
||||||
We follow TypeScript best practices and have a consistent code style:
|
We follow TypeScript best practices and have a consistent code style:
|
||||||
|
|||||||
+5
-1
@@ -17,7 +17,8 @@
|
|||||||
"build:dev": "cross-env MODE=chrome SOURCEMAP=true vite build && cross-env MODE=firefox SOURCEMAP=true vite build",
|
"build:dev": "cross-env MODE=chrome SOURCEMAP=true vite build && cross-env MODE=firefox SOURCEMAP=true vite build",
|
||||||
"convert:safari": "xcrun safari-web-extension-converter dist/safari --project-location . --app-name $npm_package_name-safari",
|
"convert:safari": "xcrun safari-web-extension-converter dist/safari --project-location . --app-name $npm_package_name-safari",
|
||||||
"dependency-graph": "depcruise src --include-only \"^src\" --output-type dot | dot -T svg > dependency-graph.svg",
|
"dependency-graph": "depcruise src --include-only \"^src\" --output-type dot | dot -T svg > dependency-graph.svg",
|
||||||
"release": "gh release create $npm_package_name@$npm_package_version ./dist/*.zip --generate-notes",
|
"lint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint \"src/**/*.{js,ts}\"",
|
||||||
|
"release": "gh release create $npm_package_version --repo BetterSEQTA/BetterSEQTA-Plus ./dist/*.zip --generate-notes",
|
||||||
"publish": "bun lib/publish.js --b",
|
"publish": "bun lib/publish.js --b",
|
||||||
"zip": "bedframe zip"
|
"zip": "bedframe zip"
|
||||||
},
|
},
|
||||||
@@ -45,9 +46,12 @@
|
|||||||
"@types/mime-types": "^3.0.1",
|
"@types/mime-types": "^3.0.1",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
||||||
|
"@typescript-eslint/parser": "^8.60.1",
|
||||||
"cross-env": "^10.0.0",
|
"cross-env": "^10.0.0",
|
||||||
"dependency-cruiser": "^17.0.1",
|
"dependency-cruiser": "^17.0.1",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"glob": "^11.0.1",
|
"glob": "^11.0.1",
|
||||||
"mime-types": "^3.0.1",
|
"mime-types": "^3.0.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
|
|||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
declare const __ENABLE_GH_RELEASE_UPDATE_CHECK__: boolean;
|
||||||
|
declare const __GH_RELEASE_REPO__: string;
|
||||||
|
declare const __UPDATE_CHANNEL__: "stable" | "nightly";
|
||||||
|
declare const __BUILD_LABEL__: string;
|
||||||
@@ -19,6 +19,12 @@
|
|||||||
import CloudPanel from "../components/CloudPanel.svelte";
|
import CloudPanel from "../components/CloudPanel.svelte";
|
||||||
import DisclaimerModal from "../components/DisclaimerModal.svelte";
|
import DisclaimerModal from "../components/DisclaimerModal.svelte";
|
||||||
import { settingsPopup } from "../hooks/SettingsPopup";
|
import { settingsPopup } from "../hooks/SettingsPopup";
|
||||||
|
import {
|
||||||
|
checkGithubReleaseUpdate,
|
||||||
|
dismissNightlyUpdate,
|
||||||
|
isGhReleaseUpdateCheckEnabled,
|
||||||
|
type GhReleaseUpdateInfo,
|
||||||
|
} from "@/utils/githubReleaseUpdate";
|
||||||
|
|
||||||
let devModeSequence = "";
|
let devModeSequence = "";
|
||||||
let settingsActiveTab = $state(0);
|
let settingsActiveTab = $state(0);
|
||||||
@@ -26,6 +32,18 @@
|
|||||||
let disclaimerCallbacks = $state<{ onConfirm: () => void, onCancel: () => void } | null>(null);
|
let disclaimerCallbacks = $state<{ onConfirm: () => void, onCancel: () => void } | null>(null);
|
||||||
let disclaimerTitle = $state("Confirm");
|
let disclaimerTitle = $state("Confirm");
|
||||||
let disclaimerMessage = $state("");
|
let disclaimerMessage = $state("");
|
||||||
|
const ghReleaseUpdateEnabled = isGhReleaseUpdateCheckEnabled();
|
||||||
|
let ghReleaseUpdate = $state<GhReleaseUpdateInfo | null>(null);
|
||||||
|
|
||||||
|
const openGhRelease = () => {
|
||||||
|
const url = ghReleaseUpdate?.url
|
||||||
|
?? "https://github.com/BetterSEQTA/BetterSEQTA-Plus/releases";
|
||||||
|
if (ghReleaseUpdate?.available) {
|
||||||
|
dismissNightlyUpdate();
|
||||||
|
}
|
||||||
|
window.open(url, "_blank");
|
||||||
|
closeExtensionPopup();
|
||||||
|
};
|
||||||
|
|
||||||
const handleDevModeToggle = () => {
|
const handleDevModeToggle = () => {
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
@@ -98,6 +116,12 @@
|
|||||||
if (standalone) {
|
if (standalone) {
|
||||||
StandaloneStore.setStandalone(true);
|
StandaloneStore.setStandalone(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ghReleaseUpdateEnabled) {
|
||||||
|
void checkGithubReleaseUpdate().then((info) => {
|
||||||
|
ghReleaseUpdate = info;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -134,7 +158,25 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{#if !standalone}
|
{#if !standalone}
|
||||||
<div class="flex absolute top-1 right-1 gap-1 items-center">
|
<div class="flex absolute top-1 right-1 gap-1 items-start">
|
||||||
|
{#if ghReleaseUpdateEnabled}
|
||||||
|
<div class="flex flex-col items-end gap-0.5 max-w-[9rem] mr-0.5">
|
||||||
|
{#if ghReleaseUpdate?.available}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={openGhRelease}
|
||||||
|
class="px-1.5 py-0.5 text-[10px] font-semibold leading-tight text-white rounded-full bg-amber-500 hover:bg-amber-600 dark:bg-amber-600 dark:hover:bg-amber-500"
|
||||||
|
title="Open GitHub release"
|
||||||
|
>
|
||||||
|
Update available — {ghReleaseUpdate.label}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
<p class="text-[9px] leading-tight text-right text-zinc-500 dark:text-zinc-400">
|
||||||
|
GitHub release build — do not upload to extension stores.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="flex gap-1 items-center">
|
||||||
<button
|
<button
|
||||||
onclick={openAbout}
|
onclick={openAbout}
|
||||||
class="flex justify-center items-center w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
class="flex justify-center items-center w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
||||||
@@ -156,6 +198,7 @@
|
|||||||
>
|
>
|
||||||
{"\uecba"}
|
{"\uecba"}
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- <button
|
<!-- <button
|
||||||
onclick={openMinecraftServer}
|
onclick={openMinecraftServer}
|
||||||
|
|||||||
@@ -585,6 +585,21 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col gap-2 px-4 py-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-bold">GitHub latest version override</h2>
|
||||||
|
<p class="text-xs">Pretend a newer GitHub release exists to test the update badge. Only applies when dev mode is on.</p>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="e.g. 9.9.9"
|
||||||
|
value={$settingsState.devGhReleaseVersionOverride ?? ""}
|
||||||
|
oninput={(e) => {
|
||||||
|
settingsState.devGhReleaseVersionOverride = e.currentTarget.value;
|
||||||
|
}}
|
||||||
|
class="px-2 py-1 text-xs rounded border bg-white dark:bg-zinc-800 border-zinc-300 dark:border-zinc-700 text-zinc-900 dark:text-zinc-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ export interface SettingsState {
|
|||||||
animations: boolean;
|
animations: boolean;
|
||||||
defaultPage: string;
|
defaultPage: string;
|
||||||
devMode?: boolean;
|
devMode?: boolean;
|
||||||
|
/** Dev-only: pretend this is the latest GitHub release version for update badge testing. */
|
||||||
|
devGhReleaseVersionOverride?: string;
|
||||||
|
/** ISO timestamp of the last acknowledged nightly release publish time. */
|
||||||
|
lastSeenNightlyPublishedAt?: string;
|
||||||
originalDarkMode?: boolean;
|
originalDarkMode?: boolean;
|
||||||
newsSource?: string;
|
newsSource?: string;
|
||||||
mockNotices?: boolean;
|
mockNotices?: boolean;
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
import semver from "semver";
|
||||||
|
import browser from "webextension-polyfill";
|
||||||
|
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||||
|
|
||||||
|
const CHECK_THROTTLE_MS = 6 * 60 * 60 * 1000;
|
||||||
|
const LAST_CHECK_KEY = "bsplus_lastGhReleaseCheck";
|
||||||
|
const NIGHTLY_TAG = "nightly";
|
||||||
|
|
||||||
|
let cachedResult: GhReleaseUpdateInfo | null = null;
|
||||||
|
|
||||||
|
export interface GhReleaseUpdateInfo {
|
||||||
|
available: boolean;
|
||||||
|
label: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUpdateCheckEnabled(): boolean {
|
||||||
|
return typeof __ENABLE_GH_RELEASE_UPDATE_CHECK__ !== "undefined"
|
||||||
|
&& __ENABLE_GH_RELEASE_UPDATE_CHECK__;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRepoSlug(): string {
|
||||||
|
return typeof __GH_RELEASE_REPO__ !== "undefined"
|
||||||
|
? __GH_RELEASE_REPO__
|
||||||
|
: "BetterSEQTA/BetterSEQTA-Plus";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUpdateChannel(): "stable" | "nightly" {
|
||||||
|
return typeof __UPDATE_CHANNEL__ !== "undefined"
|
||||||
|
? __UPDATE_CHANNEL__
|
||||||
|
: "stable";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBuildLabel(): string {
|
||||||
|
return typeof __BUILD_LABEL__ !== "undefined" ? __BUILD_LABEL__ : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentVersion(): string {
|
||||||
|
return browser.runtime.getManifest().version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function releasesBaseUrl(): string {
|
||||||
|
return `https://github.com/${getRepoSlug()}/releases`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldThrottleCheck(): boolean {
|
||||||
|
try {
|
||||||
|
const last = localStorage.getItem(LAST_CHECK_KEY);
|
||||||
|
if (!last) return false;
|
||||||
|
return Date.now() - Number(last) < CHECK_THROTTLE_MS;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function markChecked(): void {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(LAST_CHECK_KEY, String(Date.now()));
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDevOverrideVersion(): string | null {
|
||||||
|
if (!settingsState.devMode) return null;
|
||||||
|
const override = settingsState.devGhReleaseVersionOverride?.trim();
|
||||||
|
return override || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareWithOverride(current: string): GhReleaseUpdateInfo | null {
|
||||||
|
const override = getDevOverrideVersion();
|
||||||
|
if (!override) return null;
|
||||||
|
|
||||||
|
const currentCoerced = semver.coerce(current);
|
||||||
|
const overrideCoerced = semver.coerce(override);
|
||||||
|
if (!currentCoerced || !overrideCoerced) return null;
|
||||||
|
|
||||||
|
if (semver.gt(overrideCoerced, currentCoerced)) {
|
||||||
|
return {
|
||||||
|
available: true,
|
||||||
|
label: override,
|
||||||
|
url: releasesBaseUrl(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { available: false, label: "", url: releasesBaseUrl() };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GhRelease {
|
||||||
|
tag_name: string;
|
||||||
|
published_at: string;
|
||||||
|
prerelease: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchJson<T>(url: string): Promise<T | null> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: { Accept: "application/vnd.github+json" },
|
||||||
|
});
|
||||||
|
if (!response.ok) return null;
|
||||||
|
return (await response.json()) as T;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStableSemverTag(tag: string): boolean {
|
||||||
|
if (tag === NIGHTLY_TAG) return false;
|
||||||
|
return semver.valid(semver.coerce(tag)) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkStableUpdate(current: string): Promise<GhReleaseUpdateInfo> {
|
||||||
|
const url = releasesBaseUrl();
|
||||||
|
const releases = await fetchJson<GhRelease[]>(
|
||||||
|
`https://api.github.com/repos/${getRepoSlug()}/releases`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!releases?.length) {
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
let latestTag: string | null = null;
|
||||||
|
let latestVersion: semver.SemVer | null = null;
|
||||||
|
|
||||||
|
for (const release of releases) {
|
||||||
|
const tag = release.tag_name;
|
||||||
|
if (!isStableSemverTag(tag)) continue;
|
||||||
|
|
||||||
|
const coerced = semver.coerce(tag);
|
||||||
|
if (!coerced) continue;
|
||||||
|
|
||||||
|
if (!latestVersion || semver.gt(coerced, latestVersion)) {
|
||||||
|
latestVersion = coerced;
|
||||||
|
latestTag = tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCoerced = semver.coerce(current);
|
||||||
|
if (!latestTag || !latestVersion || !currentCoerced) {
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semver.gt(latestVersion, currentCoerced)) {
|
||||||
|
return { available: true, label: latestTag, url: `${url}/tag/${latestTag}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkNightlyUpdate(): Promise<GhReleaseUpdateInfo> {
|
||||||
|
const url = `${releasesBaseUrl()}/tag/${NIGHTLY_TAG}`;
|
||||||
|
const release = await fetchJson<GhRelease>(
|
||||||
|
`https://api.github.com/repos/${getRepoSlug()}/releases/tags/${NIGHTLY_TAG}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!release?.published_at) {
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastSeen = settingsState.lastSeenNightlyPublishedAt;
|
||||||
|
const buildLabel = getBuildLabel();
|
||||||
|
const label = buildLabel ? `nightly #${buildLabel}` : "nightly";
|
||||||
|
|
||||||
|
if (!lastSeen) {
|
||||||
|
settingsState.lastSeenNightlyPublishedAt = release.published_at;
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new Date(release.published_at) > new Date(lastSeen)) {
|
||||||
|
return { available: true, label, url };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { available: false, label: "", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGhReleaseUpdateCheckEnabled(): boolean {
|
||||||
|
return isUpdateCheckEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkGithubReleaseUpdate(): Promise<GhReleaseUpdateInfo> {
|
||||||
|
const fallback = { available: false, label: "", url: releasesBaseUrl() };
|
||||||
|
|
||||||
|
if (!isUpdateCheckEnabled()) return fallback;
|
||||||
|
|
||||||
|
const current = getCurrentVersion();
|
||||||
|
const overrideResult = compareWithOverride(current);
|
||||||
|
if (overrideResult) return overrideResult;
|
||||||
|
|
||||||
|
if (shouldThrottleCheck()) {
|
||||||
|
return cachedResult ?? fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
markChecked();
|
||||||
|
|
||||||
|
const result =
|
||||||
|
getUpdateChannel() === "nightly"
|
||||||
|
? await checkNightlyUpdate()
|
||||||
|
: await checkStableUpdate(current);
|
||||||
|
|
||||||
|
cachedResult = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dismissNightlyUpdate(): void {
|
||||||
|
void (async () => {
|
||||||
|
const release = await fetchJson<GhRelease>(
|
||||||
|
`https://api.github.com/repos/${getRepoSlug()}/releases/tags/${NIGHTLY_TAG}`,
|
||||||
|
);
|
||||||
|
if (release?.published_at) {
|
||||||
|
settingsState.lastSeenNightlyPublishedAt = release.published_at;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
"src/**/*.js",
|
"src/**/*.js",
|
||||||
"src/**/*.svelte",
|
"src/**/*.svelte",
|
||||||
"src/interface/+layout.svelte",
|
"src/interface/+layout.svelte",
|
||||||
|
"src/env.d.ts",
|
||||||
"declarations.d.ts"
|
"declarations.d.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,16 @@ const mode = process.env.MODE || "chrome"; // Check the environment variable to
|
|||||||
const useMillion = mode.toLowerCase() !== "firefox";
|
const useMillion = mode.toLowerCase() !== "firefox";
|
||||||
|
|
||||||
export default defineConfig(({ command }) => ({
|
export default defineConfig(({ command }) => ({
|
||||||
|
define: {
|
||||||
|
__ENABLE_GH_RELEASE_UPDATE_CHECK__: JSON.stringify(
|
||||||
|
process.env.GH_RELEASE_UPDATE_CHECK === "true",
|
||||||
|
),
|
||||||
|
__GH_RELEASE_REPO__: JSON.stringify(
|
||||||
|
process.env.GH_RELEASE_REPO ?? "BetterSEQTA/BetterSEQTA-Plus",
|
||||||
|
),
|
||||||
|
__UPDATE_CHANNEL__: JSON.stringify(process.env.UPDATE_CHANNEL ?? "stable"),
|
||||||
|
__BUILD_LABEL__: JSON.stringify(process.env.BUILD_LABEL ?? ""),
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
base64Loader,
|
base64Loader,
|
||||||
InlineWorkerPlugin(),
|
InlineWorkerPlugin(),
|
||||||
|
|||||||
Reference in New Issue
Block a user