(media: ToolMedia)
| 159 | } |
| 160 | |
| 161 | function openMediaPreview(media: ToolMedia): void { |
| 162 | if (media.kind !== 'image') return; |
| 163 | const seq = ++previewRequestSeq; |
| 164 | revokeMediaObjectUrl(); |
| 165 | detailTarget.value = 'file'; |
| 166 | previewTarget.value = null; |
| 167 | previewNormalizedPath.value = null; |
| 168 | previewError.value = null; |
| 169 | const base = { |
| 170 | path: media.path ?? 'ReadMediaFile image', |
| 171 | content: '', |
| 172 | encoding: 'utf-8' as const, |
| 173 | mime: media.mimeType ?? mimeFromDataUrl(media.url) ?? 'image/*', |
| 174 | isBinary: true, |
| 175 | size: media.bytes ?? 0, |
| 176 | }; |
| 177 | if (media.fileId) { |
| 178 | // The raw getFileUrl 401s under daemon auth (browsers load <img> without |
| 179 | // the Bearer token), so fetch the bytes with auth and preview a blob URL. |
| 180 | previewLoading.value = true; |
| 181 | previewFile.value = base; |
| 182 | void getKimiWebApi().getFileBlob(media.fileId).then((blob) => { |
| 183 | if (seq !== previewRequestSeq) return; |
| 184 | // The user may have switched to another detail panel while this was in |
| 185 | // flight — don't create (and leak) a blob URL for a hidden panel. |
| 186 | if (detailTarget.value !== 'file' || !previewFile.value) { |
| 187 | previewLoading.value = false; |
| 188 | return; |
| 189 | } |
| 190 | mediaObjectUrl = URL.createObjectURL(blob); |
| 191 | previewFile.value = { ...previewFile.value, sourceUrl: mediaObjectUrl }; |
| 192 | previewLoading.value = false; |
| 193 | }).catch(() => { |
| 194 | if (seq !== previewRequestSeq) return; |
| 195 | // Fall back to the raw URL so the user sees an honest broken state. |
| 196 | if (previewFile.value) previewFile.value = { ...previewFile.value, sourceUrl: media.url }; |
| 197 | previewLoading.value = false; |
| 198 | }); |
| 199 | } else { |
| 200 | previewLoading.value = false; |
| 201 | previewFile.value = { ...base, sourceUrl: media.url }; |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | function resetFilePreview(): void { |
| 206 | // Invalidate any in-flight authenticated media fetch so it doesn't create a |
nothing calls this directly
no test coverage detected