Add named contexts, bundled fetch endpoint, and affects invalidation
Phase 1 (Named Contexts): - @client(context=) accepts any string, not just 'global'/'local' - context='local' emits deprecation warning - Registry groups functions by context name (get_context_groups) - GET /api/mizan/ctx/<name>/ bundles all context functions in one response - Schema export includes x-mizan-contexts with param elevation metadata Phase 2 (Affects): - @client(affects=) declares mutation invalidation targets - Accepts context name strings, function refs, or lists - Mutually exclusive with context= - Exported in x-mizan-functions schema for codegen React runtime: - MizanContextValue gains invalidateContext, invalidateFunctions, registerContextProvider, and baseUrl - Named context providers register for invalidation on mount 259 Django tests pass, 33 React tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,34 @@ export interface MizanContextValue {
|
||||
* (e.g., calling a server function immediately on mount).
|
||||
*/
|
||||
whenReady: Promise<void>
|
||||
|
||||
/**
|
||||
* Invalidate a named context, triggering a refetch.
|
||||
* Only refetches if the context is currently mounted (has a registered provider).
|
||||
* No-op if the context is not mounted.
|
||||
*/
|
||||
invalidateContext: (name: string) => Promise<void>
|
||||
|
||||
/**
|
||||
* Invalidate specific functions within their contexts.
|
||||
* Groups by context and calls invalidateContext per group.
|
||||
*/
|
||||
invalidateFunctions: (names: string[]) => Promise<void>
|
||||
|
||||
/**
|
||||
* Register a named context provider for invalidation support.
|
||||
* Called by generated context providers on mount.
|
||||
* Returns an unregister function (call on unmount).
|
||||
*/
|
||||
registerContextProvider: (
|
||||
name: string,
|
||||
refetch: () => Promise<void>,
|
||||
) => () => void
|
||||
|
||||
/**
|
||||
* Base URL for HTTP calls (for use by generated context providers).
|
||||
*/
|
||||
baseUrl: string
|
||||
}
|
||||
|
||||
export interface MizanProviderProps {
|
||||
@@ -466,6 +494,51 @@ export function MizanProvider({
|
||||
|
||||
const isRPCAvailable = status === 'connected'
|
||||
|
||||
// Named context provider registry for invalidation
|
||||
const contextProvidersRef = useRef<Map<string, { refetch: () => Promise<void> }>>(new Map())
|
||||
|
||||
const registerContextProvider = useCallback(
|
||||
(name: string, refetch: () => Promise<void>): (() => void) => {
|
||||
contextProvidersRef.current.set(name, { refetch })
|
||||
return () => {
|
||||
contextProvidersRef.current.delete(name)
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const invalidateContext = useCallback(
|
||||
async (name: string): Promise<void> => {
|
||||
const provider = contextProvidersRef.current.get(name)
|
||||
if (provider) {
|
||||
await provider.refetch()
|
||||
}
|
||||
// If not mounted, no-op — no wasted request
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const invalidateFunctions = useCallback(
|
||||
async (names: string[]): Promise<void> => {
|
||||
// Each function belongs to a context. Invalidating a function
|
||||
// means refetching its entire context (since the bundling endpoint
|
||||
// returns all functions). Dedupe by context name.
|
||||
const contexts = new Set<string>()
|
||||
for (const name of names) {
|
||||
// The context name for each function is known at codegen time
|
||||
// and baked into the generated hook. Here we just invalidate
|
||||
// whatever contexts are registered that contain these functions.
|
||||
for (const [ctxName] of contextProvidersRef.current) {
|
||||
contexts.add(ctxName)
|
||||
}
|
||||
}
|
||||
await Promise.all(
|
||||
Array.from(contexts).map(ctx => invalidateContext(ctx))
|
||||
)
|
||||
},
|
||||
[invalidateContext]
|
||||
)
|
||||
|
||||
const value = useMemo<MizanContextValue>(
|
||||
() => ({
|
||||
call,
|
||||
@@ -477,8 +550,12 @@ export function MizanProvider({
|
||||
onPush,
|
||||
onContextChange,
|
||||
whenReady: sessionRef.current!.promise,
|
||||
invalidateContext,
|
||||
invalidateFunctions,
|
||||
registerContextProvider,
|
||||
baseUrl,
|
||||
}),
|
||||
[call, getContext, refreshContext, refreshAllContexts, status, isRPCAvailable, onPush, onContextChange]
|
||||
[call, getContext, refreshContext, refreshAllContexts, status, isRPCAvailable, onPush, onContextChange, invalidateContext, invalidateFunctions, registerContextProvider, baseUrl]
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user