mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
The tracker posts to `${data-host-url}${collect path}`, and the collect
path is compiled into the operator's Umami build: /api/send by default,
anything else when the instance sets COLLECT_API_ENDPOINT. The tag
pointed data-host-url at the app origin and the proxy listened only on
/api/send, so a renamed endpoint sent every page view and event to an
app path that does not exist and got a full 404 page back each time.
Point data-host-url at /api/monitoring/umami and answer every path under
it with one proxy route. The route reads the collect path from the
configured tracker (cached for an hour), forwards only that path to the
Umami host, and answers anything else, or an unreadable tracker, with an
empty response. The admin test event posts to the same learnt path. The
send-URL resolver lives in one module instead of two copies.
50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
|
|
import { UMAMI_PROXY_PREFIX } from "@/lib/monitoring/umami-paths";
|
|
|
|
interface UmamiScriptProps {
|
|
enabled: boolean;
|
|
websiteId: string | null;
|
|
}
|
|
|
|
const SCRIPT_ID = "healthlog-umami-script";
|
|
|
|
export function UmamiScript({ enabled, websiteId }: UmamiScriptProps) {
|
|
useEffect(() => {
|
|
const existing = document.getElementById(SCRIPT_ID);
|
|
if (!enabled || !websiteId) {
|
|
existing?.remove();
|
|
return;
|
|
}
|
|
|
|
const script = document.createElement("script");
|
|
script.id = SCRIPT_ID;
|
|
script.defer = true;
|
|
script.src = "/api/monitoring/umami-script";
|
|
script.setAttribute("data-website-id", websiteId);
|
|
// Send events to the same-origin proxy so CSP stays strict. The tracker
|
|
// appends its own collect path (`/api/send`, or whatever the operator's
|
|
// Umami build renamed it to), and every path under the prefix reaches
|
|
// the proxy route.
|
|
script.setAttribute(
|
|
"data-host-url",
|
|
`${window.location.origin}${UMAMI_PROXY_PREFIX}`,
|
|
);
|
|
|
|
if (existing) {
|
|
existing.replaceWith(script);
|
|
} else {
|
|
document.head.appendChild(script);
|
|
}
|
|
|
|
return () => {
|
|
const current = document.getElementById(SCRIPT_ID);
|
|
current?.remove();
|
|
};
|
|
}, [enabled, websiteId]);
|
|
|
|
return null;
|
|
}
|