tia/src/middleware.ts
Mannu 9c2e7328ab Fix PWA always opening marketing page instead of app home
Two-pronged fix for Android PWA shell launching to the wrong page:

1. middleware.ts: if a logged-in user (valid tia_session cookie) visits /,
   immediately redirect them to /home — catches all existing installs whose
   cached start_url still points to /?source=pwa
2. manifest.ts: change start_url from /?source=pwa to /home?source=pwa
   so any fresh install or reinstall opens directly to the app home

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 10:28:31 +05:30

110 lines
2.7 KiB
TypeScript

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
// PWA static assets — must bypass auth entirely.
// If the SW or manifest gets a 302→login, the browser registers the login
// page as the service worker, which breaks auth for the entire PWA session.
const pwaAssets = [
"/sw.js",
"/sw.js.map",
"/manifest.webmanifest",
"/~offline",
"/icons/",
"/serwist-",
];
// Public routes that don't require authentication
const publicRoutes = [
"/",
"/pricing",
"/privacy",
"/terms",
"/about",
"/blog",
"/partners",
"/login",
"/admin-login",
"/m",
"/invite",
"/verify",
"/api/auth/signin",
"/api/admin/auth",
"/api/onboarding",
"/api/profile",
];
// Protected API routes that need authentication
const protectedApiRoutes = [
"/api/children",
"/api/logs",
"/api/growth",
"/api/vaccinations",
"/api/medicines",
"/api/allergies",
"/api/illnesses",
"/api/visits",
"/api/family",
"/api/families",
"/api/invites",
"/api/notifications",
"/api/upload",
"/api/storage-usage",
"/api/chat",
"/api/history",
"/api/family/members",
];
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Always pass PWA assets through — never redirect to login
for (const asset of pwaAssets) {
if (pathname === asset || pathname.startsWith(asset)) {
return NextResponse.next();
}
}
// Logged-in users hitting the marketing root (or the old PWA start_url /?source=pwa)
// should land on the app home, not the marketing page.
if (pathname === "/") {
const session = request.cookies.get("tia_session")?.value;
if (session) {
return NextResponse.redirect(new URL("/home", request.url));
}
}
// Always allow public routes
for (const route of publicRoutes) {
if (pathname === route || pathname.startsWith(route + "/")) {
return NextResponse.next();
}
}
// Check session cookie for protected routes
const sessionToken = request.cookies.get("tia_session")?.value;
const adminSessionToken = request.cookies.get("tia_admin_session")?.value;
// Allow admin routes with admin session
if (pathname.startsWith("/api/admin") && adminSessionToken) {
return NextResponse.next();
}
// For protected API routes, require session
for (const route of protectedApiRoutes) {
if (pathname.startsWith(route)) {
if (!sessionToken && !adminSessionToken) {
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
}
break;
}
}
return NextResponse.next();
}
export const config = {
matcher: [
"/api/:path*",
"/((?!_next/static|_next/image|favicon.ico).*)",
],
};