* Register the uploaded object with bounded retries. The server-side handler * is idempotent (existing-record short-circuit), so safely retrying handles * dropped responses that would otherwise orphan the object in storage.
(
workspaceId: string,
result: { key: string; name: string; contentType: string },
folderId?: string | null,
signal?: AbortSignal
)
| 375 | * dropped responses that would otherwise orphan the object in storage. |
| 376 | */ |
| 377 | async function registerWithRetry( |
| 378 | workspaceId: string, |
| 379 | result: { key: string; name: string; contentType: string }, |
| 380 | folderId?: string | null, |
| 381 | signal?: AbortSignal |
| 382 | ) { |
| 383 | let lastError: unknown |
| 384 | for (let attempt = 1; attempt <= REGISTER_MAX_ATTEMPTS; attempt++) { |
| 385 | try { |
| 386 | return await requestJson(registerWorkspaceFileContract, { |
| 387 | params: { id: workspaceId }, |
| 388 | body: { |
| 389 | key: result.key, |
| 390 | name: result.name, |
| 391 | contentType: result.contentType, |
| 392 | folderId, |
| 393 | }, |
| 394 | signal, |
| 395 | }) |
| 396 | } catch (error) { |
| 397 | lastError = error |
| 398 | if (signal?.aborted) throw error |
| 399 | const isTransient = |
| 400 | !(error instanceof ApiClientError) || (error.status >= 500 && error.status < 600) |
| 401 | if (!isTransient || attempt === REGISTER_MAX_ATTEMPTS) throw error |
| 402 | await sleep(REGISTER_RETRY_DELAY_MS * attempt) |
| 403 | } |
| 404 | } |
| 405 | throw lastError |
| 406 | } |
| 407 | |
| 408 | export function useUploadWorkspaceFile() { |
| 409 | const queryClient = useQueryClient() |
no test coverage detected