@hypen-space/core 0.3.12 → 0.4.1

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 (47) hide show
  1. package/dist/app.js +7 -3
  2. package/dist/app.js.map +3 -3
  3. package/dist/components/builtin.js +7 -3
  4. package/dist/components/builtin.js.map +3 -3
  5. package/dist/discovery.js +8 -7
  6. package/dist/discovery.js.map +4 -4
  7. package/dist/engine.browser.js.map +2 -2
  8. package/dist/engine.js +3 -7
  9. package/dist/engine.js.map +3 -3
  10. package/dist/index.browser.js +242 -371
  11. package/dist/index.browser.js.map +8 -9
  12. package/dist/index.js +546 -656
  13. package/dist/index.js.map +12 -13
  14. package/dist/remote/client.js.map +1 -1
  15. package/dist/remote/index.js +336 -336
  16. package/dist/remote/index.js.map +8 -8
  17. package/dist/remote/server.js +219 -219
  18. package/dist/remote/server.js.map +7 -7
  19. package/dist/renderer.js.map +1 -1
  20. package/dist/resolver.js +31 -4
  21. package/dist/resolver.js.map +3 -3
  22. package/package.json +13 -1
  23. package/src/app.ts +14 -2
  24. package/src/discovery.ts +15 -12
  25. package/src/engine.browser.ts +4 -32
  26. package/src/engine.ts +8 -44
  27. package/src/index.browser.ts +6 -4
  28. package/src/index.ts +22 -30
  29. package/src/managed-router.ts +195 -0
  30. package/src/module-registry.ts +76 -0
  31. package/src/remote/client.ts +1 -1
  32. package/src/remote/index.ts +2 -2
  33. package/src/remote/server.ts +1 -1
  34. package/src/remote/types.ts +1 -1
  35. package/src/renderer.ts +6 -2
  36. package/src/resolver.ts +56 -9
  37. package/src/types.ts +38 -0
  38. package/wasm-browser/README.md +7 -1
  39. package/wasm-browser/hypen_engine.d.ts +1 -0
  40. package/wasm-browser/hypen_engine.js +1 -0
  41. package/wasm-browser/hypen_engine_bg.wasm +0 -0
  42. package/wasm-browser/package.json +1 -1
  43. package/wasm-node/README.md +7 -1
  44. package/wasm-node/hypen_engine.d.ts +1 -0
  45. package/wasm-node/hypen_engine.js +1 -0
  46. package/wasm-node/hypen_engine_bg.wasm +0 -0
  47. package/wasm-node/package.json +1 -1
package/dist/index.js CHANGED
@@ -27,205 +27,6 @@ var __export = (target, all) => {
27
27
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
28
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
29
 
30
- // src/logger.ts
31
- function isProduction() {
32
- if (typeof process !== "undefined" && process.env) {
33
- return false;
34
- }
35
- return false;
36
- }
37
- function setLogLevel(level) {
38
- config.level = level;
39
- }
40
- function getLogLevel() {
41
- return config.level;
42
- }
43
- function configureLogger(options) {
44
- config = { ...config, ...options };
45
- }
46
- function enableLogging() {
47
- config.level = "debug";
48
- }
49
- function disableLogging() {
50
- config.level = "none";
51
- }
52
- function setDebugMode(enabled) {
53
- config.level = enabled ? "debug" : "error";
54
- }
55
- function isDebugMode() {
56
- return config.level === "debug";
57
- }
58
- function shouldLog(level) {
59
- return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
60
- }
61
- function formatTag(tag, level) {
62
- const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
63
- if (config.colors && level !== "none") {
64
- const color = LOG_LEVEL_COLORS[level];
65
- return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
66
- }
67
- return `${timestamp}[${tag}]`;
68
- }
69
-
70
- class Logger {
71
- tag;
72
- constructor(tag) {
73
- this.tag = tag;
74
- }
75
- debug(...args) {
76
- if (!shouldLog("debug"))
77
- return;
78
- if (config.handler) {
79
- config.handler.debug(this.tag, ...args);
80
- } else {
81
- console.log(formatTag(this.tag, "debug"), ...args);
82
- }
83
- }
84
- info(...args) {
85
- if (!shouldLog("info"))
86
- return;
87
- if (config.handler) {
88
- config.handler.info(this.tag, ...args);
89
- } else {
90
- console.info(formatTag(this.tag, "info"), ...args);
91
- }
92
- }
93
- warn(...args) {
94
- if (!shouldLog("warn"))
95
- return;
96
- if (config.handler) {
97
- config.handler.warn(this.tag, ...args);
98
- } else {
99
- console.warn(formatTag(this.tag, "warn"), ...args);
100
- }
101
- }
102
- error(...args) {
103
- if (!shouldLog("error"))
104
- return;
105
- if (config.handler) {
106
- config.handler.error(this.tag, ...args);
107
- } else {
108
- console.error(formatTag(this.tag, "error"), ...args);
109
- }
110
- }
111
- time(label, fn) {
112
- if (!shouldLog("debug")) {
113
- return fn();
114
- }
115
- const start = performance.now();
116
- try {
117
- return fn();
118
- } finally {
119
- const duration = performance.now() - start;
120
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
121
- }
122
- }
123
- async timeAsync(label, fn) {
124
- if (!shouldLog("debug")) {
125
- return fn();
126
- }
127
- const start = performance.now();
128
- try {
129
- return await fn();
130
- } finally {
131
- const duration = performance.now() - start;
132
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
133
- }
134
- }
135
- child(subTag) {
136
- return new Logger(`${this.tag}:${subTag}`);
137
- }
138
- debugIf(condition, ...args) {
139
- if (condition)
140
- this.debug(...args);
141
- }
142
- warnIf(condition, ...args) {
143
- if (condition)
144
- this.warn(...args);
145
- }
146
- errorIf(condition, ...args) {
147
- if (condition)
148
- this.error(...args);
149
- }
150
- loggedOnce = new Set;
151
- warnOnce(key, ...args) {
152
- if (this.loggedOnce.has(key))
153
- return;
154
- this.loggedOnce.add(key);
155
- this.warn(...args);
156
- }
157
- debugOnce(key, ...args) {
158
- if (this.loggedOnce.has(key))
159
- return;
160
- this.loggedOnce.add(key);
161
- this.debug(...args);
162
- }
163
- }
164
- function createLogger(tag) {
165
- return new Logger(tag);
166
- }
167
- var LOG_LEVEL_ORDER, LOG_LEVEL_COLORS, RESET_COLOR = "\x1B[0m", config, logger, log, frameworkLoggers;
168
- var init_logger = __esm(() => {
169
- LOG_LEVEL_ORDER = {
170
- debug: 0,
171
- info: 1,
172
- warn: 2,
173
- error: 3,
174
- none: 4
175
- };
176
- LOG_LEVEL_COLORS = {
177
- debug: "\x1B[36m",
178
- info: "\x1B[32m",
179
- warn: "\x1B[33m",
180
- error: "\x1B[31m"
181
- };
182
- config = {
183
- level: isProduction() ? "error" : "debug",
184
- colors: true,
185
- timestamps: false
186
- };
187
- logger = createLogger("Hypen");
188
- log = {
189
- debug: (tag, ...args) => {
190
- if (!shouldLog("debug"))
191
- return;
192
- console.log(formatTag(tag, "debug"), ...args);
193
- },
194
- info: (tag, ...args) => {
195
- if (!shouldLog("info"))
196
- return;
197
- console.info(formatTag(tag, "info"), ...args);
198
- },
199
- warn: (tag, ...args) => {
200
- if (!shouldLog("warn"))
201
- return;
202
- console.warn(formatTag(tag, "warn"), ...args);
203
- },
204
- error: (tag, ...args) => {
205
- if (!shouldLog("error"))
206
- return;
207
- console.error(formatTag(tag, "error"), ...args);
208
- }
209
- };
210
- frameworkLoggers = {
211
- hypen: createLogger("Hypen"),
212
- engine: createLogger("Engine"),
213
- router: createLogger("Router"),
214
- state: createLogger("State"),
215
- events: createLogger("Events"),
216
- remote: createLogger("Remote"),
217
- renderer: createLogger("Renderer"),
218
- module: createLogger("Module"),
219
- lifecycle: createLogger("Lifecycle"),
220
- loader: createLogger("Loader"),
221
- context: createLogger("Context"),
222
- discovery: createLogger("Discovery"),
223
- plugin: createLogger("Plugin"),
224
- canvas: createLogger("Canvas"),
225
- debug: createLogger("Debug")
226
- };
227
- });
228
-
229
30
  // src/state.ts
230
31
  function deepClone(obj) {
231
32
  if (obj === null || typeof obj !== "object") {
@@ -612,60 +413,259 @@ var init_result = __esm(() => {
612
413
  };
613
414
  });
614
415
 
615
- // src/app.ts
616
- var exports_app = {};
617
- __export(exports_app, {
618
- app: () => app,
619
- HypenModuleInstance: () => HypenModuleInstance,
620
- HypenAppBuilder: () => HypenAppBuilder,
621
- HypenApp: () => HypenApp
622
- });
623
-
624
- class HypenAppBuilder {
625
- initialState;
626
- options;
627
- createdHandler;
628
- actionHandlers = new Map;
629
- destroyedHandler;
630
- disconnectHandler;
631
- reconnectHandler;
632
- expireHandler;
633
- errorHandler;
634
- template;
635
- constructor(initialState, options) {
636
- this.initialState = initialState;
637
- this.options = options || {};
638
- }
639
- onCreated(fn) {
640
- this.createdHandler = fn;
641
- return this;
642
- }
643
- onAction(name, fn) {
644
- this.actionHandlers.set(name, fn);
645
- return this;
646
- }
647
- onDestroyed(fn) {
648
- this.destroyedHandler = fn;
649
- return this;
650
- }
651
- onDisconnect(fn) {
652
- this.disconnectHandler = fn;
653
- return this;
654
- }
655
- onReconnect(fn) {
656
- this.reconnectHandler = fn;
657
- return this;
658
- }
659
- onExpire(fn) {
660
- this.expireHandler = fn;
661
- return this;
662
- }
663
- onError(fn) {
664
- this.errorHandler = fn;
665
- return this;
416
+ // src/logger.ts
417
+ function isProduction() {
418
+ if (typeof process !== "undefined" && process.env) {
419
+ return false;
666
420
  }
667
- ui(template) {
668
- this.template = template;
421
+ return false;
422
+ }
423
+ function setLogLevel(level) {
424
+ config.level = level;
425
+ }
426
+ function getLogLevel() {
427
+ return config.level;
428
+ }
429
+ function configureLogger(options) {
430
+ config = { ...config, ...options };
431
+ }
432
+ function enableLogging() {
433
+ config.level = "debug";
434
+ }
435
+ function disableLogging() {
436
+ config.level = "none";
437
+ }
438
+ function setDebugMode(enabled) {
439
+ config.level = enabled ? "debug" : "error";
440
+ }
441
+ function isDebugMode() {
442
+ return config.level === "debug";
443
+ }
444
+ function shouldLog(level) {
445
+ return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
446
+ }
447
+ function formatTag(tag, level) {
448
+ const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
449
+ if (config.colors && level !== "none") {
450
+ const color = LOG_LEVEL_COLORS[level];
451
+ return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
452
+ }
453
+ return `${timestamp}[${tag}]`;
454
+ }
455
+
456
+ class Logger {
457
+ tag;
458
+ constructor(tag) {
459
+ this.tag = tag;
460
+ }
461
+ debug(...args) {
462
+ if (!shouldLog("debug"))
463
+ return;
464
+ if (config.handler) {
465
+ config.handler.debug(this.tag, ...args);
466
+ } else {
467
+ console.log(formatTag(this.tag, "debug"), ...args);
468
+ }
469
+ }
470
+ info(...args) {
471
+ if (!shouldLog("info"))
472
+ return;
473
+ if (config.handler) {
474
+ config.handler.info(this.tag, ...args);
475
+ } else {
476
+ console.info(formatTag(this.tag, "info"), ...args);
477
+ }
478
+ }
479
+ warn(...args) {
480
+ if (!shouldLog("warn"))
481
+ return;
482
+ if (config.handler) {
483
+ config.handler.warn(this.tag, ...args);
484
+ } else {
485
+ console.warn(formatTag(this.tag, "warn"), ...args);
486
+ }
487
+ }
488
+ error(...args) {
489
+ if (!shouldLog("error"))
490
+ return;
491
+ if (config.handler) {
492
+ config.handler.error(this.tag, ...args);
493
+ } else {
494
+ console.error(formatTag(this.tag, "error"), ...args);
495
+ }
496
+ }
497
+ time(label, fn) {
498
+ if (!shouldLog("debug")) {
499
+ return fn();
500
+ }
501
+ const start = performance.now();
502
+ try {
503
+ return fn();
504
+ } finally {
505
+ const duration = performance.now() - start;
506
+ this.debug(`${label}: ${duration.toFixed(2)}ms`);
507
+ }
508
+ }
509
+ async timeAsync(label, fn) {
510
+ if (!shouldLog("debug")) {
511
+ return fn();
512
+ }
513
+ const start = performance.now();
514
+ try {
515
+ return await fn();
516
+ } finally {
517
+ const duration = performance.now() - start;
518
+ this.debug(`${label}: ${duration.toFixed(2)}ms`);
519
+ }
520
+ }
521
+ child(subTag) {
522
+ return new Logger(`${this.tag}:${subTag}`);
523
+ }
524
+ debugIf(condition, ...args) {
525
+ if (condition)
526
+ this.debug(...args);
527
+ }
528
+ warnIf(condition, ...args) {
529
+ if (condition)
530
+ this.warn(...args);
531
+ }
532
+ errorIf(condition, ...args) {
533
+ if (condition)
534
+ this.error(...args);
535
+ }
536
+ loggedOnce = new Set;
537
+ warnOnce(key, ...args) {
538
+ if (this.loggedOnce.has(key))
539
+ return;
540
+ this.loggedOnce.add(key);
541
+ this.warn(...args);
542
+ }
543
+ debugOnce(key, ...args) {
544
+ if (this.loggedOnce.has(key))
545
+ return;
546
+ this.loggedOnce.add(key);
547
+ this.debug(...args);
548
+ }
549
+ }
550
+ function createLogger(tag) {
551
+ return new Logger(tag);
552
+ }
553
+ var LOG_LEVEL_ORDER, LOG_LEVEL_COLORS, RESET_COLOR = "\x1B[0m", config, logger, log, frameworkLoggers;
554
+ var init_logger = __esm(() => {
555
+ LOG_LEVEL_ORDER = {
556
+ debug: 0,
557
+ info: 1,
558
+ warn: 2,
559
+ error: 3,
560
+ none: 4
561
+ };
562
+ LOG_LEVEL_COLORS = {
563
+ debug: "\x1B[36m",
564
+ info: "\x1B[32m",
565
+ warn: "\x1B[33m",
566
+ error: "\x1B[31m"
567
+ };
568
+ config = {
569
+ level: isProduction() ? "error" : "debug",
570
+ colors: true,
571
+ timestamps: false
572
+ };
573
+ logger = createLogger("Hypen");
574
+ log = {
575
+ debug: (tag, ...args) => {
576
+ if (!shouldLog("debug"))
577
+ return;
578
+ console.log(formatTag(tag, "debug"), ...args);
579
+ },
580
+ info: (tag, ...args) => {
581
+ if (!shouldLog("info"))
582
+ return;
583
+ console.info(formatTag(tag, "info"), ...args);
584
+ },
585
+ warn: (tag, ...args) => {
586
+ if (!shouldLog("warn"))
587
+ return;
588
+ console.warn(formatTag(tag, "warn"), ...args);
589
+ },
590
+ error: (tag, ...args) => {
591
+ if (!shouldLog("error"))
592
+ return;
593
+ console.error(formatTag(tag, "error"), ...args);
594
+ }
595
+ };
596
+ frameworkLoggers = {
597
+ hypen: createLogger("Hypen"),
598
+ engine: createLogger("Engine"),
599
+ router: createLogger("Router"),
600
+ state: createLogger("State"),
601
+ events: createLogger("Events"),
602
+ remote: createLogger("Remote"),
603
+ renderer: createLogger("Renderer"),
604
+ module: createLogger("Module"),
605
+ lifecycle: createLogger("Lifecycle"),
606
+ loader: createLogger("Loader"),
607
+ context: createLogger("Context"),
608
+ discovery: createLogger("Discovery"),
609
+ plugin: createLogger("Plugin"),
610
+ canvas: createLogger("Canvas"),
611
+ debug: createLogger("Debug")
612
+ };
613
+ });
614
+
615
+ // src/app.ts
616
+ var exports_app = {};
617
+ __export(exports_app, {
618
+ app: () => app,
619
+ HypenModuleInstance: () => HypenModuleInstance,
620
+ HypenAppBuilder: () => HypenAppBuilder,
621
+ HypenApp: () => HypenApp
622
+ });
623
+
624
+ class HypenAppBuilder {
625
+ initialState;
626
+ options;
627
+ createdHandler;
628
+ actionHandlers = new Map;
629
+ destroyedHandler;
630
+ disconnectHandler;
631
+ reconnectHandler;
632
+ expireHandler;
633
+ errorHandler;
634
+ template;
635
+ constructor(initialState, options) {
636
+ this.initialState = initialState;
637
+ this.options = options || {};
638
+ }
639
+ onCreated(fn) {
640
+ this.createdHandler = fn;
641
+ return this;
642
+ }
643
+ onAction(name, fn) {
644
+ this.actionHandlers.set(name, fn);
645
+ return this;
646
+ }
647
+ onDestroyed(fn) {
648
+ this.destroyedHandler = fn;
649
+ return this;
650
+ }
651
+ onDisconnect(fn) {
652
+ this.disconnectHandler = fn;
653
+ return this;
654
+ }
655
+ onReconnect(fn) {
656
+ this.reconnectHandler = fn;
657
+ return this;
658
+ }
659
+ onExpire(fn) {
660
+ this.expireHandler = fn;
661
+ return this;
662
+ }
663
+ onError(fn) {
664
+ this.errorHandler = fn;
665
+ return this;
666
+ }
667
+ ui(template) {
668
+ this.template = template;
669
669
  return this.build();
670
670
  }
671
671
  build() {
@@ -710,17 +710,21 @@ class HypenModuleInstance {
710
710
  this.definition = definition;
711
711
  this.routerContext = routerContext;
712
712
  this.globalContext = globalContext;
713
+ const statePrefix = (definition.name || "").toLowerCase();
713
714
  this.state = createObservableState(definition.initialState, {
714
715
  onChange: (change) => {
715
716
  this.engine.notifyStateChange(change.paths, change.newValues);
716
717
  this.stateChangeCallbacks.forEach((cb) => cb());
717
- }
718
+ },
719
+ pathPrefix: statePrefix || undefined
718
720
  });
719
- this.engine.setModule(definition.name || "AnonymousModule", definition.actions, definition.stateKeys, getStateSnapshot(this.state));
721
+ const snapshot = getStateSnapshot(this.state);
722
+ const prefixedState = statePrefix ? { [statePrefix]: snapshot } : snapshot;
723
+ this.engine.setModule(definition.name || "AnonymousModule", definition.actions, definition.stateKeys, prefixedState);
720
724
  for (const [actionName, handler] of definition.handlers.onAction) {
721
- log4.debug(`Registering action handler: ${actionName} for module ${definition.name}`);
725
+ log2.debug(`Registering action handler: ${actionName} for module ${definition.name}`);
722
726
  this.engine.onAction(actionName, async (action) => {
723
- log4.debug(`Action handler fired: ${actionName}`, action);
727
+ log2.debug(`Action handler fired: ${actionName}`, action);
724
728
  const actionCtx = {
725
729
  name: action.name,
726
730
  payload: action.payload,
@@ -742,355 +746,114 @@ class HypenModuleInstance {
742
746
  throw result.error;
743
747
  }
744
748
  } else {
745
- log4.debug(`Action handler completed: ${actionName}`);
749
+ log2.debug(`Action handler completed: ${actionName}`);
746
750
  }
747
751
  });
748
752
  }
749
753
  this.callCreatedHandler();
750
754
  }
751
755
  createGlobalContextAPI() {
752
- if (!this.globalContext) {
753
- throw new Error("Global context not available");
754
- }
755
- const ctx = this.globalContext;
756
- const api = {
757
- getModule: (id) => ctx.getModule(id),
758
- hasModule: (id) => ctx.hasModule(id),
759
- getModuleIds: () => ctx.getModuleIds(),
760
- getGlobalState: () => ctx.getGlobalState(),
761
- emit: (event, payload) => ctx.emit(event, payload),
762
- on: (event, handler) => ctx.on(event, handler)
763
- };
764
- if (ctx.__router) {
765
- api.__router = ctx.__router;
766
- }
767
- if (ctx.__hypenEngine) {
768
- api.__hypenEngine = ctx.__hypenEngine;
769
- }
770
- return api;
771
- }
772
- async executeAction(actionName, handler, ctx) {
773
- try {
774
- const result = handler(ctx);
775
- await result;
776
- return Ok(undefined);
777
- } catch (e) {
778
- return Err(new ActionError(actionName, e));
779
- }
780
- }
781
- async handleError(error, context) {
782
- const errorCtx = {
783
- error,
784
- state: this.state,
785
- actionName: context.actionName,
786
- lifecycle: context.lifecycle
787
- };
788
- if (this.definition.handlers.onError) {
789
- try {
790
- const result = await this.definition.handlers.onError(errorCtx);
791
- if (result && typeof result === "object") {
792
- if ("handled" in result && result.handled) {
793
- return false;
794
- }
795
- if ("rethrow" in result && result.rethrow) {
796
- return true;
797
- }
798
- }
799
- } catch (handlerError) {
800
- log4.error("Error in onError handler:", handlerError);
801
- }
802
- }
803
- if (this.globalContext) {
804
- const eventContext = context.actionName ? `action:${context.actionName}` : context.lifecycle ? `lifecycle:${context.lifecycle}` : "unknown";
805
- this.globalContext.emit("error", {
806
- message: error.message,
807
- error,
808
- context: eventContext
809
- });
810
- }
811
- log4.error(`${context.actionName ? `Action "${context.actionName}"` : `Lifecycle "${context.lifecycle}"`} error:`, error);
812
- return false;
813
- }
814
- async callCreatedHandler() {
815
- if (this.definition.handlers.onCreated) {
816
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
817
- await this.definition.handlers.onCreated(this.state, context);
818
- }
819
- }
820
- onStateChange(callback) {
821
- this.stateChangeCallbacks.push(callback);
822
- }
823
- async destroy() {
824
- if (this.isDestroyed)
825
- return;
826
- if (this.definition.handlers.onDestroyed) {
827
- await this.definition.handlers.onDestroyed(this.state);
828
- }
829
- this.isDestroyed = true;
830
- }
831
- getState() {
832
- return getStateSnapshot(this.state);
833
- }
834
- getLiveState() {
835
- return this.state;
836
- }
837
- updateState(patch) {
838
- Object.assign(this.state, patch);
839
- }
840
- }
841
- var log4, app;
842
- var init_app = __esm(() => {
843
- init_result();
844
- init_state();
845
- init_logger();
846
- log4 = createLogger("ModuleInstance");
847
- app = new HypenApp;
848
- });
849
-
850
- // src/engine.ts
851
- init_logger();
852
- var WasmEngineClass = null;
853
- var log2 = frameworkLoggers.engine;
854
- function unwrapForWasm(value) {
855
- if (value === null || typeof value !== "object") {
856
- return value;
857
- }
858
- if (typeof value.__getSnapshot === "function") {
859
- return value.__getSnapshot();
860
- }
861
- try {
862
- return structuredClone(value);
863
- } catch {
864
- return JSON.parse(JSON.stringify(value));
865
- }
866
- }
867
-
868
- class Engine {
869
- wasmEngine = null;
870
- initialized = false;
871
- async init() {
872
- if (this.initialized)
873
- return;
874
- if (!WasmEngineClass) {
875
- const wasm = await import("../wasm-node/hypen_engine.js");
876
- WasmEngineClass = wasm.WasmEngine;
877
- }
878
- this.wasmEngine = new WasmEngineClass;
879
- this.initialized = true;
880
- }
881
- ensureInitialized() {
882
- if (!this.wasmEngine) {
883
- throw new Error("Engine not initialized. Call init() first.");
884
- }
885
- return this.wasmEngine;
886
- }
887
- setRenderCallback(callback) {
888
- const engine = this.ensureInitialized();
889
- engine.setRenderCallback((patches) => {
890
- callback(patches);
891
- });
892
- }
893
- setComponentResolver(resolver) {
894
- const engine = this.ensureInitialized();
895
- engine.setComponentResolver((componentName, contextPath) => {
896
- const result = resolver(componentName, contextPath);
897
- return result;
898
- });
899
- }
900
- renderSource(source) {
901
- const engine = this.ensureInitialized();
902
- engine.renderSource(source);
903
- }
904
- renderLazyComponent(source) {
905
- const engine = this.ensureInitialized();
906
- engine.renderLazyComponent(source);
907
- }
908
- renderInto(source, parentNodeId, state) {
909
- const engine = this.ensureInitialized();
910
- engine.renderInto(source, parentNodeId, unwrapForWasm(state));
911
- }
912
- notifyStateChange(paths, values) {
913
- const engine = this.ensureInitialized();
914
- if (paths.length === 0) {
915
- return;
916
- }
917
- engine.updateStateSparse(paths, unwrapForWasm(values));
918
- log2.debug("State changed (sparse):", paths);
919
- }
920
- notifyStateChangeFull(paths, currentState) {
921
- const engine = this.ensureInitialized();
922
- engine.updateState(unwrapForWasm(currentState));
923
- if (paths.length > 0) {
924
- log2.debug("State changed (full):", paths);
925
- }
926
- }
927
- updateState(statePatch) {
928
- const engine = this.ensureInitialized();
929
- engine.updateState(unwrapForWasm(statePatch));
930
- }
931
- dispatchAction(name, payload) {
932
- const engine = this.ensureInitialized();
933
- engine.dispatchAction(name, payload ?? null);
934
- }
935
- onAction(actionName, handler) {
936
- const engine = this.ensureInitialized();
937
- engine.onAction(actionName, (action) => {
938
- Promise.resolve(handler(action)).catch((err) => log2.error("Action handler error:", err));
939
- });
940
- }
941
- setModule(name, actions, stateKeys, initialState) {
942
- const engine = this.ensureInitialized();
943
- engine.setModule(name, actions, stateKeys, initialState);
944
- }
945
- getRevision() {
946
- const engine = this.ensureInitialized();
947
- return Number(engine.getRevision());
948
- }
949
- clearTree() {
950
- const engine = this.ensureInitialized();
951
- engine.clearTree();
952
- }
953
- debugParseComponent(source) {
954
- const engine = this.ensureInitialized();
955
- return engine.debugParseComponent(source);
956
- }
957
- }
958
-
959
- // src/engine.browser.ts
960
- init_logger();
961
- var log3 = frameworkLoggers.engine;
962
- var wasmInit = null;
963
- var WasmEngineClass2 = null;
964
- function mapToObject(value) {
965
- if (value instanceof Map) {
966
- const obj = {};
967
- for (const [key, val] of value.entries()) {
968
- obj[key] = mapToObject(val);
756
+ if (!this.globalContext) {
757
+ throw new Error("Global context not available");
969
758
  }
970
- return obj;
971
- } else if (Array.isArray(value)) {
972
- return value.map(mapToObject);
973
- } else if (value && typeof value === "object" && value.constructor === Object) {
974
- const obj = {};
975
- for (const [key, val] of Object.entries(value)) {
976
- obj[key] = mapToObject(val);
759
+ const ctx = this.globalContext;
760
+ const api = {
761
+ getModule: (id) => ctx.getModule(id),
762
+ hasModule: (id) => ctx.hasModule(id),
763
+ getModuleIds: () => ctx.getModuleIds(),
764
+ getGlobalState: () => ctx.getGlobalState(),
765
+ emit: (event, payload) => ctx.emit(event, payload),
766
+ on: (event, handler) => ctx.on(event, handler)
767
+ };
768
+ if (ctx.__router) {
769
+ api.__router = ctx.__router;
977
770
  }
978
- return obj;
771
+ if (ctx.__hypenEngine) {
772
+ api.__hypenEngine = ctx.__hypenEngine;
773
+ }
774
+ return api;
979
775
  }
980
- return value;
981
- }
982
-
983
- class Engine2 {
984
- wasmEngine = null;
985
- initialized = false;
986
- async init(options = {}) {
987
- if (this.initialized)
988
- return;
989
- const cdnBase = "https://unpkg.com/@hypen-space/core@latest/wasm-browser";
990
- const jsUrl = options.jsUrl ?? `${cdnBase}/hypen_engine.js`;
991
- const wasmUrl = options.wasmUrl ?? `${cdnBase}/hypen_engine_bg.wasm`;
776
+ async executeAction(actionName, handler, ctx) {
992
777
  try {
993
- const wasmModule = await import(jsUrl);
994
- wasmInit = wasmModule.default;
995
- WasmEngineClass2 = wasmModule.WasmEngine;
996
- await wasmInit(wasmUrl);
997
- this.wasmEngine = new WasmEngineClass2;
998
- this.initialized = true;
999
- } catch (error) {
1000
- log3.error("Failed to initialize WASM engine:", error);
1001
- throw error;
778
+ const result = handler(ctx);
779
+ await result;
780
+ return Ok(undefined);
781
+ } catch (e) {
782
+ return Err(new ActionError(actionName, e));
1002
783
  }
1003
784
  }
1004
- ensureInitialized() {
1005
- if (!this.wasmEngine) {
1006
- throw new Error("Engine not initialized. Call init() first.");
785
+ async handleError(error, context) {
786
+ const errorCtx = {
787
+ error,
788
+ state: this.state,
789
+ actionName: context.actionName,
790
+ lifecycle: context.lifecycle
791
+ };
792
+ if (this.definition.handlers.onError) {
793
+ try {
794
+ const result = await this.definition.handlers.onError(errorCtx);
795
+ if (result && typeof result === "object") {
796
+ if ("handled" in result && result.handled) {
797
+ return false;
798
+ }
799
+ if ("rethrow" in result && result.rethrow) {
800
+ return true;
801
+ }
802
+ }
803
+ } catch (handlerError) {
804
+ log2.error("Error in onError handler:", handlerError);
805
+ }
1007
806
  }
1008
- return this.wasmEngine;
1009
- }
1010
- setRenderCallback(callback) {
1011
- const engine = this.ensureInitialized();
1012
- engine.setRenderCallback((patches) => {
1013
- callback(patches);
1014
- });
1015
- }
1016
- setComponentResolver(resolver) {
1017
- const engine = this.ensureInitialized();
1018
- engine.setComponentResolver((componentName, contextPath) => {
1019
- const result = resolver(componentName, contextPath);
1020
- return result;
1021
- });
1022
- }
1023
- renderSource(source) {
1024
- const engine = this.ensureInitialized();
1025
- engine.renderSource(source);
1026
- }
1027
- renderLazyComponent(source) {
1028
- const engine = this.ensureInitialized();
1029
- engine.renderLazyComponent(source);
1030
- }
1031
- renderInto(source, parentNodeId, state) {
1032
- const engine = this.ensureInitialized();
1033
- const safeState = JSON.parse(JSON.stringify(state));
1034
- engine.renderInto(source, parentNodeId, safeState);
1035
- }
1036
- notifyStateChange(paths, values) {
1037
- const engine = this.ensureInitialized();
1038
- if (paths.length === 0) {
1039
- return;
807
+ if (this.globalContext) {
808
+ const eventContext = context.actionName ? `action:${context.actionName}` : context.lifecycle ? `lifecycle:${context.lifecycle}` : "unknown";
809
+ this.globalContext.emit("error", {
810
+ message: error.message,
811
+ error,
812
+ context: eventContext
813
+ });
1040
814
  }
1041
- const plainValues = JSON.parse(JSON.stringify(values));
1042
- engine.updateStateSparse(paths, plainValues);
1043
- log3.debug("State changed (sparse):", paths);
815
+ log2.error(`${context.actionName ? `Action "${context.actionName}"` : `Lifecycle "${context.lifecycle}"`} error:`, error);
816
+ return false;
1044
817
  }
1045
- notifyStateChangeFull(paths, currentState) {
1046
- const engine = this.ensureInitialized();
1047
- const plainObject = JSON.parse(JSON.stringify(currentState));
1048
- engine.updateState(plainObject);
1049
- if (paths.length > 0) {
1050
- log3.debug("State changed (full):", paths);
818
+ async callCreatedHandler() {
819
+ if (this.definition.handlers.onCreated) {
820
+ const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
821
+ await this.definition.handlers.onCreated(this.state, context);
1051
822
  }
1052
823
  }
1053
- updateState(statePatch) {
1054
- const engine = this.ensureInitialized();
1055
- const plainObject = JSON.parse(JSON.stringify(statePatch));
1056
- engine.updateState(plainObject);
1057
- }
1058
- dispatchAction(name, payload) {
1059
- const engine = this.ensureInitialized();
1060
- log3.debug(`Action dispatched: ${name}`);
1061
- engine.dispatchAction(name, payload ?? null);
1062
- }
1063
- onAction(actionName, handler) {
1064
- const engine = this.ensureInitialized();
1065
- engine.onAction(actionName, (action) => {
1066
- const normalizedAction = {
1067
- ...action,
1068
- payload: action.payload ? mapToObject(action.payload) : action.payload
1069
- };
1070
- Promise.resolve(handler(normalizedAction)).catch((err) => log3.error("Action handler error:", err));
1071
- });
824
+ onStateChange(callback) {
825
+ this.stateChangeCallbacks.push(callback);
1072
826
  }
1073
- setModule(name, actions, stateKeys, initialState) {
1074
- const engine = this.ensureInitialized();
1075
- engine.setModule(name, actions, stateKeys, initialState);
827
+ async destroy() {
828
+ if (this.isDestroyed)
829
+ return;
830
+ if (this.definition.handlers.onDestroyed) {
831
+ await this.definition.handlers.onDestroyed(this.state);
832
+ }
833
+ this.isDestroyed = true;
1076
834
  }
1077
- getRevision() {
1078
- const engine = this.ensureInitialized();
1079
- return engine.getRevision();
835
+ getState() {
836
+ return getStateSnapshot(this.state);
1080
837
  }
1081
- clearTree() {
1082
- const engine = this.ensureInitialized();
1083
- engine.clearTree();
838
+ getLiveState() {
839
+ return this.state;
1084
840
  }
1085
- debugParseComponent(source) {
1086
- const engine = this.ensureInitialized();
1087
- return engine.debugParseComponent(source);
841
+ updateState(patch) {
842
+ Object.assign(this.state, patch);
1088
843
  }
1089
844
  }
845
+ var log2, app;
846
+ var init_app = __esm(() => {
847
+ init_result();
848
+ init_state();
849
+ init_logger();
850
+ log2 = createLogger("ModuleInstance");
851
+ app = new HypenApp;
852
+ });
1090
853
 
1091
854
  // src/renderer.ts
1092
855
  init_logger();
1093
- var log5 = frameworkLoggers.renderer;
856
+ var log3 = frameworkLoggers.renderer;
1094
857
 
1095
858
  class BaseRenderer {
1096
859
  nodes = new Map;
@@ -1132,14 +895,14 @@ class BaseRenderer {
1132
895
 
1133
896
  class ConsoleRenderer {
1134
897
  applyPatches(patches) {
1135
- log5.debug("Patches:", patches);
898
+ log3.debug("Patches:", patches);
1136
899
  }
1137
900
  }
1138
901
 
1139
902
  // src/router.ts
1140
903
  init_state();
1141
904
  init_logger();
1142
- var log6 = frameworkLoggers.router;
905
+ var log4 = frameworkLoggers.router;
1143
906
 
1144
907
  class HypenRouter {
1145
908
  state;
@@ -1177,7 +940,7 @@ class HypenRouter {
1177
940
  this.updatePath(newPath, false);
1178
941
  });
1179
942
  this.isInitialized = true;
1180
- log6.debug("Router initialized at:", initialPath);
943
+ log4.debug("Router initialized at:", initialPath);
1181
944
  }
1182
945
  getPathFromBrowser() {
1183
946
  if (typeof window === "undefined")
@@ -1198,21 +961,21 @@ class HypenRouter {
1198
961
  return query;
1199
962
  }
1200
963
  push(path) {
1201
- log6.debug("push:", path);
964
+ log4.debug("push:", path);
1202
965
  this.updatePath(path, true);
1203
966
  }
1204
967
  replace(path) {
1205
- log6.debug("replace:", path);
968
+ log4.debug("replace:", path);
1206
969
  this.updatePath(path, true, true);
1207
970
  }
1208
971
  back() {
1209
- log6.debug("back");
972
+ log4.debug("back");
1210
973
  if (typeof window !== "undefined") {
1211
974
  window.history.back();
1212
975
  }
1213
976
  }
1214
977
  forward() {
1215
- log6.debug("forward");
978
+ log4.debug("forward");
1216
979
  if (typeof window !== "undefined") {
1217
980
  window.history.forward();
1218
981
  }
@@ -1308,7 +1071,7 @@ class HypenRouter {
1308
1071
  try {
1309
1072
  callback(this.getState());
1310
1073
  } catch (error) {
1311
- log6.error("Error in route subscriber:", error);
1074
+ log4.error("Error in route subscriber:", error);
1312
1075
  }
1313
1076
  return () => {
1314
1077
  this.subscribers.delete(callback);
@@ -1320,7 +1083,7 @@ class HypenRouter {
1320
1083
  try {
1321
1084
  callback(routeState);
1322
1085
  } catch (error) {
1323
- log6.error("Error in route subscriber:", error);
1086
+ log4.error("Error in route subscriber:", error);
1324
1087
  }
1325
1088
  });
1326
1089
  }
@@ -1338,7 +1101,7 @@ class HypenRouter {
1338
1101
 
1339
1102
  // src/events.ts
1340
1103
  init_logger();
1341
- var log7 = frameworkLoggers.events;
1104
+ var log5 = frameworkLoggers.events;
1342
1105
 
1343
1106
  class TypedEventEmitter {
1344
1107
  eventBus = new Map;
@@ -1351,7 +1114,7 @@ class TypedEventEmitter {
1351
1114
  try {
1352
1115
  handler(payload);
1353
1116
  } catch (error) {
1354
- log7.error(`Error in event handler for "${String(event)}":`, error);
1117
+ log5.error(`Error in event handler for "${String(event)}":`, error);
1355
1118
  }
1356
1119
  });
1357
1120
  }
@@ -1404,7 +1167,7 @@ function createEventEmitter() {
1404
1167
 
1405
1168
  // src/context.ts
1406
1169
  init_logger();
1407
- var log8 = frameworkLoggers.context;
1170
+ var log6 = frameworkLoggers.context;
1408
1171
 
1409
1172
  class HypenGlobalContext {
1410
1173
  modules = new Map;
@@ -1418,14 +1181,14 @@ class HypenGlobalContext {
1418
1181
  }
1419
1182
  registerModule(id, instance) {
1420
1183
  if (this.modules.has(id)) {
1421
- log8.warn(`Module "${id}" is already registered. Overwriting.`);
1184
+ log6.warn(`Module "${id}" is already registered. Overwriting.`);
1422
1185
  }
1423
1186
  this.modules.set(id, instance);
1424
- log8.debug(`Registered module: ${id}`);
1187
+ log6.debug(`Registered module: ${id}`);
1425
1188
  }
1426
1189
  unregisterModule(id) {
1427
1190
  this.modules.delete(id);
1428
- log8.debug(`Unregistered module: ${id}`);
1191
+ log6.debug(`Unregistered module: ${id}`);
1429
1192
  }
1430
1193
  getModule(id) {
1431
1194
  const module = this.modules.get(id);
@@ -1454,14 +1217,14 @@ class HypenGlobalContext {
1454
1217
  emit(event, payload) {
1455
1218
  const handlers = this.legacyEventBus.get(event);
1456
1219
  if (!handlers || handlers.size === 0) {
1457
- log8.debug(`Event "${event}" emitted but no listeners`);
1220
+ log6.debug(`Event "${event}" emitted but no listeners`);
1458
1221
  } else {
1459
- log8.debug(`Emitting event: ${event}`, payload);
1222
+ log6.debug(`Emitting event: ${event}`, payload);
1460
1223
  handlers.forEach((handler) => {
1461
1224
  try {
1462
1225
  handler(payload);
1463
1226
  } catch (error) {
1464
- log8.error(`Error in event handler for "${event}":`, error);
1227
+ log6.error(`Error in event handler for "${event}":`, error);
1465
1228
  }
1466
1229
  });
1467
1230
  }
@@ -1475,7 +1238,7 @@ class HypenGlobalContext {
1475
1238
  }
1476
1239
  const handlers = this.legacyEventBus.get(event);
1477
1240
  handlers.add(handler);
1478
- log8.debug(`Listening to event: ${event}`);
1241
+ log6.debug(`Listening to event: ${event}`);
1479
1242
  return () => {
1480
1243
  handlers.delete(handler);
1481
1244
  if (handlers.size === 0) {
@@ -1510,7 +1273,7 @@ class HypenGlobalContext {
1510
1273
 
1511
1274
  // src/disposable.ts
1512
1275
  init_logger();
1513
- var log9 = frameworkLoggers.lifecycle;
1276
+ var log7 = frameworkLoggers.lifecycle;
1514
1277
  function isDisposable(obj) {
1515
1278
  return obj !== null && typeof obj === "object" && "dispose" in obj && typeof obj.dispose === "function";
1516
1279
  }
@@ -1542,7 +1305,7 @@ class DisposableStack {
1542
1305
  try {
1543
1306
  item.dispose();
1544
1307
  } catch (error) {
1545
- log9.error("Error during dispose:", error);
1308
+ log7.error("Error during dispose:", error);
1546
1309
  }
1547
1310
  }
1548
1311
  }
@@ -1633,7 +1396,7 @@ function compositeDisposable(...disposables) {
1633
1396
  try {
1634
1397
  d.dispose();
1635
1398
  } catch (error) {
1636
- log9.error("Error during dispose:", error);
1399
+ log7.error("Error during dispose:", error);
1637
1400
  }
1638
1401
  }
1639
1402
  }
@@ -1787,7 +1550,7 @@ var RetryPresets = {
1787
1550
 
1788
1551
  // src/remote/client.ts
1789
1552
  init_logger();
1790
- var log10 = frameworkLoggers.remote;
1553
+ var log8 = frameworkLoggers.remote;
1791
1554
 
1792
1555
  class RemoteEngine {
1793
1556
  ws = null;
@@ -1895,7 +1658,7 @@ class RemoteEngine {
1895
1658
  }
1896
1659
  dispatchAction(action, payload) {
1897
1660
  if (this.state !== "connected" || !this.ws) {
1898
- log10.warn("Cannot dispatch action: not connected");
1661
+ log8.warn("Cannot dispatch action: not connected");
1899
1662
  return;
1900
1663
  }
1901
1664
  const message = {
@@ -1968,7 +1731,7 @@ class RemoteEngine {
1968
1731
  break;
1969
1732
  }
1970
1733
  } catch (e) {
1971
- log10.error("Error handling remote message:", e);
1734
+ log8.error("Error handling remote message:", e);
1972
1735
  const error = e instanceof Error ? e : new Error(String(e));
1973
1736
  this.errorCallbacks.forEach((cb) => cb(error));
1974
1737
  }
@@ -1997,7 +1760,7 @@ class RemoteEngine {
1997
1760
  }
1998
1761
  handlePatch(message) {
1999
1762
  if (message.revision <= this.currentRevision) {
2000
- log10.warn(`Out of order patch: expected > ${this.currentRevision}, got ${message.revision}`);
1763
+ log8.warn(`Out of order patch: expected > ${this.currentRevision}, got ${message.revision}`);
2001
1764
  return;
2002
1765
  }
2003
1766
  this.currentRevision = message.revision;
@@ -2023,16 +1786,121 @@ class RemoteEngine {
2023
1786
  maxDelayMs: 30000,
2024
1787
  jitter: 0.1,
2025
1788
  onRetry: (attempt, error) => {
2026
- log10.debug(`Reconnection attempt ${attempt}/${this.options.maxReconnectAttempts} failed: ${error.message}`);
1789
+ log8.debug(`Reconnection attempt ${attempt}/${this.options.maxReconnectAttempts} failed: ${error.message}`);
2027
1790
  }
2028
1791
  }).catch((error) => {
2029
- log10.error("Max reconnection attempts reached:", error.message);
1792
+ log8.error("Max reconnection attempts reached:", error.message);
2030
1793
  this.errorCallbacks.forEach((cb) => cb(new ConnectionError(this.url, error, this.options.maxReconnectAttempts)));
2031
1794
  });
2032
1795
  }, this.options.reconnectInterval);
2033
1796
  }
2034
1797
  }
2035
1798
 
1799
+ // src/engine.ts
1800
+ init_logger();
1801
+ import { WasmEngine } from "../wasm-node/hypen_engine.js";
1802
+ var log9 = frameworkLoggers.engine;
1803
+ function unwrapForWasm(value) {
1804
+ if (value === null || typeof value !== "object") {
1805
+ return value;
1806
+ }
1807
+ if (typeof value.__getSnapshot === "function") {
1808
+ return value.__getSnapshot();
1809
+ }
1810
+ try {
1811
+ return structuredClone(value);
1812
+ } catch {
1813
+ return JSON.parse(JSON.stringify(value));
1814
+ }
1815
+ }
1816
+
1817
+ class Engine {
1818
+ wasmEngine = null;
1819
+ initialized = false;
1820
+ async init() {
1821
+ if (this.initialized)
1822
+ return;
1823
+ this.wasmEngine = new WasmEngine;
1824
+ this.initialized = true;
1825
+ }
1826
+ ensureInitialized() {
1827
+ if (!this.wasmEngine) {
1828
+ throw new Error("Engine not initialized. Call init() first.");
1829
+ }
1830
+ return this.wasmEngine;
1831
+ }
1832
+ setRenderCallback(callback) {
1833
+ const engine = this.ensureInitialized();
1834
+ engine.setRenderCallback((patches) => {
1835
+ callback(patches);
1836
+ });
1837
+ }
1838
+ setComponentResolver(resolver) {
1839
+ const engine = this.ensureInitialized();
1840
+ engine.setComponentResolver((componentName, contextPath) => {
1841
+ const result = resolver(componentName, contextPath);
1842
+ return result;
1843
+ });
1844
+ }
1845
+ renderSource(source) {
1846
+ const engine = this.ensureInitialized();
1847
+ engine.renderSource(source);
1848
+ }
1849
+ renderLazyComponent(source) {
1850
+ const engine = this.ensureInitialized();
1851
+ engine.renderLazyComponent(source);
1852
+ }
1853
+ renderInto(source, parentNodeId, state) {
1854
+ const engine = this.ensureInitialized();
1855
+ engine.renderInto(source, parentNodeId, unwrapForWasm(state));
1856
+ }
1857
+ notifyStateChange(paths, values) {
1858
+ const engine = this.ensureInitialized();
1859
+ if (paths.length === 0) {
1860
+ return;
1861
+ }
1862
+ engine.updateStateSparse(paths, unwrapForWasm(values));
1863
+ log9.debug("State changed (sparse):", paths);
1864
+ }
1865
+ notifyStateChangeFull(paths, currentState) {
1866
+ const engine = this.ensureInitialized();
1867
+ engine.updateState(unwrapForWasm(currentState));
1868
+ if (paths.length > 0) {
1869
+ log9.debug("State changed (full):", paths);
1870
+ }
1871
+ }
1872
+ updateState(statePatch) {
1873
+ const engine = this.ensureInitialized();
1874
+ engine.updateState(unwrapForWasm(statePatch));
1875
+ }
1876
+ dispatchAction(name, payload) {
1877
+ const engine = this.ensureInitialized();
1878
+ engine.dispatchAction(name, payload ?? null);
1879
+ }
1880
+ onAction(actionName, handler) {
1881
+ const engine = this.ensureInitialized();
1882
+ engine.onAction(actionName, (action) => {
1883
+ Promise.resolve(handler(action)).catch((err) => log9.error("Action handler error:", err));
1884
+ });
1885
+ }
1886
+ setModule(name, actions, stateKeys, initialState) {
1887
+ const engine = this.ensureInitialized();
1888
+ engine.setModule(name, actions, stateKeys, initialState);
1889
+ }
1890
+ getRevision() {
1891
+ const engine = this.ensureInitialized();
1892
+ return Number(engine.getRevision());
1893
+ }
1894
+ clearTree() {
1895
+ const engine = this.ensureInitialized();
1896
+ engine.clearTree();
1897
+ }
1898
+ debugParseComponent(source) {
1899
+ const engine = this.ensureInitialized();
1900
+ return engine.debugParseComponent(source);
1901
+ }
1902
+ }
1903
+
2036
1904
  // src/remote/server.ts
2037
1905
  init_app();
2038
1906
 
@@ -2162,7 +2030,7 @@ class SessionManager {
2162
2030
 
2163
2031
  // src/remote/server.ts
2164
2032
  init_logger();
2165
- var log11 = frameworkLoggers.remote;
2033
+ var log10 = frameworkLoggers.remote;
2166
2034
 
2167
2035
  class RemoteServer {
2168
2036
  _module = null;
@@ -2240,7 +2108,7 @@ class RemoteServer {
2240
2108
  return new Response("Hypen Remote Server", { status: 200 });
2241
2109
  }
2242
2110
  });
2243
- log11.info(`Hypen app streaming on ws://${hostname}:${finalPort}`);
2111
+ log10.info(`Hypen app streaming on ws://${hostname}:${finalPort}`);
2244
2112
  return this;
2245
2113
  }
2246
2114
  stop() {
@@ -2283,7 +2151,7 @@ class RemoteServer {
2283
2151
  }
2284
2152
  }, 1000);
2285
2153
  } catch (error) {
2286
- log11.error("Error handling WebSocket open:", error);
2154
+ log10.error("Error handling WebSocket open:", error);
2287
2155
  ws.close(1011, "Internal server error");
2288
2156
  }
2289
2157
  }
@@ -2454,7 +2322,7 @@ class RemoteServer {
2454
2322
  break;
2455
2323
  }
2456
2324
  } catch (error) {
2457
- log11.error("Error handling WebSocket message:", error);
2325
+ log10.error("Error handling WebSocket message:", error);
2458
2326
  }
2459
2327
  }
2460
2328
  async handleClose(ws) {
@@ -2537,7 +2405,7 @@ function serve(options) {
2537
2405
  init_logger();
2538
2406
  import { existsSync, readdirSync, readFileSync } from "fs";
2539
2407
  import { join } from "path";
2540
- var log12 = frameworkLoggers.loader;
2408
+ var log11 = frameworkLoggers.loader;
2541
2409
 
2542
2410
  class ComponentLoader {
2543
2411
  components = new Map;
@@ -2572,16 +2440,16 @@ class ComponentLoader {
2572
2440
  const templatePath = join(dirPath, "component.hypen");
2573
2441
  const template = readFileSync(templatePath, "utf-8");
2574
2442
  this.register(name, module, template, dirPath);
2575
- log12.debug(`Loaded component: ${name} from ${dirPath}`);
2443
+ log11.debug(`Loaded component: ${name} from ${dirPath}`);
2576
2444
  } catch (error) {
2577
- log12.error(`Failed to load component ${name} from ${dirPath}:`, error);
2445
+ log11.error(`Failed to load component ${name} from ${dirPath}:`, error);
2578
2446
  throw error;
2579
2447
  }
2580
2448
  }
2581
2449
  async loadFromComponentsDir(baseDir) {
2582
2450
  try {
2583
2451
  if (!existsSync(baseDir)) {
2584
- log12.warn(`Components directory not found: ${baseDir}`);
2452
+ log11.warn(`Components directory not found: ${baseDir}`);
2585
2453
  return;
2586
2454
  }
2587
2455
  const entries = readdirSync(baseDir, { withFileTypes: true });
@@ -2594,9 +2462,9 @@ class ComponentLoader {
2594
2462
  await this.loadFromDirectory(entry.name, componentDir);
2595
2463
  }
2596
2464
  }
2597
- log12.debug(`Loaded ${this.components.size} components from ${baseDir}`);
2465
+ log11.debug(`Loaded ${this.components.size} components from ${baseDir}`);
2598
2466
  } catch (error) {
2599
- log12.error(`Failed to load components from ${baseDir}:`, error);
2467
+ log11.error(`Failed to load components from ${baseDir}:`, error);
2600
2468
  throw error;
2601
2469
  }
2602
2470
  }
@@ -2607,14 +2475,32 @@ var componentLoader = new ComponentLoader;
2607
2475
  class ComponentResolver {
2608
2476
  cache = new Map;
2609
2477
  options;
2478
+ moduleRegistry;
2610
2479
  constructor(options = {}) {
2611
2480
  this.options = {
2612
2481
  baseDir: options.baseDir || process.cwd(),
2613
2482
  cache: options.cache ?? true,
2614
- customFetch: options.customFetch || this.defaultFetch.bind(this)
2483
+ customFetch: options.customFetch || this.defaultFetch.bind(this),
2484
+ moduleRegistry: options.moduleRegistry
2615
2485
  };
2486
+ this.moduleRegistry = options.moduleRegistry;
2616
2487
  }
2617
2488
  async resolve(importStmt) {
2489
+ if (this.moduleRegistry) {
2490
+ const names = importStmt.clause.type === "named" ? importStmt.clause.names : [importStmt.clause.name];
2491
+ const allFound = names.every((name) => this.moduleRegistry.has(name));
2492
+ if (allFound) {
2493
+ const result = {};
2494
+ for (const name of names) {
2495
+ const def = this.moduleRegistry.get(name);
2496
+ result[name] = {
2497
+ module: def,
2498
+ template: def?.template || ""
2499
+ };
2500
+ }
2501
+ return result;
2502
+ }
2503
+ }
2618
2504
  const sourcePath = this.getSourcePath(importStmt.source);
2619
2505
  if (this.options.cache && this.cache.has(sourcePath)) {
2620
2506
  const cached = this.cache.get(sourcePath);
@@ -2632,8 +2518,17 @@ class ComponentResolver {
2632
2518
  return this.extractComponents(importStmt.clause, component);
2633
2519
  }
2634
2520
  async resolveLocal(path) {
2635
- throw new Error(`Dynamic local component resolution not yet implemented: ${path}
2636
- ` + `Please use the build-components.ts script to generate component imports.`);
2521
+ const { resolve, join: join2 } = await import("path");
2522
+ const { readFile } = await import("fs/promises");
2523
+ const basePath = resolve(this.options.baseDir, path);
2524
+ const hypenPath = basePath.endsWith(".hypen") ? basePath : `${basePath}.hypen`;
2525
+ const template = await readFile(hypenPath, "utf-8");
2526
+ const modulePath = hypenPath.replace(/\.hypen$/, ".ts");
2527
+ let module = {};
2528
+ try {
2529
+ module = await import(modulePath);
2530
+ } catch {}
2531
+ return { module, template };
2637
2532
  }
2638
2533
  async resolveUrl(url) {
2639
2534
  try {
@@ -2701,29 +2596,26 @@ class ComponentResolver {
2701
2596
  init_logger();
2702
2597
  import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, watch } from "fs";
2703
2598
  import { join as join2, basename, resolve } from "path";
2704
- function removeImports(text) {
2705
- return text.replace(/import\s+(?:\{[^}]+\}|\w+)\s+from\s+["'][^"']+["']\s*/g, "");
2706
- }
2707
2599
  async function discoverComponents(baseDir, options = {}) {
2708
2600
  const {
2709
2601
  patterns = ["single-file", "folder", "sibling", "index"],
2710
2602
  recursive = false,
2711
2603
  debug = false
2712
2604
  } = options;
2713
- const log13 = debug ? (...args) => frameworkLoggers.discovery.debug(...args) : () => {};
2605
+ const log12 = debug ? (...args) => frameworkLoggers.discovery.debug(...args) : () => {};
2714
2606
  const resolvedDir = resolve(baseDir);
2715
2607
  const components = [];
2716
2608
  const seen = new Set;
2717
- log13("Scanning directory:", resolvedDir);
2718
- log13("Patterns:", patterns);
2609
+ log12("Scanning directory:", resolvedDir);
2610
+ log12("Patterns:", patterns);
2719
2611
  const addTwoFileComponent = (name, hypenPath, modulePath) => {
2720
2612
  if (seen.has(name)) {
2721
- log13(`Skipping duplicate: ${name}`);
2613
+ log12(`Skipping duplicate: ${name}`);
2722
2614
  return;
2723
2615
  }
2724
2616
  seen.add(name);
2725
2617
  const templateRaw = readFileSync2(hypenPath, "utf-8");
2726
- const template = removeImports(templateRaw).trim();
2618
+ const template = templateRaw.trim();
2727
2619
  components.push({
2728
2620
  name,
2729
2621
  hypenPath,
@@ -2732,11 +2624,11 @@ async function discoverComponents(baseDir, options = {}) {
2732
2624
  hasModule: modulePath !== null,
2733
2625
  isSingleFile: false
2734
2626
  });
2735
- log13(`Found: ${name} (two-file, ${modulePath ? "with module" : "stateless"})`);
2627
+ log12(`Found: ${name} (two-file, ${modulePath ? "with module" : "stateless"})`);
2736
2628
  };
2737
2629
  const addSingleFileComponent = (name, modulePath, template) => {
2738
2630
  if (seen.has(name)) {
2739
- log13(`Skipping duplicate: ${name}`);
2631
+ log12(`Skipping duplicate: ${name}`);
2740
2632
  return;
2741
2633
  }
2742
2634
  seen.add(name);
@@ -2748,7 +2640,7 @@ async function discoverComponents(baseDir, options = {}) {
2748
2640
  hasModule: true,
2749
2641
  isSingleFile: true
2750
2642
  });
2751
- log13(`Found: ${name} (single-file with inline template)`);
2643
+ log12(`Found: ${name} (single-file with inline template)`);
2752
2644
  };
2753
2645
  const scanForFolderComponents = (dir) => {
2754
2646
  if (!existsSync2(dir))
@@ -2832,7 +2724,7 @@ async function discoverComponents(baseDir, options = {}) {
2832
2724
  addSingleFileComponent(baseName, modulePath, module.template);
2833
2725
  }
2834
2726
  } catch (e) {
2835
- log13(`Failed to import potential single-file component: ${entry.name}`, e);
2727
+ log12(`Failed to import potential single-file component: ${entry.name}`, e);
2836
2728
  }
2837
2729
  }
2838
2730
  }
@@ -2846,7 +2738,7 @@ async function discoverComponents(baseDir, options = {}) {
2846
2738
  if (patterns.includes("single-file")) {
2847
2739
  await scanForSingleFileComponents(resolvedDir);
2848
2740
  }
2849
- log13(`Discovered ${components.length} components`);
2741
+ log12(`Discovered ${components.length} components`);
2850
2742
  return components;
2851
2743
  }
2852
2744
  async function loadDiscoveredComponents(components) {
@@ -2882,7 +2774,7 @@ function watchComponents(baseDir, options = {}) {
2882
2774
  debug = false,
2883
2775
  ...discoveryOptions
2884
2776
  } = options;
2885
- const log13 = debug ? (...args) => frameworkLoggers.discovery.debug("[watch]", ...args) : () => {};
2777
+ const log12 = debug ? (...args) => frameworkLoggers.discovery.debug("[watch]", ...args) : () => {};
2886
2778
  let currentComponents = new Map;
2887
2779
  let debounceTimer = null;
2888
2780
  const initialScan = async () => {
@@ -2895,22 +2787,22 @@ function watchComponents(baseDir, options = {}) {
2895
2787
  clearTimeout(debounceTimer);
2896
2788
  }
2897
2789
  debounceTimer = setTimeout(async () => {
2898
- log13("Rescanning...");
2790
+ log12("Rescanning...");
2899
2791
  const newComponents = await discoverComponents(resolvedDir, discoveryOptions);
2900
2792
  const newMap = new Map(newComponents.map((c) => [c.name, c]));
2901
2793
  for (const [name, component] of newMap) {
2902
2794
  const existing = currentComponents.get(name);
2903
2795
  if (!existing) {
2904
- log13("Added:", name);
2796
+ log12("Added:", name);
2905
2797
  onAdd?.(component);
2906
2798
  } else if (existing.template !== component.template || existing.modulePath !== component.modulePath) {
2907
- log13("Updated:", name);
2799
+ log12("Updated:", name);
2908
2800
  onUpdate?.(component);
2909
2801
  }
2910
2802
  }
2911
2803
  for (const name of currentComponents.keys()) {
2912
2804
  if (!newMap.has(name)) {
2913
- log13("Removed:", name);
2805
+ log12("Removed:", name);
2914
2806
  onRemove?.(name);
2915
2807
  }
2916
2808
  }
@@ -2922,7 +2814,7 @@ function watchComponents(baseDir, options = {}) {
2922
2814
  if (!filename)
2923
2815
  return;
2924
2816
  if (filename.endsWith(".hypen") || filename.endsWith(".ts")) {
2925
- log13("File changed:", filename);
2817
+ log12("File changed:", filename);
2926
2818
  rescan();
2927
2819
  }
2928
2820
  });
@@ -3045,28 +2937,28 @@ function parseImports(text) {
3045
2937
  }
3046
2938
  return imports;
3047
2939
  }
3048
- function removeImports2(text) {
2940
+ function removeImports(text) {
3049
2941
  return text.replace(/import\s+(?:\{[^}]+\}|\w+)\s+from\s+["'][^"']+["']\s*/g, "");
3050
2942
  }
3051
2943
  function hypenPlugin(options = {}) {
3052
2944
  const { debug = false, patterns = ["sibling", "component", "index"] } = options;
3053
- const log13 = debug ? (...args) => frameworkLoggers.plugin.debug(...args) : () => {};
2945
+ const log12 = debug ? (...args) => frameworkLoggers.plugin.debug(...args) : () => {};
3054
2946
  return {
3055
2947
  name: "hypen-loader",
3056
2948
  async setup(build) {
3057
2949
  build.onLoad({ filter: /\.hypen$/ }, async (args) => {
3058
2950
  const hypenPath = resolve2(args.path);
3059
- log13("Loading:", hypenPath);
2951
+ log12("Loading:", hypenPath);
3060
2952
  const templateRaw = readFileSync3(hypenPath, "utf-8");
3061
2953
  const imports = parseImports(templateRaw);
3062
- const template = removeImports2(templateRaw).trim();
2954
+ const template = removeImports(templateRaw).trim();
3063
2955
  if (imports.length > 0) {
3064
- log13("Found imports:", imports);
2956
+ log12("Found imports:", imports);
3065
2957
  }
3066
2958
  const componentName = getComponentName(hypenPath);
3067
- log13("Component name:", componentName);
2959
+ log12("Component name:", componentName);
3068
2960
  const modulePath = findModulePath(hypenPath, patterns);
3069
- log13("Module path:", modulePath);
2961
+ log12("Module path:", modulePath);
3070
2962
  let contents;
3071
2963
  if (modulePath) {
3072
2964
  const relativeModulePath = modulePath.replace(/\.ts$/, ".js");
@@ -3078,7 +2970,7 @@ export const name = ${JSON.stringify(componentName)};
3078
2970
  export default { module: _module, template: ${JSON.stringify(template)}, name: ${JSON.stringify(componentName)} };
3079
2971
  `;
3080
2972
  } else {
3081
- log13("No module found, creating stateless component");
2973
+ log12("No module found, creating stateless component");
3082
2974
  contents = `
3083
2975
  import { app } from "@hypen-space/core";
3084
2976
  const _module = app.defineState({}).build();
@@ -3105,19 +2997,19 @@ var plugin_default = hypenPlugin;
3105
2997
  // src/components/builtin.ts
3106
2998
  init_app();
3107
2999
  init_logger();
3108
- var log13 = frameworkLoggers.router;
3000
+ var log12 = frameworkLoggers.router;
3109
3001
  var Router = app.defineState({
3110
3002
  currentPath: "/",
3111
3003
  matchedRoute: null,
3112
3004
  routeParams: {}
3113
3005
  }, { name: "__Router" }).onCreated((state, context) => {
3114
3006
  if (!context) {
3115
- log13.error("Requires global context");
3007
+ log12.error("Requires global context");
3116
3008
  return;
3117
3009
  }
3118
3010
  const router = context.__router;
3119
3011
  if (!router) {
3120
- log13.error("Router not found in context");
3012
+ log12.error("Router not found in context");
3121
3013
  return;
3122
3014
  }
3123
3015
  const hypenEngine = context.__hypenEngine;
@@ -3139,13 +3031,13 @@ var Router = app.defineState({
3139
3031
  try {
3140
3032
  await hypenEngine.renderLazyRoute(routePath, componentName, htmlEl);
3141
3033
  } catch (err) {
3142
- log13.error(`Failed to render route ${routePath}:`, err);
3034
+ log12.error(`Failed to render route ${routePath}:`, err);
3143
3035
  }
3144
3036
  }
3145
3037
  }
3146
3038
  }
3147
3039
  if (!matchFound) {
3148
- log13.warn(`No route matched path: ${currentPath}. Available routes:`, Array.from(routeElements).map((el) => el.dataset.routePath));
3040
+ log12.warn(`No route matched path: ${currentPath}. Available routes:`, Array.from(routeElements).map((el) => el.dataset.routePath));
3149
3041
  }
3150
3042
  };
3151
3043
  setTimeout(() => {
@@ -3164,7 +3056,7 @@ var Link = app.defineState({
3164
3056
  }, { name: "__Link" }).onAction("navigate", ({ state, context }) => {
3165
3057
  const router = context?.__router;
3166
3058
  if (!router) {
3167
- log13.error("Link requires router context");
3059
+ log12.error("Link requires router context");
3168
3060
  return;
3169
3061
  }
3170
3062
  const targetPath = state.to;
@@ -3314,16 +3206,14 @@ export {
3314
3206
  HypenAppBuilder,
3315
3207
  HypenApp,
3316
3208
  Err,
3317
- Engine,
3318
3209
  DisposableStack,
3319
3210
  DisposableMixin,
3320
3211
  ConsoleRenderer,
3321
3212
  ConnectionError,
3322
3213
  ComponentResolver,
3323
3214
  ComponentLoader,
3324
- Engine2 as BrowserEngine,
3325
3215
  BaseRenderer,
3326
3216
  ActionError
3327
3217
  };
3328
3218
 
3329
- //# debugId=202EDC5229AA5FFA64756E2164756E21
3219
+ //# debugId=C03FB9EC8278859464756E2164756E21