All files / routes/homeowner auth.routes.ts

96.66% Statements 29/30
92.85% Branches 13/14
100% Functions 2/2
96.66% Lines 29/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79              1x             1x 5x 5x     5x 2x                   3x 3x 3x   3x 3x                     1x 9x 9x     9x 9x 4x 4x 4x   1x       9x 9x 8x 1x 1x   7x   1x 1x 1x              
import { Hono } from "hono";
import { getDb } from "../../db";
import { createHomeownerAuth } from "../../lib/homeowner-auth";
import { createDualCache } from "../../lib/cache";
import { getCachedHoSession, invalidateHoSession } from "../../lib/ho-session-cache";
import { logger } from "../../lib/logger";
 
const app = new Hono<{ Bindings: CloudflareBindings }>();
 
// Cached get-session handler. The marketplace calls this on every page load
// (and on tab visibility change) for multiple hydration islands; caching via
// KV+memory turns 800-1700ms D1 round trips into ~20-50ms on cache hits, and
// the Cache-Control header lets the browser skip the network entirely within
// a 30s window. The session-token cache is invalidated on sign-out below.
app.get("/get-session", async (c) => {
	const cookie = c.req.raw.headers.get("cookie") || "";
	const hasToken = /ho\.session_token=/.test(cookie);
 
	// Anonymous fast-path: skip DB and Better Auth entirely.
	if (!hasToken) {
		return new Response("null", {
			status: 200,
			headers: {
				"content-type": "application/json",
				"cache-control": "private, max-age=30",
				vary: "Cookie",
			},
		});
	}
 
	const db = getDb(c.env.DB);
	const auth = createHomeownerAuth(db, c.env);
	const dualCache = createDualCache(c.env.KV_CACHE);
 
	const session = await getCachedHoSession(dualCache, auth, c.req.raw.headers);
	return new Response(JSON.stringify(session ?? null), {
		status: 200,
		headers: {
			"content-type": "application/json",
			"cache-control": "private, max-age=30",
			vary: "Cookie",
		},
	});
});
 
// Better Auth handler for all other homeowner auth routes
app.on(["POST", "GET"], "/*", async (c) => {
	const db = getDb(c.env.DB);
	const auth = createHomeownerAuth(db, c.env);
 
	// Invalidate session cache on sign-out
	const isSignOut = c.req.path.includes("sign-out");
	if (isSignOut) {
		try {
			const dualCache = createDualCache(c.env.KV_CACHE);
			await invalidateHoSession(dualCache, c.req.raw.headers);
		} catch (err) {
			logger.error("[HO-AUTH] Failed to invalidate session cache:", err);
		}
	}
 
	try {
		const response = await auth.handler(c.req.raw);
		if (isSignOut && response.status >= 400) {
			logger.error("[HO-AUTH] Sign-out returned", response.status);
			return new Response(null, { status: 200 });
		}
		return response;
	} catch (err) {
		logger.error("[HO-AUTH] Handler error:", c.req.path, err);
		Eif (isSignOut) {
			return new Response(null, { status: 200 });
		}
		throw err;
	}
});
 
export default app;