@hypen-space/core 0.4.3 → 0.4.11

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 (72) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +79 -22
  3. package/dist/app.js +248 -155
  4. package/dist/app.js.map +5 -5
  5. package/dist/components/builtin.js +251 -158
  6. package/dist/components/builtin.js.map +6 -6
  7. package/dist/context.js +1 -1
  8. package/dist/context.js.map +1 -1
  9. package/dist/discovery.d.ts +1 -1
  10. package/dist/discovery.js +249 -156
  11. package/dist/discovery.js.map +6 -6
  12. package/dist/disposable.js +1 -1
  13. package/dist/disposable.js.map +1 -1
  14. package/dist/engine.browser.d.ts +6 -0
  15. package/dist/engine.browser.js +192 -5
  16. package/dist/engine.browser.js.map +5 -4
  17. package/dist/engine.d.ts +6 -0
  18. package/dist/engine.js +192 -5
  19. package/dist/engine.js.map +5 -4
  20. package/dist/events.js +1 -1
  21. package/dist/events.js.map +1 -1
  22. package/dist/index.browser.d.ts +1 -1
  23. package/dist/index.browser.js +248 -155
  24. package/dist/index.browser.js.map +6 -6
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +254 -158
  27. package/dist/index.js.map +7 -7
  28. package/dist/loader.js +1 -1
  29. package/dist/loader.js.map +1 -1
  30. package/dist/logger.js +245 -0
  31. package/dist/logger.js.map +10 -0
  32. package/dist/managed-router.d.ts +3 -4
  33. package/dist/plugin.js +1 -1
  34. package/dist/plugin.js.map +1 -1
  35. package/dist/remote/client.js +34 -2
  36. package/dist/remote/client.js.map +3 -3
  37. package/dist/remote/index.js +609 -163
  38. package/dist/remote/index.js.map +8 -7
  39. package/dist/remote/server.d.ts +46 -15
  40. package/dist/remote/server.js +609 -163
  41. package/dist/remote/server.js.map +8 -7
  42. package/dist/renderer.js +1 -1
  43. package/dist/renderer.js.map +1 -1
  44. package/dist/result.d.ts +18 -0
  45. package/dist/router.js +1 -1
  46. package/dist/router.js.map +1 -1
  47. package/dist/types.d.ts +1 -1
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +9 -0
  50. package/package.json +1 -1
  51. package/src/app.ts +162 -41
  52. package/src/components/builtin.ts +3 -4
  53. package/src/discovery.ts +2 -2
  54. package/src/engine.browser.ts +27 -4
  55. package/src/engine.ts +27 -4
  56. package/src/index.browser.ts +0 -2
  57. package/src/index.ts +3 -2
  58. package/src/managed-router.ts +5 -6
  59. package/src/remote/server.ts +116 -21
  60. package/src/result.ts +48 -0
  61. package/src/types.ts +1 -1
  62. package/wasm-browser/hypen_engine.d.ts +3 -3
  63. package/wasm-browser/hypen_engine.js +73 -66
  64. package/wasm-browser/hypen_engine_bg.wasm +0 -0
  65. package/wasm-browser/hypen_engine_bg.wasm.d.ts +3 -3
  66. package/wasm-browser/package.json +1 -1
  67. package/wasm-node/hypen_engine.js +74 -66
  68. package/wasm-node/hypen_engine_bg.wasm +0 -0
  69. package/wasm-node/hypen_engine_bg.wasm.d.ts +3 -3
  70. package/wasm-node/package.json +1 -1
  71. package/dist/module-registry.d.ts +0 -42
  72. package/src/module-registry.ts +0 -76
@@ -6,6 +6,6 @@
6
6
  "/**\n * Renderer abstraction interface\n *\n * Renderers are pluggable and can be implemented for different platforms\n * (DOM, Canvas, Native, etc.)\n */\n\nimport type { Patch } from \"./types.js\";\nimport { frameworkLoggers } from \"./logger.js\";\n\nconst log = frameworkLoggers.renderer;\n\n/**\n * Renderer interface that all platform renderers must implement\n */\nexport interface Renderer {\n /**\n * Apply a batch of patches to the render tree\n */\n applyPatches(patches: Patch[]): void;\n\n /**\n * Get a node by its ID (optional, for debugging)\n */\n getNode?(id: string): any;\n\n /**\n * Clear the entire render tree\n */\n clear?(): void;\n}\n\n/**\n * Base renderer class with common utilities\n */\nexport abstract class BaseRenderer implements Renderer {\n protected nodes: Map<string, any> = new Map();\n\n abstract applyPatches(patches: Patch[]): void;\n\n getNode(id: string): any {\n return this.nodes.get(id);\n }\n\n clear(): void {\n this.nodes.clear();\n }\n\n /**\n * Apply a single patch\n */\n protected applyPatch(patch: Patch): void {\n switch (patch.type) {\n case \"create\":\n this.onCreate(patch.id!, patch.elementType!, patch.props || {});\n break;\n case \"setProp\":\n this.onSetProp(patch.id!, patch.name!, patch.value);\n break;\n case \"setText\":\n this.onSetText(patch.id!, patch.text!);\n break;\n case \"insert\":\n this.onInsert(patch.parentId!, patch.id!, patch.beforeId);\n break;\n case \"move\":\n this.onMove(patch.parentId!, patch.id!, patch.beforeId);\n break;\n case \"remove\":\n this.onRemove(patch.id!);\n break;\n case \"attachEvent\":\n this.onAttachEvent(patch.id!, patch.eventName!);\n break;\n case \"detachEvent\":\n this.onDetachEvent(patch.id!, patch.eventName!);\n break;\n }\n }\n\n /**\n * Platform-specific patch handlers\n */\n protected abstract onCreate(id: string, elementType: string, props: Record<string, any>): void;\n protected abstract onSetProp(id: string, name: string, value: any): void;\n protected abstract onSetText(id: string, text: string): void;\n protected abstract onInsert(parentId: string, id: string, beforeId?: string): void;\n protected abstract onMove(parentId: string, id: string, beforeId?: string): void;\n protected abstract onRemove(id: string): void;\n protected abstract onAttachEvent(id: string, eventName: string): void;\n protected abstract onDetachEvent(id: string, eventName: string): void;\n}\n\n/**\n * Console/Debug renderer that logs patches\n */\nexport class ConsoleRenderer implements Renderer {\n applyPatches(patches: Patch[]): void {\n console.group(\"Hypen Patches\");\n for (const patch of patches) {\n console.log(patch);\n }\n console.groupEnd();\n }\n}\n"
7
7
  ],
8
8
  "mappings": "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",
9
- "debugId": "1A339EED8B6121F964756E2164756E21",
9
+ "debugId": "FCB7787E6FDE288364756E2164756E21",
10
10
  "names": []
11
11
  }
package/dist/result.d.ts CHANGED
@@ -114,3 +114,21 @@ export declare class StateError extends HypenError {
114
114
  readonly path?: string;
115
115
  constructor(message: string, path?: string, cause?: unknown);
116
116
  }
117
+ /**
118
+ * Error thrown when parsing Hypen DSL source fails
119
+ */
120
+ export declare class ParseError extends HypenError {
121
+ readonly source?: string;
122
+ constructor(message: string, source?: string, cause?: unknown);
123
+ }
124
+ /**
125
+ * Error thrown when rendering fails
126
+ */
127
+ export declare class RenderError extends HypenError {
128
+ constructor(message: string, cause?: unknown);
129
+ }
130
+ /**
131
+ * Classify a WASM engine error string into the appropriate HypenError subclass.
132
+ * The engine returns JsValue error strings with known prefixes.
133
+ */
134
+ export declare function classifyEngineError(err: unknown): HypenError;
package/dist/router.js CHANGED
@@ -677,4 +677,4 @@ export {
677
677
  HypenRouter
678
678
  };
679
679
 
680
- //# debugId=1EA602E55D61B3C664756E2164756E21
680
+ //# debugId=00FB5513845955B364756E2164756E21
@@ -7,6 +7,6 @@
7
7
  "/**\n * Hypen Router - Declarative routing system\n * Integrated with Hypen's reactive state management\n */\n\nimport { createObservableState, getStateSnapshot } from \"./state.js\";\nimport { frameworkLoggers } from \"./logger.js\";\n\nconst log = frameworkLoggers.router;\n\nexport type RouteMatch = {\n params: Record<string, string>;\n query: Record<string, string>;\n path: string;\n};\n\nexport type RouteState = {\n currentPath: string;\n params: Record<string, string>;\n query: Record<string, string>;\n previousPath: string | null;\n};\n\nexport type RouteChangeCallback = (route: RouteState) => void;\n\n/**\n * Hypen Router - Manages application routing with pattern matching\n */\nexport class HypenRouter {\n private state: RouteState;\n private subscribers = new Set<RouteChangeCallback>();\n private isInitialized = false;\n private isUpdating = false;\n\n constructor() {\n // Create observable state for reactivity\n this.state = createObservableState<RouteState>(\n {\n currentPath: \"/\",\n params: {},\n query: {},\n previousPath: null,\n },\n {\n onChange: () => {\n this.notifySubscribers();\n },\n }\n );\n\n // Initialize from browser if available\n if (typeof window !== \"undefined\") {\n this.initializeBrowserSync();\n }\n }\n\n /**\n * Initialize browser history sync\n */\n private initializeBrowserSync() {\n // Get initial path from hash or pathname\n const initialPath = this.getPathFromBrowser();\n this.state.currentPath = initialPath;\n this.state.params = {};\n this.state.query = this.parseQuery();\n\n // Listen for browser back/forward\n window.addEventListener(\"popstate\", () => {\n const newPath = this.getPathFromBrowser();\n this.updatePath(newPath, false); // Don't push to history again\n });\n\n // Listen for hash changes\n window.addEventListener(\"hashchange\", () => {\n // Don't respond to hashchange events we triggered ourselves\n if (this.isUpdating) return;\n const newPath = this.getPathFromBrowser();\n this.updatePath(newPath, false);\n });\n\n this.isInitialized = true;\n log.debug(\"Router initialized at:\", initialPath);\n }\n\n /**\n * Get path from browser URL (supports both hash and pathname)\n */\n private getPathFromBrowser(): string {\n if (typeof window === \"undefined\") return \"/\";\n\n // Prefer hash-based routing for simplicity\n const hash = window.location.hash.slice(1);\n if (hash) return hash;\n\n // Fallback to pathname\n return window.location.pathname;\n }\n\n /**\n * Parse query string from URL\n */\n private parseQuery(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n\n const query: Record<string, string> = {};\n const searchParams = new URLSearchParams(window.location.search);\n\n searchParams.forEach((value, key) => {\n query[key] = value;\n });\n\n return query;\n }\n\n /**\n * Navigate to a new path\n */\n push(path: string) {\n log.debug(\"push:\", path);\n this.updatePath(path, true);\n }\n\n /**\n * Replace current path without adding to history\n */\n replace(path: string) {\n log.debug(\"replace:\", path);\n this.updatePath(path, true, true);\n }\n\n /**\n * Go back in history\n */\n back() {\n log.debug(\"back\");\n if (typeof window !== \"undefined\") {\n window.history.back();\n }\n }\n\n /**\n * Go forward in history\n */\n forward() {\n log.debug(\"forward\");\n if (typeof window !== \"undefined\") {\n window.history.forward();\n }\n }\n\n /**\n * Update the current path\n */\n private updatePath(\n path: string,\n updateBrowser: boolean,\n replace: boolean = false\n ) {\n // Prevent re-entrant updates\n if (this.isUpdating) return;\n\n this.isUpdating = true;\n try {\n const oldPath = this.state.currentPath;\n this.state.previousPath = oldPath;\n this.state.currentPath = path;\n this.state.query = this.parseQuery();\n\n // Notify subscribers synchronously before any browser events\n this.notifySubscribers();\n\n // Update browser URL if needed\n if (updateBrowser && typeof window !== \"undefined\") {\n const url = \"#\" + path;\n if (replace) {\n window.history.replaceState(null, \"\", url);\n } else {\n window.history.pushState(null, \"\", url);\n }\n\n // Manually trigger hashchange event\n const hashChangeEvent = new HashChangeEvent(\"hashchange\", {\n oldURL: window.location.href.replace(window.location.hash, \"#\" + oldPath),\n newURL: window.location.href,\n });\n window.dispatchEvent(hashChangeEvent);\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n /**\n * Get current path\n */\n getCurrentPath(): string {\n return this.state.currentPath;\n }\n\n /**\n * Get current route params\n */\n getParams(): Record<string, string> {\n return { ...this.state.params };\n }\n\n /**\n * Get current query params\n */\n getQuery(): Record<string, string> {\n return { ...this.state.query };\n }\n\n /**\n * Get full route state snapshot\n */\n getState(): RouteState {\n return getStateSnapshot(this.state);\n }\n\n /**\n * Match a pattern against a path\n */\n matchPath(pattern: string, path: string): RouteMatch | null {\n // Handle invalid inputs gracefully\n if (!pattern || typeof pattern !== 'string') {\n return null;\n }\n if (!path || typeof path !== 'string') {\n return null;\n }\n\n // Exact match\n if (pattern === path) {\n return {\n params: {},\n query: this.state.query,\n path,\n };\n }\n\n // Wildcard match: /dashboard/* matches /dashboard/anything\n if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -2);\n if (path === prefix || path.startsWith(prefix + \"/\")) {\n return {\n params: {},\n query: this.state.query,\n path,\n };\n }\n return null;\n }\n\n // Parameter match: /users/:id matches /users/123\n const paramNames: string[] = [];\n const regexPattern = pattern\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {\n paramNames.push(name);\n return \"([^/]+)\";\n })\n .replace(/\\*/g, \".*\");\n\n const regex = new RegExp(`^${regexPattern}$`);\n const match = path.match(regex);\n\n if (!match) return null;\n\n // Extract params\n const params: Record<string, string> = {};\n paramNames.forEach((name, i) => {\n const value = match[i + 1];\n if (value !== undefined) {\n params[name] = decodeURIComponent(value);\n }\n });\n\n return {\n params,\n query: this.state.query,\n path,\n };\n }\n\n /**\n * Subscribe to route changes\n */\n onNavigate(callback: RouteChangeCallback): () => void {\n this.subscribers.add(callback);\n\n // Call immediately with current state\n try {\n callback(this.getState());\n } catch (error) {\n log.error(\"Error in route subscriber:\", error);\n }\n\n // Return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Notify all subscribers of route change\n */\n private notifySubscribers() {\n const routeState = this.getState();\n this.subscribers.forEach((callback) => {\n try {\n callback(routeState);\n } catch (error) {\n log.error(\"Error in route subscriber:\", error);\n }\n });\n }\n\n /**\n * Check if a path matches the current route\n */\n isActive(pattern: string): boolean {\n return this.matchPath(pattern, this.state.currentPath) !== null;\n }\n\n /**\n * Get a URL with query params\n */\n buildUrl(path: string, query?: Record<string, string>): string {\n if (!query || Object.keys(query).length === 0) {\n return path;\n }\n\n const queryString = new URLSearchParams(query).toString();\n return `${path}?${queryString}`;\n }\n}\n"
8
8
  ],
9
9
  "mappings": "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",
10
- "debugId": "1EA602E55D61B3C664756E2164756E21",
10
+ "debugId": "00FB5513845955B364756E2164756E21",
11
11
  "names": []
12
12
  }
package/dist/types.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * packages can import them without pulling in any WASM code.
6
6
  */
7
7
  export type Patch = {
8
- type: "create" | "setProp" | "setText" | "insert" | "move" | "remove" | "attachEvent" | "detachEvent";
8
+ type: "create" | "setProp" | "removeProp" | "setText" | "insert" | "move" | "remove" | "attachEvent" | "detachEvent";
9
9
  id?: string;
10
10
  elementType?: string;
11
11
  props?: Record<string, any>;
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# debugId=9FCB033A2878230664756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "9FCB033A2878230664756E2164756E21",
8
+ "names": []
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypen-space/core",
3
- "version": "0.4.3",
3
+ "version": "0.4.11",
4
4
  "description": "Hypen core engine - Platform-agnostic reactive UI runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/app.ts CHANGED
@@ -21,22 +21,12 @@ import { createLogger } from "./logger.js";
21
21
 
22
22
  const log = createLogger("ModuleInstance");
23
23
 
24
- export type RouterContext = {
25
- root: HypenRouter;
26
- current?: HypenRouter;
27
- parent?: HypenRouter;
28
- };
29
-
30
- export type ActionContext = {
24
+ export type ActionContext<P = unknown> = {
31
25
  name: string;
32
- payload?: unknown;
26
+ payload?: P;
33
27
  sender?: string;
34
28
  };
35
29
 
36
- export type ActionNext = {
37
- router: HypenRouter; // Direct access to router instance (from nearest parent)
38
- };
39
-
40
30
  export type GlobalContext = {
41
31
  getModule: <T = unknown>(id: string) => ModuleReference<T>;
42
32
  hasModule: (id: string) => boolean;
@@ -44,7 +34,7 @@ export type GlobalContext = {
44
34
  getGlobalState: () => Record<string, unknown>;
45
35
  emit: (event: string, payload?: unknown) => void;
46
36
  on: (event: string, handler: (payload?: unknown) => void) => () => void;
47
- __router?: unknown; // Internal: router instance for built-in Router component
37
+ router: HypenRouter | null;
48
38
  };
49
39
 
50
40
  export type LifecycleHandler<T> = (
@@ -55,17 +45,16 @@ export type LifecycleHandler<T> = (
55
45
  /**
56
46
  * Action handler context - all parameters available explicitly
57
47
  */
58
- export interface ActionHandlerContext<T> {
59
- action: ActionContext;
48
+ export interface ActionHandlerContext<T, P = unknown> {
49
+ action: ActionContext<P>;
60
50
  state: T;
61
- next: ActionNext;
62
51
  context: GlobalContext;
63
52
  }
64
53
 
65
54
  /**
66
55
  * Action handler - receives all context in a single object
67
56
  */
68
- export type ActionHandler<T> = (ctx: ActionHandlerContext<T>) => void | Promise<void>;
57
+ export type ActionHandler<T, P = unknown> = (ctx: ActionHandlerContext<T, P>) => void | Promise<void>;
69
58
 
70
59
  /**
71
60
  * Context passed to onDisconnect handler
@@ -152,7 +141,7 @@ export interface HypenModuleDefinition<T = unknown> {
152
141
  template?: string;
153
142
  handlers: {
154
143
  onCreated?: LifecycleHandler<T>;
155
- onAction: Map<string, ActionHandler<T>>;
144
+ onAction: Map<string, ActionHandler<T, any>>;
156
145
  onDestroyed?: LifecycleHandler<T>;
157
146
  /** Called when client disconnects (session persists for TTL) */
158
147
  onDisconnect?: DisconnectHandler<T>;
@@ -177,20 +166,23 @@ export class HypenAppBuilder<T> {
177
166
  private initialState: T;
178
167
  private options: { persist?: boolean; version?: number; name?: string };
179
168
  private createdHandler?: LifecycleHandler<T>;
180
- private actionHandlers: Map<string, ActionHandler<T>> = new Map();
169
+ private actionHandlers: Map<string, ActionHandler<T, any>> = new Map();
181
170
  private destroyedHandler?: LifecycleHandler<T>;
182
171
  private disconnectHandler?: DisconnectHandler<T>;
183
172
  private reconnectHandler?: ReconnectHandler<T>;
184
173
  private expireHandler?: ExpireHandler;
185
174
  private errorHandler?: ErrorHandler<T>;
186
175
  private template?: string;
176
+ private _registry?: Map<string, HypenModuleDefinition>;
187
177
 
188
178
  constructor(
189
179
  initialState: T,
190
- options?: { persist?: boolean; version?: number; name?: string }
180
+ options?: { persist?: boolean; version?: number; name?: string },
181
+ registry?: Map<string, HypenModuleDefinition>
191
182
  ) {
192
183
  this.initialState = initialState;
193
184
  this.options = options || {};
185
+ this._registry = registry;
194
186
  }
195
187
 
196
188
  /**
@@ -202,10 +194,24 @@ export class HypenAppBuilder<T> {
202
194
  }
203
195
 
204
196
  /**
205
- * Register a handler for a specific action
197
+ * Register a handler for a specific action.
198
+ * Optionally provide a payload type parameter for typed action payloads.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * // Typed payload:
203
+ * .onAction<{ amount: number }>("add", ({ action, state }) => {
204
+ * action.payload.amount; // fully typed
205
+ * })
206
+ *
207
+ * // Untyped (payload is unknown):
208
+ * .onAction("add", ({ action, state }) => {
209
+ * action.payload; // unknown
210
+ * })
211
+ * ```
206
212
  */
207
- onAction(name: string, fn: ActionHandler<T>): this {
208
- this.actionHandlers.set(name, fn);
213
+ onAction<P = unknown>(name: string, fn: ActionHandler<T, P>): this {
214
+ this.actionHandlers.set(name, fn as ActionHandler<T, any>);
209
215
  return this;
210
216
  }
211
217
 
@@ -319,7 +325,7 @@ export class HypenAppBuilder<T> {
319
325
  ? Object.keys(this.initialState)
320
326
  : [];
321
327
 
322
- return {
328
+ const definition: HypenModuleDefinition<T> = {
323
329
  name: this.options.name,
324
330
  actions: Array.from(this.actionHandlers.keys()),
325
331
  stateKeys,
@@ -337,13 +343,27 @@ export class HypenAppBuilder<T> {
337
343
  onError: this.errorHandler,
338
344
  },
339
345
  };
346
+
347
+ // Auto-register in the app registry when the module has a name
348
+ if (this.options.name && this._registry) {
349
+ this._registry.set(this.options.name, definition as HypenModuleDefinition);
350
+ }
351
+
352
+ return definition;
340
353
  }
341
354
  }
342
355
 
343
356
  /**
344
- * Hypen App API
357
+ * Hypen App API — singleton factory and component registry.
358
+ *
359
+ * Modules built with a `name` are automatically registered here.
360
+ * Consumers (ManagedRouter, RemoteServer, ComponentResolver) read from this
361
+ * registry instead of requiring a separate ModuleRegistry instance.
345
362
  */
346
363
  export class HypenApp {
364
+ /** @internal */
365
+ readonly _registry = new Map<string, HypenModuleDefinition>();
366
+
347
367
  /**
348
368
  * Define the initial state for a module
349
369
  */
@@ -351,7 +371,83 @@ export class HypenApp {
351
371
  initial: T,
352
372
  options?: { persist?: boolean; version?: number; name?: string }
353
373
  ): HypenAppBuilder<T> {
354
- return new HypenAppBuilder(initial, options);
374
+ return new HypenAppBuilder(initial, options, this._registry);
375
+ }
376
+
377
+ /**
378
+ * Convenience: start a module builder with a name pre-set.
379
+ *
380
+ * @example
381
+ * ```typescript
382
+ * export default app
383
+ * .module("Settings")
384
+ * .defineState({ theme: "dark" })
385
+ * .ui(hypen`...`);
386
+ * ```
387
+ */
388
+ module(name: string) {
389
+ const registry = this._registry;
390
+ return {
391
+ defineState: <T>(
392
+ initial: T,
393
+ options?: { persist?: boolean; version?: number }
394
+ ): HypenAppBuilder<T> => {
395
+ return new HypenAppBuilder(initial, { ...options, name }, registry);
396
+ },
397
+ };
398
+ }
399
+
400
+ // ---------------------------------------------------------------------------
401
+ // Registry API
402
+ // ---------------------------------------------------------------------------
403
+
404
+ /**
405
+ * Get a registered module definition by component name.
406
+ */
407
+ get(name: string): HypenModuleDefinition | undefined {
408
+ return this._registry.get(name);
409
+ }
410
+
411
+ /**
412
+ * Check if a module definition is registered.
413
+ */
414
+ has(name: string): boolean {
415
+ return this._registry.has(name);
416
+ }
417
+
418
+ /**
419
+ * Read-only view of all registered component definitions.
420
+ */
421
+ get components(): ReadonlyMap<string, HypenModuleDefinition> {
422
+ return this._registry;
423
+ }
424
+
425
+ /**
426
+ * Get all registered component names.
427
+ */
428
+ getNames(): string[] {
429
+ return Array.from(this._registry.keys());
430
+ }
431
+
432
+ /**
433
+ * Number of registered definitions.
434
+ */
435
+ get size(): number {
436
+ return this._registry.size;
437
+ }
438
+
439
+ /**
440
+ * Unregister a module definition.
441
+ */
442
+ unregister(name: string): void {
443
+ this._registry.delete(name);
444
+ }
445
+
446
+ /**
447
+ * Clear all registered definitions.
448
+ */
449
+ clear(): void {
450
+ this._registry.clear();
355
451
  }
356
452
  }
357
453
 
@@ -368,19 +464,19 @@ export class HypenModuleInstance<T extends object = any> {
368
464
  private definition: HypenModuleDefinition<T>;
369
465
  private state: T;
370
466
  private isDestroyed = false;
371
- private routerContext?: RouterContext;
467
+ private router: HypenRouter | null;
372
468
  private globalContext?: HypenGlobalContext;
373
469
  private stateChangeCallbacks: Array<() => void> = [];
374
470
 
375
471
  constructor(
376
472
  engine: IEngine,
377
473
  definition: HypenModuleDefinition<T>,
378
- routerContext?: RouterContext,
474
+ router?: HypenRouter | null,
379
475
  globalContext?: HypenGlobalContext
380
476
  ) {
381
477
  this.engine = engine;
382
478
  this.definition = definition;
383
- this.routerContext = routerContext;
479
+ this.router = router ?? null;
384
480
  this.globalContext = globalContext;
385
481
 
386
482
  // Named state prefix — all lowercase per convention
@@ -425,10 +521,6 @@ export class HypenModuleInstance<T extends object = any> {
425
521
  sender: action.sender,
426
522
  };
427
523
 
428
- const next: ActionNext = {
429
- router: this.routerContext?.root || (null as any),
430
- };
431
-
432
524
  const context: GlobalContext | undefined = this.globalContext
433
525
  ? this.createGlobalContextAPI()
434
526
  : undefined;
@@ -437,7 +529,6 @@ export class HypenModuleInstance<T extends object = any> {
437
529
  const result = await this.executeAction(actionName, handler, {
438
530
  action: actionCtx,
439
531
  state: this.state,
440
- next,
441
532
  context: context!,
442
533
  });
443
534
 
@@ -452,6 +543,22 @@ export class HypenModuleInstance<T extends object = any> {
452
543
  });
453
544
  }
454
545
 
546
+ // Auto-register __hypen_bind for .bind() two-way binding support
547
+ this.engine.onAction("__hypen_bind", (action: Action) => {
548
+ const payload = action.payload as { path?: string; value?: unknown } | null;
549
+ if (!payload?.path) return;
550
+
551
+ const segments = payload.path.split(".");
552
+ let target: any = this.state;
553
+ for (let i = 0; i < segments.length - 1; i++) {
554
+ const seg = segments[i]!;
555
+ target = target?.[seg];
556
+ if (target == null) return;
557
+ }
558
+ const lastSeg = segments[segments.length - 1]!;
559
+ target[lastSeg] = payload.value;
560
+ });
561
+
455
562
  // Call onCreated
456
563
  this.callCreatedHandler();
457
564
  }
@@ -473,12 +580,10 @@ export class HypenModuleInstance<T extends object = any> {
473
580
  emit: (event: string, payload?: any) => ctx.emit(event, payload),
474
581
  on: (event: string, handler: (payload?: any) => void) =>
475
582
  ctx.on(event, handler),
583
+ router: this.router,
476
584
  };
477
585
 
478
- // Expose router and hypen engine for built-in components (if available)
479
- if ((ctx as any).__router) {
480
- api.__router = (ctx as any).__router;
481
- }
586
+ // Expose hypen engine for built-in components (if available)
482
587
  if ((ctx as any).__hypenEngine) {
483
588
  (api as any).__hypenEngine = (ctx as any).__hypenEngine;
484
589
  }
@@ -492,7 +597,7 @@ export class HypenModuleInstance<T extends object = any> {
492
597
  */
493
598
  private async executeAction(
494
599
  actionName: string,
495
- handler: ActionHandler<T>,
600
+ handler: ActionHandler<T, any>,
496
601
  ctx: ActionHandlerContext<T>
497
602
  ): Promise<Result<void, ActionError>> {
498
603
  try {
@@ -575,7 +680,15 @@ export class HypenModuleInstance<T extends object = any> {
575
680
  private async callCreatedHandler(): Promise<void> {
576
681
  if (this.definition.handlers.onCreated) {
577
682
  const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
578
- await this.definition.handlers.onCreated(this.state, context);
683
+ try {
684
+ await this.definition.handlers.onCreated(this.state, context);
685
+ } catch (e) {
686
+ const error = e instanceof HypenError ? e : new ActionError("onCreated", e);
687
+ const shouldRethrow = await this.handleError(error, { lifecycle: "created" });
688
+ if (shouldRethrow) {
689
+ throw error;
690
+ }
691
+ }
579
692
  }
580
693
  }
581
694
 
@@ -593,7 +706,15 @@ export class HypenModuleInstance<T extends object = any> {
593
706
  if (this.isDestroyed) return;
594
707
 
595
708
  if (this.definition.handlers.onDestroyed) {
596
- await this.definition.handlers.onDestroyed(this.state);
709
+ try {
710
+ await this.definition.handlers.onDestroyed(this.state);
711
+ } catch (e) {
712
+ const error = e instanceof HypenError ? e : new ActionError("onDestroyed", e);
713
+ const shouldRethrow = await this.handleError(error, { lifecycle: "destroyed" });
714
+ if (shouldRethrow) {
715
+ throw error;
716
+ }
717
+ }
597
718
  }
598
719
 
599
720
  this.isDestroyed = true;
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { app } from "../app.js";
7
- import type { HypenRouter } from "../router.js";
8
7
  import { frameworkLoggers } from "../logger.js";
9
8
 
10
9
  const log = frameworkLoggers.router;
@@ -36,7 +35,7 @@ export const Router = app
36
35
  }
37
36
 
38
37
  // Subscribe to router changes
39
- const router = (context as any).__router as HypenRouter;
38
+ const router = context.router;
40
39
  if (!router) {
41
40
  log.error("Router not found in context");
42
41
  return;
@@ -149,7 +148,7 @@ export const Link = app
149
148
  { name: "__Link" }
150
149
  )
151
150
  .onAction("navigate", ({ state, context }) => {
152
- const router = (context as any)?.__router as HypenRouter;
151
+ const router = context?.router;
153
152
  if (!router) {
154
153
  log.error("Link requires router context");
155
154
  return;
@@ -162,7 +161,7 @@ export const Link = app
162
161
  if (!context) return;
163
162
 
164
163
  // Check if current path matches this link's target
165
- const router = (context as any).__router as HypenRouter;
164
+ const router = context.router;
166
165
  if (router) {
167
166
  router.onNavigate((routeState) => {
168
167
  state.isActive = routeState.currentPath === state.to;
package/src/discovery.ts CHANGED
@@ -43,7 +43,7 @@ export interface DiscoveryOptions {
43
43
 
44
44
  /**
45
45
  * Recursively scan subdirectories
46
- * Default: false
46
+ * Default: true
47
47
  */
48
48
  recursive?: boolean;
49
49
 
@@ -95,7 +95,7 @@ export async function discoverComponents(
95
95
  ): Promise<DiscoveredComponent[]> {
96
96
  const {
97
97
  patterns = ["single-file", "folder", "sibling", "index"],
98
- recursive = false,
98
+ recursive = true,
99
99
  debug = false,
100
100
  } = options;
101
101
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { frameworkLoggers } from "./logger.js";
7
+ import { classifyEngineError } from "./result.js";
7
8
  import type { Patch, Action, RenderCallback, ActionHandler, ResolvedComponent, ComponentResolver } from "./types.js";
8
9
 
9
10
  // Re-export types so existing consumers of "./engine.browser.js" still work
@@ -125,10 +126,16 @@ export class Engine {
125
126
 
126
127
  /**
127
128
  * Parse and render Hypen DSL source code
129
+ * @throws {ParseError} if the source fails to parse
130
+ * @throws {RenderError} if rendering fails
128
131
  */
129
132
  renderSource(source: string): void {
130
133
  const engine = this.ensureInitialized();
131
- engine.renderSource(source);
134
+ try {
135
+ engine.renderSource(source);
136
+ } catch (err) {
137
+ throw classifyEngineError(err);
138
+ }
132
139
  }
133
140
 
134
141
  /**
@@ -141,15 +148,22 @@ export class Engine {
141
148
 
142
149
  /**
143
150
  * Render a component into a specific parent node (subtree rendering)
151
+ * @throws {ParseError} if the source fails to parse
152
+ * @throws {RenderError} if the parent node is not found or rendering fails
144
153
  */
145
154
  renderInto(source: string, parentNodeId: string, state: Record<string, any>): void {
146
155
  const engine = this.ensureInitialized();
147
156
  const safeState = JSON.parse(JSON.stringify(state));
148
- engine.renderInto(source, parentNodeId, safeState);
157
+ try {
158
+ engine.renderInto(source, parentNodeId, safeState);
159
+ } catch (err) {
160
+ throw classifyEngineError(err);
161
+ }
149
162
  }
150
163
 
151
164
  /**
152
165
  * Notify the engine of state changes using sparse updates
166
+ * @throws {StateError} if the state patch is invalid
153
167
  */
154
168
  notifyStateChange(paths: string[], values: Record<string, any>): void {
155
169
  const engine = this.ensureInitialized();
@@ -159,7 +173,11 @@ export class Engine {
159
173
  }
160
174
 
161
175
  const plainValues = JSON.parse(JSON.stringify(values));
162
- engine.updateStateSparse(paths, plainValues);
176
+ try {
177
+ engine.updateStateSparse(paths, plainValues);
178
+ } catch (err) {
179
+ throw classifyEngineError(err);
180
+ }
163
181
  log.debug("State changed (sparse):", paths);
164
182
  }
165
183
 
@@ -189,11 +207,16 @@ export class Engine {
189
207
 
190
208
  /**
191
209
  * Dispatch an action
210
+ * @throws {HypenError} if the action dispatch fails
192
211
  */
193
212
  dispatchAction(name: string, payload?: any): void {
194
213
  const engine = this.ensureInitialized();
195
214
  log.debug(`Action dispatched: ${name}`);
196
- engine.dispatchAction(name, payload ?? null);
215
+ try {
216
+ engine.dispatchAction(name, payload ?? null);
217
+ } catch (err) {
218
+ throw classifyEngineError(err);
219
+ }
197
220
  }
198
221
 
199
222
  /**