mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
Quality-leap release between two HealthKit milestones. The headline is a P0 hotfix for the `/api/analytics` 500 that broke the Insights mother page for any account with more than a few thousand measurements: the six per-metric status helpers were spreading the entire numeric history into `Math.min` / `Math.max`, which trips a stack overflow once a single argument list exceeds the V8 spread cap. Both the surfaced symptom and the latent risk in five sibling helpers were folded onto a reduce-based min/max path. Around that hotfix landed a deep polish pass: the Insights mother page now defers three below-the-fold blocks behind `next/dynamic` to trim the cold mount cost, the analytics endpoint gained a `?slice=summaries` slim slice that the per-metric sub-pages now ride, the Coach snapshot builder picked up a 60 s LRU keyed on `(userId, scope)`, the Settings shell consolidated three duplicate copies of the about / notifications / about-dropdown surfaces, the navigation strip dropped a redundant "Home" group label and a colliding "Notifications" sibling, every icon-only button on the medications and admin surfaces gained an accessible name, every Progress bar gained one too, three pages had their heading hierarchy repaired to a sequential h1 → h2 → h3, the mobile Coach FAB now hides while a chart tooltip is open so it cannot occlude the read-out, and the auth shell normalised every authenticated route to a single `max-w-screen-xl` container. Also lands the Apple App Site Association handler at `/.well-known/apple-app-site-association` on every host that fronts the app, advertising the iOS bundle's App ID prefix (S8WDX4W5KX.dev.healthlog.app) under `webcredentials.apps` so the passkey ceremony shares cleanly between the web origin and the iOS app. The release closes nineteen issues from a five-surface audit + a runtime bug-hunt pass, plus six follow-up tracks of polish across the affected surfaces.
75 lines
2.9 KiB
TypeScript
75 lines
2.9 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { NextRequest } from "next/server";
|
|
|
|
/**
|
|
* v1.4.33 — `/.well-known/*` is a credential-free IETF discovery
|
|
* namespace (RFC 8615). Apple in particular reads
|
|
* `/.well-known/apple-app-site-association` without a session to wire
|
|
* Web Credentials (passkey sharing) and Universal Links to the iOS
|
|
* bundle. This guard locks the proxy allowlist in place so a future
|
|
* refactor of `src/proxy.ts` can't silently re-gate the namespace
|
|
* behind a session cookie and break the Apple CDN fetch.
|
|
*/
|
|
|
|
vi.mock("@/lib/process-type", () => ({
|
|
shouldRunWeb: () => true,
|
|
}));
|
|
|
|
import { proxy } from "../proxy";
|
|
|
|
function makeRequest(
|
|
pathname: string,
|
|
cookies: Record<string, string> = {},
|
|
): NextRequest {
|
|
const cookieHeader = Object.entries(cookies)
|
|
.map(([k, v]) => `${k}=${v}`)
|
|
.join("; ");
|
|
return new NextRequest(`http://localhost${pathname}`, {
|
|
headers: cookieHeader ? { cookie: cookieHeader } : {},
|
|
});
|
|
}
|
|
|
|
describe("proxy.ts /.well-known/* public-allowlist (v1.4.33)", () => {
|
|
it("does not 307 unauthenticated requests for the AASA file", () => {
|
|
const res = proxy(makeRequest("/.well-known/apple-app-site-association"));
|
|
expect(res.status).toBe(200);
|
|
expect(res.headers.get("location")).toBeNull();
|
|
});
|
|
|
|
it("does not 307 a pending-onboarding session away from the AASA file", () => {
|
|
// Apple's CDN fetch carries no cookies, so this branch is mainly
|
|
// a belt-and-braces check; the redirect would only fire for a
|
|
// human visitor who happened to have a half-finished onboarding
|
|
// session and typed the URL by hand. Either way the asset must
|
|
// answer 200 with the JSON body unchanged.
|
|
const res = proxy(
|
|
makeRequest("/.well-known/apple-app-site-association", {
|
|
healthlog_session: "sess-1",
|
|
hl_onboarding: "pending",
|
|
}),
|
|
);
|
|
expect(res.status).toBe(200);
|
|
expect(res.headers.get("location")).toBeNull();
|
|
});
|
|
|
|
it("admits any other future /.well-known/* discovery file", () => {
|
|
// The allowlist entry is a `/.well-known/` prefix so future
|
|
// additions (e.g. `/.well-known/security.txt` or
|
|
// `/.well-known/openid-configuration`) don't need a second proxy
|
|
// edit. This check fails the moment the prefix is tightened to
|
|
// a literal `/.well-known/apple-app-site-association` only.
|
|
const res = proxy(makeRequest("/.well-known/security.txt"));
|
|
expect(res.status).toBe(200);
|
|
expect(res.headers.get("location")).toBeNull();
|
|
});
|
|
|
|
it("still redirects unauthenticated requests for protected pages", () => {
|
|
// Negative check — confirms the test fixture would catch a real
|
|
// regression. `/insights` is not public; an unauthenticated visit
|
|
// must still 307 to /auth/login.
|
|
const res = proxy(makeRequest("/insights"));
|
|
expect([307, 308]).toContain(res.status);
|
|
expect(res.headers.get("location")).toMatch(/\/auth\/login/);
|
|
});
|
|
});
|