Regenerate example code + fix broken paths from repo restructure

- Fix testapp/apps.py: import djarea_clients (file was never renamed)
- Fix fetch.mjs: command is export_djarea_schema not export_mizan_schema
- Fix harness package.json: dependency path to mizan-react after restructure
- Add package.json for generator (openapi-typescript dependency)
- Regenerate all example code with new protocol format:
  - generated.provider.tsx uses raw context responses + SSR hydration
  - generated.server.ts uses GET /ctx/global/ with response.ok check
  - generated.forms.ts, channels.ts, channels.hooks.tsx refreshed
- Remove stale generated.django.tsx and generated.django.server.ts
- Update imports: fixtures.tsx and main.tsx import from ./api (index)
- Use MizanContext instead of deprecated DjangoContext in examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 03:13:35 -04:00
parent 711e92ac4d
commit 658cbebce1
10 changed files with 43 additions and 339 deletions

View File

@@ -6,4 +6,4 @@ class TestAppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField" default_auto_field = "django.db.models.BigAutoField"
def ready(self): def ready(self):
import testapp.mizan_clients # noqa: F401 import testapp.djarea_clients # noqa: F401

View File

@@ -7,7 +7,7 @@
"dev": "vite --port 5174" "dev": "vite --port 5174"
}, },
"dependencies": { "dependencies": {
"@rythazhur/mizan": "file:../../react", "@rythazhur/mizan": "file:../../../packages/mizan-react",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"zod": "^4.3.6" "zod": "^4.3.6"

View File

@@ -1,62 +0,0 @@
// AUTO-GENERATED by mizan - do not edit manually
// Regenerate with: npm run schemas
//
// Server-side functions for SSR hydration.
// These run in Next.js server components/layouts.
import type { currentUserOutput, greetOutput } from './generated.mizan'
// ============================================================================
// Hydration Types
// ============================================================================
/** Typed hydration data for SSR */
export interface DjangoHydration {
currentUser?: currentUserOutput
greet?: greetOutput
}
// ============================================================================
// SSR Hydration Helper
// ============================================================================
/**
* Fetch hydration data for SSR.
*
* Call this in your server component:
* const hydration = await getDjangoHydration(client)
* return <DjangoContext hydration={hydration}>...</DjangoContext>
*/
export async function getDjangoHydration(
client: { request: (method: string, url: string, body?: unknown) => Promise<Response> }
): Promise<DjangoHydration> {
const hydration: DjangoHydration = {}
const results = await Promise.allSettled([
client.request('POST', '/api/mizan/call/', { fn: 'current_user', args: {} }),
client.request('POST', '/api/mizan/call/', { fn: 'greet', args: {} }),
])
if (results[0].status === 'fulfilled') {
const data = await (results[0] as PromiseFulfilledResult<Response>).value.json()
if (data.error) {
console.error('[getDjangoHydration] current_user failed:', data.code, data.message)
} else {
hydration.currentUser = data.data
}
} else {
console.error('[getDjangoHydration] current_user request failed:', (results[0] as PromiseRejectedResult).reason)
}
if (results[1].status === 'fulfilled') {
const data = await (results[1] as PromiseFulfilledResult<Response>).value.json()
if (data.error) {
console.error('[getDjangoHydration] greet failed:', data.code, data.message)
} else {
hydration.greet = data.data
}
} else {
console.error('[getDjangoHydration] greet request failed:', (results[1] as PromiseRejectedResult).reason)
}
return hydration
}

View File

@@ -1,257 +0,0 @@
'use client'
// AUTO-GENERATED by mizan - do not edit manually
// Regenerate with: npm run schemas
// This file provides typed wrappers around the mizan library.
// - DjangoContext: Typed provider wrapping mizanProvider
// - Typed hooks: useAuthStatus(), useUser(), etc.
import { type ReactNode, useCallback } from 'react'
import {
mizanProvider,
usemizan,
usemizanContext,
usemizanCall,
type mizanHydration,
type Transport,
} from 'mizan'
import { ChannelProvider, ChannelConnection } from 'mizan/channels'
import { useRef } from 'react'
import type { addEmailSchemaOutput, addEmailValidateInput, addEmailValidateOutput, addInput, addOutput, buggyFnOutput, contactSchemaInput, contactSchemaOutput, contactSubmitOutput, contactValidateInput, contactValidateOutput, currentUserOutput, echoInput, echoOutput, greetInput, greetOutput, httpOnlyEchoInput, httpOnlyEchoOutput, itemFormsetSchemaInput, itemFormsetSchemaOutput, itemFormsetSubmitInput, itemFormsetSubmitOutput, itemFormsetValidateInput, itemFormsetValidateOutput, itemSchemaInput, itemSchemaOutput, itemSubmitOutput, itemValidateInput, itemValidateOutput, jwtObtainOutput, jwtRefreshInput, jwtRefreshOutput, loginSchemaOutput, loginSubmitInput, loginSubmitOutput, loginValidateInput, loginValidateOutput, multiplyInput, multiplyOutput, notImplementedFnOutput, permissionCheckFnInput, permissionCheckFnOutput, signupSchemaOutput, signupSubmitInput, signupSubmitOutput, signupValidateInput, signupValidateOutput, staffOnlyOutput, superuserOnlyOutput, verifiedOnlyOutput, whoamiOutput, wsWhoamiOutput } from './generated.mizan'
// ============================================================================
// Hydration Types
// ============================================================================
/** Typed hydration data for SSR */
export interface DjangoHydration {
currentUser?: currentUserOutput
greet?: greetOutput
}
/** Convert typed hydration to mizan format */
function tomizanHydration(hydration?: DjangoHydration): mizanHydration | undefined {
if (!hydration) return undefined
const result: mizanHydration = {}
if (hydration.currentUser !== undefined) result['current_user'] = hydration.currentUser
if (hydration.greet !== undefined) result['greet'] = hydration.greet
return result
}
// ============================================================================
// Provider
// ============================================================================
export interface DjangoContextProps {
children: ReactNode
/** SSR hydration data */
hydration?: DjangoHydration
/** WebSocket URL for RPC calls (default: /ws/) */
wsUrl?: string
/** Base URL for HTTP fallback (default: /api/mizan) */
baseUrl?: string
}
/**
* Typed Django context provider.
*
* Wraps mizanProvider with:
* - Typed hydration
* - Auto-fetch for registered contexts
*
* Usage:
* <DjangoContext hydration={hydration}>
* <App />
* </DjangoContext>
*/
export function DjangoContext({
children,
hydration,
wsUrl,
baseUrl,
}: DjangoContextProps) {
const connectionRef = useRef<ChannelConnection | null>(null)
if (!connectionRef.current) {
connectionRef.current = new ChannelConnection({ url: wsUrl || '/ws/' })
}
return (
<mizanProvider
hydration={tomizanHydration(hydration)}
contexts={['current_user', 'greet']}
wsUrl={wsUrl}
baseUrl={baseUrl}
connection={connectionRef.current}
>
<ChannelProvider connection={connectionRef.current} autoConnect={true}>
{children}
</ChannelProvider>
</mizanProvider>
)
}
// ============================================================================
// Context Hooks (typed wrappers)
// ============================================================================
/**
* Get current_user context data.
* @throws if context not loaded yet
*/
export function useCurrentUser(): currentUserOutput {
const data = usemizanContext<currentUserOutput>('current_user')
if (data === undefined) {
throw new Error('useCurrentUser: context not loaded yet')
}
return data
}
/**
* Get greet context data.
* @throws if context not loaded yet
*/
export function useGreet(): greetOutput {
const data = usemizanContext<greetOutput>('greet')
if (data === undefined) {
throw new Error('useGreet: context not loaded yet')
}
return data
}
/**
* Get context refresh functions without subscribing to data changes.
* Use this in components that only need to trigger refreshes.
*/
export function useDjangoRefresh() {
const { refreshContext, refreshAllContexts } = usemizan()
return {
refreshCurrentUser: () => refreshContext('current_user'),
refreshGreet: () => refreshContext('greet'),
refreshAll: refreshAllContexts,
}
}
// ============================================================================
// Function Hooks (typed wrappers)
// ============================================================================
/**
* Call echo server function.
* Transport: websocket
*/
export function useEcho() {
return usemizanCall<echoInput, echoOutput>('echo', 'websocket')
}
/**
* Call add server function.
* Transport: websocket
*/
export function useAdd() {
return usemizanCall<addInput, addOutput>('add', 'websocket')
}
/**
* Call whoami server function.
* Transport: http
*/
export function useWhoami() {
return usemizanCall<void, whoamiOutput>('whoami', 'http')
}
/**
* Call http_only_echo server function.
* Transport: http
*/
export function useHttpOnlyEcho() {
return usemizanCall<httpOnlyEchoInput, httpOnlyEchoOutput>('http_only_echo', 'http')
}
/**
* Call staff_only server function.
* Transport: http
*/
export function useStaffOnly() {
return usemizanCall<void, staffOnlyOutput>('staff_only', 'http')
}
/**
* Call superuser_only server function.
* Transport: http
*/
export function useSuperuserOnly() {
return usemizanCall<void, superuserOnlyOutput>('superuser_only', 'http')
}
/**
* Call verified_only server function.
* Transport: http
*/
export function useVerifiedOnly() {
return usemizanCall<void, verifiedOnlyOutput>('verified_only', 'http')
}
/**
* Call multiply server function.
* Transport: http
*/
export function useMultiply() {
return usemizanCall<multiplyInput, multiplyOutput>('multiply', 'http')
}
/**
* Call not_implemented_fn server function.
* Transport: http
*/
export function useNotImplementedFn() {
return usemizanCall<void, notImplementedFnOutput>('not_implemented_fn', 'http')
}
/**
* Call buggy_fn server function.
* Transport: http
*/
export function useBuggyFn() {
return usemizanCall<void, buggyFnOutput>('buggy_fn', 'http')
}
/**
* Call permission_check_fn server function.
* Transport: http
*/
export function usePermissionCheckFn() {
return usemizanCall<permissionCheckFnInput, permissionCheckFnOutput>('permission_check_fn', 'http')
}
/**
* Call ws_whoami server function.
* Transport: websocket
*/
export function useWsWhoami() {
return usemizanCall<void, wsWhoamiOutput>('ws_whoami', 'websocket')
}
/**
* Call jwt_obtain server function.
* Transport: http
*/
export function useJwtObtain() {
return usemizanCall<void, jwtObtainOutput>('jwt_obtain', 'http')
}
/**
* Call jwt_refresh server function.
* Transport: http
*/
export function useJwtRefresh() {
return usemizanCall<jwtRefreshInput, jwtRefreshOutput>('jwt_refresh', 'http')
}
// ============================================================================
// Re-exports from mizan library
// ============================================================================
export { usemizan, usemizanStatus, usePush, DjangoError } from 'mizan'
export type { ConnectionStatus, PushMessage, PushListener } from 'mizan'

View File

@@ -192,7 +192,7 @@ export function useItemFormset(
// Form Registry // Form Registry
// ============================================================================ // ============================================================================
export const DJANGO_FORMS = { export const MIZAN_FORMS = {
login: { login: {
name: 'login', name: 'login',
schema: LoginSchema, schema: LoginSchema,

View File

@@ -6,11 +6,10 @@
* @example * @example
* ```tsx * ```tsx
* import { * import {
* DjangoContext, * MizanContext,
* useUser, * useCurrentUser,
* useEcho, * useEcho,
* useChatChannel, * useChatChannel,
* DjangoError,
* } from '@/api' * } from '@/api'
* ``` * ```
*/ */
@@ -23,22 +22,30 @@
// ============================================================================= // =============================================================================
export { export {
getMizanHydration,
getDjangoHydration, getDjangoHydration,
type MizanHydrationData,
type DjangoHydration, type DjangoHydration,
} from './generated.django.server' } from './generated.server'
export { export {
// Provider // Provider
MizanContext,
type MizanContextProps,
DjangoContext, DjangoContext,
type DjangoContextProps, type DjangoContextProps,
// Context hooks // Global context hooks
useCurrentUser, useCurrentUser,
useGreet,
// Refresh hooks // Refresh hooks
useMizanRefresh,
useDjangoRefresh, useDjangoRefresh,
// Named context providers
LocalContext,
useGreet,
// Function hooks // Function hooks
useEcho, useEcho,
useAdd, useAdd,
@@ -56,14 +63,14 @@ export {
useJwtRefresh, useJwtRefresh,
// Re-exports from mizan library // Re-exports from mizan library
usemizan, useMizan,
usemizanStatus, useMizanStatus,
usePush, usePush,
DjangoError, DjangoError,
type ConnectionStatus, type ConnectionStatus,
type PushMessage, type PushMessage,
type PushListener, type PushListener,
} from './generated.django' } from './generated.provider'
// ============================================================================= // =============================================================================
// Channel Hooks // Channel Hooks

View File

@@ -11,7 +11,7 @@ import { useState, useEffect, useRef } from 'react'
// Generated typed hooks — the actual mizan API // Generated typed hooks — the actual mizan API
import { import {
DjangoContext, MizanContext,
useEcho, useEcho,
useAdd, useAdd,
useMultiply, useMultiply,
@@ -25,9 +25,9 @@ import {
useCurrentUser, useCurrentUser,
DjangoError, DjangoError,
useMizan, useMizan,
} from './api/generated.django' useChatChannel,
} from './api'
import { useContactForm, useLoginForm } from './api/generated.forms' import { useContactForm, useLoginForm } from './api/generated.forms'
import { useChatChannel } from './api/generated.channels.hooks'
// ─── Fixture router ───────────────────────────────────────────────────────── // ─── Fixture router ─────────────────────────────────────────────────────────
@@ -228,7 +228,7 @@ function FormContactSubmit() {
// ─── Channel fixtures ─────────────────────────────────────────────────────── // ─── Channel fixtures ───────────────────────────────────────────────────────
function ChannelChatFixture() { function ChannelChatFixture() {
// DjangoContext already includes ChannelProvider // MizanContext already includes ChannelProvider
return <ChannelChat /> return <ChannelChat />
} }

View File

@@ -1,12 +1,12 @@
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import { DjangoContext } from './api/generated.django' import { MizanContext } from './api'
import { Fixtures } from './fixtures' import { Fixtures } from './fixtures'
function App() { function App() {
return ( return (
<DjangoContext baseUrl="/api/mizan"> <MizanContext baseUrl="/api/mizan">
<Fixtures /> <Fixtures />
</DjangoContext> </MizanContext>
) )
} }

View File

@@ -84,5 +84,5 @@ export async function fetchMizanSchema(source, cwd) {
if (!source.django) { if (!source.django) {
throw new Error('mizan schema export requires django source configuration') throw new Error('mizan schema export requires django source configuration')
} }
return runDjangoCommand(source, cwd, 'export_mizan_schema') return runDjangoCommand(source, cwd, 'export_djarea_schema')
} }

View File

@@ -0,0 +1,16 @@
{
"name": "generate",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"openapi-typescript": "^7.13.0"
}
}