fix(review): adopt latest server_rev on PUT; retry once on 409
Review was POSTing price/sku to /review before each save; that endpoint persists those overrides and bumps server_rev, so the following PUT sent a stale client_rev and hit 409 — Continue to Publish stayed disabled. Stop sending price/sku on review probes (PUT already persists them) and have updateSlab refetch + retry once on revision_conflict.
This commit is contained in:
@@ -45,6 +45,9 @@ export interface Slab {
|
||||
inference_status: string | null;
|
||||
calibration_photo_id: string | null;
|
||||
woo_product_id: number | null;
|
||||
/** Create-time optimistic token; updates compare against server_rev, not this. */
|
||||
client_rev: number;
|
||||
/** Optimistic concurrency token; send as client_rev on PUT. */
|
||||
server_rev: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
@@ -135,7 +138,7 @@ export function getSlab(id: string): Promise<Slab> {
|
||||
return fetch(`/api/v1/slabs/${encodeURIComponent(id)}`).then((r) => parse<Slab>(r));
|
||||
}
|
||||
|
||||
export function updateSlab(id: string, patch: SlabInput & { client_rev: number }): Promise<Slab> {
|
||||
function putSlab(id: string, patch: SlabInput & { client_rev: number }): Promise<Slab> {
|
||||
return fetch(`/api/v1/slabs/${encodeURIComponent(id)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -143,6 +146,37 @@ export function updateSlab(id: string, patch: SlabInput & { client_rev: number }
|
||||
}).then((r) => parse<Slab>(r));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT a slab patch. `client_rev` must equal the slab's current `server_rev`.
|
||||
* On 409 revision_conflict (stale rev — e.g. review POST bumped server_rev, or
|
||||
* a concurrent save), refetch once, adopt the latest server_rev, and retry.
|
||||
* A second 409 surfaces a clear reload message.
|
||||
*/
|
||||
export async function updateSlab(
|
||||
id: string,
|
||||
patch: SlabInput & { client_rev: number },
|
||||
): Promise<Slab> {
|
||||
try {
|
||||
return await putSlab(id, patch);
|
||||
} catch (e) {
|
||||
if (!(e instanceof ApiError) || e.status !== 409) throw e;
|
||||
const latest = await getSlab(id);
|
||||
try {
|
||||
return await putSlab(id, { ...patch, client_rev: latest.server_rev });
|
||||
} catch (e2) {
|
||||
if (e2 instanceof ApiError && e2.status === 409) {
|
||||
throw new ApiError(
|
||||
409,
|
||||
e2.code ?? 'revision_conflict',
|
||||
'This slab changed elsewhere. Reload the page and try again.',
|
||||
e2.detail,
|
||||
);
|
||||
}
|
||||
throw e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteSlab(id: string): Promise<void> {
|
||||
return fetch(`/api/v1/slabs/${encodeURIComponent(id)}`, { method: 'DELETE' }).then((r) =>
|
||||
parse<void>(r),
|
||||
|
||||
Reference in New Issue
Block a user