diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index e39b132e8..2e3f64014 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -37,6 +37,7 @@ import { DocumentManagementActions, type DocumentDeleteResult } from "@/componen import { documentCitationHref, formatCompactCitationLabel, formatCitationLabel } from "@/lib/citations"; import { extractSafetyFindings, formatSafetyFindingLabel } from "@/lib/clinical-safety"; import { clearCachedSignedUrl, getCachedSignedUrl, setCachedSignedUrl } from "@/lib/signed-url-cache"; +import { readLocalProjectIdentity, unsafeLocalProjectMessage } from "@/lib/local-project-identity"; import { isLocalNoAuthMode } from "@/lib/env"; import { appBackdrop, @@ -179,14 +180,6 @@ type SetupStatusPayload = { indexingActive?: boolean; pollAfterMs?: number | null; }; -type LocalProjectIdentityPayload = { - localServer?: { - currentUrl?: string | null; - projectPortStart?: number; - projectPortEnd?: number; - safeLocalOrigin?: boolean; - }; -}; type DocumentsPayload = { documents?: ClinicalDocument[]; pagination?: DocumentPagination | null; @@ -225,21 +218,6 @@ type SearchResultModePayload = payload: AnswerPayload; }; -async function readLocalProjectIdentity() { - const response = await fetch("/api/local-project-id", { cache: "no-store" }); - if (!response.ok) return null; - return (await response.json()) as LocalProjectIdentityPayload; -} - -function unsafeLocalProjectMessage(identity: LocalProjectIdentityPayload | null) { - const range = - typeof identity?.localServer?.projectPortStart === "number" && - typeof identity.localServer.projectPortEnd === "number" - ? ` Use the URL printed by npm run ensure; managed ports are ${identity.localServer.projectPortStart}-${identity.localServer.projectPortEnd}.` - : " Use the URL printed by npm run ensure."; - return `This tab is not using the guarded Clinical KB local URL.${range}`; -} - function parseSseData(lines: string[]) { const data = lines.join("\n").trim(); if (!data) return null; @@ -4093,7 +4071,7 @@ export function ClinicalDashboard() { key={`${section.heading}:${section.citation_chunk_ids.join(",")}:${section.body.slice(0, 24)}`} className={cn(panelSubtle, "space-y-3 p-4")} > -
+
diff --git a/src/components/DocumentViewer.tsx b/src/components/DocumentViewer.tsx index 49bae6082..99f354bc3 100644 --- a/src/components/DocumentViewer.tsx +++ b/src/components/DocumentViewer.tsx @@ -47,6 +47,7 @@ import { toolbarButton, } from "@/components/ui-primitives"; import { clearCachedSignedUrl, getCachedSignedUrl, setCachedSignedUrl } from "@/lib/signed-url-cache"; +import { readLocalProjectIdentity, unsafeLocalProjectMessage } from "@/lib/local-project-identity"; import { formatClinicalDate, normalizeSourceMetadata, sourceStatusLabel } from "@/lib/source-metadata"; import { isLocalNoAuthMode } from "@/lib/env"; import { useAuthSession } from "@/lib/supabase/client"; @@ -68,29 +69,6 @@ type PageRow = { ocr_used: boolean; }; -type LocalProjectIdentityPayload = { - localServer?: { - projectPortStart?: number; - projectPortEnd?: number; - safeLocalOrigin?: boolean; - }; -}; - -async function readLocalProjectIdentity() { - const response = await fetch("/api/local-project-id", { cache: "no-store" }); - if (!response.ok) return null; - return (await response.json()) as LocalProjectIdentityPayload; -} - -function unsafeLocalProjectMessage(identity: LocalProjectIdentityPayload | null) { - const range = - typeof identity?.localServer?.projectPortStart === "number" && - typeof identity.localServer.projectPortEnd === "number" - ? ` Use the URL printed by npm run ensure; managed ports are ${identity.localServer.projectPortStart}-${identity.localServer.projectPortEnd}.` - : " Use the URL printed by npm run ensure."; - return `This tab is not using the guarded Clinical KB local URL.${range}`; -} - type ImageRow = { id: string; page_number: number | null; diff --git a/src/lib/local-project-guard.ts b/src/lib/local-project-guard.ts index 8557bf1e0..1336000c5 100644 --- a/src/lib/local-project-guard.ts +++ b/src/lib/local-project-guard.ts @@ -1,24 +1,9 @@ import { NextResponse } from "next/server"; +import type { LocalProjectIdentityPayload } from "@/lib/local-project-identity"; import { appName, localProjectId, projectPortEnd, projectPortStart } from "../../scripts/local-server-utils.mjs"; const localHosts = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]); -export type LocalProjectIdentityPayload = { - appName: string; - projectId: string; - identityPath: "/api/local-project-id"; - localServer: { - currentUrl: string | null; - currentPort: number | null; - projectPortStart: number; - projectPortEnd: number; - safeLocalOrigin: boolean; - requestOrigin: string | null; - requestReferer: string | null; - unsafeLocalCaller: string | null; - }; -}; - function portFor(url: URL) { const explicit = Number.parseInt(url.port, 10); if (Number.isInteger(explicit)) return explicit; diff --git a/src/lib/local-project-identity.ts b/src/lib/local-project-identity.ts new file mode 100644 index 000000000..a23215cda --- /dev/null +++ b/src/lib/local-project-identity.ts @@ -0,0 +1,30 @@ +export type LocalProjectIdentityPayload = { + appName: string; + projectId: string; + identityPath: "/api/local-project-id"; + localServer: { + currentUrl: string | null; + currentPort: number | null; + projectPortStart: number; + projectPortEnd: number; + safeLocalOrigin: boolean; + requestOrigin: string | null; + requestReferer: string | null; + unsafeLocalCaller: string | null; + }; +}; + +export async function readLocalProjectIdentity() { + const response = await fetch("/api/local-project-id", { cache: "no-store" }); + if (!response.ok) return null; + return (await response.json()) as LocalProjectIdentityPayload; +} + +export function unsafeLocalProjectMessage(identity: LocalProjectIdentityPayload | null) { + const range = + typeof identity?.localServer?.projectPortStart === "number" && + typeof identity.localServer.projectPortEnd === "number" + ? ` Use the URL printed by npm run ensure; managed ports are ${identity.localServer.projectPortStart}-${identity.localServer.projectPortEnd}.` + : " Use the URL printed by npm run ensure."; + return `This tab is not using the guarded Clinical KB local URL.${range}`; +}