Add incoming webhooks, fix stale service worker and push re-registration

- Webhooks for automations: per-job secret, Gitea/GitHub HMAC signatures,
  payload appended to the instructions; settings on the automations page
- Service worker gets a new file name per build (proxies that cache *.js
  served a stale worker, which broke updates and Android installation);
  /sw.js is a kill switch that removes old workers
- Push: devices re-register their subscription with the server on start and
  before a test; the test reports why a push service rejected a message

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-09 00:38:04 +01:00
1 parent 6dffcb501a
commit 10d4b64289
16 files changed
+267 -18

No files matched your search

+9 -4
View File
@@ -6,7 +6,7 @@ import { getLang, languages, setLang, useT, type Key } from "../i18n";
import { navigate } from "../router";
import { useStore } from "../store";
import { canPrompt, isInstalled, onInstallChange, platformHint, promptInstall } from "../install";
import { currentSubscription, disablePush, enablePush, pushSupported, testPush } from "../push";
import { currentSubscription, disablePush, enablePush, pushSupported, syncPush, testPush } from "../push";
import { applyTheme, getTheme, getThemeMode, onThemeChange, THEME_MODES, THEMES, type Theme, type ThemeMode } from "../theme";
import { setReasoningMode, useReasoningMode, type ReasoningMode } from "../prefs";
import { ModelSelect } from "./ModelSelect";
@@ -149,7 +149,11 @@ function PushControl() {
if (!pushSupported()) return setState("unsupported");
if (Notification.permission === "denied") return setState("denied");
currentSubscription()
.then((s) => setState(s ? "on" : "off"))
.then(async (s) => {
setState(s ? "on" : "off");
// A subscription the server lost (or never got) is registered again.
if (s) await syncPush().catch(() => undefined);
})
.catch(() => setState("off"));
}, []);
const run = (f: () => Promise<unknown>) => async () => {
@@ -174,8 +178,9 @@ function PushControl() {
className="small"
disabled={busy}
onClick={run(async () => {
const n = await testPush();
toast(n > 0 ? t("settings.pushTestSent") : t("settings.pushTestNone"));
const r = await testPush();
if (r.sent > 0) toast(t("settings.pushTestSent"), "success");
else toast(r.errors?.length ? `${t("settings.pushTestFailed")}: ${r.errors.join("; ")}` : t("settings.pushTestNone"));
})}
>
{t("settings.pushTest")}