fix: redirect apple-touch-icon and favicons to org-specific icons on iOS

iOS uses the apple-touch-icon link tag for the home screen icon, not
the manifest. The worker now intercepts requests for apple-touch-icon
and favicon PNGs, redirecting to the org-specific version from R2
when the x-org-id cookie is set.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arthur Belleville 2026-04-02 22:44:28 +02:00
parent bf66fc4000
commit ba2de823c6
No known key found for this signature in database
2 changed files with 42 additions and 0 deletions

View file

@ -1,5 +1,6 @@
import { describe, it, expect } from "vitest";
import { buildManifest, parseOrgIdFromCookie } from "./index";
import worker from "./index";
describe("parseOrgIdFromCookie", () => {
it("returns null when no cookie header", () => {
@ -35,3 +36,30 @@ describe("buildManifest", () => {
expect(manifest.icons[2].purpose).toBe("maskable");
});
});
describe("worker icon redirects", () => {
it("redirects apple-touch-icon to org-specific icon when cookie is set", async () => {
const request = new Request("https://app.xtablo.com/pwa-icons/apple-touch-icon-180x180.png", {
headers: { cookie: "x-org-id=42" },
});
const response = await worker.fetch(request);
expect(response.status).toBe(302);
expect(response.headers.get("location")).toBe("https://assets.xtablo.com/org-icons/42/icon-180.png");
});
it("does not redirect apple-touch-icon when no cookie", async () => {
const request = new Request("https://app.xtablo.com/pwa-icons/apple-touch-icon-180x180.png");
const response = await worker.fetch(request);
// Falls through to 404 (no static assets in test)
expect(response.status).toBe(404);
});
it("redirects favicon to org-specific icon when cookie is set", async () => {
const request = new Request("https://app.xtablo.com/pwa-icons/favicon-32x32.png", {
headers: { cookie: "x-org-id=7" },
});
const response = await worker.fetch(request);
expect(response.status).toBe(302);
expect(response.headers.get("location")).toBe("https://assets.xtablo.com/org-icons/7/icon-32.png");
});
});

View file

@ -64,6 +64,20 @@ export default {
fetch(request: Request) {
const url = new URL(request.url);
// Redirect PWA icons to org-specific versions when cookie is set
const iconRedirects: Record<string, string> = {
"/pwa-icons/apple-touch-icon-180x180.png": "icon-180.png",
"/pwa-icons/favicon-32x32.png": "icon-32.png",
"/pwa-icons/favicon-16x16.png": "icon-16.png",
};
if (iconRedirects[url.pathname]) {
const cookieHeader = request.headers.get("cookie");
const orgId = parseOrgIdFromCookie(cookieHeader);
if (orgId !== null) {
return Response.redirect(`${ASSETS_BASE_URL}/org-icons/${orgId}/${iconRedirects[url.pathname]}`, 302);
}
}
if (url.pathname === "/manifest.webmanifest") {
const cookieHeader = request.headers.get("cookie");
const orgId = parseOrgIdFromCookie(cookieHeader);