@hypen-space/core 0.2.1 → 0.2.3
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.
- package/README.md +199 -154
- package/dist/src/app.js +2 -1
- package/dist/src/app.js.map +3 -3
- package/dist/src/engine.browser.js +2 -2
- package/dist/src/engine.browser.js.map +2 -2
- package/dist/src/engine.js +4 -3
- package/dist/src/engine.js.map +3 -3
- package/dist/src/index.js +18 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin.js +126 -0
- package/dist/src/plugin.js.map +10 -0
- package/dist/src/resolver.js +102 -0
- package/dist/src/resolver.js.map +10 -0
- package/dist/src/router.js +37 -18
- package/dist/src/router.js.map +3 -3
- package/dist/src/state.js +9 -1
- package/dist/src/state.js.map +3 -3
- package/package.json +15 -2
- package/src/app.ts +1 -0
- package/src/engine.browser.ts +1 -1
- package/src/engine.ts +4 -2
- package/src/index.ts +21 -1
- package/src/plugin.ts +219 -0
- package/src/resolver.ts +216 -0
- package/src/router.ts +43 -21
- package/src/state.ts +20 -0
- package/wasm-browser/README.md +425 -0
- package/wasm-browser/hypen_engine.d.ts +151 -0
- package/wasm-browser/hypen_engine.js +811 -0
- package/wasm-browser/hypen_engine_bg.js +736 -0
- package/wasm-browser/hypen_engine_bg.wasm +0 -0
- package/wasm-browser/hypen_engine_bg.wasm.d.ts +30 -0
- package/wasm-browser/package.json +15 -0
- package/wasm-node/README.md +425 -0
- package/wasm-node/hypen_engine.d.ts +97 -0
- package/wasm-node/hypen_engine.js +751 -0
- package/wasm-node/hypen_engine_bg.js +736 -0
- package/wasm-node/hypen_engine_bg.wasm +0 -0
- package/wasm-node/hypen_engine_bg.wasm.d.ts +30 -0
- package/wasm-node/package.json +11 -0
package/README.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# @hypen-space/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The reactive runtime for Hypen - a declarative UI language that separates what your UI looks like from how it behaves.
|
|
4
|
+
|
|
5
|
+
## What is Hypen?
|
|
6
|
+
|
|
7
|
+
Hypen lets you write UI templates in a clean, declarative syntax:
|
|
8
|
+
|
|
9
|
+
```hypen
|
|
10
|
+
Column {
|
|
11
|
+
Text("Hello, ${state.user.name}!")
|
|
12
|
+
Button(onClick: @actions.logout) {
|
|
13
|
+
Text("Sign Out")
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `@hypen-space/core` package provides the engine that:
|
|
19
|
+
|
|
20
|
+
1. **Parses** your Hypen templates
|
|
21
|
+
2. **Tracks** reactive state bindings (like `${state.user.name}`)
|
|
22
|
+
3. **Generates patches** when state changes (instead of re-rendering everything)
|
|
23
|
+
4. **Dispatches actions** triggered from the UI (like `@actions.logout`)
|
|
24
|
+
|
|
25
|
+
You provide a renderer that applies those patches to your platform (DOM, Canvas, Native, etc).
|
|
4
26
|
|
|
5
27
|
## Installation
|
|
6
28
|
|
|
@@ -10,12 +32,54 @@ npm install @hypen-space/core
|
|
|
10
32
|
bun add @hypen-space/core
|
|
11
33
|
```
|
|
12
34
|
|
|
35
|
+
## Core Concepts
|
|
36
|
+
|
|
37
|
+
### Templates
|
|
38
|
+
|
|
39
|
+
Hypen templates describe your UI structure. Components can have:
|
|
40
|
+
|
|
41
|
+
- **Arguments**: `Text("Hello")` or `Button(disabled: true)`
|
|
42
|
+
- **Children**: Nested inside `{ }` braces
|
|
43
|
+
- **Applicators**: Chained styling like `.padding(16).color(blue)`
|
|
44
|
+
|
|
45
|
+
### State Bindings
|
|
46
|
+
|
|
47
|
+
Use `${state.path}` to bind template values to your module's state:
|
|
48
|
+
|
|
49
|
+
```hypen
|
|
50
|
+
Text("Count: ${state.count}")
|
|
51
|
+
Text("User: ${state.user.name}")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
When state changes, only the affected parts of the UI update.
|
|
55
|
+
|
|
56
|
+
### Actions
|
|
57
|
+
|
|
58
|
+
Use `@actions.name` to dispatch events from the UI to your module:
|
|
59
|
+
|
|
60
|
+
```hypen
|
|
61
|
+
Button(onClick: @actions.increment) { Text("+") }
|
|
62
|
+
Button(onClick: @actions.submitForm) { Text("Submit") }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Patches
|
|
66
|
+
|
|
67
|
+
The engine doesn't manipulate the UI directly. Instead, it emits **patches** - minimal instructions describing what changed:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
{ type: "Create", id: "1", elementType: "Text", props: { text: "Hello" } }
|
|
71
|
+
{ type: "SetProp", id: "1", name: "text", value: "Hello, World" }
|
|
72
|
+
{ type: "Remove", id: "1" }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Your renderer applies these patches to the actual platform.
|
|
76
|
+
|
|
13
77
|
## Quick Start
|
|
14
78
|
|
|
15
79
|
```typescript
|
|
16
80
|
import { Engine, app } from "@hypen-space/core";
|
|
17
81
|
|
|
18
|
-
// 1. Define
|
|
82
|
+
// 1. Define your module's state and actions
|
|
19
83
|
const counter = app
|
|
20
84
|
.defineState({ count: 0 })
|
|
21
85
|
.onAction("increment", ({ state }) => state.count++)
|
|
@@ -26,14 +90,14 @@ const counter = app
|
|
|
26
90
|
const engine = new Engine();
|
|
27
91
|
await engine.init();
|
|
28
92
|
|
|
29
|
-
// 3.
|
|
93
|
+
// 3. Connect your renderer
|
|
30
94
|
engine.setRenderCallback((patches) => {
|
|
31
|
-
// Apply patches to your platform (DOM, Canvas, Native, etc.)
|
|
32
95
|
myRenderer.applyPatches(patches);
|
|
33
96
|
});
|
|
34
97
|
|
|
35
|
-
// 4. Register module and render
|
|
98
|
+
// 4. Register the module and render
|
|
36
99
|
engine.setModule("counter", counter.actions, counter.stateKeys, counter.initialState);
|
|
100
|
+
|
|
37
101
|
engine.renderSource(`
|
|
38
102
|
Column {
|
|
39
103
|
Text("Count: \${state.count}")
|
|
@@ -45,75 +109,9 @@ engine.renderSource(`
|
|
|
45
109
|
`);
|
|
46
110
|
```
|
|
47
111
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
Auto-discover `.hypen` components from the filesystem:
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
import { discoverComponents, loadDiscoveredComponents, watchComponents } from "@hypen-space/core";
|
|
54
|
-
|
|
55
|
-
// Discover components in a directory
|
|
56
|
-
const components = await discoverComponents("./src/components", {
|
|
57
|
-
patterns: ["folder", "sibling", "index"], // Naming conventions
|
|
58
|
-
recursive: false,
|
|
59
|
-
debug: true,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Load discovered components with their modules
|
|
63
|
-
const loaded = await loadDiscoveredComponents(components);
|
|
64
|
-
|
|
65
|
-
// Watch for changes (hot reload)
|
|
66
|
-
const watcher = watchComponents("./src/components", {
|
|
67
|
-
onAdd: (c) => console.log("Added:", c.name),
|
|
68
|
-
onUpdate: (c) => console.log("Updated:", c.name),
|
|
69
|
-
onRemove: (name) => console.log("Removed:", name),
|
|
70
|
-
onChange: (all) => console.log("All components:", all.length),
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Stop watching
|
|
74
|
-
watcher.stop();
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Supported Patterns
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
# Folder-based (recommended)
|
|
81
|
-
Counter/
|
|
82
|
-
├── component.hypen
|
|
83
|
-
└── component.ts
|
|
112
|
+
## Modules
|
|
84
113
|
|
|
85
|
-
|
|
86
|
-
Counter.hypen
|
|
87
|
-
Counter.ts
|
|
88
|
-
|
|
89
|
-
# Index-based
|
|
90
|
-
Counter/
|
|
91
|
-
├── index.hypen
|
|
92
|
-
└── index.ts
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Component Loader
|
|
96
|
-
|
|
97
|
-
Register and manage components:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
import { componentLoader, ComponentLoader } from "@hypen-space/core";
|
|
101
|
-
|
|
102
|
-
// Use the global loader
|
|
103
|
-
componentLoader.register("Counter", counterModule, counterTemplate);
|
|
104
|
-
componentLoader.get("Counter"); // Get component
|
|
105
|
-
componentLoader.has("Counter"); // Check if exists
|
|
106
|
-
componentLoader.getNames(); // List all names
|
|
107
|
-
|
|
108
|
-
// Or create your own
|
|
109
|
-
const loader = new ComponentLoader();
|
|
110
|
-
await loader.loadFromDirectory("Counter", "./src/components/Counter");
|
|
111
|
-
await loader.loadFromComponentsDir("./src/components"); // Auto-load all
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Module System
|
|
115
|
-
|
|
116
|
-
Create stateful modules with the fluent `app` builder:
|
|
114
|
+
Modules manage state and handle actions. Use the `app` builder to define them:
|
|
117
115
|
|
|
118
116
|
```typescript
|
|
119
117
|
import { app } from "@hypen-space/core";
|
|
@@ -126,13 +124,13 @@ interface UserState {
|
|
|
126
124
|
const userModule = app
|
|
127
125
|
.defineState<UserState>({ user: null, loading: false })
|
|
128
126
|
|
|
129
|
-
//
|
|
127
|
+
// Called when module is created
|
|
130
128
|
.onCreated(async ({ state, next }) => {
|
|
131
129
|
state.loading = true;
|
|
132
|
-
next(); // Sync state to engine
|
|
130
|
+
next(); // Sync state changes to engine
|
|
133
131
|
})
|
|
134
132
|
|
|
135
|
-
//
|
|
133
|
+
// Handle actions dispatched from UI
|
|
136
134
|
.onAction("loadUser", async ({ state, action, next }) => {
|
|
137
135
|
const userId = action.payload?.id;
|
|
138
136
|
state.user = await fetchUser(userId);
|
|
@@ -145,16 +143,19 @@ const userModule = app
|
|
|
145
143
|
next();
|
|
146
144
|
})
|
|
147
145
|
|
|
146
|
+
// Called when module is destroyed
|
|
148
147
|
.onDestroyed(({ state }) => {
|
|
149
|
-
console.log("
|
|
148
|
+
console.log("Cleanup");
|
|
150
149
|
})
|
|
151
150
|
|
|
152
151
|
.build();
|
|
153
152
|
```
|
|
154
153
|
|
|
155
|
-
|
|
154
|
+
The `next()` callback synchronizes state changes with the engine after async operations.
|
|
155
|
+
|
|
156
|
+
## State
|
|
156
157
|
|
|
157
|
-
|
|
158
|
+
State is automatically tracked via Proxy. Mutations trigger UI updates:
|
|
158
159
|
|
|
159
160
|
```typescript
|
|
160
161
|
import { createObservableState, batchStateUpdates, getStateSnapshot } from "@hypen-space/core";
|
|
@@ -169,19 +170,50 @@ const state = createObservableState({ count: 0, items: [] }, {
|
|
|
169
170
|
state.count = 5;
|
|
170
171
|
state.items.push("item");
|
|
171
172
|
|
|
172
|
-
// Batch multiple updates
|
|
173
|
+
// Batch multiple updates into one render cycle
|
|
173
174
|
batchStateUpdates(state, () => {
|
|
174
175
|
state.count = 10;
|
|
175
176
|
state.items = ["a", "b", "c"];
|
|
176
177
|
});
|
|
177
178
|
|
|
178
|
-
// Get immutable snapshot
|
|
179
|
+
// Get an immutable snapshot
|
|
179
180
|
const snapshot = getStateSnapshot(state);
|
|
180
181
|
```
|
|
181
182
|
|
|
183
|
+
## Custom Renderers
|
|
184
|
+
|
|
185
|
+
Extend `BaseRenderer` to render to any platform:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { BaseRenderer } from "@hypen-space/core";
|
|
189
|
+
|
|
190
|
+
class MyRenderer extends BaseRenderer {
|
|
191
|
+
protected onCreate(id: string, type: string, props: Record<string, any>) {
|
|
192
|
+
// Create an element
|
|
193
|
+
}
|
|
194
|
+
protected onSetProp(id: string, name: string, value: any) {
|
|
195
|
+
// Update a property
|
|
196
|
+
}
|
|
197
|
+
protected onSetText(id: string, text: string) {
|
|
198
|
+
// Set text content
|
|
199
|
+
}
|
|
200
|
+
protected onInsert(parentId: string, id: string, beforeId?: string) {
|
|
201
|
+
// Insert into parent
|
|
202
|
+
}
|
|
203
|
+
protected onMove(parentId: string, id: string, beforeId?: string) {
|
|
204
|
+
// Reorder element
|
|
205
|
+
}
|
|
206
|
+
protected onRemove(id: string) {
|
|
207
|
+
// Remove element
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
See `@hypen-space/web` for a DOM renderer implementation.
|
|
213
|
+
|
|
182
214
|
## Routing
|
|
183
215
|
|
|
184
|
-
Built-in hash
|
|
216
|
+
Built-in hash or pathname routing:
|
|
185
217
|
|
|
186
218
|
```typescript
|
|
187
219
|
import { HypenRouter } from "@hypen-space/core";
|
|
@@ -191,46 +223,90 @@ const router = new HypenRouter();
|
|
|
191
223
|
router.navigate("/products/123");
|
|
192
224
|
|
|
193
225
|
router.subscribe((state) => {
|
|
194
|
-
console.log("
|
|
195
|
-
console.log("Params:", state.params);
|
|
226
|
+
console.log("Path:", state.currentPath);
|
|
227
|
+
console.log("Params:", state.params); // { id: "123" }
|
|
196
228
|
console.log("Query:", state.query);
|
|
197
229
|
});
|
|
198
230
|
```
|
|
199
231
|
|
|
200
|
-
|
|
232
|
+
Use built-in components in templates:
|
|
201
233
|
|
|
202
|
-
|
|
234
|
+
```hypen
|
|
235
|
+
Router {
|
|
236
|
+
Route(path: "/") { HomePage }
|
|
237
|
+
Route(path: "/products/:id") { ProductPage }
|
|
238
|
+
}
|
|
239
|
+
Link(to: "/products/42") { Text("View Product") }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Component Discovery
|
|
243
|
+
|
|
244
|
+
For larger apps, organize components as files and auto-discover them:
|
|
203
245
|
|
|
204
246
|
```typescript
|
|
205
|
-
import {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// Route(path: "/") { HomePage }
|
|
210
|
-
// Route(path: "/products") { ProductList }
|
|
211
|
-
// }
|
|
212
|
-
// Link(to: "/products") { Text("View Products") }
|
|
247
|
+
import { discoverComponents, loadDiscoveredComponents } from "@hypen-space/core";
|
|
248
|
+
|
|
249
|
+
const components = await discoverComponents("./src/components");
|
|
250
|
+
const loaded = await loadDiscoveredComponents(components);
|
|
213
251
|
```
|
|
214
252
|
|
|
215
|
-
|
|
253
|
+
Supported file patterns:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
Counter/
|
|
257
|
+
├── component.hypen # Template
|
|
258
|
+
└── component.ts # Module
|
|
216
259
|
|
|
217
|
-
|
|
260
|
+
Counter.hypen # Or sibling files
|
|
261
|
+
Counter.ts
|
|
262
|
+
|
|
263
|
+
Counter/
|
|
264
|
+
├── index.hypen # Or index-based
|
|
265
|
+
└── index.ts
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Watch for changes (hot reload):
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { watchComponents } from "@hypen-space/core";
|
|
272
|
+
|
|
273
|
+
const watcher = watchComponents("./src/components", {
|
|
274
|
+
onUpdate: (c) => console.log("Updated:", c.name),
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Component Loader
|
|
279
|
+
|
|
280
|
+
Register components programmatically:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { componentLoader, ComponentLoader } from "@hypen-space/core";
|
|
284
|
+
|
|
285
|
+
// Global loader
|
|
286
|
+
componentLoader.register("Counter", counterModule, counterTemplate);
|
|
287
|
+
componentLoader.get("Counter");
|
|
288
|
+
componentLoader.has("Counter");
|
|
289
|
+
|
|
290
|
+
// Or create your own
|
|
291
|
+
const loader = new ComponentLoader();
|
|
292
|
+
await loader.loadFromComponentsDir("./src/components");
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Remote UI
|
|
296
|
+
|
|
297
|
+
Connect to a Hypen server for server-driven UI:
|
|
218
298
|
|
|
219
299
|
```typescript
|
|
220
300
|
import { RemoteEngine } from "@hypen-space/core";
|
|
221
301
|
|
|
222
302
|
const remote = new RemoteEngine("ws://localhost:3000", {
|
|
223
303
|
autoReconnect: true,
|
|
224
|
-
reconnectInterval: 3000,
|
|
225
|
-
maxReconnectAttempts: 10,
|
|
226
304
|
});
|
|
227
305
|
|
|
228
306
|
remote
|
|
229
307
|
.onPatches((patches) => renderer.applyPatches(patches))
|
|
230
308
|
.onStateUpdate((state) => console.log("Server state:", state))
|
|
231
|
-
.onConnect(() => console.log("Connected"))
|
|
232
|
-
.onDisconnect(() => console.log("Disconnected"))
|
|
233
|
-
.onError((error) => console.error("Error:", error));
|
|
309
|
+
.onConnect(() => console.log("Connected"));
|
|
234
310
|
|
|
235
311
|
await remote.connect();
|
|
236
312
|
remote.dispatchAction("loadData", { page: 1 });
|
|
@@ -238,86 +314,55 @@ remote.dispatchAction("loadData", { page: 1 });
|
|
|
238
314
|
|
|
239
315
|
## Global Context
|
|
240
316
|
|
|
241
|
-
|
|
317
|
+
Share state and events across modules:
|
|
242
318
|
|
|
243
319
|
```typescript
|
|
244
320
|
import { HypenGlobalContext } from "@hypen-space/core";
|
|
245
321
|
|
|
246
322
|
const context = new HypenGlobalContext();
|
|
247
323
|
|
|
248
|
-
context.registerModule("auth",
|
|
249
|
-
context.registerModule("cart",
|
|
324
|
+
context.registerModule("auth", authModule);
|
|
325
|
+
context.registerModule("cart", cartModule);
|
|
250
326
|
|
|
251
|
-
|
|
252
|
-
const
|
|
327
|
+
// Cross-module access
|
|
328
|
+
const user = context.getModule("auth").getState().user;
|
|
253
329
|
|
|
254
|
-
// Event
|
|
255
|
-
context.on("userLoggedIn", (user) =>
|
|
330
|
+
// Event bus
|
|
331
|
+
context.on("userLoggedIn", (user) => { /* ... */ });
|
|
256
332
|
context.emit("userLoggedIn", { id: "1", name: "Ian" });
|
|
257
333
|
```
|
|
258
334
|
|
|
259
|
-
##
|
|
260
|
-
|
|
261
|
-
Implement the `Renderer` interface for any platform:
|
|
335
|
+
## Browser vs Node.js
|
|
262
336
|
|
|
263
337
|
```typescript
|
|
264
|
-
|
|
338
|
+
// Node.js / Bundler - WASM loads automatically
|
|
339
|
+
import { Engine } from "@hypen-space/core";
|
|
340
|
+
const engine = new Engine();
|
|
341
|
+
await engine.init();
|
|
265
342
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
protected onSetProp(id: string, name: string, value: any) {
|
|
271
|
-
// Set property
|
|
272
|
-
}
|
|
273
|
-
protected onSetText(id: string, text: string) {
|
|
274
|
-
// Set text
|
|
275
|
-
}
|
|
276
|
-
protected onInsert(parentId: string, id: string, beforeId?: string) {
|
|
277
|
-
// Insert into parent
|
|
278
|
-
}
|
|
279
|
-
protected onMove(parentId: string, id: string, beforeId?: string) {
|
|
280
|
-
// Move element
|
|
281
|
-
}
|
|
282
|
-
protected onRemove(id: string) {
|
|
283
|
-
// Remove element
|
|
284
|
-
}
|
|
285
|
-
}
|
|
343
|
+
// Browser - specify WASM path
|
|
344
|
+
import { BrowserEngine } from "@hypen-space/core";
|
|
345
|
+
const engine = new BrowserEngine();
|
|
346
|
+
await engine.init({ wasmPath: "/hypen_engine_bg.wasm" });
|
|
286
347
|
```
|
|
287
348
|
|
|
288
|
-
## Exports
|
|
349
|
+
## Package Exports
|
|
289
350
|
|
|
290
351
|
| Export | Description |
|
|
291
352
|
|--------|-------------|
|
|
292
|
-
| `@hypen-space/core` | Main entry
|
|
293
|
-
| `@hypen-space/core/engine` | Low-level WASM engine
|
|
294
|
-
| `@hypen-space/core/engine/browser` | Browser-optimized engine
|
|
295
|
-
| `@hypen-space/core/app` | Module builder
|
|
353
|
+
| `@hypen-space/core` | Main entry point |
|
|
354
|
+
| `@hypen-space/core/engine` | Low-level WASM engine |
|
|
355
|
+
| `@hypen-space/core/engine/browser` | Browser-optimized engine |
|
|
356
|
+
| `@hypen-space/core/app` | Module builder |
|
|
296
357
|
| `@hypen-space/core/state` | Observable state utilities |
|
|
297
|
-
| `@hypen-space/core/renderer` | Abstract renderer
|
|
358
|
+
| `@hypen-space/core/renderer` | Abstract renderer |
|
|
298
359
|
| `@hypen-space/core/router` | Routing system |
|
|
299
|
-
| `@hypen-space/core/events` | Typed event emitter |
|
|
300
360
|
| `@hypen-space/core/context` | Global context |
|
|
301
361
|
| `@hypen-space/core/remote` | Remote UI protocol |
|
|
302
|
-
| `@hypen-space/core/remote/client` | WebSocket client |
|
|
303
362
|
| `@hypen-space/core/loader` | Component loader |
|
|
304
363
|
| `@hypen-space/core/discovery` | Component discovery |
|
|
305
364
|
| `@hypen-space/core/components` | Built-in Router, Route, Link |
|
|
306
365
|
|
|
307
|
-
## Browser vs Node.js
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
// Node.js / Bundler (auto WASM init)
|
|
311
|
-
import { Engine } from "@hypen-space/core";
|
|
312
|
-
const engine = new Engine();
|
|
313
|
-
await engine.init();
|
|
314
|
-
|
|
315
|
-
// Browser (explicit WASM path)
|
|
316
|
-
import { BrowserEngine } from "@hypen-space/core";
|
|
317
|
-
const engine = new BrowserEngine();
|
|
318
|
-
await engine.init({ wasmPath: "/hypen_engine_bg.wasm" });
|
|
319
|
-
```
|
|
320
|
-
|
|
321
366
|
## Requirements
|
|
322
367
|
|
|
323
368
|
- Node.js >= 18.0.0
|
package/dist/src/app.js
CHANGED
|
@@ -95,6 +95,7 @@ class HypenModuleInstance {
|
|
|
95
95
|
console.log(`[ModuleInstance] Action handler completed: ${actionName}`);
|
|
96
96
|
} catch (error) {
|
|
97
97
|
console.error(`[ModuleInstance] Action handler error for ${actionName}:`, error);
|
|
98
|
+
throw error;
|
|
98
99
|
}
|
|
99
100
|
});
|
|
100
101
|
}
|
|
@@ -157,4 +158,4 @@ export {
|
|
|
157
158
|
|
|
158
159
|
export { HypenAppBuilder, HypenApp, app, HypenModuleInstance };
|
|
159
160
|
|
|
160
|
-
//# debugId=
|
|
161
|
+
//# debugId=CC570FF56ABF0FB064756E2164756E21
|
package/dist/src/app.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/app.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Hypen App Builder API\n * Implements the stateful module system from RFC-0001\n */\n\nimport type { Action } from \"./engine.js\";\n\n// Interface for engine compatibility (works with both engine.js and engine.browser.js)\nexport interface IEngine {\n setModule(name: string, actions: string[], stateKeys: string[], initialState: unknown): void;\n onAction(actionName: string, handler: (action: Action) => void | Promise<void>): void;\n notifyStateChange(paths: string[], changedValues: Record<string, unknown>): void;\n}\n\nimport { createObservableState, type StateChange, getStateSnapshot } from \"./state.js\";\nimport type { HypenRouter } from \"./router.js\";\nimport type { HypenGlobalContext, ModuleReference } from \"./context.js\";\n\nexport type RouterContext = {\n root: HypenRouter;\n current?: HypenRouter;\n parent?: HypenRouter;\n};\n\nexport type ActionContext = {\n name: string;\n payload?: unknown;\n sender?: string;\n};\n\nexport type ActionNext = {\n router: HypenRouter; // Direct access to router instance (from nearest parent)\n};\n\nexport type GlobalContext = {\n getModule: <T = unknown>(id: string) => ModuleReference<T>;\n hasModule: (id: string) => boolean;\n getModuleIds: () => string[];\n getGlobalState: () => Record<string, unknown>;\n emit: (event: string, payload?: unknown) => void;\n on: (event: string, handler: (payload?: unknown) => void) => () => void;\n __router?: unknown; // Internal: router instance for built-in Router component\n};\n\nexport type LifecycleHandler<T> = (\n state: T,\n context?: GlobalContext\n) => void | Promise<void>;\n\n/**\n * Action handler context - all parameters available explicitly\n */\nexport interface ActionHandlerContext<T> {\n action: ActionContext;\n state: T;\n next: ActionNext;\n context: GlobalContext;\n}\n\n/**\n * Action handler - receives all context in a single object\n */\nexport type ActionHandler<T> = (ctx: ActionHandlerContext<T>) => void | Promise<void>;\n\nexport interface HypenModuleDefinition<T = unknown> {\n name?: string;\n actions: string[];\n stateKeys: string[];\n persist?: boolean;\n version?: number;\n initialState: T;\n handlers: {\n onCreated?: LifecycleHandler<T>;\n onAction: Map<string, ActionHandler<T>>;\n onDestroyed?: LifecycleHandler<T>;\n };\n}\n\n/**\n * Alias for HypenModuleDefinition for backward compatibility\n */\nexport type HypenModule<T = unknown> = HypenModuleDefinition<T>;\n\n/**\n * Builder for creating Hypen app modules\n */\nexport class HypenAppBuilder<T> {\n private initialState: T;\n private options: { persist?: boolean; version?: number; name?: string };\n private createdHandler?: LifecycleHandler<T>;\n private actionHandlers: Map<string, ActionHandler<T>> = new Map();\n private destroyedHandler?: LifecycleHandler<T>;\n\n constructor(\n initialState: T,\n options?: { persist?: boolean; version?: number; name?: string }\n ) {\n this.initialState = initialState;\n this.options = options || {};\n }\n\n /**\n * Register a handler for module creation\n */\n onCreated(fn: LifecycleHandler<T>): this {\n this.createdHandler = fn;\n return this;\n }\n\n /**\n * Register a handler for a specific action\n */\n onAction(name: string, fn: ActionHandler<T>): this {\n this.actionHandlers.set(name, fn);\n return this;\n }\n\n /**\n * Register a handler for module destruction\n */\n onDestroyed(fn: LifecycleHandler<T>): this {\n this.destroyedHandler = fn;\n return this;\n }\n\n /**\n * Build the module definition\n */\n build(): HypenModuleDefinition<T> {\n // Safe way to get keys from initialState\n const stateKeys = this.initialState !== null && typeof this.initialState === 'object'\n ? Object.keys(this.initialState)\n : [];\n\n return {\n name: this.options.name,\n actions: Array.from(this.actionHandlers.keys()),\n stateKeys,\n persist: this.options.persist,\n version: this.options.version,\n initialState: this.initialState,\n handlers: {\n onCreated: this.createdHandler,\n onAction: this.actionHandlers,\n onDestroyed: this.destroyedHandler,\n },\n };\n }\n}\n\n/**\n * Hypen App API\n */\nexport class HypenApp {\n /**\n * Define the initial state for a module\n */\n defineState<T>(\n initial: T,\n options?: { persist?: boolean; version?: number; name?: string }\n ): HypenAppBuilder<T> {\n return new HypenAppBuilder(initial, options);\n }\n}\n\n/**\n * The main app instance for creating modules\n */\nexport const app = new HypenApp();\n\n/**\n * Module Instance - manages a running module with typed state\n */\nexport class HypenModuleInstance<T extends object = any> {\n private engine: IEngine;\n private definition: HypenModuleDefinition<T>;\n private state: T;\n private isDestroyed = false;\n private routerContext?: RouterContext;\n private globalContext?: HypenGlobalContext;\n private stateChangeCallbacks: Array<() => void> = [];\n\n constructor(\n engine: IEngine,\n definition: HypenModuleDefinition<T>,\n routerContext?: RouterContext,\n globalContext?: HypenGlobalContext\n ) {\n this.engine = engine;\n this.definition = definition;\n this.routerContext = routerContext;\n this.globalContext = globalContext;\n\n // Create observable state that sends only changed paths and values to engine\n this.state = createObservableState<T>(definition.initialState as T & object, {\n onChange: (change: StateChange) => {\n // Send only the changed paths and their new values (not the whole state)\n this.engine.notifyStateChange(change.paths, change.newValues);\n // Notify all registered callbacks\n this.stateChangeCallbacks.forEach(cb => cb());\n },\n });\n\n // Register with engine (initial state registration)\n this.engine.setModule(\n definition.name || \"AnonymousModule\",\n definition.actions,\n definition.stateKeys,\n getStateSnapshot(this.state)\n );\n\n // Register action handlers with flexible parameter support\n for (const [actionName, handler] of definition.handlers.onAction) {\n console.log(`[ModuleInstance] Registering action handler: ${actionName} for module ${definition.name}`);\n this.engine.onAction(actionName, async (action: Action) => {\n console.log(`[ModuleInstance] Action handler fired: ${actionName}`, action);\n\n const actionCtx: ActionContext = {\n name: action.name,\n payload: action.payload,\n sender: action.sender,\n };\n\n const next: ActionNext = {\n router: this.routerContext?.root || (null as any),\n };\n\n const context: GlobalContext | undefined = this.globalContext\n ? this.createGlobalContextAPI()\n : undefined;\n\n try {\n await handler({\n action: actionCtx,\n state: this.state,\n next,\n context: context!,\n });\n console.log(`[ModuleInstance] Action handler completed: ${actionName}`);\n } catch (error) {\n console.error(`[ModuleInstance] Action handler error for ${actionName}:`, error);\n }\n });\n }\n\n // Call onCreated\n this.callCreatedHandler();\n }\n\n /**\n * Create the global context API for this module\n */\n private createGlobalContextAPI(): GlobalContext {\n if (!this.globalContext) {\n throw new Error(\"Global context not available\");\n }\n\n const ctx = this.globalContext;\n const api: GlobalContext = {\n getModule: (id: string) => ctx.getModule(id),\n hasModule: (id: string) => ctx.hasModule(id),\n getModuleIds: () => ctx.getModuleIds(),\n getGlobalState: () => ctx.getGlobalState(),\n emit: (event: string, payload?: any) => ctx.emit(event, payload),\n on: (event: string, handler: (payload?: any) => void) =>\n ctx.on(event, handler),\n };\n\n // Expose router and hypen engine for built-in components (if available)\n if ((ctx as any).__router) {\n api.__router = (ctx as any).__router;\n }\n if ((ctx as any).__hypenEngine) {\n (api as any).__hypenEngine = (ctx as any).__hypenEngine;\n }\n\n return api;\n }\n\n /**\n * Call the onCreated handler\n */\n private async callCreatedHandler(): Promise<void> {\n if (this.definition.handlers.onCreated) {\n const context = this.globalContext ? this.createGlobalContextAPI() : undefined;\n await this.definition.handlers.onCreated(this.state, context);\n }\n }\n\n /**\n * Register a callback to be notified when state changes\n */\n onStateChange(callback: () => void): void {\n this.stateChangeCallbacks.push(callback);\n }\n\n /**\n * Destroy the module instance\n */\n async destroy(): Promise<void> {\n if (this.isDestroyed) return;\n\n if (this.definition.handlers.onDestroyed) {\n await this.definition.handlers.onDestroyed(this.state);\n }\n\n this.isDestroyed = true;\n }\n\n /**\n * Get the current state (returns a snapshot)\n */\n getState(): T {\n return getStateSnapshot(this.state);\n }\n\n /**\n * Get the live observable state\n */\n getLiveState(): T {\n return this.state;\n }\n\n /**\n * Update state directly (merges with existing state)\n */\n updateState(patch: Partial<T>): void {\n Object.assign(this.state, patch);\n }\n}\n"
|
|
5
|
+
"/**\n * Hypen App Builder API\n * Implements the stateful module system from RFC-0001\n */\n\nimport type { Action } from \"./engine.js\";\n\n// Interface for engine compatibility (works with both engine.js and engine.browser.js)\nexport interface IEngine {\n setModule(name: string, actions: string[], stateKeys: string[], initialState: unknown): void;\n onAction(actionName: string, handler: (action: Action) => void | Promise<void>): void;\n notifyStateChange(paths: string[], changedValues: Record<string, unknown>): void;\n}\n\nimport { createObservableState, type StateChange, getStateSnapshot } from \"./state.js\";\nimport type { HypenRouter } from \"./router.js\";\nimport type { HypenGlobalContext, ModuleReference } from \"./context.js\";\n\nexport type RouterContext = {\n root: HypenRouter;\n current?: HypenRouter;\n parent?: HypenRouter;\n};\n\nexport type ActionContext = {\n name: string;\n payload?: unknown;\n sender?: string;\n};\n\nexport type ActionNext = {\n router: HypenRouter; // Direct access to router instance (from nearest parent)\n};\n\nexport type GlobalContext = {\n getModule: <T = unknown>(id: string) => ModuleReference<T>;\n hasModule: (id: string) => boolean;\n getModuleIds: () => string[];\n getGlobalState: () => Record<string, unknown>;\n emit: (event: string, payload?: unknown) => void;\n on: (event: string, handler: (payload?: unknown) => void) => () => void;\n __router?: unknown; // Internal: router instance for built-in Router component\n};\n\nexport type LifecycleHandler<T> = (\n state: T,\n context?: GlobalContext\n) => void | Promise<void>;\n\n/**\n * Action handler context - all parameters available explicitly\n */\nexport interface ActionHandlerContext<T> {\n action: ActionContext;\n state: T;\n next: ActionNext;\n context: GlobalContext;\n}\n\n/**\n * Action handler - receives all context in a single object\n */\nexport type ActionHandler<T> = (ctx: ActionHandlerContext<T>) => void | Promise<void>;\n\nexport interface HypenModuleDefinition<T = unknown> {\n name?: string;\n actions: string[];\n stateKeys: string[];\n persist?: boolean;\n version?: number;\n initialState: T;\n handlers: {\n onCreated?: LifecycleHandler<T>;\n onAction: Map<string, ActionHandler<T>>;\n onDestroyed?: LifecycleHandler<T>;\n };\n}\n\n/**\n * Alias for HypenModuleDefinition for backward compatibility\n */\nexport type HypenModule<T = unknown> = HypenModuleDefinition<T>;\n\n/**\n * Builder for creating Hypen app modules\n */\nexport class HypenAppBuilder<T> {\n private initialState: T;\n private options: { persist?: boolean; version?: number; name?: string };\n private createdHandler?: LifecycleHandler<T>;\n private actionHandlers: Map<string, ActionHandler<T>> = new Map();\n private destroyedHandler?: LifecycleHandler<T>;\n\n constructor(\n initialState: T,\n options?: { persist?: boolean; version?: number; name?: string }\n ) {\n this.initialState = initialState;\n this.options = options || {};\n }\n\n /**\n * Register a handler for module creation\n */\n onCreated(fn: LifecycleHandler<T>): this {\n this.createdHandler = fn;\n return this;\n }\n\n /**\n * Register a handler for a specific action\n */\n onAction(name: string, fn: ActionHandler<T>): this {\n this.actionHandlers.set(name, fn);\n return this;\n }\n\n /**\n * Register a handler for module destruction\n */\n onDestroyed(fn: LifecycleHandler<T>): this {\n this.destroyedHandler = fn;\n return this;\n }\n\n /**\n * Build the module definition\n */\n build(): HypenModuleDefinition<T> {\n // Safe way to get keys from initialState\n const stateKeys = this.initialState !== null && typeof this.initialState === 'object'\n ? Object.keys(this.initialState)\n : [];\n\n return {\n name: this.options.name,\n actions: Array.from(this.actionHandlers.keys()),\n stateKeys,\n persist: this.options.persist,\n version: this.options.version,\n initialState: this.initialState,\n handlers: {\n onCreated: this.createdHandler,\n onAction: this.actionHandlers,\n onDestroyed: this.destroyedHandler,\n },\n };\n }\n}\n\n/**\n * Hypen App API\n */\nexport class HypenApp {\n /**\n * Define the initial state for a module\n */\n defineState<T>(\n initial: T,\n options?: { persist?: boolean; version?: number; name?: string }\n ): HypenAppBuilder<T> {\n return new HypenAppBuilder(initial, options);\n }\n}\n\n/**\n * The main app instance for creating modules\n */\nexport const app = new HypenApp();\n\n/**\n * Module Instance - manages a running module with typed state\n */\nexport class HypenModuleInstance<T extends object = any> {\n private engine: IEngine;\n private definition: HypenModuleDefinition<T>;\n private state: T;\n private isDestroyed = false;\n private routerContext?: RouterContext;\n private globalContext?: HypenGlobalContext;\n private stateChangeCallbacks: Array<() => void> = [];\n\n constructor(\n engine: IEngine,\n definition: HypenModuleDefinition<T>,\n routerContext?: RouterContext,\n globalContext?: HypenGlobalContext\n ) {\n this.engine = engine;\n this.definition = definition;\n this.routerContext = routerContext;\n this.globalContext = globalContext;\n\n // Create observable state that sends only changed paths and values to engine\n this.state = createObservableState<T>(definition.initialState as T & object, {\n onChange: (change: StateChange) => {\n // Send only the changed paths and their new values (not the whole state)\n this.engine.notifyStateChange(change.paths, change.newValues);\n // Notify all registered callbacks\n this.stateChangeCallbacks.forEach(cb => cb());\n },\n });\n\n // Register with engine (initial state registration)\n this.engine.setModule(\n definition.name || \"AnonymousModule\",\n definition.actions,\n definition.stateKeys,\n getStateSnapshot(this.state)\n );\n\n // Register action handlers with flexible parameter support\n for (const [actionName, handler] of definition.handlers.onAction) {\n console.log(`[ModuleInstance] Registering action handler: ${actionName} for module ${definition.name}`);\n this.engine.onAction(actionName, async (action: Action) => {\n console.log(`[ModuleInstance] Action handler fired: ${actionName}`, action);\n\n const actionCtx: ActionContext = {\n name: action.name,\n payload: action.payload,\n sender: action.sender,\n };\n\n const next: ActionNext = {\n router: this.routerContext?.root || (null as any),\n };\n\n const context: GlobalContext | undefined = this.globalContext\n ? this.createGlobalContextAPI()\n : undefined;\n\n try {\n await handler({\n action: actionCtx,\n state: this.state,\n next,\n context: context!,\n });\n console.log(`[ModuleInstance] Action handler completed: ${actionName}`);\n } catch (error) {\n console.error(`[ModuleInstance] Action handler error for ${actionName}:`, error);\n throw error; // Re-throw to allow callers to handle the error\n }\n });\n }\n\n // Call onCreated\n this.callCreatedHandler();\n }\n\n /**\n * Create the global context API for this module\n */\n private createGlobalContextAPI(): GlobalContext {\n if (!this.globalContext) {\n throw new Error(\"Global context not available\");\n }\n\n const ctx = this.globalContext;\n const api: GlobalContext = {\n getModule: (id: string) => ctx.getModule(id),\n hasModule: (id: string) => ctx.hasModule(id),\n getModuleIds: () => ctx.getModuleIds(),\n getGlobalState: () => ctx.getGlobalState(),\n emit: (event: string, payload?: any) => ctx.emit(event, payload),\n on: (event: string, handler: (payload?: any) => void) =>\n ctx.on(event, handler),\n };\n\n // Expose router and hypen engine for built-in components (if available)\n if ((ctx as any).__router) {\n api.__router = (ctx as any).__router;\n }\n if ((ctx as any).__hypenEngine) {\n (api as any).__hypenEngine = (ctx as any).__hypenEngine;\n }\n\n return api;\n }\n\n /**\n * Call the onCreated handler\n */\n private async callCreatedHandler(): Promise<void> {\n if (this.definition.handlers.onCreated) {\n const context = this.globalContext ? this.createGlobalContextAPI() : undefined;\n await this.definition.handlers.onCreated(this.state, context);\n }\n }\n\n /**\n * Register a callback to be notified when state changes\n */\n onStateChange(callback: () => void): void {\n this.stateChangeCallbacks.push(callback);\n }\n\n /**\n * Destroy the module instance\n */\n async destroy(): Promise<void> {\n if (this.isDestroyed) return;\n\n if (this.definition.handlers.onDestroyed) {\n await this.definition.handlers.onDestroyed(this.state);\n }\n\n this.isDestroyed = true;\n }\n\n /**\n * Get the current state (returns a snapshot)\n */\n getState(): T {\n return getStateSnapshot(this.state);\n }\n\n /**\n * Get the live observable state\n */\n getLiveState(): T {\n return this.state;\n }\n\n /**\n * Update state directly (merges with existing state)\n */\n updateState(patch: Partial<T>): void {\n Object.assign(this.state, patch);\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;AAsFO,MAAM,gBAAmB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAgD,IAAI;AAAA,EACpD;AAAA,EAER,WAAW,CACT,cACA,SACA;AAAA,IACA,KAAK,eAAe;AAAA,IACpB,KAAK,UAAU,WAAW,CAAC;AAAA;AAAA,EAM7B,SAAS,CAAC,IAA+B;AAAA,IACvC,KAAK,iBAAiB;AAAA,IACtB,OAAO;AAAA;AAAA,EAMT,QAAQ,CAAC,MAAc,IAA4B;AAAA,IACjD,KAAK,eAAe,IAAI,MAAM,EAAE;AAAA,IAChC,OAAO;AAAA;AAAA,EAMT,WAAW,CAAC,IAA+B;AAAA,IACzC,KAAK,mBAAmB;AAAA,IACxB,OAAO;AAAA;AAAA,EAMT,KAAK,GAA6B;AAAA,IAEhC,MAAM,YAAY,KAAK,iBAAiB,QAAQ,OAAO,KAAK,iBAAiB,WACzE,OAAO,KAAK,KAAK,YAAY,IAC7B,CAAC;AAAA,IAEL,OAAO;AAAA,MACL,MAAM,KAAK,QAAQ;AAAA,MACnB,SAAS,MAAM,KAAK,KAAK,eAAe,KAAK,CAAC;AAAA,MAC9C;AAAA,MACA,SAAS,KAAK,QAAQ;AAAA,MACtB,SAAS,KAAK,QAAQ;AAAA,MACtB,cAAc,KAAK;AAAA,MACnB,UAAU;AAAA,QACR,WAAW,KAAK;AAAA,QAChB,UAAU,KAAK;AAAA,QACf,aAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAAA;AAEJ;AAAA;AAKO,MAAM,SAAS;AAAA,EAIpB,WAAc,CACZ,SACA,SACoB;AAAA,IACpB,OAAO,IAAI,gBAAgB,SAAS,OAAO;AAAA;AAE/C;AAKO,IAAM,MAAM,IAAI;AAAA;AAKhB,MAAM,oBAA4C;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,uBAA0C,CAAC;AAAA,EAEnD,WAAW,CACT,QACA,YACA,eACA,eACA;AAAA,IACA,KAAK,SAAS;AAAA,IACd,KAAK,aAAa;AAAA,IAClB,KAAK,gBAAgB;AAAA,IACrB,KAAK,gBAAgB;AAAA,IAGrB,KAAK,QAAQ,sBAAyB,WAAW,cAA4B;AAAA,MAC3E,UAAU,CAAC,WAAwB;AAAA,QAEjC,KAAK,OAAO,kBAAkB,OAAO,OAAO,OAAO,SAAS;AAAA,QAE5D,KAAK,qBAAqB,QAAQ,QAAM,GAAG,CAAC;AAAA;AAAA,IAEhD,CAAC;AAAA,IAGD,KAAK,OAAO,UACV,WAAW,QAAQ,mBACnB,WAAW,SACX,WAAW,WACX,iBAAiB,KAAK,KAAK,CAC7B;AAAA,IAGA,YAAY,YAAY,YAAY,WAAW,SAAS,UAAU;AAAA,MAChE,QAAQ,IAAI,gDAAgD,yBAAyB,WAAW,MAAM;AAAA,MACtG,KAAK,OAAO,SAAS,YAAY,OAAO,WAAmB;AAAA,QACzD,QAAQ,IAAI,0CAA0C,cAAc,MAAM;AAAA,QAE1E,MAAM,YAA2B;AAAA,UAC/B,MAAM,OAAO;AAAA,UACb,SAAS,OAAO;AAAA,UAChB,QAAQ,OAAO;AAAA,QACjB;AAAA,QAEA,MAAM,OAAmB;AAAA,UACvB,QAAQ,KAAK,eAAe,QAAS;AAAA,QACvC;AAAA,QAEA,MAAM,UAAqC,KAAK,gBAC5C,KAAK,uBAAuB,IAC5B;AAAA,QAEJ,IAAI;AAAA,UACF,MAAM,QAAQ;AAAA,YACZ,QAAQ;AAAA,YACR,OAAO,KAAK;AAAA,YACZ;AAAA,YACA;AAAA,UACF,CAAC;AAAA,UACD,QAAQ,IAAI,8CAA8C,YAAY;AAAA,UACtE,OAAO,OAAO;AAAA,UACd,QAAQ,MAAM,6CAA6C,eAAe,KAAK;AAAA;AAAA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "CC570FF56ABF0FB064756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -33,7 +33,7 @@ class Engine {
|
|
|
33
33
|
return;
|
|
34
34
|
const wasmPath = options.wasmPath ?? "/hypen_engine_bg.wasm";
|
|
35
35
|
try {
|
|
36
|
-
const wasmModule = await import("../wasm/hypen_engine.js");
|
|
36
|
+
const wasmModule = await import("../wasm-browser/hypen_engine.js");
|
|
37
37
|
wasmInit = wasmModule.default;
|
|
38
38
|
WasmEngineClass = wasmModule.WasmEngine;
|
|
39
39
|
await wasmInit(wasmPath);
|
|
@@ -127,4 +127,4 @@ export {
|
|
|
127
127
|
|
|
128
128
|
export { Engine };
|
|
129
129
|
|
|
130
|
-
//# debugId=
|
|
130
|
+
//# debugId=ABF5E4E7E0C79CD064756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/engine.browser.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Browser-compatible wrapper around the WASM engine\n * Uses web target for browser environments\n */\n\n// Dynamic import path - will be configured at build time\n// For browser, the WASM needs to be served and initialized explicitly\nlet wasmInit: ((path?: string) => Promise<void>) | null = null;\nlet WasmEngineClass: any = null;\n\nexport type Patch = {\n type: \"create\" | \"setProp\" | \"setText\" | \"insert\" | \"move\" | \"remove\" | \"attachEvent\" | \"detachEvent\";\n id?: string;\n element_type?: string;\n props?: Record<string, any> | Map<string, any>;\n name?: string;\n value?: any;\n text?: string;\n parent_id?: string;\n before_id?: string;\n event_name?: string;\n};\n\nexport type Action = {\n name: string;\n payload?: any;\n sender?: string;\n};\n\nexport type RenderCallback = (patches: Patch[]) => void;\nexport type ActionHandler = (action: Action) => void | Promise<void>;\n\nexport type ResolvedComponent = {\n source: string;\n path: string;\n};\n\nexport type ComponentResolver = (\n componentName: string,\n contextPath: string | null\n) => ResolvedComponent | null;\n\nexport interface EngineInitOptions {\n /** Path to the WASM file (default: \"/hypen_engine_bg.wasm\") */\n wasmPath?: string;\n}\n\n/**\n * Recursively convert Maps and nested structures to plain objects\n */\nfunction mapToObject(value: any): any {\n if (value instanceof Map) {\n const obj: Record<string, any> = {};\n for (const [key, val] of value.entries()) {\n obj[key] = mapToObject(val);\n }\n return obj;\n } else if (Array.isArray(value)) {\n return value.map(mapToObject);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n const obj: Record<string, any> = {};\n for (const [key, val] of Object.entries(value)) {\n obj[key] = mapToObject(val);\n }\n return obj;\n }\n return value;\n}\n\n/**\n * Engine wraps the WASM engine and provides a TypeScript-friendly API\n * Browser version with explicit WASM initialization\n */\nexport class Engine {\n private wasmEngine: any = null;\n private initialized = false;\n\n /**\n * Initialize the WASM module\n * @param options - Initialization options including wasmPath\n */\n async init(options: EngineInitOptions = {}): Promise<void> {\n if (this.initialized) return;\n\n const wasmPath = options.wasmPath ?? \"/hypen_engine_bg.wasm\";\n\n // Dynamically import the WASM module\n // This allows the path to be configured at runtime\n try {\n const wasmModule: any = await import(\"../wasm/hypen_engine.js\");\n wasmInit = wasmModule.default;\n WasmEngineClass = wasmModule.WasmEngine;\n\n // Initialize WASM with explicit path\n await wasmInit!(wasmPath);\n\n this.wasmEngine = new WasmEngineClass();\n this.initialized = true;\n } catch (error) {\n console.error(\"[Hypen] Failed to initialize WASM engine:\", error);\n throw error;\n }\n }\n\n /**\n * Ensure the engine is initialized before operations\n */\n private ensureInitialized(): any {\n if (!this.wasmEngine) {\n throw new Error(\"Engine not initialized. Call init() first.\");\n }\n return this.wasmEngine;\n }\n\n /**\n * Set the render callback that receives patches\n */\n setRenderCallback(callback: RenderCallback): void {\n const engine = this.ensureInitialized();\n engine.setRenderCallback((patches: Patch[]) => {\n callback(patches);\n });\n }\n\n /**\n * Set the component resolver for dynamic component composition\n */\n setComponentResolver(resolver: ComponentResolver): void {\n const engine = this.ensureInitialized();\n engine.setComponentResolver((componentName: string, contextPath: string | null) => {\n const result = resolver(componentName, contextPath);\n return result;\n });\n }\n\n /**\n * Parse and render Hypen DSL source code\n */\n renderSource(source: string): void {\n const engine = this.ensureInitialized();\n engine.renderSource(source);\n }\n\n /**\n * Render a lazy component (for lazy route loading)\n */\n renderLazyComponent(source: string): void {\n const engine = this.ensureInitialized();\n engine.renderLazyComponent(source);\n }\n\n /**\n * Render a component into a specific parent node (subtree rendering)\n */\n renderInto(source: string, parentNodeId: string, state: Record<string, any>): void {\n const engine = this.ensureInitialized();\n const safeState = JSON.parse(JSON.stringify(state));\n engine.renderInto(source, parentNodeId, safeState);\n }\n\n /**\n * Notify the engine of state changes\n */\n notifyStateChange(paths: string[], currentState: Record<string, any>): void {\n const engine = this.ensureInitialized();\n\n const plainObject = JSON.parse(JSON.stringify(currentState));\n engine.updateState(plainObject);\n\n if (paths.length > 0) {\n console.debug(\"[Hypen] State changed:\", paths);\n }\n }\n\n /**\n * Update state (triggers re-render of affected nodes)\n * @deprecated Use notifyStateChange instead\n */\n updateState(statePatch: Record<string, any>): void {\n const engine = this.ensureInitialized();\n const plainObject = JSON.parse(JSON.stringify(statePatch));\n engine.updateState(plainObject);\n }\n\n /**\n * Dispatch an action\n */\n dispatchAction(name: string, payload?: any): void {\n const engine = this.ensureInitialized();\n console.log(`[Engine] Action dispatched: ${name}`);\n engine.dispatchAction(name, payload ?? null);\n }\n\n /**\n * Register an action handler\n */\n onAction(actionName: string, handler: ActionHandler): void {\n const engine = this.ensureInitialized();\n engine.onAction(actionName, (action: Action) => {\n const normalizedAction: Action = {\n ...action,\n payload: action.payload ? mapToObject(action.payload) : action.payload,\n };\n Promise.resolve(handler(normalizedAction)).catch(console.error);\n });\n }\n\n /**\n * Initialize a module\n */\n setModule(\n name: string,\n actions: string[],\n stateKeys: string[],\n initialState: Record<string, any>\n ): void {\n const engine = this.ensureInitialized();\n engine.setModule(name, actions, stateKeys, initialState);\n }\n\n /**\n * Get the current revision number\n */\n getRevision(): bigint {\n const engine = this.ensureInitialized();\n return engine.getRevision();\n }\n\n /**\n * Clear the engine tree\n */\n clearTree(): void {\n const engine = this.ensureInitialized();\n engine.clearTree();\n }\n\n /**\n * Debug method to inspect parsed components\n */\n debugParseComponent(source: string): string {\n const engine = this.ensureInitialized();\n return engine.debugParseComponent(source);\n }\n}\n"
|
|
5
|
+
"/**\n * Browser-compatible wrapper around the WASM engine\n * Uses web target for browser environments\n */\n\n// Dynamic import path - will be configured at build time\n// For browser, the WASM needs to be served and initialized explicitly\nlet wasmInit: ((path?: string) => Promise<void>) | null = null;\nlet WasmEngineClass: any = null;\n\nexport type Patch = {\n type: \"create\" | \"setProp\" | \"setText\" | \"insert\" | \"move\" | \"remove\" | \"attachEvent\" | \"detachEvent\";\n id?: string;\n element_type?: string;\n props?: Record<string, any> | Map<string, any>;\n name?: string;\n value?: any;\n text?: string;\n parent_id?: string;\n before_id?: string;\n event_name?: string;\n};\n\nexport type Action = {\n name: string;\n payload?: any;\n sender?: string;\n};\n\nexport type RenderCallback = (patches: Patch[]) => void;\nexport type ActionHandler = (action: Action) => void | Promise<void>;\n\nexport type ResolvedComponent = {\n source: string;\n path: string;\n};\n\nexport type ComponentResolver = (\n componentName: string,\n contextPath: string | null\n) => ResolvedComponent | null;\n\nexport interface EngineInitOptions {\n /** Path to the WASM file (default: \"/hypen_engine_bg.wasm\") */\n wasmPath?: string;\n}\n\n/**\n * Recursively convert Maps and nested structures to plain objects\n */\nfunction mapToObject(value: any): any {\n if (value instanceof Map) {\n const obj: Record<string, any> = {};\n for (const [key, val] of value.entries()) {\n obj[key] = mapToObject(val);\n }\n return obj;\n } else if (Array.isArray(value)) {\n return value.map(mapToObject);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n const obj: Record<string, any> = {};\n for (const [key, val] of Object.entries(value)) {\n obj[key] = mapToObject(val);\n }\n return obj;\n }\n return value;\n}\n\n/**\n * Engine wraps the WASM engine and provides a TypeScript-friendly API\n * Browser version with explicit WASM initialization\n */\nexport class Engine {\n private wasmEngine: any = null;\n private initialized = false;\n\n /**\n * Initialize the WASM module\n * @param options - Initialization options including wasmPath\n */\n async init(options: EngineInitOptions = {}): Promise<void> {\n if (this.initialized) return;\n\n const wasmPath = options.wasmPath ?? \"/hypen_engine_bg.wasm\";\n\n // Dynamically import the WASM module\n // This allows the path to be configured at runtime\n try {\n const wasmModule: any = await import(\"../wasm-browser/hypen_engine.js\");\n wasmInit = wasmModule.default;\n WasmEngineClass = wasmModule.WasmEngine;\n\n // Initialize WASM with explicit path\n await wasmInit!(wasmPath);\n\n this.wasmEngine = new WasmEngineClass();\n this.initialized = true;\n } catch (error) {\n console.error(\"[Hypen] Failed to initialize WASM engine:\", error);\n throw error;\n }\n }\n\n /**\n * Ensure the engine is initialized before operations\n */\n private ensureInitialized(): any {\n if (!this.wasmEngine) {\n throw new Error(\"Engine not initialized. Call init() first.\");\n }\n return this.wasmEngine;\n }\n\n /**\n * Set the render callback that receives patches\n */\n setRenderCallback(callback: RenderCallback): void {\n const engine = this.ensureInitialized();\n engine.setRenderCallback((patches: Patch[]) => {\n callback(patches);\n });\n }\n\n /**\n * Set the component resolver for dynamic component composition\n */\n setComponentResolver(resolver: ComponentResolver): void {\n const engine = this.ensureInitialized();\n engine.setComponentResolver((componentName: string, contextPath: string | null) => {\n const result = resolver(componentName, contextPath);\n return result;\n });\n }\n\n /**\n * Parse and render Hypen DSL source code\n */\n renderSource(source: string): void {\n const engine = this.ensureInitialized();\n engine.renderSource(source);\n }\n\n /**\n * Render a lazy component (for lazy route loading)\n */\n renderLazyComponent(source: string): void {\n const engine = this.ensureInitialized();\n engine.renderLazyComponent(source);\n }\n\n /**\n * Render a component into a specific parent node (subtree rendering)\n */\n renderInto(source: string, parentNodeId: string, state: Record<string, any>): void {\n const engine = this.ensureInitialized();\n const safeState = JSON.parse(JSON.stringify(state));\n engine.renderInto(source, parentNodeId, safeState);\n }\n\n /**\n * Notify the engine of state changes\n */\n notifyStateChange(paths: string[], currentState: Record<string, any>): void {\n const engine = this.ensureInitialized();\n\n const plainObject = JSON.parse(JSON.stringify(currentState));\n engine.updateState(plainObject);\n\n if (paths.length > 0) {\n console.debug(\"[Hypen] State changed:\", paths);\n }\n }\n\n /**\n * Update state (triggers re-render of affected nodes)\n * @deprecated Use notifyStateChange instead\n */\n updateState(statePatch: Record<string, any>): void {\n const engine = this.ensureInitialized();\n const plainObject = JSON.parse(JSON.stringify(statePatch));\n engine.updateState(plainObject);\n }\n\n /**\n * Dispatch an action\n */\n dispatchAction(name: string, payload?: any): void {\n const engine = this.ensureInitialized();\n console.log(`[Engine] Action dispatched: ${name}`);\n engine.dispatchAction(name, payload ?? null);\n }\n\n /**\n * Register an action handler\n */\n onAction(actionName: string, handler: ActionHandler): void {\n const engine = this.ensureInitialized();\n engine.onAction(actionName, (action: Action) => {\n const normalizedAction: Action = {\n ...action,\n payload: action.payload ? mapToObject(action.payload) : action.payload,\n };\n Promise.resolve(handler(normalizedAction)).catch(console.error);\n });\n }\n\n /**\n * Initialize a module\n */\n setModule(\n name: string,\n actions: string[],\n stateKeys: string[],\n initialState: Record<string, any>\n ): void {\n const engine = this.ensureInitialized();\n engine.setModule(name, actions, stateKeys, initialState);\n }\n\n /**\n * Get the current revision number\n */\n getRevision(): bigint {\n const engine = this.ensureInitialized();\n return engine.getRevision();\n }\n\n /**\n * Clear the engine tree\n */\n clearTree(): void {\n const engine = this.ensureInitialized();\n engine.clearTree();\n }\n\n /**\n * Debug method to inspect parsed components\n */\n debugParseComponent(source: string): string {\n const engine = this.ensureInitialized();\n return engine.debugParseComponent(source);\n }\n}\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
8
|
+
"debugId": "ABF5E4E7E0C79CD064756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/src/engine.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import"../chunk-5va59f7m.js";
|
|
2
2
|
|
|
3
3
|
// src/engine.ts
|
|
4
|
-
import { WasmEngine } from "../wasm/hypen_engine.js";
|
|
4
|
+
import { WasmEngine } from "../wasm-node/hypen_engine.js";
|
|
5
5
|
|
|
6
6
|
class Engine {
|
|
7
7
|
wasmEngine = null;
|
|
@@ -49,7 +49,8 @@ class Engine {
|
|
|
49
49
|
if (paths.length === 0) {
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
const plainValues = JSON.parse(JSON.stringify(values));
|
|
53
|
+
engine.updateStateSparse(paths, plainValues);
|
|
53
54
|
console.debug("[Hypen] State changed (sparse):", paths);
|
|
54
55
|
}
|
|
55
56
|
notifyStateChangeFull(paths, currentState) {
|
|
@@ -98,4 +99,4 @@ export {
|
|
|
98
99
|
|
|
99
100
|
export { Engine };
|
|
100
101
|
|
|
101
|
-
//# debugId=
|
|
102
|
+
//# debugId=D2189D9A62B205BE64756E2164756E21
|