Fix H3, H6, H11, H13, M11, M18 — quick wins from expert review
H3: mizanFetch retries 2x on server errors (5xx) and network failures. 200ms/400ms backoff. Mutations NOT retried (not idempotent). H6: refreshContext now uses GET /ctx/<name>/ instead of POST /call/. Context reads go to the context endpoint, not the mutation endpoint. H11: Python cache key derivation normalizes True→"true", False→"false", None→"null" for cross-language HMAC consistency with JavaScript's String() behavior. H13: Forms isValid now checks that all required fields have been touched, not just that touched fields have no errors. M11: execute_function return type updated to include HttpResponseBase for view-path functions. M18: registerContext cleanup uses ?. instead of ! to prevent crash if Map was cleared (already fixed in H2 commit but documenting). 373 Django + 33 React tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -151,6 +151,24 @@ function flush(): void {
|
||||
|
||||
// === Fetch ===
|
||||
|
||||
async function fetchWithRetry(
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit,
|
||||
retries = 2,
|
||||
): Promise<Response> {
|
||||
for (let attempt = 0; ; attempt++) {
|
||||
try {
|
||||
const res = await fetch(input, init)
|
||||
// Don't retry client errors (4xx) — only server/network errors
|
||||
if (res.ok || (res.status >= 400 && res.status < 500)) return res
|
||||
if (attempt >= retries) return res
|
||||
} catch (e) {
|
||||
if (attempt >= retries) throw e
|
||||
}
|
||||
await new Promise(r => setTimeout(r, (attempt + 1) * 200))
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveHeaders(): Promise<Record<string, string>> {
|
||||
await initSession()
|
||||
|
||||
@@ -179,7 +197,7 @@ export async function mizanFetch(
|
||||
}
|
||||
|
||||
const headers = await resolveHeaders()
|
||||
const res = await fetch(url.toString(), { headers, credentials: 'same-origin' })
|
||||
const res = await fetchWithRetry(url.toString(), { headers, credentials: 'same-origin' })
|
||||
if (!res.ok) throw new MizanError(res.status, await res.text())
|
||||
return res.json()
|
||||
}
|
||||
@@ -191,6 +209,7 @@ export async function mizanCall(
|
||||
const headers = await resolveHeaders()
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
// Mutations are not retried — they are not idempotent
|
||||
const res = await fetch(`${config.baseUrl}/call/`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
|
||||
Reference in New Issue
Block a user