Fix protocol mismatch + add SSR hydration to codegen
Three bugs fixed:
1. MizanProvider.call() read data.data but server returns data.result.
Now reads data.result and processes data.invalidate for server-driven
invalidation (triggering refetch on mounted context providers).
2. GlobalContextLoader expected {error, data} wrapper but context GET
returns raw bundled data. Fixed to iterate response directly.
3. Named context providers had same wrapper assumption. Fixed to
setData(result) directly.
Two features added:
1. SSR hydration: GlobalContextLoader checks window.__MIZAN_SSR_DATA__
on mount. If present, populates contexts from it and skips fetch.
2. SSR hydration: Named context providers check __MIZAN_SSR_DATA__ in
useState initializer. If SSR data exists for their functions, they
render immediately without fetching.
3. Server-driven invalidation in MizanProvider.call(): reads the
invalidate array from mutation responses and triggers refetch on
mounted providers. Generated mutation hooks' hardcoded invalidation
is now redundant but idempotent — both paths coexist safely.
Also fixed FunctionSuccessResponse type to match new protocol:
{ result: T, invalidate?: [...] }
373 Django + 33 React tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -528,8 +528,8 @@ import { DjangoError, type FunctionErrorResponse } from '../errors'
|
||||
* Success response from a server function
|
||||
*/
|
||||
export interface FunctionSuccessResponse<T> {
|
||||
error: false
|
||||
data: T
|
||||
result: T
|
||||
invalidate?: Array<string | { context: string; params: Record<string, any> }>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,6 +580,6 @@ export async function httpFunctionCall<TInput = unknown, TOutput = unknown>(
|
||||
throw new DjangoError(data)
|
||||
}
|
||||
|
||||
return data.data
|
||||
return (data as FunctionSuccessResponse<TOutput>).result
|
||||
}
|
||||
|
||||
|
||||
@@ -343,13 +343,26 @@ export function MizanProvider({
|
||||
{ fn: functionName, args: input }
|
||||
)
|
||||
|
||||
const data: FunctionResponse<TOutput> = await response.json()
|
||||
const data = await response.json()
|
||||
|
||||
if (data.error) {
|
||||
throw new DjangoError(data as FunctionErrorResponse)
|
||||
}
|
||||
|
||||
return data.data
|
||||
// Server-driven invalidation: process the invalidate array
|
||||
if (data.invalidate && Array.isArray(data.invalidate)) {
|
||||
for (const entry of data.invalidate) {
|
||||
if (typeof entry === 'string') {
|
||||
const provider = contextProvidersRef.current.get(entry)
|
||||
if (provider) provider.refetch()
|
||||
} else if (entry.context) {
|
||||
const provider = contextProvidersRef.current.get(entry.context)
|
||||
if (provider) provider.refetch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data.result as TOutput
|
||||
},
|
||||
[connection, baseUrl, httpClient]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user