* Duplicate a KB document's stored blob to a fresh child-scoped KB storage key so the copied * document never points at the source's object. The child key is written with a `file_metadata` * ownership binding owned by the CHILD workspace (mirroring the canonical KB upload), so * `verifyKBFileAcce
(
doc: { storageKey: string | null; filename: string; mimeType: string },
childWorkspaceId: string,
userId: string,
requestId: string
)
| 876 | * copy fails - best-effort, so a single blob failure never aborts the KB. |
| 877 | */ |
| 878 | async function copyKbDocumentBlob( |
| 879 | doc: { storageKey: string | null; filename: string; mimeType: string }, |
| 880 | childWorkspaceId: string, |
| 881 | userId: string, |
| 882 | requestId: string |
| 883 | ): Promise<{ storageKey: string; fileUrl: string } | null> { |
| 884 | if (!doc.storageKey) return null |
| 885 | try { |
| 886 | const buffer = await downloadFile({ |
| 887 | key: doc.storageKey, |
| 888 | context: 'knowledge-base', |
| 889 | maxBytes: MAX_FILE_SIZE, |
| 890 | }) |
| 891 | const targetKey = generateKnowledgeBaseFileKey(doc.filename) |
| 892 | await uploadFile({ |
| 893 | file: buffer, |
| 894 | fileName: doc.filename, |
| 895 | contentType: doc.mimeType, |
| 896 | context: 'knowledge-base', |
| 897 | customKey: targetKey, |
| 898 | preserveKey: true, |
| 899 | metadata: { |
| 900 | userId, |
| 901 | workspaceId: childWorkspaceId, |
| 902 | originalName: doc.filename, |
| 903 | }, |
| 904 | }) |
| 905 | return { storageKey: targetKey, fileUrl: `/api/files/serve/${encodeURIComponent(targetKey)}` } |
| 906 | } catch (error) { |
| 907 | logger.warn(`[${requestId}] Failed to copy KB document blob during fork; keeping source key`, { |
| 908 | sourceStorageKey: doc.storageKey, |
| 909 | error: getErrorMessage(error), |
| 910 | }) |
| 911 | return null |
| 912 | } |
| 913 | } |
no test coverage detected