diff --git a/.gitea/workflows/publish-django.yaml b/.gitea/workflows/publish-django.yaml index cf63f39..3d98e0a 100644 --- a/.gitea/workflows/publish-django.yaml +++ b/.gitea/workflows/publish-django.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: django + working-directory: backends/mizan-django steps: - uses: actions/checkout@v4 diff --git a/.gitea/workflows/publish-react.yaml b/.gitea/workflows/publish-react.yaml index 98b9be4..879d95e 100644 --- a/.gitea/workflows/publish-react.yaml +++ b/.gitea/workflows/publish-react.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: react + working-directory: frontends/mizan-react steps: - uses: actions/checkout@v4 diff --git a/CLAUDE.md b/CLAUDE.md index 79f34a8..34f21c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,23 +10,21 @@ Django + React ships first. The protocol is language-agnostic (proven by mizan-t ## Package Layout -Two layers per side. Per-framework adapters wrap a single shared kernel; codegen targets the adapter. +Tree organized by role. Per-framework adapters wrap a single shared kernel; codegen targets the adapter. -**Backend protocol adapters** — implement the wire protocol on a server stack: - -- `mizan-django/` — Django adapter -- `mizan-ts/` — TypeScript adapter (proves the protocol is language-agnostic) - -**Frontend kernel + framework adapters** — kernel is the imperative client primitive set; each framework adapter wraps the kernel in its own idiomatic constructs: - -- `mizan-runtime/` — framework-agnostic kernel; owns data, status, error; adapters subscribe -- `mizan-react/` — React contexts + hooks over the kernel -- `mizan-vue/` — Vue composables over the kernel -- `mizan-svelte/` — Svelte stores/runes over the kernel - -**SSR worker:** - -- `mizan-ssr/` — Bun subprocess used by the Django template backend +``` +backends/ server protocol adapters + mizan-django/ Django adapter + mizan-ts/ TypeScript adapter (proves the protocol is language-agnostic) +frontends/ client kernel + per-framework adapters + mizan-base/ framework-agnostic kernel; owns data, status, error; adapters subscribe + mizan-react/ React contexts + hooks over the kernel + mizan-vue/ Vue composables over the kernel + mizan-svelte/ Svelte stores/runes over the kernel +cores/ shared language-level primitives (currently empty; mizan-python forthcoming) +workers/ runtime workers / bridges + mizan-ssr/ Bun subprocess used by the Django template backend +``` --- @@ -444,7 +442,7 @@ urlpatterns = [ ## Codegen — Current State -The codegen is two-stage and per-framework. Stage 1 (in `mizan-django/generate/`) emits the framework-agnostic protocol layer (`callXxx` for mutations, `fetchXxx` for context bundles, types). Stage 2 emits per-framework hooks/composables/stores that subscribe to the `mizan-runtime` kernel. +The codegen is two-stage and per-framework. Stage 1 (in `mizan-django/generate/`) emits the framework-agnostic protocol layer (`callXxx` for mutations, `fetchXxx` for context bundles, types). Stage 2 emits per-framework hooks/composables/stores that subscribe to the `mizan-base` kernel. **What's in place:** diff --git a/ISSUES.md b/ISSUES.md index fd7807f..2eecce9 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -24,7 +24,7 @@ Identified by domain expert review (Cloudflare, Serverless, Vercel, React Query, ## Remaining Critical ### C6. No loading/error/stale states in runtime -**File:** `mizan-runtime/src/index.ts` +**File:** `mizan-base/src/index.ts` The kernel stores only `{params, refetch}`. No `data`, `status`, `error`. Every adapter reinvents loading tracking. Blocks stale-while-revalidate. ## Remaining High @@ -103,7 +103,7 @@ Context listeners called inside `setContextStore()` updater. ### A1. Legacy MizanProvider not yet removed **File:** `mizan-react/src/context.tsx` (~750 lines) -Superseded by the kernel (`mizan-runtime`) + generated React adapter (`useSyncExternalStore`). Still exported as `MizanProvider`, `useMizan`, `useMizanContext`, etc. Must be deleted or replaced with thin shims that call `configure()` + delegate to the new generated hooks. +Superseded by the kernel (`mizan-base`) + generated React adapter (`useSyncExternalStore`). Still exported as `MizanProvider`, `useMizan`, `useMizanContext`, etc. Must be deleted or replaced with thin shims that call `configure()` + delegate to the new generated hooks. ### A2. Allauth pending extraction **File:** `legacy/allauth/` (44 files) @@ -131,7 +131,7 @@ Written before the kernel rewrite. References to MizanProvider responsibilities ## Test Coverage Gaps ### T1. No tests for C6 kernel state machine -**File:** `mizan-runtime/` has no `tests/` directory at all +**File:** `mizan-base/` has no `tests/` directory at all The state-owning kernel has zero unit tests. No coverage of: - `registerContext` returning `getState/subscribe/refetch/unregister` - Status transitions: idle → loading → success/error diff --git a/Makefile b/Makefile index 587ad40..7a6ab7e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: install test test-django test-react test-integration docker-up docker-down clean -DJANGO = packages/mizan-django -REACT = packages/mizan-react +DJANGO = backends/mizan-django +REACT = frontends/mizan-react # ─── Setup ─────────────────────────────────────────────────────────────────── diff --git a/ROADMAP.md b/ROADMAP.md index e2fa05f..594ed74 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -20,7 +20,7 @@ - **HMAC cache keying** — origin-side cache with cross-language HMAC conformance (Python + TypeScript pin) - **Edge manifest** — `python manage.py export_edge_manifest`; both RPC and view-path functions - **SSR bridge** — Django template backend → persistent Bun subprocess via JSON-RPC -- **`mizan-runtime` kernel** — framework-agnostic imperative client primitives (data/status/error owned by kernel) +- **`mizan-base` kernel** — framework-agnostic imperative client primitives (data/status/error owned by kernel) - **Two-stage codegen** — Stage 1 emits framework-agnostic protocol layer; Stage 2 emits per-framework hooks (React, Vue, Svelte) - **`mizan-ts`** — TypeScript backend adapter; proves the protocol is language-agnostic @@ -28,7 +28,7 @@ ### Next (in progress) -- **React adapter wrapper layer** — codegen emits `MizanContext` provider, `useMizan` hook, `DjangoError` class on top of the `mizan-runtime` kernel. Equivalent wrapper layers for Vue and Svelte adapters. The harness in `examples/django-react-site` is blocked on this. +- **React adapter wrapper layer** — codegen emits `MizanContext` provider, `useMizan` hook, `DjangoError` class on top of the `mizan-base` kernel. Equivalent wrapper layers for Vue and Svelte adapters. The harness in `examples/django-react-site` is blocked on this. - **Legacy `MizanProvider` removal (A1)** — `mizan-react/src/context.tsx` (~750 lines) replaced by codegen-emitted wrappers. Blocks v1 `mizan-react` publishing. - **Forms migration to kernel (A3)** — `mizan-react/src/forms.ts` (~1163 lines) currently consumes legacy `MizanProvider`. Rewrite to use `mizanCall` from the kernel. Blocks A1. - **Allauth extraction (A2)** — `legacy/allauth/` becomes `mizan-django-allauth` package consuming Mizan's public API. diff --git a/backends/mizan-django/generate/generator/lib/adapters/react.mjs b/backends/mizan-django/generate/generator/lib/adapters/react.mjs index 601dc5a..b2f5442 100644 --- a/backends/mizan-django/generate/generator/lib/adapters/react.mjs +++ b/backends/mizan-django/generate/generator/lib/adapters/react.mjs @@ -23,7 +23,7 @@ export function generateReactAdapter(schema) { '// AUTO-GENERATED by mizan — do not edit', '', "import { createContext, useContext, useState, useEffect, useCallback, useRef, useSyncExternalStore, type ReactNode } from 'react'", - "import { registerContext, mizanFetch, mizanCall, type ContextState } from '@mizan/runtime'", + "import { registerContext, mizanFetch, mizanCall, type ContextState } from '@mizan/base'", '', ] @@ -172,8 +172,8 @@ export function generateReactAdapter(schema) { // ── Re-export runtime types ───────────────────────────────────────── - lines.push("export type { ContextState } from '@mizan/runtime'") - lines.push("export { configure, initSession, MizanError } from '@mizan/runtime'") + lines.push("export type { ContextState } from '@mizan/base'") + lines.push("export { configure, initSession, MizanError } from '@mizan/base'") lines.push('') return lines.join('\n') diff --git a/backends/mizan-django/generate/generator/lib/adapters/svelte.mjs b/backends/mizan-django/generate/generator/lib/adapters/svelte.mjs index 6b501c2..bc580fb 100644 --- a/backends/mizan-django/generate/generator/lib/adapters/svelte.mjs +++ b/backends/mizan-django/generate/generator/lib/adapters/svelte.mjs @@ -18,7 +18,7 @@ export function generateSvelteAdapter(schema) { '// AUTO-GENERATED by mizan — do not edit', '', "import { readable, type Readable } from 'svelte/store'", - "import { registerContext, type ContextState } from '@mizan/runtime'", + "import { registerContext, type ContextState } from '@mizan/base'", '', ] @@ -70,8 +70,8 @@ export function generateSvelteAdapter(schema) { } lines.push('') - lines.push("export type { ContextState } from '@mizan/runtime'") - lines.push("export { configure, initSession, MizanError } from '@mizan/runtime'") + lines.push("export type { ContextState } from '@mizan/base'") + lines.push("export { configure, initSession, MizanError } from '@mizan/base'") lines.push('') return lines.join('\n') diff --git a/backends/mizan-django/generate/generator/lib/adapters/vue.mjs b/backends/mizan-django/generate/generator/lib/adapters/vue.mjs index 22626ef..13ce58a 100644 --- a/backends/mizan-django/generate/generator/lib/adapters/vue.mjs +++ b/backends/mizan-django/generate/generator/lib/adapters/vue.mjs @@ -18,7 +18,7 @@ export function generateVueAdapter(schema) { '// AUTO-GENERATED by mizan — do not edit', '', "import { ref, computed, onMounted, onUnmounted, onServerPrefetch, type ComputedRef } from 'vue'", - "import { registerContext, type ContextState } from '@mizan/runtime'", + "import { registerContext, type ContextState } from '@mizan/base'", '', ] @@ -96,8 +96,8 @@ export function generateVueAdapter(schema) { lines.push('') } - lines.push("export type { ContextState } from '@mizan/runtime'") - lines.push("export { configure, initSession, MizanError } from '@mizan/runtime'") + lines.push("export type { ContextState } from '@mizan/base'") + lines.push("export { configure, initSession, MizanError } from '@mizan/base'") lines.push('') return lines.join('\n') diff --git a/backends/mizan-django/generate/generator/lib/stage1.mjs b/backends/mizan-django/generate/generator/lib/stage1.mjs index 588246c..248e87f 100644 --- a/backends/mizan-django/generate/generator/lib/stage1.mjs +++ b/backends/mizan-django/generate/generator/lib/stage1.mjs @@ -80,7 +80,7 @@ export function generateContextFile(ctxName, ctxMeta, functions) { const lines = [ '// AUTO-GENERATED by mizan — do not edit', '', - "import { mizanFetch } from '@mizan/runtime'", + "import { mizanFetch } from '@mizan/base'", '', ] @@ -133,7 +133,7 @@ export function generateMutationFile(fn) { const lines = [ '// AUTO-GENERATED by mizan — do not edit', '', - "import { mizanCall } from '@mizan/runtime'", + "import { mizanCall } from '@mizan/base'", '', ] diff --git a/docs/AFI_ARCHITECTURE.md b/docs/AFI_ARCHITECTURE.md index 1ff78e7..d29dbc2 100644 --- a/docs/AFI_ARCHITECTURE.md +++ b/docs/AFI_ARCHITECTURE.md @@ -5,32 +5,21 @@ server-client unification layer. ## Package layout -Two layers per side. Independent packages, single shared protocol. +Tree organized by role. -**Backend protocol adapters** — implement the wire protocol on a -server stack: - -| Package | Role | -|---|---| -| `mizan-django` | Django adapter | -| `mizan-ts` | TypeScript adapter (proves the protocol is language-agnostic) | - -**Frontend kernel + framework adapters** — the kernel is the -imperative client primitive set; each framework adapter wraps the -kernel in its own idiomatic constructs: - -| Package | Role | -|---|---| -| `mizan-runtime` | Framework-agnostic client kernel — owns data, status, error; adapters subscribe | -| `mizan-react` | React contexts + hooks over the kernel | -| `mizan-vue` | Vue composables over the kernel | -| `mizan-svelte` | Svelte stores/runes over the kernel | - -**SSR worker:** - -| Package | Role | -|---|---| -| `mizan-ssr` | Bun subprocess used by the Django template backend | +``` +backends/ server protocol adapters + mizan-django/ Django adapter + mizan-ts/ TypeScript adapter (proves the protocol is language-agnostic) +frontends/ client kernel + per-framework adapters + mizan-base/ framework-agnostic kernel; owns data, status, error; adapters subscribe + mizan-react/ React contexts + hooks over the kernel + mizan-vue/ Vue composables over the kernel + mizan-svelte/ Svelte stores/runes over the kernel +cores/ shared language-level primitives (mizan-python forthcoming) +workers/ runtime workers / bridges + mizan-ssr/ Bun subprocess used by the Django template backend +``` ## Two orthogonal products @@ -42,7 +31,7 @@ compose. ## Kernel model -The client kernel (`mizan-runtime`) is the one hard thing. Per- +The client kernel (`mizan-base`) is the one hard thing. Per- framework adapters are thin idiomatic wrappers around it. Codegen emits typed bindings against the framework adapter's surface, not against the raw kernel — so a React developer gets `useEcho()` and diff --git a/examples/django-react-desktop-app/frontend/package.json b/examples/django-react-desktop-app/frontend/package.json index c58f83e..62d826b 100644 --- a/examples/django-react-desktop-app/frontend/package.json +++ b/examples/django-react-desktop-app/frontend/package.json @@ -7,7 +7,7 @@ "build": "vite build" }, "dependencies": { - "@rythazhur/mizan": "file:../../../packages/mizan-react", + "@rythazhur/mizan": "file:../../../frontends/mizan-react", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/examples/django-react-desktop-app/frontend/vite.config.ts b/examples/django-react-desktop-app/frontend/vite.config.ts index bb0d407..b51b055 100644 --- a/examples/django-react-desktop-app/frontend/vite.config.ts +++ b/examples/django-react-desktop-app/frontend/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import path from 'path' -const reactPkg = path.resolve(__dirname, '../../../packages/mizan-react/src') +const reactPkg = path.resolve(__dirname, '../../../frontends/mizan-react/src') export default defineConfig({ plugins: [react()], diff --git a/examples/django-react-site/Dockerfile.test b/examples/django-react-site/Dockerfile.test index 32e75e0..0a6aea6 100644 --- a/examples/django-react-site/Dockerfile.test +++ b/examples/django-react-site/Dockerfile.test @@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* # Install mizan from local source with channels support -COPY packages/mizan-django/ /app/django/ +COPY backends/mizan-django/ /app/django/ RUN pip install --no-cache-dir /app/django[channels] daphne # Copy example app diff --git a/examples/django-react-site/harness/django.config.mjs b/examples/django-react-site/harness/django.config.mjs index 23a63cc..5d5d15a 100644 --- a/examples/django-react-site/harness/django.config.mjs +++ b/examples/django-react-site/harness/django.config.mjs @@ -10,9 +10,9 @@ export default { source: { django: { managePath: path.join(root, 'examples/django-react-site/backend/manage.py'), - command: [path.join(root, 'packages/mizan-django/.venv/bin/python')], + command: [path.join(root, 'backends/mizan-django/.venv/bin/python')], env: { - PYTHONPATH: `${path.join(root, 'packages/mizan-django/src')}:${path.join(root, 'examples/django-react-site/backend')}`, + PYTHONPATH: `${path.join(root, 'backends/mizan-django/src')}:${path.join(root, 'examples/django-react-site/backend')}`, DJANGO_SETTINGS_MODULE: 'testapp.settings', }, }, diff --git a/examples/django-react-site/harness/package.json b/examples/django-react-site/harness/package.json index 56b0dfa..0f0c4e7 100644 --- a/examples/django-react-site/harness/package.json +++ b/examples/django-react-site/harness/package.json @@ -7,7 +7,7 @@ "dev": "vite --port 5174" }, "dependencies": { - "@rythazhur/mizan": "file:../../../packages/mizan-react", + "@rythazhur/mizan": "file:../../../frontends/mizan-react", "react": "^19.0.0", "react-dom": "^19.0.0", "zod": "^4.3.6" diff --git a/examples/django-react-site/harness/vite.config.ts b/examples/django-react-site/harness/vite.config.ts index 6ce9d03..ee1caf7 100644 --- a/examples/django-react-site/harness/vite.config.ts +++ b/examples/django-react-site/harness/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import path from 'path' -const reactPkg = path.resolve(__dirname, '../../../packages/mizan-react/src') +const reactPkg = path.resolve(__dirname, '../../../frontends/mizan-react/src') export default defineConfig({ plugins: [react()], diff --git a/frontends/mizan-base/package.json b/frontends/mizan-base/package.json index 30b5cd9..3eb7a05 100644 --- a/frontends/mizan-base/package.json +++ b/frontends/mizan-base/package.json @@ -1,5 +1,5 @@ { - "name": "@mizan/runtime", + "name": "@mizan/base", "version": "0.1.0", "description": "Mizan client runtime — context registry, invalidation, fetch. Zero framework dependencies.", "type": "module", diff --git a/frontends/mizan-base/src/index.ts b/frontends/mizan-base/src/index.ts index 2ab88b0..9bb03ec 100644 --- a/frontends/mizan-base/src/index.ts +++ b/frontends/mizan-base/src/index.ts @@ -1,5 +1,5 @@ /** - * @mizan/runtime — The client state kernel. + * @mizan/base — The client state kernel. * * Zero framework dependencies. React, Vue, Svelte — all import from here. * diff --git a/frontends/mizan-svelte/package.json b/frontends/mizan-svelte/package.json index 478b410..1f1e92f 100644 --- a/frontends/mizan-svelte/package.json +++ b/frontends/mizan-svelte/package.json @@ -1,11 +1,11 @@ { "name": "@mizan/svelte", "version": "0.1.0", - "description": "Mizan Svelte adapter — stores generated from @mizan/runtime.", + "description": "Mizan Svelte adapter — stores generated from @mizan/base.", "type": "module", "peerDependencies": { "svelte": ">=4", - "@mizan/runtime": ">=0.1.0" + "@mizan/base": ">=0.1.0" }, "license": "MIT" } diff --git a/frontends/mizan-vue/package.json b/frontends/mizan-vue/package.json index acfae61..8102e1e 100644 --- a/frontends/mizan-vue/package.json +++ b/frontends/mizan-vue/package.json @@ -1,11 +1,11 @@ { "name": "@mizan/vue", "version": "0.1.0", - "description": "Mizan Vue adapter — composables generated from @mizan/runtime.", + "description": "Mizan Vue adapter — composables generated from @mizan/base.", "type": "module", "peerDependencies": { "vue": ">=3", - "@mizan/runtime": ">=0.1.0" + "@mizan/base": ">=0.1.0" }, "license": "MIT" }