|
| 1 | +--- |
| 2 | +number: 5 |
| 3 | +title: "Unified Server/Client Interaction API Refactoring" |
| 4 | +state: open |
| 5 | +labels: |
| 6 | +--- |
| 7 | + |
| 8 | +## 1. Problem Description |
| 9 | +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. |
| 10 | +* It is not immediately obvious which functions are RPC endpoints versus fire-and-forget signals. |
| 11 | +* There is no unified way to handle custom events (e.g., "game_started", "user_joined") other than raw WebSocket hooks. |
| 12 | +* 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. |
| 13 | + |
| 14 | +## 2. Proposed Design |
| 15 | +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?" |
| 16 | + |
| 17 | +### 2.1 Server-Side API (`@app.server`) |
| 18 | +Methods decorated here execute on the Python Backend (FastAPI). |
| 19 | + |
| 20 | +* **`@app.server.rpc`** |
| 21 | + * **Behavior:** Exposed to the client via HTTP/Fetch. |
| 22 | + * **Contract:** Request/Response. The client `await`s this and receives a return value. |
| 23 | + * **Use Case:** Database queries, heavy computation, sensitive logic. |
| 24 | + |
| 25 | +* **`@app.server.realtime`** |
| 26 | + * **Behavior:** Exposed to the client via WebSocket. |
| 27 | + * **Contract:** Fire-and-forget. The client calls this but **does not** wait for a result. |
| 28 | + * **Safety:** If the decorated function returns a value, the server logs a warning (data loss). |
| 29 | + * **Use Case:** High-frequency telemetry, keystrokes, broadcasting state updates. |
| 30 | + |
| 31 | +* **`@app.server.on(event: str)`** |
| 32 | + * **Behavior:** Registers a handler for lifecycle or custom events. |
| 33 | + * **Lifecycle Events:** `"start"`, `"stop"`, `"connect"`, `"disconnect"`. |
| 34 | + * **Custom Events:** Triggered via `app.emit(event, data)`. |
| 35 | + |
| 36 | +### 2.2 Client-Side API (`@app.client`) |
| 37 | +Methods decorated here are transpiled/sent to the browser (Pyodide). |
| 38 | + |
| 39 | +* **`@app.client`** (Base) |
| 40 | + * **Behavior:** Marks function for transpilation. Callable by other client-side code. |
| 41 | + |
| 42 | +* **`@app.client.callback`** |
| 43 | + * **Behavior:** Specific marker for DOM Event Listeners. |
| 44 | + * **Validation:** The DOM binder (e.g., `div.on("click", func)`) must check for this decorator. If missing, raise `ValueError` to prevent runtime hydration errors. |
| 45 | + |
| 46 | +* **`@app.client.realtime`** |
| 47 | + * **Behavior:** Registers the function as a target for Server-to-Client WebSocket calls (Reverse RPC). |
| 48 | + * **Contract:** Fire-and-forget. The server calls this to push updates to the browser. |
| 49 | + * **Use Case:** Updating UI based on server state changes, notifications. |
| 50 | + |
| 51 | +* **`@app.client.on(event: str)`** |
| 52 | + * **Behavior:** Registers a handler for client-side events. |
| 53 | + * **Lifecycle Events:** `"ready"` (hydration done), `"connect"`, `"disconnect"`. |
| 54 | + |
| 55 | +### 2.3 Runtime & Internals |
| 56 | +* **`window.violetear`**: The JavaScript global object acting as the Single Source of Truth for the client. |
| 57 | +* **`violetear.runtime`**: |
| 58 | + * **`get_runtime()`**: Returns a proxy to `window.violetear` (available only in Browser). |
| 59 | + * **`runtime.emit(event, data)`**: Allows Python client code to trigger the JS event bus. |
| 60 | + |
| 61 | +## 3. Implementation Roadmap |
| 62 | + |
| 63 | +### Phase 1: Core Refactoring (`violetear/app.py`) |
| 64 | +- [ ] Create `Server` and `Client` nested classes within `App` to handle the new decorator syntax. |
| 65 | +- [ ] Deprecate old decorators (`@app.startup`, `@app.connect`) in favor of lifecycle events (`@app.client.on("ready")`, `@app.server.on("connect")`). |
| 66 | + |
| 67 | +### Phase 2: Event Bus & Runtime (`violetear/client.py`) |
| 68 | +- [ ] Implement `window.violetear` in the JS bundle to manage event listeners. |
| 69 | +- [ ] Implement `violetear.runtime` module for Python access to the event bus. |
| 70 | +- [ ] Implement Message Queue: Ensure `emit` calls made before the socket connects are buffered and flushed upon connection. |
| 71 | + |
| 72 | +### Phase 3: Communication Layer (`SocketManager`) |
| 73 | +- [ ] Update `SocketManager` to distinguish between `rpc` (fetch) and `realtime` (websocket) messages. |
| 74 | +- [ ] Implement the "Reverse RPC" mechanism for `@app.client.realtime`. |
| 75 | + |
| 76 | +## 4. Considerations & Constraints |
| 77 | +* **Serialization:** Events and Realtime calls are limited to JSON-serializable data. |
| 78 | +* **Ambiguity:** Ensure strict warnings if a user tries to `await` a `realtime` function (client-side stubs should return `None`). |
| 79 | +* **Execution Order:** Ensure handlers for `"ready"` and `"connect"` fire reliably regardless of network race conditions (client loads faster/slower than socket connects). |
0 commit comments