C6: Runtime kernel owns data, status, error — adapters subscribe
The kernel is no longer a blind refetch pipe. Each context entry has:
{ data, status: idle|loading|success|error, error }
registerContext() returns { getState, subscribe, refetch, unregister }.
Adapters subscribe to state changes via callbacks. The kernel does
the fetch and notifies subscribers with the new state.
React adapter uses useSyncExternalStore for tear-free reads.
Vue adapter uses ref + subscribe callback.
Svelte adapter uses readable store backed by kernel subscription.
All three adapters also get:
- Mutation hooks with { mutate, isPending, error } (fixes H5)
- Vue: onServerPrefetch for Nuxt SSR (fixes M9)
- Svelte: readable store auto-cleans up on unsubscribe (fixes H9)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,96 +1,229 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
import { ref, computed, watch, onMounted, onUnmounted, provide, inject, type Ref, type ComputedRef, type InjectionKey } from 'vue'
|
||||
import { registerContext } from '@mizan/runtime'
|
||||
import { ref, computed, onMounted, onUnmounted, onServerPrefetch, type ComputedRef } from 'vue'
|
||||
import { registerContext, type ContextState } from '@mizan/runtime'
|
||||
|
||||
import { fetchGlobalContext, type GlobalContextData, type GlobalContextParams, fetchLocalContext, type LocalContextData, type LocalContextParams, callEcho, callAdd, callWhoami, callHttpOnlyEcho, callStaffOnly, callSuperuserOnly, callVerifiedOnly, callMultiply, callNotImplementedFn, callBuggyFn, callPermissionCheckFn, callWsWhoami, callJwtObtain, callJwtRefresh } from '../index'
|
||||
|
||||
// Global context
|
||||
const GlobalKey: InjectionKey<{ data: Ref<GlobalContextData | null>, loading: Ref<boolean> }> = Symbol('global')
|
||||
export function useGlobalContext() {
|
||||
const state = ref<ContextState<GlobalContextData>>({ data: null, status: 'idle', error: null })
|
||||
let handle: ReturnType<typeof registerContext> | null = null
|
||||
|
||||
export function provideGlobalContext() {
|
||||
const data = ref<GlobalContextData | null>(null)
|
||||
const loading = ref(true)
|
||||
|
||||
const refetch = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
data.value = await fetchGlobalContext({} as any)
|
||||
} catch (e) { console.error('[mizan] global fetch failed:', e) }
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
let unregister: (() => void) | null = null
|
||||
onMounted(() => {
|
||||
refetch()
|
||||
unregister = registerContext('global', {}, refetch)
|
||||
handle = registerContext('global', {} as any, () => fetchGlobalContext({} as any))
|
||||
handle.subscribe(() => { state.value = handle!.getState() })
|
||||
handle.refetch()
|
||||
})
|
||||
onUnmounted(() => { unregister?.() })
|
||||
|
||||
provide(GlobalKey, { data, loading })
|
||||
}
|
||||
onServerPrefetch(async () => {
|
||||
handle = registerContext('global', {} as any, () => fetchGlobalContext({} as any))
|
||||
await handle.refetch()
|
||||
state.value = handle.getState()
|
||||
})
|
||||
|
||||
export function useCurrentUser(): ComputedRef<currentUserOutput | null> {
|
||||
const ctx = inject(GlobalKey)
|
||||
if (!ctx) throw new Error('useCurrentUser requires provideGlobalContext in a parent')
|
||||
return computed(() => ctx.data.value?.current_user ?? null)
|
||||
}
|
||||
onUnmounted(() => { handle?.unregister() })
|
||||
|
||||
// Local context
|
||||
const LocalKey: InjectionKey<{ data: Ref<LocalContextData | null>, loading: Ref<boolean> }> = Symbol('local')
|
||||
|
||||
export function provideLocalContext(params: { name: string }) {
|
||||
const data = ref<LocalContextData | null>(null)
|
||||
const loading = ref(true)
|
||||
|
||||
const refetch = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
data.value = await fetchLocalContext(params as any)
|
||||
} catch (e) { console.error('[mizan] local fetch failed:', e) }
|
||||
loading.value = false
|
||||
return {
|
||||
state,
|
||||
currentUser: computed(() => state.value.data?.current_user ?? null) as ComputedRef<currentUserOutput | null>,
|
||||
loading: computed(() => state.value.status === 'loading'),
|
||||
error: computed(() => state.value.error),
|
||||
}
|
||||
}
|
||||
|
||||
export function useLocalContext(params: LocalContextParams) {
|
||||
const state = ref<ContextState<LocalContextData>>({ data: null, status: 'idle', error: null })
|
||||
let handle: ReturnType<typeof registerContext> | null = null
|
||||
|
||||
let unregister: (() => void) | null = null
|
||||
onMounted(() => {
|
||||
refetch()
|
||||
unregister = registerContext('local', params, refetch)
|
||||
handle = registerContext('local', params, () => fetchLocalContext(params))
|
||||
handle.subscribe(() => { state.value = handle!.getState() })
|
||||
handle.refetch()
|
||||
})
|
||||
onUnmounted(() => { unregister?.() })
|
||||
|
||||
provide(LocalKey, { data, loading })
|
||||
onServerPrefetch(async () => {
|
||||
handle = registerContext('local', params, () => fetchLocalContext(params))
|
||||
await handle.refetch()
|
||||
state.value = handle.getState()
|
||||
})
|
||||
|
||||
onUnmounted(() => { handle?.unregister() })
|
||||
|
||||
return {
|
||||
state,
|
||||
greet: computed(() => state.value.data?.greet ?? null) as ComputedRef<greetOutput | null>,
|
||||
loading: computed(() => state.value.status === 'loading'),
|
||||
error: computed(() => state.value.error),
|
||||
}
|
||||
}
|
||||
|
||||
export function useGreet(): ComputedRef<greetOutput | null> {
|
||||
const ctx = inject(LocalKey)
|
||||
if (!ctx) throw new Error('useGreet requires provideLocalContext in a parent')
|
||||
return computed(() => ctx.data.value?.greet ?? null)
|
||||
export function useEcho() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callEcho>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callEcho(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useEcho = callEcho
|
||||
export function useAdd() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callAdd>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callAdd(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useAdd = callAdd
|
||||
export function useWhoami() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callWhoami() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useWhoami = callWhoami
|
||||
export function useHttpOnlyEcho() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callHttpOnlyEcho>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callHttpOnlyEcho(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useHttpOnlyEcho = callHttpOnlyEcho
|
||||
export function useStaffOnly() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callStaffOnly() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useStaffOnly = callStaffOnly
|
||||
export function useSuperuserOnly() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callSuperuserOnly() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useSuperuserOnly = callSuperuserOnly
|
||||
export function useVerifiedOnly() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callVerifiedOnly() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useVerifiedOnly = callVerifiedOnly
|
||||
export function useMultiply() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callMultiply>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callMultiply(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useMultiply = callMultiply
|
||||
export function useNotImplementedFn() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callNotImplementedFn() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useNotImplementedFn = callNotImplementedFn
|
||||
export function useBuggyFn() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callBuggyFn() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useBuggyFn = callBuggyFn
|
||||
export function usePermissionCheckFn() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callPermissionCheckFn>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callPermissionCheckFn(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const usePermissionCheckFn = callPermissionCheckFn
|
||||
export function useWsWhoami() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callWsWhoami() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useWsWhoami = callWsWhoami
|
||||
export function useJwtObtain() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate() {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callJwtObtain() }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useJwtObtain = callJwtObtain
|
||||
export function useJwtRefresh() {
|
||||
const isPending = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
async function mutate(args: Parameters<typeof callJwtRefresh>[0]) {
|
||||
isPending.value = true; error.value = null
|
||||
try { return await callJwtRefresh(args) }
|
||||
catch (e) { error.value = e as Error; throw e }
|
||||
finally { isPending.value = false }
|
||||
}
|
||||
return { mutate, isPending, error }
|
||||
}
|
||||
|
||||
export const useJwtRefresh = callJwtRefresh
|
||||
export type { ContextState } from '@mizan/runtime'
|
||||
export { configure, initSession, MizanError } from '@mizan/runtime'
|
||||
|
||||
Reference in New Issue
Block a user