1. Problem Description
The current API for defining client-side logic (@app.client, @app.startup) and server-side interactions (@app.server, @app.connect) is functional but lacks a cohesive structural philosophy.
- It is not immediately obvious which functions are RPC endpoints versus fire-and-forget signals.
- There is no unified way to handle custom events (e.g., "game_started", "user_joined") other than raw WebSocket hooks.
- Client-side DOM event handlers lack validation, leading to potential runtime errors if a user attaches a non-async or non-client function to an element.
2. Proposed Design
We will consolidate all interaction logic under two main namespaces: @app.server and @app.client. This creates a clear mental model: "Where does this code run?" and "How is it triggered?"
2.1 Server-Side API (@app.server)
Methods decorated here execute on the Python Backend (FastAPI).
2.2 Client-Side API (@app.client)
Methods decorated here are transpiled/sent to the browser (Pyodide).
2.3 Runtime & Internals
window.violetear: The JavaScript global object acting as the Single Source of Truth for the client.
violetear.runtime:
get_runtime(): Returns a proxy to window.violetear (available only in Browser).
runtime.emit(event, data): Allows Python client code to trigger the JS event bus.
3. Implementation Roadmap
Phase 1: Core Refactoring (violetear/app.py)
Phase 2: Event Bus & Runtime (violetear/client.py)
Phase 3: Communication Layer (SocketManager)
4. Considerations & Constraints
- Serialization: Events and Realtime calls are limited to JSON-serializable data.
- Ambiguity: Ensure strict warnings if a user tries to
await a realtime function (client-side stubs should return None).
- Execution Order: Ensure handlers for
"ready" and "connect" fire reliably regardless of network race conditions (client loads faster/slower than socket connects).
1. Problem Description
The current API for defining client-side logic (
@app.client,@app.startup) and server-side interactions (@app.server,@app.connect) is functional but lacks a cohesive structural philosophy.2. Proposed Design
We will consolidate all interaction logic under two main namespaces:
@app.serverand@app.client. This creates a clear mental model: "Where does this code run?" and "How is it triggered?"2.1 Server-Side API (
@app.server)Methods decorated here execute on the Python Backend (FastAPI).
@app.server.rpcawaits this and receives a return value.@app.server.realtime@app.server.on(event: str)"start","stop","connect","disconnect".app.emit(event, data).2.2 Client-Side API (
@app.client)Methods decorated here are transpiled/sent to the browser (Pyodide).
@app.client(Base)@app.client.callbackdiv.on("click", func)) must check for this decorator. If missing, raiseValueErrorto prevent runtime hydration errors.@app.client.realtime@app.client.on(event: str)"ready"(hydration done),"connect","disconnect".2.3 Runtime & Internals
window.violetear: The JavaScript global object acting as the Single Source of Truth for the client.violetear.runtime:get_runtime(): Returns a proxy towindow.violetear(available only in Browser).runtime.emit(event, data): Allows Python client code to trigger the JS event bus.3. Implementation Roadmap
Phase 1: Core Refactoring (
violetear/app.py)ServerandClientnested classes withinAppto handle the new decorator syntax.@app.startup,@app.connect) in favor of lifecycle events (@app.client.on("ready"),@app.server.on("connect")).Phase 2: Event Bus & Runtime (
violetear/client.py)window.violetearin the JS bundle to manage event listeners.violetear.runtimemodule for Python access to the event bus.emitcalls made before the socket connects are buffered and flushed upon connection.Phase 3: Communication Layer (
SocketManager)SocketManagerto distinguish betweenrpc(fetch) andrealtime(websocket) messages.@app.client.realtime.4. Considerations & Constraints
awaitarealtimefunction (client-side stubs should returnNone)."ready"and"connect"fire reliably regardless of network race conditions (client loads faster/slower than socket connects).