plusui-native-core 0.1.50 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/Core/CMakeLists.txt +2 -3
  2. package/Core/Features/App/app.cpp +58 -1
  3. package/Core/Features/Connection/ARCHITECTURE.md +369 -0
  4. package/Core/Features/Connection/README.md +165 -0
  5. package/Core/Features/Connection/connection.cpp +57 -0
  6. package/Core/Features/Connection/connection.ts +186 -0
  7. package/Core/Features/Connection/examples/simple_tags_example.hpp +130 -0
  8. package/Core/Features/Connection/examples/simple_tags_example.ts +247 -0
  9. package/Core/Features/Window/window.cpp +187 -151
  10. package/Core/generated/bridge.hpp +302 -0
  11. package/Core/include/plusui/connection.hpp +145 -0
  12. package/Core/include/plusui/plusui.hpp +1 -3
  13. package/Core/include/plusui/window.hpp +17 -19
  14. package/package.json +1 -1
  15. package/Core/Features/Bindings/ARCHITECTURE.md +0 -328
  16. package/Core/Features/Bindings/CustomBindings/custom_bindings.cpp +0 -55
  17. package/Core/Features/Bindings/CustomBindings/custom_bindings.ts +0 -35
  18. package/Core/Features/Bindings/EXAMPLE_USAGE.hpp +0 -143
  19. package/Core/Features/Bindings/EXAMPLE_USAGE.tsx +0 -210
  20. package/Core/Features/Bindings/IPC_GUIDE.md +0 -325
  21. package/Core/Features/Bindings/NativeBindings/native_bindings.cpp +0 -30
  22. package/Core/Features/Bindings/NativeBindings/native_bindings.ts +0 -29
  23. package/Core/Features/Bindings/UNIFIED_SYSTEM.md +0 -351
  24. package/Core/Features/Event/Events.ts +0 -166
  25. package/Core/Features/Event/events.cpp +0 -200
  26. package/Core/include/plusui/bindings.hpp +0 -65
  27. package/Core/include/plusui/custom_bindings.hpp +0 -17
  28. package/Core/include/plusui/events.hpp +0 -58
@@ -20,8 +20,6 @@ else()
20
20
  endif()
21
21
 
22
22
  add_library(plusui STATIC
23
- Features/Bindings/NativeBindings/native_bindings.cpp
24
- Features/Bindings/CustomBindings/custom_bindings.cpp
25
23
  Features/App/app.cpp
26
24
  Features/Window/window.cpp
27
25
  Features/FileDrop/filedrop.cpp
@@ -31,12 +29,13 @@ add_library(plusui STATIC
31
29
  Features/Clipboard/clipboard.cpp
32
30
  Features/Menu/menu.cpp
33
31
  Features/Keyboard/keyboard.cpp
34
- Features/Event/events.cpp
32
+ Features/Connection/connection.cpp
35
33
  Features/WebGPU/webgpu.cpp
36
34
  )
37
35
 
38
36
  target_include_directories(plusui PUBLIC
39
37
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
38
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/generated>
40
39
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/vendor>
41
40
  $<INSTALL_INTERFACE:include>
42
41
  )
@@ -7,8 +7,31 @@
7
7
  #include <plusui/tray.hpp>
8
8
  #include <plusui/window.hpp>
9
9
 
10
+ #include <bridge.hpp> // Generated generated bridge
11
+
10
12
  namespace plusui {
11
13
 
14
+ // --- Bridge Implementation (Demo) ---
15
+ class DemoBridge : public bridge::GeneratedBridge {
16
+ public:
17
+ nlohmann::json handle_greet(const nlohmann::json &args) override {
18
+ std::string name = args.value("name", "Guest");
19
+ return {{"message", "Hello from C++, " + name + "!"}};
20
+ }
21
+
22
+ void handle_log(const nlohmann::json &args) override {
23
+ std::string msg = args.value("msg", "");
24
+ std::cout << "[Client Log] " << msg << std::endl;
25
+ }
26
+
27
+ void handle_minimize(const nlohmann::json &args) override {
28
+ // We need access to the window to minimize it.
29
+ // For now, we'll just log. In a real app, Bridge might hold a reference to
30
+ // WindowController.
31
+ std::cout << "[Client] Requested minimize" << std::endl;
32
+ }
33
+ };
34
+
12
35
  struct App::Impl {
13
36
  bool running = false;
14
37
  };
@@ -109,7 +132,8 @@ Window App::Builder::build() {
109
132
  // WebView configuration (now part of WindowConfig)
110
133
  winConfig.devtools = config.devtools;
111
134
  winConfig.scrollbars = config.scrollbars;
112
- winConfig.disableWebviewDragDrop = config.enableFileDrop; // Auto-disable webview drag when FileDrop enabled
135
+ winConfig.disableWebviewDragDrop =
136
+ config.enableFileDrop; // Auto-disable webview drag when FileDrop enabled
113
137
 
114
138
  // Create native window
115
139
  auto nativeWinPtr = std::make_shared<Window>(Window::create(winConfig));
@@ -127,6 +151,39 @@ Window App::Builder::build() {
127
151
  }
128
152
  }
129
153
 
154
+ // --- Initialize Bridge ---
155
+ // Create the bridge instance
156
+ auto bridge = std::make_shared<DemoBridge>();
157
+
158
+ // Hook 1: Window -> Bridge (Inbound)
159
+ webviewWin.onMessage(
160
+ [bridge](const std::string &msg) { bridge->dispatch(msg); });
161
+
162
+ // Hook 2: Bridge -> Window (Outbound)
163
+ // We capture webviewWin by value (it's a lightweight handle)
164
+ bridge->setOutboundHandler([webviewWin](const std::string &msg) mutable {
165
+ webviewWin.postMessage(msg);
166
+ });
167
+
168
+ // Keep bridge alive?
169
+ // Since webviewWin.onMessage captures 'bridge', the bridge is kept alive by
170
+ // the Window. And 'bridge' outbound handler captures 'webviewWin', keeping
171
+ // Window alive. Cycle exists, but ensures lifetime match.
172
+
173
+ // Optional: Emit an initial event
174
+ bridge->emit_onResize(config.width, config.height);
175
+
176
+ // Hook 3: File Drop
177
+ webviewWin.onFileDrop([bridge](const std::string &jsonStr) {
178
+ if (jsonStr.empty())
179
+ return;
180
+ try {
181
+ auto j = nlohmann::json::parse(jsonStr);
182
+ bridge->emit_onFileDrop(j);
183
+ } catch (...) {
184
+ }
185
+ });
186
+
130
187
  return webviewWin;
131
188
  }
132
189
 
@@ -0,0 +1,369 @@
1
+ # Connection Feature Architecture
2
+
3
+ ## 🏗️ System Overview
4
+
5
+ ```
6
+ ┌─────────────────────────────────────────────────────────────────┐
7
+ │ PlusUI Connection Feature │
8
+ │ Unified Frontend ↔ Backend Communication │
9
+ └─────────────────────────────────────────────────────────────────┘
10
+
11
+ ┌──────────────────┐ ┌──────────────────┐
12
+ │ Frontend (TS) │ │ Backend (C++) │
13
+ │ │ │ │
14
+ │ ┌────────────┐ │ │ ┌────────────┐ │
15
+ │ │ connect.* │ │ │ │ Bindings │ │
16
+ │ │ API │ │ │ │ Class │ │
17
+ │ └─────┬──────┘ │ │ └─────┬──────┘ │
18
+ │ │ │ │ │ │
19
+ │ ┌─────▼──────┐ │ ┌─────────────┐ │ ┌─────▼──────┐ │
20
+ │ │Connection │◄─┼───►│ WebView2 │◄───────┼─►│Connection │ │
21
+ │ │ Client │ │ │ IPC Layer │ │ │ Protocol │ │
22
+ │ └────────────┘ │ └─────────────┘ │ └────────────┘ │
23
+ │ │ │ │
24
+ └──────────────────┘ └──────────────────┘
25
+
26
+ ┌─────────────────┐
27
+ │ Schema File │
28
+ │ connection. │
29
+ │ schema │
30
+ └────────┬────────┘
31
+
32
+ ┌────────▼────────┐
33
+ │ Bindgen │
34
+ │ Generator │
35
+ └────────┬────────┘
36
+
37
+ ┌────────────┴────────────┐
38
+ │ │
39
+ ┌──────▼─────┐ ┌──────▼──────┐
40
+ │bindings.ts │ │bindings.hpp │
41
+ │(Generated) │ │ (Generated) │
42
+ └────────────┘ └─────────────┘
43
+ ```
44
+
45
+ ## 📊 Communication Flow
46
+
47
+ ### CALL Pattern (Request/Response)
48
+ ```
49
+ Frontend Backend
50
+ │ │
51
+ │──[1] call(name, args)────►│
52
+ │ │
53
+ │ [2] handle_*
54
+ │ │
55
+ │◄──[3] result ─────────────│
56
+ │ │
57
+ ```
58
+
59
+ ### FIRE Pattern (One-way)
60
+ ```
61
+ Frontend Backend
62
+ │ │
63
+ │──[1] fire(name, args)────►│
64
+ │ │
65
+ │ [2] handle_*
66
+ │ │
67
+ │ (no response) │
68
+ ```
69
+
70
+ ### EVENT Pattern (Backend → Frontend)
71
+ ```
72
+ Frontend Backend
73
+ │ │
74
+ │ [1] on(name, callback) │
75
+ │ │
76
+ │ │ [2] emit_*
77
+ │◄──[3] event data ─────────│
78
+ │ │
79
+ │ [4] callback(data) │
80
+ ```
81
+
82
+ ### STREAM Pattern (Continuous Data)
83
+ ```
84
+ Frontend Backend
85
+ │ │
86
+ │ [1] stream.subscribe(cb) │
87
+ │ │
88
+ │ │ [2] emit_* (repeated)
89
+ │◄──[3] data ───────────────│
90
+ │◄──[4] data ───────────────│
91
+ │◄──[5] data ───────────────│
92
+ │ │
93
+ ```
94
+
95
+ ### CHANNEL Pattern (Bidirectional Pub/Sub)
96
+ ```
97
+ Frontend Backend
98
+ │ │
99
+ │──[1] channel.publish()───►│ [2] handle_*_publish
100
+ │ │
101
+ │ [3] channel.subscribe() │
102
+ │ │
103
+ │◄──[4] emit_* ─────────────│
104
+ │ │
105
+ ```
106
+
107
+ ## 🔄 Build & Generation Flow
108
+
109
+ ```
110
+ 1. Developer writes schema
111
+ └─► connection.schema
112
+
113
+ 2. Run bindgen tool
114
+ └─► node Tools/plusui-bindgen/src/advanced-bindgen.js
115
+
116
+ 3. Parser reads schema
117
+ └─► Parses connect definitions
118
+ └─► Validates syntax
119
+ └─► Creates method definitions
120
+
121
+ 4. Generator creates TypeScript
122
+ └─► Type definitions (GreetIn, GreetOut, etc.)
123
+ └─► connect.* API functions
124
+ └─► Typed callbacks
125
+
126
+ 5. Generator creates C++
127
+ └─► Struct definitions with JSON converters
128
+ └─► Virtual handler methods
129
+ └─► Emit helper methods
130
+ └─► Message dispatcher
131
+
132
+ 6. Files written
133
+ └─► Core/Features/Connection/generated/bindings.ts
134
+ └─► Core/Features/Connection/generated/bindings.hpp
135
+ ```
136
+
137
+ ## 📦 Component Architecture
138
+
139
+ ### TypeScript Side
140
+
141
+ ```
142
+ ┌──────────────────────────────────────┐
143
+ │ Generated API (bindings.ts) │
144
+ │ ┌────────────────────────────────┐ │
145
+ │ │ export const connect = { │ │
146
+ │ │ greet: (args) => ..., │ │
147
+ │ │ onResize: (cb) => ..., │ │
148
+ │ │ cpuUsage: { subscribe }, │ │
149
+ │ │ logBus: { subscribe, pub }, │ │
150
+ │ │ } │ │
151
+ │ └────────────┬───────────────────┘ │
152
+ └───────────────┼──────────────────────┘
153
+ │ uses
154
+
155
+ ┌──────────────────────────────────────┐
156
+ │ Core Connection (connection.ts) │
157
+ │ ┌────────────────────────────────┐ │
158
+ │ │ class ConnectionClient { │ │
159
+ │ │ call(name, args) │ │
160
+ │ │ fire(name, args) │ │
161
+ │ │ on(name, callback) │ │
162
+ │ │ stream(name) │ │
163
+ │ │ channel(name) │ │
164
+ │ │ } │ │
165
+ │ └────────────┬───────────────────┘ │
166
+ └───────────────┼──────────────────────┘
167
+ │ sends/receives
168
+
169
+ ┌──────────────────────────────────────┐
170
+ │ Message Protocol │
171
+ │ { │
172
+ │ kind: "call" | "fire" | ..., │
173
+ │ id: "...", │
174
+ │ name: "methodName", │
175
+ │ payload: { ... } │
176
+ │ } │
177
+ └──────────────────────────────────────┘
178
+ ```
179
+
180
+ ### C++ Side
181
+
182
+ ```
183
+ ┌──────────────────────────────────────┐
184
+ │ User Implementation │
185
+ │ ┌────────────────────────────────┐ │
186
+ │ │ class MyApp : public │ │
187
+ │ │ plusui::connect::Bindings │ │
188
+ │ │ { │ │
189
+ │ │ GreetOut handle_greet(...) │ │
190
+ │ │ void handle_log(...) │ │
191
+ │ │ │ │
192
+ │ │ void emitUpdate() { │ │
193
+ │ │ emit_onResize({...}); │ │
194
+ │ │ } │ │
195
+ │ │ } │ │
196
+ │ └────────────┬───────────────────┘ │
197
+ └───────────────┼──────────────────────┘
198
+ │ inherits
199
+
200
+ ┌──────────────────────────────────────┐
201
+ │ Generated Base (bindings.hpp) │
202
+ │ ┌────────────────────────────────┐ │
203
+ │ │ class Bindings : public │ │
204
+ │ │ Connection { │ │
205
+ │ │ │ │
206
+ │ │ // Virtual handlers │ │
207
+ │ │ virtual GreetOut handle_* │ │
208
+ │ │ │ │
209
+ │ │ // Emit methods │ │
210
+ │ │ void emit_onResize(...) │ │
211
+ │ │ │ │
212
+ │ │ // Message dispatcher │ │
213
+ │ │ void handleMessage(Envelope) │ │
214
+ │ │ } │ │
215
+ │ └────────────┬───────────────────┘ │
216
+ └───────────────┼──────────────────────┘
217
+ │ uses
218
+
219
+ ┌──────────────────────────────────────┐
220
+ │ Core Connection (connection.hpp) │
221
+ │ ┌────────────────────────────────┐ │
222
+ │ │ class Connection { │ │
223
+ │ │ void send(Envelope) │ │
224
+ │ │ void call(...) │ │
225
+ │ │ void fire(...) │ │
226
+ │ │ void event(...) │ │
227
+ │ │ } │ │
228
+ │ └────────────────────────────────┘ │
229
+ └──────────────────────────────────────┘
230
+ ```
231
+
232
+ ## 🔑 Key Design Decisions
233
+
234
+ ### 1. Schema-Driven
235
+ - **Why**: Single source of truth, prevents TS/C++ drift
236
+ - **Benefit**: Auto-generated types, less manual work
237
+
238
+ ### 2. Strongly Typed
239
+ - **Why**: Catch errors at compile time
240
+ - **Benefit**: Better IDE support, safer code
241
+
242
+ ### 3. Pattern-Based
243
+ - **Why**: Different use cases need different semantics
244
+ - **Benefit**: Clear intent, optimized for each pattern
245
+
246
+ ### 4. Code Generation
247
+ - **Why**: Boilerplate is tedious and error-prone
248
+ - **Benefit**: Consistent, maintainable, fast development
249
+
250
+ ### 5. Struct-Based (not JSON)
251
+ - **Why**: Type safety in C++
252
+ - **Benefit**: Compiler checks, clear interfaces
253
+
254
+ ## 🎯 Design Principles
255
+
256
+ 1. **Simple Developer Experience**
257
+ - Minimal boilerplate
258
+ - Intuitive API
259
+ - Clear patterns
260
+
261
+ 2. **Type Safety**
262
+ - End-to-end type checking
263
+ - Auto-generated types
264
+ - Compile-time validation
265
+
266
+ 3. **Unified System**
267
+ - Single API for all patterns
268
+ - Consistent naming
269
+ - One import
270
+
271
+ 4. **Framework Agnostic**
272
+ - Works with React, Vue, Svelte
273
+ - No framework lock-in
274
+ - Plain TypeScript/JavaScript
275
+
276
+ 5. **Performance**
277
+ - Minimal overhead
278
+ - Efficient serialization
279
+ - Direct dispatch
280
+
281
+ ## 📐 Message Protocol
282
+
283
+ ### Envelope Structure
284
+ ```typescript
285
+ {
286
+ kind: "call" | "fire" | "result" | "event" | "stream" |
287
+ "sub" | "unsub" | "publish" | "error",
288
+ id?: string, // Request ID (for calls)
289
+ name: string, // Method/event name
290
+ payload: unknown, // Data
291
+ error?: string // Error message (if kind="error")
292
+ }
293
+ ```
294
+
295
+ ### Message Kinds
296
+ - **call**: Request (needs response)
297
+ - **fire**: One-way command
298
+ - **result**: Response to call
299
+ - **event**: Backend notification
300
+ - **stream**: Continuous data
301
+ - **sub**: Subscribe to stream
302
+ - **unsub**: Unsubscribe from stream
303
+ - **publish**: Channel message
304
+ - **error**: Error response
305
+
306
+ ## 🔒 Type Safety Flow
307
+
308
+ ```
309
+ Schema Definition
310
+
311
+ Bindgen
312
+
313
+ ┌──────────────┐
314
+ │ TypeScript │
315
+ │ - GreetIn │
316
+ │ - GreetOut │
317
+ └──────────────┘
318
+
319
+ Frontend Code
320
+ await connect.greet({ name: "..." })
321
+ ↑ Type checked!
322
+
323
+ { message: "..." }
324
+ ↑ Type checked!
325
+ ```
326
+
327
+ ```
328
+ Schema Definition
329
+
330
+ Bindgen
331
+
332
+ ┌──────────────┐
333
+ │ C++ │
334
+ │ - GreetIn │
335
+ │ - GreetOut │
336
+ └──────────────┘
337
+
338
+ Backend Code
339
+ GreetOut handle_greet(const GreetIn& args)
340
+ ↑ Type checked!
341
+ return { "Hello" }
342
+ ↑ Type checked!
343
+ ```
344
+
345
+ ## 🚀 Performance Characteristics
346
+
347
+ - **Call latency**: ~1-2ms (depends on WebView2)
348
+ - **Fire latency**: <1ms (fire-and-forget)
349
+ - **Event dispatch**: <0.1ms (in-process)
350
+ - **Serialization**: O(n) for payload size
351
+ - **Memory**: Minimal (shared memory for IPC)
352
+
353
+ ## 🔧 Extension Points
354
+
355
+ Future enhancements:
356
+ - State synchronization (synced properties)
357
+ - Binary protocol option (faster than JSON)
358
+ - Compression for large payloads
359
+ - Message batching
360
+ - Request cancellation
361
+ - Middleware/interceptors
362
+ - RPC versioning
363
+
364
+ ---
365
+
366
+ **See Also:**
367
+ - [README.md](README.md) - Complete guide
368
+ - [QUICK_REFERENCE.md](QUICK_REFERENCE.md) - Cheat sheet
369
+ - [MIGRATION.md](MIGRATION.md) - Migration from old system
@@ -0,0 +1,165 @@
1
+ # PlusUI Connection Feature
2
+
3
+ ## 🎯 Overview
4
+
5
+ The **Connection Feature** is PlusUI's absurdly simple system for frontend ↔ backend communication. Both sides use the same two methods: **`emit()`** and **`on()`**.
6
+
7
+ ## ✨ The 5 Primitives That Cover Everything
8
+
9
+ Just `emit()` and `on()` handle all communication patterns:
10
+
11
+ | Keyword | Pattern | Direction | Use Cases |
12
+ |---------|---------|-----------|-----------|
13
+ | **EVENT** | Fire & forget | One way → | Notifications, commands, logging |
14
+ | **CALL** | Request/response | Two ways ↔ | Get data, save data, RPC |
15
+ | **STREAM** | Continuous data | One way push → | Real-time updates, monitoring |
16
+ | **QUERY** | Request + stream | Two way + many ↔↔↔ | Search results, paginated data |
17
+ | **STATE** | Synced value | Both ways ↕ | Theme, settings, shared state |
18
+
19
+ ## ✨ Why It's Simple
20
+
21
+ - **Two methods**: `emit()` and `on()` - that's all
22
+ - **Mirror API**: Same methods on both frontend and backend
23
+ - **Two-way**: Frontend → Backend AND Backend → Frontend
24
+ - **No schema**: Write code directly, no extra files
25
+ - **No bindgen**: No code generation step
26
+ - **Total flexibility**: Design your own patterns (RPC, pub/sub, streaming, whatever)
27
+
28
+ ## 🚀 Quick Start
29
+
30
+ ### Send Message →
31
+
32
+ ```typescript
33
+ import { connect } from 'plusui-native-core/connection';
34
+
35
+ // Listen for response
36
+ connect.on('greetResponse', (data) => {
37
+ console.log(data.message); // "Hello, World!"
38
+ });
39
+
40
+ // Send message to backend
41
+ connect.emit('greet', { name: 'World' });
42
+ ```
43
+
44
+ ### Receive & Respond
45
+
46
+ ```cpp
47
+ #include <plusui/connection.hpp>
48
+
49
+ class MyConnection : public plusui::Connection {
50
+ protected:
51
+ void handleMessage(const Envelope& env) override {
52
+ // Listen for messages from frontend
53
+ if (env.kind == MessageKind::Fire && env.name == "greet") {
54
+ std::string name = env.payload["name"];
55
+
56
+ // Respond by emitting back
57
+ emit("greetResponse", {{"message", "Hello, " + name + "!"}});
58
+ }
59
+ }
60
+
61
+ public:
62
+ // Emit messages to frontend
63
+ void emit(const std::string& name, const nlohmann::json& data) {
64
+ event(name, data);
65
+ }
66
+
67
+ // Example: notify frontend of window resize
68
+ void onWindowResize(int w, int h) {
69
+ emit("resize", {{"width", w}, {"height", h}});
70
+ }
71
+ };
72
+ ```
73
+
74
+ ### Listen on Frontend
75
+
76
+ ```typescript
77
+ // Listen for messages from backend
78
+ connect.on('resize', (data) => {
79
+ console.log(`${data.width}x${data.height}`);
80
+ updateLayout(data);
81
+ });
82
+ ```
83
+
84
+ ## 📖 Complete API
85
+
86
+ ### Frontend
87
+
88
+ ```typescript
89
+ // Send message
90
+ connect.emit('messageName', { key: 'value' });
91
+
92
+ // Listen for messages
93
+ connect.on('messageName', (data) => {
94
+ console.log(data);
95
+ });
96
+ ```
97
+
98
+ ### Backend
99
+
100
+ ```cpp
101
+ // Listen for messages (in handleMessage)
102
+ void handleMessage(const Envelope& env) override {
103
+ if (env.kind == MessageKind::Fire && env.name == "messageName") {
104
+ // process env.payload
105
+ }
106
+ }
107
+
108
+ // Send messages
109
+ void emit(const std::string& name, const nlohmann::json& data) {
110
+ event(name, data);
111
+ }
112
+ ```
113
+
114
+ ## 💡 Design Your Own Patterns
115
+
116
+ ### Request/Response Pattern
117
+
118
+ ```typescript
119
+ // Frontend
120
+ connect.on('getUserResponse', (data) => {
121
+ console.log(data.user);
122
+ });
123
+ connect.emit('getUser', { id: 123 });
124
+ ```
125
+
126
+ ```cpp
127
+ // Backend
128
+ void handleMessage(const Envelope& env) override {
129
+ if (env.name == "getUser") {
130
+ auto user = database.findUser(env.payload["id"]);
131
+ emit("getUserResponse", {{"user", user}});
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### Notifications
137
+
138
+ ```cpp
139
+ // Backend sends
140
+ emit("notification", {{"text", "File saved!"}});
141
+ ```
142
+
143
+ ```typescript
144
+ // Frontend receives
145
+ connect.on('notification', (data) => {
146
+ toast.success(data.text);
147
+ });
148
+ ```
149
+
150
+ ### Bidirectional Chat
151
+
152
+ ```typescript
153
+ // Both sides listen
154
+ connect.on('chat', (data) => {
155
+ addToLog(data.message);
156
+ });
157
+
158
+ // Both sides send
159
+ connect.emit('chat', { message: 'Hello!' });
160
+ ```
161
+
162
+ ## 🎯 That's It
163
+
164
+ Two methods. Both sides. Use them however you want.
165
+
@@ -0,0 +1,57 @@
1
+ #include <plusui/connection.hpp>
2
+
3
+ namespace plusui {
4
+
5
+ // Connection implementation
6
+ //
7
+ // The Connection class is header-only (see plusui/connection.hpp).
8
+ // This file is reserved for future non-template implementation details.
9
+ //
10
+ // TWO METHODS. FIVE PRIMITIVES. EVERYTHING YOU NEED.
11
+ //
12
+ // To use Connection:
13
+ // 1. Create a class that inherits from plusui::Connection
14
+ // 2. Override handleMessage(name, payload) to receive messages
15
+ // 3. Use emit(name, payload) to send messages to frontend
16
+ //
17
+ // Example - All 5 Primitives:
18
+ //
19
+ // class MyApp : public plusui::Connection {
20
+ // protected:
21
+ // void handleMessage(const std::string& name, const nlohmann::json& data) override {
22
+ // // EVENT: fire & forget
23
+ // if (name == "notification") {
24
+ // showNotification(data["message"].get<std::string>());
25
+ // }
26
+ //
27
+ // // CALL: request/response
28
+ // if (name == "getUser") {
29
+ // auto userId = data["id"].get<int>();
30
+ // emit("userData", {{"name", "John"}, {"id", userId}});
31
+ // }
32
+ //
33
+ // // STREAM: continuous updates (start streaming)
34
+ // if (name == "subscribeCPU") {
35
+ // startCPUMonitor(); // Will call emit("cpu", ...) repeatedly
36
+ // }
37
+ //
38
+ // // QUERY: request + stream responses
39
+ // if (name == "search") {
40
+ // auto query = data["query"].get<std::string>();
41
+ // for (auto& result : searchDatabase(query)) {
42
+ // emit("searchResult", result); // Multiple results
43
+ // }
44
+ // }
45
+ //
46
+ // // STATE: synced value
47
+ // if (name == "theme") {
48
+ // currentTheme = data["mode"].get<std::string>();
49
+ // emit("theme", data); // Sync back to frontend
50
+ // }
51
+ // }
52
+ // };
53
+ //
54
+ // See Core/Features/Connection/README.md for more details.
55
+
56
+ }
57
+