mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(documents): consume the ?doc= deep link during render, not in an effect
The one-shot deep-link consumption moves to the render-phase derived- state pattern the view already uses for its search draft (the effect variant trips the set-state-in-effect rule), gated on resolved auth so a deep link never burns before the module flag is known. Refs: document-vault plan W3-T4
This commit is contained in:
1 parent
8bff4d0c86
commit
23e371965b
2 files changed
+25
-24
No files matched your search
@@ -211,24 +211,21 @@ describe("serving-posture header matrix (Class A inline vs Class B attachment)",
|
||||
["image/png", "scan.png"],
|
||||
["image/webp", "scan.webp"],
|
||||
["image/gif", "anim.gif"],
|
||||
])(
|
||||
"Class A %s → inline, true type, nosniff",
|
||||
async (mime, name) => {
|
||||
seed(mime, name);
|
||||
const res = await callGet(makeReq("doc-m"), ctx("doc-m"));
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers.get("Content-Type")).toBe(mime);
|
||||
expect(res.headers.get("Content-Disposition")).toContain("inline");
|
||||
expect(res.headers.get("X-Content-Type-Options")).toBe("nosniff");
|
||||
// The response CSP is owned by the proxy carve-out (`default-src
|
||||
// 'none'; frame-ancestors 'self'`, deliberately no sandbox —
|
||||
// Chromium force-downloads sandboxed PDFs). A route-level value
|
||||
// would be overwritten there, so the route must not set one; see
|
||||
// src/__tests__/proxy-document-serve-framing.test.ts for the pin.
|
||||
expect(res.headers.get("Content-Security-Policy")).toBeNull();
|
||||
expect(res.headers.get("Cache-Control")).toBe("private, no-store");
|
||||
},
|
||||
);
|
||||
])("Class A %s → inline, true type, nosniff", async (mime, name) => {
|
||||
seed(mime, name);
|
||||
const res = await callGet(makeReq("doc-m"), ctx("doc-m"));
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers.get("Content-Type")).toBe(mime);
|
||||
expect(res.headers.get("Content-Disposition")).toContain("inline");
|
||||
expect(res.headers.get("X-Content-Type-Options")).toBe("nosniff");
|
||||
// The response CSP is owned by the proxy carve-out (`default-src
|
||||
// 'none'; frame-ancestors 'self'`, deliberately no sandbox —
|
||||
// Chromium force-downloads sandboxed PDFs). A route-level value
|
||||
// would be overwritten there, so the route must not set one; see
|
||||
// src/__tests__/proxy-document-serve-framing.test.ts for the pin.
|
||||
expect(res.headers.get("Content-Security-Policy")).toBeNull();
|
||||
expect(res.headers.get("Cache-Control")).toBe("private, no-store");
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
|
||||
@@ -464,15 +464,19 @@ export function DocumentsView() {
|
||||
|
||||
// `?doc=<id>` deep link (used by the illness page's document rows): open
|
||||
// the detail sheet once per value; closing the sheet strips the param so
|
||||
// back/forward and refresh behave. The id is shape-checked before it is
|
||||
// interpolated into an API path.
|
||||
// back/forward and refresh behave. Render-phase derived-state adjustment
|
||||
// (the file's established pattern), consumed only once auth has resolved
|
||||
// so a deep link never burns before the module flag is known. The id is
|
||||
// shape-checked before it is interpolated into an API path.
|
||||
const docParam = searchParams.get("doc");
|
||||
const [consumedDocParam, setConsumedDocParam] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!moduleEnabled || !docParam || docParam === consumedDocParam) return;
|
||||
if (!authLoading && moduleEnabled && docParam !== consumedDocParam) {
|
||||
setConsumedDocParam(docParam);
|
||||
if (/^[a-zA-Z0-9_-]{1,40}$/.test(docParam)) openDetail(docParam);
|
||||
}, [docParam, consumedDocParam, moduleEnabled, openDetail]);
|
||||
if (docParam !== null && /^[a-zA-Z0-9_-]{1,40}$/.test(docParam)) {
|
||||
setDetailId(docParam);
|
||||
setDetailOpen(true);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDetailOpenChange = useCallback(
|
||||
(open: boolean) => {
|
||||
|
||||
Reference in new issue
Block a user