diff --git a/frontend/src/app/useDocumentPreview.ts b/frontend/src/app/useDocumentPreview.ts index aa09d21..848b64d 100644 --- a/frontend/src/app/useDocumentPreview.ts +++ b/frontend/src/app/useDocumentPreview.ts @@ -40,7 +40,6 @@ interface UseDocumentPreviewArgs { }; selectedFolder?: FolderId | null; api: ApiClient; - resolveApiPath?: (path: string) => string; notifyApiError: (error: unknown, message: string) => void; navigate: NavigateHandler; locationPathname: string; @@ -67,7 +66,6 @@ const useDocumentPreview = ({ documentsManager, selectedFolder, api, - resolveApiPath, notifyApiError, navigate, locationPathname, @@ -109,7 +107,7 @@ const useDocumentPreview = ({ async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise => { if (!documentId) return null; - const existing = documentLinks.get(documentId) || null; + const existing = documentLinks.get(documentId); const now = Date.now(); const expiresAt = Number.isFinite(existing?.expiresAt) ? Number(existing?.expiresAt) : null; if (!force && existing && (!expiresAt || expiresAt > now)) { @@ -123,17 +121,17 @@ const useDocumentPreview = ({ const request: Promise = (async () => { try { const docResponse = await api.get<{ document?: Record }>(`/documents/${documentId}`); - const downloadPath = docResponse.data?.document?.current_version?.download_path; - if (!downloadPath || !resolveApiPath) { - throw new Error('Document missing download path'); + const download = docResponse.data?.document?.current_version?.download || null; + const downloadUrl = download?.url; + if (!downloadUrl) { + throw new Error('Document missing download url'); } - const href = resolveApiPath(downloadPath); const entry: DocumentLink = { - url: href, + url: downloadUrl, contentType: docResponse.data?.document?.current_version?.version?.content_type || null, filename: docResponse.data?.document?.filename, - expiresAt: Date.now() + 5 * 60 * 1000, + expiresAt: download?.expires_at, }; setDocumentLinks((prev) => { const next = new Map(prev); @@ -152,7 +150,7 @@ const useDocumentPreview = ({ previewInflightRef.current.set(documentId, request); return request; }, - [documentLinks, api, resolveApiPath, notifyApiError], + [documentLinks, api, notifyApiError], ); const ensurePreviewData = useCallback( diff --git a/frontend/src/asset_manager.ts b/frontend/src/asset_manager.ts index deb6161..ec4fded 100644 --- a/frontend/src/asset_manager.ts +++ b/frontend/src/asset_manager.ts @@ -8,7 +8,7 @@ export interface AssetObject { ordinal?: number; url?: string | null; metadata?: Record | null; - expires_at?: number | null; + expires_at?: number; [key: string]: unknown; } @@ -16,10 +16,8 @@ export interface AssetLike { id?: Identifier; asset_type?: string; cardinality?: number | null; - url?: string | null; - expires_at?: number | null; + download?: { url: string; expires_at: number } | null; metadata?: Record | null; - expiresAt?: number | null; assets?: Record | AssetLike[] | null; objects?: AssetObject[] | null; [key: string]: unknown; @@ -37,19 +35,11 @@ export interface DocumentLike { [key: string]: unknown; } -export const resolveAssetExpiresAt = ( - asset?: { expiresAt?: number | null; expires_at?: number | null } | null, -): number | null => { - const camel = Number(asset?.expiresAt); - if (Number.isFinite(camel)) { - return camel; - } - const snake = Number(asset?.expires_at); - if (Number.isFinite(snake)) { - return snake; - } - return null; -}; +export const resolveAssetExpiresAt = (asset?: { download?: { expires_at: number } | null } | null): number | null => + asset?.download?.expires_at ?? null; + +export const resolveAssetUrl = (asset?: { download?: { url: string } | null } | null): string | null => + asset?.download?.url ?? null; export type EnsureAssetUrl = ( documentId: Identifier, @@ -78,7 +68,7 @@ export const getAssetFromVersion = (currentVersion: Nullable { @@ -140,10 +130,11 @@ export class AssetView { } if (ordinal === 1 && this.asset) { - if (this.asset.url || this.asset.metadata) { + const primaryUrl = resolveAssetUrl(this.asset); + if (primaryUrl || this.asset.metadata) { return { ordinal: 1, - url: this.asset.url || null, + url: primaryUrl || null, metadata: this.asset.metadata || null, expires_at: resolveAssetExpiresAt(this.asset), }; @@ -242,7 +233,7 @@ class AssetManager { { force = false }: { force?: boolean } = {}, ): Promise> { if (!documentId || !asset?.id) { - return Promise.resolve(asset ?? null); + return Promise.resolve(asset); } const baseAsset = this.assetCache.get(asset.id) || asset; @@ -258,7 +249,8 @@ class AssetManager { return true; } } - if (baseAsset.url && (!assetExpiresAt || assetExpiresAt > now)) { + const assetUrl = resolveAssetUrl(baseAsset); + if (assetUrl && (!assetExpiresAt || assetExpiresAt > now)) { return true; } return false; @@ -288,13 +280,13 @@ class AssetManager { .then(({ data }) => { const cachedEntry = this.assetCache.get(asset.id) || baseAsset; const combined = { ...cachedEntry, ...asset, ...data }; - const expiresAt = + const expires_at = resolveAssetExpiresAt(data) - ?? resolveAssetExpiresAt(combined) - ?? Date.now() + this.assetPresignTtlMs; + ?? resolveAssetExpiresAt(combined); const entry = { ...combined, - expiresAt, + url: resolveAssetUrl(combined), + expires_at, }; this.rememberAsset(entry); diff --git a/frontend/src/documents/documentActions.ts b/frontend/src/documents/documentActions.ts index 099639c..c1875c2 100644 --- a/frontend/src/documents/documentActions.ts +++ b/frontend/src/documents/documentActions.ts @@ -13,14 +13,14 @@ export type DocumentLike = OcrDocumentLike; const asyncFalse = async () => false; const resolveDocumentDownloadHref = (document?: DocumentLike | null, resolveApiPath?: ResolveApiPath | null): string | null => { - if (!document || !resolveApiPath) { + if (!document) { return null; } - const downloadPath = (document.current_version as { download_path?: string | null } | null)?.download_path; - if (!downloadPath) { + const downloadUrl = (document.current_version as { download?: { url: string } | null } | null)?.download?.url; + if (!downloadUrl) { return null; } - return resolveApiPath(downloadPath); + return resolveApiPath ? resolveApiPath(downloadUrl) : downloadUrl; }; const hasDocumentOcrAsset = (document?: DocumentLike | null, getDocumentAsset?: GetDocumentAsset | null): boolean => { diff --git a/frontend/src/hooks/documents/useDocumentsWorkspace.ts b/frontend/src/hooks/documents/useDocumentsWorkspace.ts index ccc850d..1d2f1ac 100644 --- a/frontend/src/hooks/documents/useDocumentsWorkspace.ts +++ b/frontend/src/hooks/documents/useDocumentsWorkspace.ts @@ -450,7 +450,6 @@ const useDocumentsWorkspace = ({ documentsManager, selectedFolder, api, - resolveApiPath, notifyApiError, navigate, locationPathname: location.pathname, diff --git a/frontend/src/preview/DocumentViewerPanel.tsx b/frontend/src/preview/DocumentViewerPanel.tsx index 65a5ca2..6ee8cf8 100644 --- a/frontend/src/preview/DocumentViewerPanel.tsx +++ b/frontend/src/preview/DocumentViewerPanel.tsx @@ -38,7 +38,9 @@ interface DocumentLike { correspondents?: Array<{ id?: string | number; name?: string }>; current_version?: { version_number?: number; + download?: { url?: string | null; expires_at?: number } | null; version?: { content_type?: string | null } | null; + filename?: string | null; } | null; documentLink?: { url: string; @@ -261,11 +263,8 @@ const DocumentViewerPanel: React.FC = ({ if (!document) { return null; } - const downloadPath = document.current_version?.download_path; - if (!downloadPath) { - return null; - } - const href = resolveApiPath ? resolveApiPath(downloadPath) : downloadPath; + const downloadUrl = document.current_version?.download?.url; + const href = resolveApiPath ? resolveApiPath(downloadUrl) : downloadUrl; if (!href) { return null; } diff --git a/frontend/src/utils/ocr.ts b/frontend/src/utils/ocr.ts index 9d44b06..0c6e4d6 100644 --- a/frontend/src/utils/ocr.ts +++ b/frontend/src/utils/ocr.ts @@ -6,12 +6,8 @@ import type { GetAsset as AssetManagerGetAsset, } from '../asset_manager'; -interface DocumentVersion extends DocumentVersionLike { - download_path?: string | null; -} - export interface DocumentLike extends AssetManagerDocumentLike { - current_version?: DocumentVersion | null; + current_version?: DocumentVersionLike | null; } export type AssetLike = AssetManagerAssetLike;