@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.
Files changed (40) hide show
  1. package/README.md +199 -154
  2. package/dist/src/app.js +2 -1
  3. package/dist/src/app.js.map +3 -3
  4. package/dist/src/engine.browser.js +2 -2
  5. package/dist/src/engine.browser.js.map +2 -2
  6. package/dist/src/engine.js +4 -3
  7. package/dist/src/engine.js.map +3 -3
  8. package/dist/src/index.js +18 -6
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/plugin.js +126 -0
  11. package/dist/src/plugin.js.map +10 -0
  12. package/dist/src/resolver.js +102 -0
  13. package/dist/src/resolver.js.map +10 -0
  14. package/dist/src/router.js +37 -18
  15. package/dist/src/router.js.map +3 -3
  16. package/dist/src/state.js +9 -1
  17. package/dist/src/state.js.map +3 -3
  18. package/package.json +15 -2
  19. package/src/app.ts +1 -0
  20. package/src/engine.browser.ts +1 -1
  21. package/src/engine.ts +4 -2
  22. package/src/index.ts +21 -1
  23. package/src/plugin.ts +219 -0
  24. package/src/resolver.ts +216 -0
  25. package/src/router.ts +43 -21
  26. package/src/state.ts +20 -0
  27. package/wasm-browser/README.md +425 -0
  28. package/wasm-browser/hypen_engine.d.ts +151 -0
  29. package/wasm-browser/hypen_engine.js +811 -0
  30. package/wasm-browser/hypen_engine_bg.js +736 -0
  31. package/wasm-browser/hypen_engine_bg.wasm +0 -0
  32. package/wasm-browser/hypen_engine_bg.wasm.d.ts +30 -0
  33. package/wasm-browser/package.json +15 -0
  34. package/wasm-node/README.md +425 -0
  35. package/wasm-node/hypen_engine.d.ts +97 -0
  36. package/wasm-node/hypen_engine.js +751 -0
  37. package/wasm-node/hypen_engine_bg.js +736 -0
  38. package/wasm-node/hypen_engine_bg.wasm +0 -0
  39. package/wasm-node/hypen_engine_bg.wasm.d.ts +30 -0
  40. package/wasm-node/package.json +11 -0
package/README.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # @hypen-space/core
2
2
 
3
- Platform-agnostic reactive UI runtime for the Hypen declarative UI language.
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 a stateful module
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. Set up render callback (you provide the renderer)
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
- ## Component Discovery
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
- # Sibling files
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
- // Lifecycle hooks
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
- // Action handlers
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("Module cleanup");
148
+ console.log("Cleanup");
150
149
  })
151
150
 
152
151
  .build();
153
152
  ```
154
153
 
155
- ## State Management
154
+ The `next()` callback synchronizes state changes with the engine after async operations.
155
+
156
+ ## State
156
157
 
157
- Observable state with automatic change tracking:
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-based or pathname-based routing:
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("Route:", state.currentPath);
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
- ## Built-in Components
232
+ Use built-in components in templates:
201
233
 
202
- Framework-provided components for routing:
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 { Router, Route, Link } from "@hypen-space/core";
206
-
207
- // Use in templates:
208
- // Router {
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
- ## Remote UI (WebSocket)
253
+ Supported file patterns:
254
+
255
+ ```
256
+ Counter/
257
+ ├── component.hypen # Template
258
+ └── component.ts # Module
216
259
 
217
- Connect to a remote Hypen server:
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
- Cross-module communication:
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", authModuleInstance);
249
- context.registerModule("cart", cartModuleInstance);
324
+ context.registerModule("auth", authModule);
325
+ context.registerModule("cart", cartModule);
250
326
 
251
- const auth = context.getModule("auth");
252
- const cartState = context.getModule("cart").getState();
327
+ // Cross-module access
328
+ const user = context.getModule("auth").getState().user;
253
329
 
254
- // Event system
255
- context.on("userLoggedIn", (user) => console.log("Logged in:", user));
330
+ // Event bus
331
+ context.on("userLoggedIn", (user) => { /* ... */ });
256
332
  context.emit("userLoggedIn", { id: "1", name: "Ian" });
257
333
  ```
258
334
 
259
- ## Custom Renderer
260
-
261
- Implement the `Renderer` interface for any platform:
335
+ ## Browser vs Node.js
262
336
 
263
337
  ```typescript
264
- import { BaseRenderer, type Patch } from "@hypen-space/core";
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
- class MyRenderer extends BaseRenderer {
267
- protected onCreate(id: string, type: string, props: Record<string, any>) {
268
- // Create element
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 - Engine, app, state, router, discovery, loader |
293
- | `@hypen-space/core/engine` | Low-level WASM engine API |
294
- | `@hypen-space/core/engine/browser` | Browser-optimized engine (explicit WASM init) |
295
- | `@hypen-space/core/app` | Module builder and HypenModuleInstance |
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 interface |
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=220ACA4FDA4DC86164756E2164756E21
161
+ //# debugId=CC570FF56ABF0FB064756E2164756E21
@@ -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": "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",
8
- "debugId": "220ACA4FDA4DC86164756E2164756E21",
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=FB3794C86EF3E0CF64756E2164756E21
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": "FB3794C86EF3E0CF64756E2164756E21",
8
+ "debugId": "ABF5E4E7E0C79CD064756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -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
- engine.updateStateSparse(paths, values);
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=9CDE98592668DEA364756E2164756E21
102
+ //# debugId=D2189D9A62B205BE64756E2164756E21