diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 55a720ae2..3e0ac7109 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -27,6 +27,11 @@ const baseMetadata: Metadata = { }, }; +/** + * Generates application metadata with a request-aware base URL. + * + * @returns The application metadata, including its resolved base URL. + */ export async function generateMetadata(): Promise { const requestHeaders = await headers(); return { diff --git a/src/components/DocumentViewer.tsx b/src/components/DocumentViewer.tsx index 55e2d101b..2e0f497ef 100644 --- a/src/components/DocumentViewer.tsx +++ b/src/components/DocumentViewer.tsx @@ -1995,6 +1995,14 @@ function DocumentOverviewLanding({ ); } +/** + * Renders the clinical document viewer with source previews, extracted content, summaries, and document tools. + * + * @param documentId - The identifier of the document to load. + * @param initialPage - The page to display initially in the source preview. + * @param chunkId - An optional indexed passage to pin and scroll into view. + * @returns The document viewer interface. + */ export function DocumentViewer({ documentId, initialPage, diff --git a/src/lib/api-rate-limit.ts b/src/lib/api-rate-limit.ts index 505071bc0..3fb53f15e 100644 --- a/src/lib/api-rate-limit.ts +++ b/src/lib/api-rate-limit.ts @@ -149,6 +149,21 @@ export async function consumeApiRateLimit(args: { }; } +/** + * Applies an API rate limit to an owner or anonymous subject. + * + * Anonymous requests to answer and document upload buckets are constrained by + * both subject-specific and aggregate bucket limits. Limiter unavailability may + * use an in-memory fallback when permitted. + * + * @param args - Rate-limiting configuration and request subject. + * @param args.subject - The authenticated owner or anonymous subject to limit. + * @param args.bucket - The API resource bucket being limited. + * @param args.limit - Optional subject-specific request limit. + * @param args.windowSeconds - Optional subject-specific rate-limit window. + * @param args.allowInMemoryFallbackOnUnavailable - Whether local fallback may be used when the durable limiter is unavailable. + * @returns The computed rate-limit outcome. + */ export async function consumeSubjectApiRateLimit(args: { supabase: SupabaseAdmin; subject: RateLimitSubject; diff --git a/src/lib/document-viewer-navigation.ts b/src/lib/document-viewer-navigation.ts index 4e05e2911..2cf9eac2a 100644 --- a/src/lib/document-viewer-navigation.ts +++ b/src/lib/document-viewer-navigation.ts @@ -1,4 +1,10 @@ -/** Build a useful-page link without retaining evidence pinned to a different page. */ +/** + * Builds a URL for a specific document page in the PDF preview section. + * + * @param documentId - The document identifier to include in the URL + * @param page - The requested page number, normalized to an integer of at least 1 + * @returns A document page URL with the encoded document identifier and normalized page number + */ export function documentPageHref(documentId: string, page: number) { const normalizedPage = Number.isFinite(page) ? Math.max(1, Math.trunc(page)) : 1; const params = new URLSearchParams({ page: String(normalizedPage) }); diff --git a/src/lib/metadata-base.ts b/src/lib/metadata-base.ts index 19da73187..5a7f6e4b7 100644 --- a/src/lib/metadata-base.ts +++ b/src/lib/metadata-base.ts @@ -4,7 +4,12 @@ export type MetadataBaseOptions = { allowRequestOrigin?: boolean; }; -/** Parse an absolute HTTP(S) URL without allowing invalid configuration to escape. */ +/** + * Parses a value as an HTTP or HTTPS URL. + * + * @param value - The URL value to parse. + * @returns The parsed URL when it uses HTTP or HTTPS; `undefined` otherwise. + */ function httpUrl(value: string | undefined) { const candidate = value?.trim(); if (!candidate) return undefined; @@ -16,7 +21,16 @@ function httpUrl(value: string | undefined) { } } -/** Resolve metadata from validated configuration, trusted deployment state, or an explicit dev fallback. */ +/** + * Resolves the base URL used for metadata generation. + * + * Sources are considered in order: configured site URL, trusted deployment domain, + * and the request origin when explicitly enabled. + * + * @param requestHeaders - Headers used to derive the request origin. + * @param options - Configuration controlling the fallback sources. + * @returns A valid HTTP or HTTPS metadata base URL, or `undefined` when none can be resolved. + */ export function resolveMetadataBase(requestHeaders: Headers, options: MetadataBaseOptions = {}) { const configuredUrl = httpUrl(options.configuredSiteUrl); if (configuredUrl) return configuredUrl; diff --git a/src/lib/public-api-access.ts b/src/lib/public-api-access.ts index 36e35fdd9..b17007cad 100644 --- a/src/lib/public-api-access.ts +++ b/src/lib/public-api-access.ts @@ -11,7 +11,12 @@ type AdminClient = ReturnType; export type RateLimitSubject = { kind: "owner"; ownerId: string } | { kind: "anonymous"; subjectKey: string }; -/** Read the deployment proxy's appended address from a forwarded IP chain. */ +/** + * Extracts the last non-empty IP address from a proxy forwarding header value. + * + * @param value - A comma-separated proxy forwarding header value + * @returns The last trimmed IP address, or an empty string when no address is present + */ function trustedProxyIp(value: string | null) { const forwarded = value ?.split(",") @@ -20,7 +25,12 @@ function trustedProxyIp(value: string | null) { return forwarded?.at(-1) ?? ""; } -/** Select the strongest deployment-owned request identity signal available. */ +/** + * Determines the request's source IP from trusted proxy forwarding headers. + * + * @param request - The request containing the proxy forwarding headers + * @returns The last non-empty address from `x-forwarded-for`, the address from `x-real-ip`, or `"unknown-ip"` when neither header provides an address + */ function requestIpSignal(request: Request) { return ( trustedProxyIp(request.headers.get("x-forwarded-for")) || @@ -29,7 +39,12 @@ function requestIpSignal(request: Request) { ); } -/** Derive a stable, non-reversible quota subject for an anonymous caller. */ +/** + * Creates a stable anonymous rate-limit subject key from the request's trusted proxy IP signal. + * + * @param request - The request from which to derive the IP signal + * @returns A prefixed, truncated SHA-256 hash of the source IP signal + */ export function anonymousApiSubjectKey(request: Request) { // Trust only the deployment proxy's appended forwarding entry. Ignore the // caller-controlled Cloudflare/User-Agent values and any leading XFF entries: