infra/stacks/rybbit/worker/index.js
Viktor Barzin 57fdea4b99 [rybbit] Remove ollama favicon cache entry (deploy on next manual wrangler)
## Context
Stage 6 of ollama decommission. The Cloudflare Worker at
stacks/rybbit/worker/index.js maps hostnames → rybbit analytics site IDs.
With `ollama.viktorbarzin.me` going away, the mapping is dead.

## This change
- Removes the `"ollama.viktorbarzin.me": "e73bebea399f"` entry from SITE_IDS.
- **Source-only** — does NOT auto-deploy. Cloudflare Workers are deployed
  via `wrangler deploy` (manual, per user preference). The change will take
  effect on the next manual deploy at the user's convenience.

## Manual deploy (when convenient)
```
cd stacks/rybbit/worker
wrangler deploy
```

## Test plan
### Automated
- Node syntax check: file remains valid JS (trailing comma rules preserved).

### Manual Verification
After `wrangler deploy`:
1. Hit `ollama.viktorbarzin.me` (while it still exists) — should NOT inject
   rybbit script (map lookup misses, DEFAULT_SITE_ID is null).
2. Hit any other mapped host (e.g. `immich.viktorbarzin.me`) — should
   continue to inject correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 11:14:38 +00:00

76 lines
2.6 KiB
JavaScript

// Rybbit analytics injection via Cloudflare Worker
// Injects the rybbit tracking script into HTML responses using HTMLRewriter.
// Deployed as a route-based worker on *.viktorbarzin.me/*
// Site ID mapping: hostname → rybbit site ID
// These were previously injected via Traefik's rewrite-body plugin (broken on v3.6).
const SITE_IDS = {
"viktorbarzin.me": "da853a2438d0",
"www.viktorbarzin.me": "da853a2438d0",
"actualbudget.viktorbarzin.me": "3e6b6b68088a",
"crowdsec.viktorbarzin.me": "d09137795ccc",
"cyberchef.viktorbarzin.me": "7c460afc68c4",
"dawarich.viktorbarzin.me": "0abfd409f2fb",
"pma.viktorbarzin.me": "942c76b8bd4d",
"pgadmin.viktorbarzin.me": "7cef78e30485",
"audiobookshelf.viktorbarzin.me": "17a5c7fbb077",
"calibre.viktorbarzin.me": "ce5f8aed6bbb",
"stacks.viktorbarzin.me": "b38fda4285df",
"f1.viktorbarzin.me": "7e69786f66d5",
"frigate.viktorbarzin.me": "0d4044069ff5",
"highlights-immich.viktorbarzin.me": "602167601c6b",
"immich.viktorbarzin.me": "35eedb7a3d2b",
"mail.viktorbarzin.me": "082f164faa7d",
"navidrome.viktorbarzin.me": "8a3844ff75ba",
"networking-toolbox.viktorbarzin.me": "50e38577e41c",
"nextcloud.viktorbarzin.me": "5a3bfe59a3fe",
"paperless-ngx.viktorbarzin.me": "be6d140cbed8",
"privatebin.viktorbarzin.me": "3ae810b0476d",
"wrongmove.viktorbarzin.me": "edee05de453d",
"rybbit.viktorbarzin.me": "3c476801a777",
"send.viktorbarzin.me": "c1b8f8aa831b",
"stirling-pdf.viktorbarzin.me": "a55ac54ec749",
"uptime-kuma.viktorbarzin.me": "8fef77b1f7fe",
"vaultwarden.viktorbarzin.me": "b8fc85e18683",
};
// Default site ID for any proxied host not in the map above.
// Set to null to skip injection for unmapped hosts.
const DEFAULT_SITE_ID = null;
class HeadInjector {
constructor(siteId) {
this.siteId = siteId;
}
element(element) {
element.prepend(
`<script src="https://rybbit.viktorbarzin.me/api/script.js" data-site-id="${this.siteId}" defer></script>`,
{ html: true }
);
}
}
export default {
async fetch(request) {
const url = new URL(request.url);
const hostname = url.hostname;
// Look up site ID for this hostname
const siteId = SITE_IDS[hostname] || DEFAULT_SITE_ID;
// Fetch the origin response
const response = await fetch(request);
// Only inject into HTML responses that have a site ID
const contentType = response.headers.get("content-type") || "";
if (!siteId || !contentType.includes("text/html")) {
return response;
}
// Use HTMLRewriter to inject the script before </head>
return new HTMLRewriter()
.on("head", new HeadInjector(siteId))
.transform(response);
},
};