fix(12.2): close code-review blockers on uploads, JSON caps, and pivot fill

Keep form save behind in-flight uploads, make retries idempotent via X-Upload-Id, cap remaining JSON bodies, and surface pending pivot type errors instead of zeroing them.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-02 23:10:48 +02:00
parent 6bfc0faa8a
commit 516f9c9025
22 changed files with 533 additions and 96 deletions

View File

@@ -37,9 +37,12 @@ export interface UploadHandle {
export type UploadProgress = (loaded: number, total: number) => void
/** Everything a fileupload control does with its files. */
/** Client upload id sent as X-Upload-Id so a retry returns the stored file. */
export const UPLOAD_ID_HEADER = 'X-Upload-Id'
export interface FileRoutes {
list(): Promise<FileCallResult<FileItem[]>>
upload(file: File, onProgress?: UploadProgress): UploadHandle
upload(file: File, onProgress?: UploadProgress, uploadId?: string): UploadHandle
update(file: number, body: AdminFileCaptionRequest): Promise<FileCallResult<FileItem>>
remove(file: number): Promise<FileCallResult<FileMutationResult>>
reorder(ids: number[]): Promise<FileCallResult<FileItem[]>>
@@ -137,6 +140,7 @@ export function uploadWithProgress(
file: File,
headers: Record<string, string>,
onProgress?: UploadProgress,
uploadId?: string,
): UploadHandle {
let current: XMLHttpRequest | null = null
let aborted = false
@@ -151,6 +155,9 @@ export function uploadWithProgress(
for (const [name, value] of Object.entries(headers)) {
request.setRequestHeader(name, value)
}
if (uploadId) {
request.setRequestHeader(UPLOAD_ID_HEADER, uploadId)
}
request.upload.onprogress = (event: ProgressEvent) => {
if (event.lengthComputable) {
onProgress?.(event.loaded, event.total)
@@ -208,7 +215,7 @@ export function parentFileRoutes(
const url = `${controllerUrl(source)}/${segment(recordId)}/files/${segment(field)}`
return {
list: () => settle(() => api.GET('/{vendor}/{plugin}/{controller}/{id}/files/{field}', { params: { path, header } })),
upload: (file, onProgress) => uploadWithProgress(url, file, { ...header }, onProgress),
upload: (file, onProgress, uploadId) => uploadWithProgress(url, file, { ...header }, onProgress, uploadId),
update: (file, body) =>
settle(() =>
api.PUT('/{vendor}/{plugin}/{controller}/{id}/files/{field}/{file}', {
@@ -273,7 +280,7 @@ export function childFileRoutes(
params: { path, header },
}),
),
upload: (file, onProgress) => uploadWithProgress(url, file, { ...header }, onProgress),
upload: (file, onProgress, uploadId) => uploadWithProgress(url, file, { ...header }, onProgress, uploadId),
update: (file, body) =>
settle(() =>
api.PUT('/{vendor}/{plugin}/{controller}/{id}/relations/{name}/records/{child}/files/{field}/{file}', {