plusui-native-core 0.1.54 β†’ 0.1.56

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.
@@ -29,7 +29,7 @@ add_library(plusui STATIC
29
29
  Features/Clipboard/clipboard.cpp
30
30
  Features/Menu/menu.cpp
31
31
  Features/Keyboard/keyboard.cpp
32
- Features/Connection/connection.cpp
32
+ Features/Connection/connect.cpp
33
33
  Features/WebGPU/webgpu.cpp
34
34
  )
35
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plusui-native-core",
3
- "version": "0.1.54",
3
+ "version": "0.1.56",
4
4
  "description": "PlusUI Core framework (frontend + backend implementations)",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,369 +0,0 @@
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 Connect (connect.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
@@ -1,130 +0,0 @@
1
- /**
2
- * Example: Simple Tag-Based Connection (C++ Backend)
3
- *
4
- * No schema file needed! Just tag your methods and bindgen does the rest.
5
- */
6
-
7
- #pragma once
8
- #include <plusui/connect.hpp>
9
- #include <string>
10
-
11
- namespace example {
12
-
13
- class SimpleApp : public plusui::Connect {
14
- public:
15
-
16
- // ============================================
17
- // CONNECT_CALL: Request/Response
18
- // Frontend can await the result
19
- // ============================================
20
-
21
- // Simple call with one parameter
22
- CONNECT_CALL(greet, std::string, std::string name)
23
- std::string greet(const std::string& name) {
24
- return "Hello, " + name + "!";
25
- }
26
-
27
- // Call with multiple parameters β†’ returns object
28
- CONNECT_CALL(calculate, double, double a, double b)
29
- double calculate(double a, double b) {
30
- return a + b;
31
- }
32
-
33
- // Call with complex return (auto-generates struct)
34
- CONNECT_CALL(getUser, {int id, std::string name, std::string email}, int userId)
35
- auto getUser(int userId) {
36
- struct Result { int id; std::string name; std::string email; };
37
- return Result{ userId, "John Doe", "john@example.com" };
38
- }
39
-
40
- // ============================================
41
- // CONNECT_FIRE: One-way to Backend
42
- // No response expected
43
- // ============================================
44
-
45
- CONNECT_FIRE(minimize, void)
46
- void minimize() {
47
- // Minimize window
48
- std::cout << "Minimizing..." << std::endl;
49
- }
50
-
51
- CONNECT_FIRE(log, void, std::string level, std::string message)
52
- void log(const std::string& level, const std::string& message) {
53
- std::cout << "[" << level << "] " << message << std::endl;
54
- }
55
-
56
- // ============================================
57
- // CONNECT_EVENT: Backend β†’ Frontend
58
- // Backend emits, frontend listens
59
- // ============================================
60
-
61
- CONNECT_EVENT(onResize, int width, int height)
62
- void emitResize(int width, int height) {
63
- // Auto-generated emit method
64
- emit_onResize(width, height);
65
- }
66
-
67
- CONNECT_EVENT(onFileDrop, std::vector<std::string> files)
68
- void emitFileDrop(const std::vector<std::string>& files) {
69
- emit_onFileDrop(files);
70
- }
71
-
72
- // ============================================
73
- // CONNECT_STREAM: Continuous Data
74
- // Backend streams, frontend subscribes
75
- // ============================================
76
-
77
- CONNECT_STREAM(cpuUsage, double percent)
78
- void startMonitoring() {
79
- // Stream CPU usage continuously
80
- std::thread([this]() {
81
- while (running) {
82
- double cpu = getCpuUsage();
83
- emit_cpuUsage(cpu);
84
- std::this_thread::sleep_for(std::chrono::seconds(1));
85
- }
86
- }).detach();
87
- }
88
-
89
- // ============================================
90
- // CONNECT_CHANNEL: Bidirectional
91
- // Both sides can send and receive
92
- // ============================================
93
-
94
- CONNECT_CHANNEL(logBus, std::string level, std::string line)
95
-
96
- // Receive from frontend
97
- void onLogFromFrontend(const std::string& level, const std::string& line) {
98
- std::cout << "[Frontend] " << level << ": " << line << std::endl;
99
- }
100
-
101
- // Send to frontend
102
- void sendLogToFrontend(const std::string& level, const std::string& line) {
103
- emit_logBus(level, line);
104
- }
105
-
106
- private:
107
- bool running = true;
108
-
109
- double getCpuUsage() {
110
- return 50.0 + (rand() % 30);
111
- }
112
- };
113
-
114
- } // namespace example
115
-
116
- /**
117
- * This example shows how simple it is:
118
- *
119
- * 1. Tag your methods with CONNECT_* macros
120
- * 2. Run: npm run bindgen
121
- * 3. Use in TypeScript:
122
- *
123
- * const result = await connect.greet({ name: 'World' });
124
- * connect.minimize();
125
- * connect.onResize((w, h) => updateUI(w, h));
126
- * connect.cpuUsage.subscribe((cpu) => showCpu(cpu));
127
- * connect.logBus.publish({ level: 'info', line: 'msg' });
128
- *
129
- * That's it! No separate schema file, no manual typing.
130
- */
@@ -1,247 +0,0 @@
1
- /**
2
- * Example: Simple Tag-Based Connection (TypeScript Frontend)
3
- *
4
- * After running bindgen, use the auto-generated connect API
5
- */
6
-
7
- import { connect } from '../generated/bindings';
8
-
9
- /**
10
- * All these methods are auto-generated from C++ CONNECT_* tags!
11
- */
12
-
13
- // ============================================
14
- // CALL - Request/Response
15
- // ============================================
16
-
17
- async function callExamples() {
18
- // Simple call
19
- const greeting = await connect.greet({ name: 'PlusUI' });
20
- console.log(greeting); // "Hello, PlusUI!"
21
-
22
- // Call with multiple params
23
- const sum = await connect.calculate({ a: 10, b: 20 });
24
- console.log(sum); // 30
25
-
26
- // Complex return type
27
- const user = await connect.getUser({ userId: 123 });
28
- console.log(user.name, user.email);
29
- }
30
-
31
- // ============================================
32
- // FIRE - One-way to Backend
33
- // ============================================
34
-
35
- function fireExamples() {
36
- // Fire with no params
37
- connect.minimize();
38
-
39
- // Fire with params
40
- connect.log({
41
- level: 'info',
42
- message: 'User clicked button'
43
- });
44
-
45
- // Fire and forget - doesn't wait
46
- connect.log({ level: 'debug', message: 'Debug info' });
47
- doSomethingElse(); // Runs immediately
48
- }
49
-
50
- // ============================================
51
- // EVENT - Listen to Backend
52
- // ============================================
53
-
54
- function eventExamples() {
55
- // Listen for resize events
56
- const unsubResize = connect.onResize((data) => {
57
- console.log(`Window: ${data.width}x${data.height}`);
58
- updateLayout(data.width, data.height);
59
- });
60
-
61
- // Listen for file drops
62
- connect.onFileDrop((data) => {
63
- console.log('Files dropped:', data.files);
64
- data.files.forEach(file => processFile(file));
65
- });
66
-
67
- // Clean up when done
68
- // unsubResize();
69
- }
70
-
71
- // ============================================
72
- // STREAM - Subscribe to Continuous Data
73
- // ============================================
74
-
75
- function streamExamples() {
76
- // Subscribe to CPU usage stream
77
- const unsub = connect.cpuUsage.subscribe((data) => {
78
- updateCpuChart(data.percent);
79
-
80
- if (data.percent > 90) {
81
- showWarning('High CPU!');
82
- }
83
- });
84
-
85
- // Unsubscribe when component unmounts
86
- return unsub;
87
- }
88
-
89
- // ============================================
90
- // CHANNEL - Bidirectional Communication
91
- // ============================================
92
-
93
- function channelExamples() {
94
- // Subscribe to receive from backend
95
- connect.logBus.subscribe((msg) => {
96
- const color = msg.level === 'error' ? 'red' : 'gray';
97
- console.log(`%c[${msg.level}] ${msg.line}`, `color: ${color}`);
98
- addToLogView(msg);
99
- });
100
-
101
- // Publish to backend
102
- connect.logBus.publish({
103
- level: 'info',
104
- line: 'Frontend initialized'
105
- });
106
-
107
- // Both sides can communicate freely
108
- document.onclick = () => {
109
- connect.logBus.publish({
110
- level: 'debug',
111
- line: 'User clicked somewhere'
112
- });
113
- };
114
- }
115
-
116
- // ============================================
117
- // React Component Example
118
- // ============================================
119
-
120
- function ReactExample() {
121
- const [greeting, setGreeting] = React.useState('');
122
- const [cpu, setCpu] = React.useState(0);
123
-
124
- React.useEffect(() => {
125
- // Call on mount
126
- connect.greet({ name: 'React' })
127
- .then(result => setGreeting(result));
128
-
129
- // Subscribe to events
130
- const unsubResize = connect.onResize((data) => {
131
- console.log('Resize:', data);
132
- });
133
-
134
- // Subscribe to stream
135
- const unsubCpu = connect.cpuUsage.subscribe((data) => {
136
- setCpu(data.percent);
137
- });
138
-
139
- // Subscribe to channel
140
- const unsubLog = connect.logBus.subscribe((msg) => {
141
- console.log(msg);
142
- });
143
-
144
- // Cleanup all subscriptions
145
- return () => {
146
- unsubResize();
147
- unsubCpu();
148
- unsubLog();
149
- };
150
- }, []);
151
-
152
- const handleMinimize = () => {
153
- connect.minimize();
154
- };
155
-
156
- const handleLog = () => {
157
- connect.log({
158
- level: 'info',
159
- message: 'Button clicked!'
160
- });
161
- };
162
-
163
- return (
164
- <div>
165
- <h1>{greeting}</h1>
166
- <div>CPU: {cpu.toFixed(1)}%</div>
167
- <button onClick={handleMinimize}>Minimize</button>
168
- <button onClick={handleLog}>Log Message</button>
169
- </div>
170
- );
171
- }
172
-
173
- // ============================================
174
- // Vue Composition API Example
175
- // ============================================
176
-
177
- function vueExample() {
178
- const greeting = ref('');
179
- const cpu = ref(0);
180
-
181
- onMounted(async () => {
182
- // Call backend
183
- const result = await connect.greet({ name: 'Vue' });
184
- greeting.value = result;
185
-
186
- // Subscribe to stream
187
- const unsub = connect.cpuUsage.subscribe((data) => {
188
- cpu.value = data.percent;
189
- });
190
-
191
- onUnmounted(() => {
192
- unsub();
193
- });
194
- });
195
-
196
- return {
197
- greeting,
198
- cpu,
199
- minimize: () => connect.minimize(),
200
- log: (msg: string) => connect.log({ level: 'info', message: msg }),
201
- };
202
- }
203
-
204
- // ============================================
205
- // Helper Functions
206
- // ============================================
207
-
208
- function updateLayout(width: number, height: number) {
209
- // Update UI layout
210
- }
211
-
212
- function processFile(file: string) {
213
- // Process dropped file
214
- }
215
-
216
- function updateCpuChart(percent: number) {
217
- // Update chart
218
- }
219
-
220
- function showWarning(msg: string) {
221
- // Show warning toast
222
- }
223
-
224
- function addToLogView(msg: any) {
225
- // Add to log view
226
- }
227
-
228
- function doSomethingElse() {
229
- // Continue execution
230
- }
231
-
232
- /**
233
- * THAT'S IT!
234
- *
235
- * No schema file needed.
236
- * No manual type definitions.
237
- * Just tag your C++ methods and use them in TypeScript.
238
- *
239
- * Bindgen automatically:
240
- * - Finds all CONNECT_* tags
241
- * - Generates TypeScript types
242
- * - Creates the connect.* API
243
- * - Handles all serialization
244
- * - Manages subscriptions
245
- *
246
- * Perfect developer experience! πŸš€
247
- */
@@ -1,302 +0,0 @@
1
- /**
2
- * Auto-generated by plusui-bindgen
3
- * DO NOT EDIT - Changes will be overwritten
4
- * Generated from: connect.schema
5
- */
6
- #pragma once
7
- #include <plusui/connect.hpp>
8
- #include <string>
9
- #include <vector>
10
-
11
- namespace plusui {
12
- namespace connect {
13
-
14
- // ============================================
15
- // Type Definitions
16
- // ============================================
17
-
18
- struct GreetIn {
19
- std::string name;
20
-
21
- static GreetIn from_json(const nlohmann::json& j) {
22
- GreetIn result;
23
- if (j.contains("name")) { result.name = j["name"]; }
24
- return result;
25
- }
26
-
27
- nlohmann::json to_json() const {
28
- nlohmann::json j;
29
- j["name"] = name;
30
- return j;
31
- }
32
- };
33
-
34
- struct GreetOut {
35
- std::string message;
36
-
37
- static GreetOut from_json(const nlohmann::json& j) {
38
- GreetOut result;
39
- if (j.contains("message")) { result.message = j["message"]; }
40
- return result;
41
- }
42
-
43
- nlohmann::json to_json() const {
44
- nlohmann::json j;
45
- j["message"] = message;
46
- return j;
47
- }
48
- };
49
-
50
- struct LogIn {
51
- std::string msg;
52
-
53
- static LogIn from_json(const nlohmann::json& j) {
54
- LogIn result;
55
- if (j.contains("msg")) { result.msg = j["msg"]; }
56
- return result;
57
- }
58
-
59
- nlohmann::json to_json() const {
60
- nlohmann::json j;
61
- j["msg"] = msg;
62
- return j;
63
- }
64
- };
65
-
66
- struct OnResizeIn {
67
- double width;
68
- double height;
69
-
70
- static OnResizeIn from_json(const nlohmann::json& j) {
71
- OnResizeIn result;
72
- if (j.contains("width")) { result.width = j["width"]; }
73
- if (j.contains("height")) { result.height = j["height"]; }
74
- return result;
75
- }
76
-
77
- nlohmann::json to_json() const {
78
- nlohmann::json j;
79
- j["width"] = width;
80
- j["height"] = height;
81
- return j;
82
- }
83
- };
84
-
85
- struct OnResizeData {
86
- double width;
87
- double height;
88
-
89
- static OnResizeData from_json(const nlohmann::json& j) {
90
- OnResizeData result;
91
- if (j.contains("width")) { result.width = j["width"]; }
92
- if (j.contains("height")) { result.height = j["height"]; }
93
- return result;
94
- }
95
-
96
- nlohmann::json to_json() const {
97
- nlohmann::json j;
98
- j["width"] = width;
99
- j["height"] = height;
100
- return j;
101
- }
102
- };
103
-
104
- struct OnFileDropIn {
105
- nlohmann::json files;
106
-
107
- static OnFileDropIn from_json(const nlohmann::json& j) {
108
- OnFileDropIn result;
109
- if (j.contains("files")) { result.files = j["files"]; }
110
- return result;
111
- }
112
-
113
- nlohmann::json to_json() const {
114
- nlohmann::json j;
115
- j["files"] = files;
116
- return j;
117
- }
118
- };
119
-
120
- struct OnFileDropData {
121
- nlohmann::json files;
122
-
123
- static OnFileDropData from_json(const nlohmann::json& j) {
124
- OnFileDropData result;
125
- if (j.contains("files")) { result.files = j["files"]; }
126
- return result;
127
- }
128
-
129
- nlohmann::json to_json() const {
130
- nlohmann::json j;
131
- j["files"] = files;
132
- return j;
133
- }
134
- };
135
-
136
- struct CpuUsageIn {
137
- double percent;
138
-
139
- static CpuUsageIn from_json(const nlohmann::json& j) {
140
- CpuUsageIn result;
141
- if (j.contains("percent")) { result.percent = j["percent"]; }
142
- return result;
143
- }
144
-
145
- nlohmann::json to_json() const {
146
- nlohmann::json j;
147
- j["percent"] = percent;
148
- return j;
149
- }
150
- };
151
-
152
- struct CpuUsageData {
153
- double percent;
154
-
155
- static CpuUsageData from_json(const nlohmann::json& j) {
156
- CpuUsageData result;
157
- if (j.contains("percent")) { result.percent = j["percent"]; }
158
- return result;
159
- }
160
-
161
- nlohmann::json to_json() const {
162
- nlohmann::json j;
163
- j["percent"] = percent;
164
- return j;
165
- }
166
- };
167
-
168
- struct LogBusIn {
169
- std::string level;
170
- std::string line;
171
-
172
- static LogBusIn from_json(const nlohmann::json& j) {
173
- LogBusIn result;
174
- if (j.contains("level")) { result.level = j["level"]; }
175
- if (j.contains("line")) { result.line = j["line"]; }
176
- return result;
177
- }
178
-
179
- nlohmann::json to_json() const {
180
- nlohmann::json j;
181
- j["level"] = level;
182
- j["line"] = line;
183
- return j;
184
- }
185
- };
186
-
187
- struct LogBusData {
188
- std::string level;
189
- std::string line;
190
-
191
- static LogBusData from_json(const nlohmann::json& j) {
192
- LogBusData result;
193
- if (j.contains("level")) { result.level = j["level"]; }
194
- if (j.contains("line")) { result.line = j["line"]; }
195
- return result;
196
- }
197
-
198
- nlohmann::json to_json() const {
199
- nlohmann::json j;
200
- j["level"] = level;
201
- j["line"] = line;
202
- return j;
203
- }
204
- };
205
-
206
- // ============================================
207
- // Generated Bindings Base Class
208
- // ============================================
209
-
210
- /**
211
- * Auto-generated connection bindings
212
- * Inherit from this class and implement the handler methods
213
- */
214
- class Bindings : public Connection {
215
- public:
216
-
217
- // ========================================
218
- // Handler Methods (implement these)
219
- // ========================================
220
-
221
- /** [CALL] greet - Request/response handler */
222
- virtual GreetOut handle_greet(const GreetIn& args) = 0;
223
-
224
- /** [FIRE] log - One-way handler */
225
- virtual void handle_log(const LogIn& args) = 0;
226
-
227
- /** [FIRE] minimize - One-way handler */
228
- virtual void handle_minimize() = 0;
229
-
230
- /** [CHANNEL] logBus - Publish handler */
231
- virtual void handle_logBus_publish(const LogBusData& data) = 0;
232
-
233
- // ========================================
234
- // Emit Methods (call these to send to frontend)
235
- // ========================================
236
-
237
- /** [EVENT] onResize - Emit to frontend */
238
- void emit_onResize(const OnResizeData& data) {
239
- auto payload = data.to_json();
240
- event("onResize", payload);
241
- }
242
-
243
- /** [EVENT] onFileDrop - Emit to frontend */
244
- void emit_onFileDrop(const OnFileDropData& data) {
245
- auto payload = data.to_json();
246
- event("onFileDrop", payload);
247
- }
248
-
249
- /** [STREAM] cpuUsage - Emit to frontend */
250
- void emit_cpuUsage(const CpuUsageData& data) {
251
- auto payload = data.to_json();
252
- stream("cpuUsage", payload);
253
- }
254
-
255
- /** [CHANNEL] logBus - Emit to frontend */
256
- void emit_logBus(const LogBusData& data) {
257
- auto payload = data.to_json();
258
- publish("logBus", payload);
259
- }
260
-
261
- protected:
262
- // ========================================
263
- // Message Dispatcher (auto-generated)
264
- // ========================================
265
-
266
- void handleMessage(const std::string &name, const nlohmann::json &payload) override {
267
- try {
268
- // TODO: Update bindgen to generate simplified handlers
269
- // For now, all messages are treated as events
270
-
271
- if (name == "greet") {
272
- auto args = GreetIn::from_json(payload);
273
- auto res = handle_greet(args);
274
- emit("greetResult", res.to_json());
275
- return;
276
- }
277
-
278
- if (name == "log") {
279
- auto args = LogIn::from_json(payload);
280
- handle_log(args);
281
- return;
282
- }
283
-
284
- if (name == "minimize") {
285
- handle_minimize();
286
- return;
287
- }
288
-
289
- if (name == "logBus") {
290
- auto data = LogBusData::from_json(payload);
291
- handle_logBus_publish(data);
292
- return;
293
- }
294
- } catch (const std::exception& e) {
295
- // Error handling simplified - just log or ignore
296
- // sendError(env.id, env.name, std::string("Handler error: ") + e.what());
297
- }
298
- }
299
- };
300
-
301
- } // namespace connect
302
- } // namespace plusui