diff --git a/src/hooks.ts b/src/hooks.ts new file mode 100644 index 00000000..392bbb11 --- /dev/null +++ b/src/hooks.ts @@ -0,0 +1,22 @@ +import type { Reroute } from "@sveltejs/kit"; + +// Back-compat for issue #759: heartbeat URLs used to be `/ext/heartbeat/:`, +// one path segment joined by a colon. A `:` is illegal in Windows file paths, so the +// route is now `/ext/heartbeat//` (two segments). Legacy colon-form URLs +// live forever in external cron jobs / uptime pingers, so rewrite them internally to +// the new path. Returns a 200 (no redirect) — heartbeat clients often don't follow 3xx. +// +// `reroute` is a *universal* hook: it MUST be in src/hooks.ts. A `reroute` exported from +// src/hooks.server.ts is silently ignored by SvelteKit. Keep this file free of +// server-only imports — it is bundled for the client too. Must stay pure/side-effect-free. +// +// The transform is in-place (no path reconstruction), so any KENER_BASE_PATH prefix is +// preserved automatically. `[^/:]+` matches the validated tag charset; only the first +// colon after `/ext/heartbeat/` is rewritten. +const LEGACY_HEARTBEAT = /(\/ext\/heartbeat\/[^/:]+):/; + +export const reroute: Reroute = ({ url }) => { + if (LEGACY_HEARTBEAT.test(url.pathname)) { + return url.pathname.replace(LEGACY_HEARTBEAT, "$1/"); + } +}; diff --git a/src/routes/(docs)/docs/content/v4/monitors/heartbeat.md b/src/routes/(docs)/docs/content/v4/monitors/heartbeat.md index c04890e6..f936dc63 100644 --- a/src/routes/(docs)/docs/content/v4/monitors/heartbeat.md +++ b/src/routes/(docs)/docs/content/v4/monitors/heartbeat.md @@ -10,11 +10,13 @@ Heartbeat monitors are push-based: your job calls a URL, and Kener measures how URL format: ``` -/ext/heartbeat/{tag}:{secret} +/ext/heartbeat/{tag}/{secret} ``` Accepted methods: `GET` and `POST`. +> Older heartbeat URLs used a colon — `/ext/heartbeat/{tag}:{secret}`. Those still work; they are rewritten to the path-separated form automatically, so existing cron jobs need no changes. + ## Minimum setup {#minimum-setup} Set: @@ -53,11 +55,11 @@ Latency is recorded as elapsed time since the last heartbeat (ms). Minimal cron usage pattern: ```bash -*/5 * * * * /path/to/job.sh && curl -s "https://your-kener-host/ext/heartbeat/my-job:my-secret" +*/5 * * * * /path/to/job.sh && curl -s "https://your-kener-host/ext/heartbeat/my-job/my-secret" ``` ## Troubleshooting {#troubleshooting} -- **Always NO_DATA**: endpoint never called or wrong `tag:secret` +- **Always NO_DATA**: endpoint never called or wrong `tag`/`secret` - **Always DOWN/DEGRADED**: thresholds too low for actual job interval - **Signal accepted but stale**: ensure heartbeat is sent only after successful completion diff --git a/src/routes/(ext)/ext/heartbeat/[tag]:[secret]/+server.ts b/src/routes/(ext)/ext/heartbeat/[tag]/[secret]/+server.ts similarity index 100% rename from src/routes/(ext)/ext/heartbeat/[tag]:[secret]/+server.ts rename to src/routes/(ext)/ext/heartbeat/[tag]/[secret]/+server.ts diff --git a/src/routes/(manage)/manage/app/monitors/[tag]/types/monitor-heartbeat.svelte b/src/routes/(manage)/manage/app/monitors/[tag]/types/monitor-heartbeat.svelte index 36d8db98..d2ffa00d 100644 --- a/src/routes/(manage)/manage/app/monitors/[tag]/types/monitor-heartbeat.svelte +++ b/src/routes/(manage)/manage/app/monitors/[tag]/types/monitor-heartbeat.svelte @@ -24,7 +24,7 @@ // Generate heartbeat URL let heartbeatUrl = $derived( tag - ? window.location.origin + clientResolve(resolve, `/ext/heartbeat/${tag}:${data.secretString}`) + ? window.location.origin + clientResolve(resolve, `/ext/heartbeat/${tag}/${data.secretString}`) : "Save the monitor first to get the heartbeat URL" );