Update getHelpPathFromRoute to point at the help pages that actually
exist: rename source-* links to provider-*, the home alias to domains,
and add coverage for login, signup, notifications, provider features,
domain history, import/export, subdomains, services, checks,
availability and whois routes.
Both documents are served no-cache but had no validator, so every
revalidation re-downloaded the full body and could never return 304.
Serve them via http.ServeContent with an ETag computed once at handler
creation, letting conditional requests answer 304. manifest.json is now
pre-rendered once instead of re-read and re-transformed per request.
The service worker controls all client-side caching, so it must never be
pinned to an old version. It was served with no explicit cache policy;
mark it no-cache so updates are always picked up.
/fonts, /img and /favicon.ico live at stable, non-content-hashed URLs, so
the 7-day immutable header meant a changed favicon, image or font would
not reach already-cached clients for up to a week.
Serve them with a revalidated policy (max-age=86400, must-revalidate) set
on the successful response instead, and drop the now-unused immutable
middleware. Only the content-hashed /_app tree keeps immutable.
The immutable middleware set Cache-Control before the handler ran, so a
missing content-hashed asset under /_app/immutable/ 404'd with the 7-day
immutable header still attached: a stale client could pin a negative
response for a week. The stale-bundle fallback also only covered .js,
leaving dropped .css (and other) chunks exposed.
Open the asset first and set the immutable directive only on a successful
serve, so a 404 never inherits it. Broaden the stale-asset path to mark
any missing /_app/immutable/ response no-cache, still returning the
self-healing reload module for .js.
The SPA references content-hashed bundles under /_app/immutable/ embedded
in the binary. After a deploy the binary ships new hashes and drops the old
ones, so a browser reusing a cached HTML page (or a stale /_app bundle)
requests hashes that 404: the page renders but the app never starts, leaving
it visible but frozen.
- routes.go: serve the page HTML (and the rewritten manifest.json) with
Cache-Control no-cache so clients always revalidate and load a page that
points at bundles which actually exist; /_app/* stays immutable.
- routes.go: when a missing /_app/immutable/*.js is requested (a stale cached
client), return a self-healing reload module (200) instead of a dead 404 so
already-stuck clients recover on their own.
The reload module is issued synchronously and throws at the end of evaluation
so the failing import() rejects: SvelteKit's bootstrap never reaches
kit.start(...), avoiding a "kit.start is not a function" TypeError. We do not
touch the Cache Storage API: the service worker manages its own cache
lifecycle and async caches.* work would lose the race against kit.start.
When updating a service on a published zone, the backend creates a new
derivative zone with a new ID. The frontend was navigating back using the
old zone ID, causing the layout loader to re-fetch the pre-update zone and
overwrite the store, making the change appear lost. Unify add and update
paths to always refresh domains and navigate to the returned zone ID.
Move the by-name sort into listScopedCheckers so every consumer gets a
stable ordering, and drop the redundant sort wrappers in CheckerListPage
and CheckResultsDashboard.
Add with_availables query param to checker status endpoint; restrict
default listing to checkers that auto-schedule or have an active plan.
Introduce IsAutoScheduled helper unifying scheduler eligibility logic.
The route at /domains/[dn]/checks listed checker configurations, not check
runs. Rename it to /checkers and use /checks for a new aggregated dashboard
that surfaces the latest result for every enabled checker across the domain
and its services in one place. Same split applied at service scope.
Refactors the admin backup usecase to share per-user collection logic
via backupOneUser(), then adds BackupUser() which filters system-wide
collections (checker configs, plans, evaluations, executions, discovery)
down to the requesting user by UserId.
Wires the backup usecase into the public API dependency graph and adds
a download button in the /me settings page near the delete-account
section.
Replace the per-route editableGroups/readOnlyGroups callback pair in
CheckerConfigPage with a single groups prop that returns both lists, and
switch all call-sites to buildOptionGroupLayout. Add showCheckerInfo and
showExecutions flags so the admin checker page can reuse CheckerConfigPage
without schedule controls or execution links.
CheckerOptionsPanel now shows an "Overriding inherited" badge and a
"Reset to inherited" link for fields where a local value shadows an
inherited one. CheckerOptionsGroups shows the effective inherited value
next to the type hint in read-only groups.
Extend collectAllOptionDocs, splitPositionalOptions, and
collectAutoFillKeys to include serviceOpts alongside the existing
adminOpts/userOpts/domainOpts buckets.
Add buildOptionGroupLayout which derives editable/read-only group lists
from the checker's option documentation and a CheckerPageScope ("admin",
"domain", or "service"). This consolidates the per-route hand-curated
arrays into one place.
Improve splitPositionalOptions with an optional isCurrentScope predicate
so the correct positional is selected for the page's scope instead of
always taking the last stored entry.
Make CheckerScope.domainId optional so callers can target the global
admin scope (no domain). getScopedCheckStatus, getScopedCheckOptions,
and updateScopedCheckOptions now short-circuit to the admin /checkers/*
routes when domainId is absent. All narrower-scope callsites gain the
non-null assertion required by the type change.
Add a `disableMetrics` store that gets set when metrics fail to load,
preventing users from switching to a broken metrics view. Also disable
the JSON view button when no observations data is present.
Remove the invalid bind:rr chain between RecordLine and RecordText (RecordText only reads rr, never writes back), and use refreshDomains + invalidateAll instead of directly setting thisZone when the returned zone has a new ID, matching the pattern already used in the domain layout.
Treat io.EOF from ShouldBindJSON as "no body provided" so callers can
POST without a request body to trigger random password generation. Also
fix double-pointer bug (&urp where urp is already *resetPassword) and
bump checker dependencies.
When POST /auth returned 401 with an errmsg (e.g. "Invalid username or
password"), customFetch was ignoring it and attempting a session refresh
via GET /auth. The refresh also failed, ultimately throwing
NotAuthorizedError("Not authenticated") instead of the actual credential
error. This also triggered an extra toast in some cases.
Fix by reading errmsg from any 401 response body first: if present, throw
it directly as a plain Error, bypassing the session-refresh logic entirely.
The previous click-to-copy behavior wasn't obvious to users. Show the
URL in a modal with an explicit copy button and a brief scrape_configs
example so users understand what the endpoint is for.
When switching between checkers via the sidebar, plan.enabled retained
the previous checker's values because the guard condition prevented
re-initialization. Reset all derived state eagerly on checkerId change
and always repopulate plan.enabled from fresh status.
- Move enable/disable toggle to card header (inverted to "Enable scheduling")
- Replace Save button with debounced autosave (700ms) with inline status indicator
- Show interval controls only when enabled; paused hint when disabled
- Remove obsolete no-schedule-yet alert and save button translation keys
The HTML placeholder attribute is rendered in plaintext even on
type="password" inputs, so an inherited secret value injected as a
placeholder was visible without toggling the eye button. Replace the
placeholder with bullets of the same length while the secret is hidden, and
reveal the real value only when the user explicitly toggles visibility.
Rules are now collapsed under the Advanced options toggle instead of
being always visible, and each rule's description is displayed as
helper text below the checkbox when available.
The GetCheckerOptions controller appends a synthetic positional carrying
resolved auto-fill values (consumed by RunCheckModal). splitPositionalOptions
was treating that last entry as the current scope, pushing actual stored
options into inheritedValues — they then showed as placeholders, broke
<select> value matching, and were sent as nil overrides on save. Callers now
pass the auto-fill key set so the synthetic positional is filtered out before
splitting.
Adds an explicit Disabled field on CheckPlan so users can pause a
checker's automatic execution without clearing per-rule state. The
scheduler skips Disabled plans alongside fully-disabled ones, and the
schedule card exposes a switch bound through the existing save path.
Switch the bulk toggle from every-enabled to some-enabled so the
"All" switch reflects an OR across rules: on when at least one is
active, off only when all are disabled.
Rule toggle switches now call a dedicated handleSavePlan() wrapper with
"rules-updated"/"rules-update-failed" messages, separate from the schedule
card's "Schedule saved" toast. CheckerScheduleCard.save() is split into a
raw export (no toasts) and an internal handleSave() used by its own button.
The SDK's new POST /definition returns per-rule precheck errors for the
current options. happyDomain now calls it (or the in-process equivalent
when no remote endpoint is configured) while building each
CheckerStatus, exposes the result as CheckerStatus.PrecheckFailures,
and the rules card in the UI disables the toggle and shows the reason
for any rule whose prerequisites are unmet.
Replace class?: string with class?: ClassValue across Svelte components,
adopting the idiomatic Svelte 5 array syntax (class={["base", className]})
instead of string interpolation for combining static and dynamic classes.
When opening an execution detail page while the execution is still
pending or running, defer fetching observations/results/metrics and
poll the execution status every 3s until it reaches a terminal state.
The loading view shows a "Running" label in the meantime.
- Replace DRONE_TAG##v with DRONE_SEMVER across all pipelines
- Add missing VERSION build_args and tag-specific Docker publish steps to amd64 pipeline
- Add prerelease: true to amd64 release publish steps for consistency with arm64
- Pin swag and go-licenses versions with renovate annotations
- Add renovate regex manager to track go install versions in .drone.yml
- Add BuildKit cache mounts and OCI labels to Dockerfiles
- Improve Dockerfile layer efficiency (separate web/web-admin asset copies, smaller COPY targets)
- Move npm build/generate directives to separate generate_npm.go files with //go:build ignore
- Update README build instructions to include web-admin and correct step order