@hypen-space/core 0.4.37 → 0.4.39

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 (85) hide show
  1. package/README.md +13 -14
  2. package/dist/app.js +304 -227
  3. package/dist/app.js.map +5 -5
  4. package/dist/components/builtin.d.ts +17 -0
  5. package/dist/components/builtin.js +336 -256
  6. package/dist/components/builtin.js.map +6 -6
  7. package/dist/context.d.ts +11 -20
  8. package/dist/context.js +69 -101
  9. package/dist/context.js.map +3 -3
  10. package/dist/datasource.js +80 -0
  11. package/dist/datasource.js.map +10 -0
  12. package/dist/disposable.js +60 -63
  13. package/dist/disposable.js.map +2 -2
  14. package/dist/events.js +60 -63
  15. package/dist/events.js.map +2 -2
  16. package/dist/hypen.js +78 -0
  17. package/dist/hypen.js.map +10 -0
  18. package/dist/index.browser.d.ts +2 -1
  19. package/dist/index.browser.js +327 -281
  20. package/dist/index.browser.js.map +7 -8
  21. package/dist/index.d.ts +0 -3
  22. package/dist/index.js +547 -246
  23. package/dist/index.js.map +9 -9
  24. package/dist/logger.js +60 -64
  25. package/dist/logger.js.map +2 -2
  26. package/dist/remote/client.js +258 -158
  27. package/dist/remote/client.js.map +6 -6
  28. package/dist/remote/index.d.ts +6 -5
  29. package/dist/remote/index.js +255 -1985
  30. package/dist/remote/index.js.map +6 -13
  31. package/dist/remote/session.js +151 -0
  32. package/dist/remote/session.js.map +10 -0
  33. package/dist/renderer.js +60 -63
  34. package/dist/renderer.js.map +2 -2
  35. package/dist/result.js +235 -0
  36. package/dist/result.js.map +10 -0
  37. package/dist/retry.js +344 -0
  38. package/dist/retry.js.map +11 -0
  39. package/dist/router.js +62 -70
  40. package/dist/router.js.map +2 -2
  41. package/dist/state.js +3 -8
  42. package/dist/state.js.map +2 -2
  43. package/package.json +11 -56
  44. package/src/components/builtin.ts +78 -56
  45. package/src/context.ts +22 -65
  46. package/src/index.browser.ts +5 -4
  47. package/src/index.ts +10 -23
  48. package/src/remote/index.ts +9 -5
  49. package/src/result.ts +11 -0
  50. package/dist/discovery.d.ts +0 -90
  51. package/dist/discovery.js +0 -1334
  52. package/dist/discovery.js.map +0 -15
  53. package/dist/engine.browser.d.ts +0 -116
  54. package/dist/engine.browser.js +0 -479
  55. package/dist/engine.browser.js.map +0 -12
  56. package/dist/engine.d.ts +0 -107
  57. package/dist/engine.js +0 -543
  58. package/dist/engine.js.map +0 -12
  59. package/dist/loader.d.ts +0 -51
  60. package/dist/loader.js +0 -292
  61. package/dist/loader.js.map +0 -11
  62. package/dist/plugin.d.ts +0 -39
  63. package/dist/plugin.js +0 -685
  64. package/dist/plugin.js.map +0 -12
  65. package/dist/remote/server.d.ts +0 -188
  66. package/dist/remote/server.js +0 -2270
  67. package/dist/remote/server.js.map +0 -19
  68. package/src/discovery.ts +0 -527
  69. package/src/engine.browser.ts +0 -302
  70. package/src/engine.ts +0 -282
  71. package/src/loader.ts +0 -136
  72. package/src/plugin.ts +0 -220
  73. package/src/remote/server.ts +0 -879
  74. package/wasm-browser/README.md +0 -594
  75. package/wasm-browser/hypen_engine.d.ts +0 -389
  76. package/wasm-browser/hypen_engine.js +0 -1070
  77. package/wasm-browser/hypen_engine_bg.wasm +0 -0
  78. package/wasm-browser/hypen_engine_bg.wasm.d.ts +0 -37
  79. package/wasm-browser/package.json +0 -24
  80. package/wasm-node/README.md +0 -594
  81. package/wasm-node/hypen_engine.d.ts +0 -327
  82. package/wasm-node/hypen_engine.js +0 -979
  83. package/wasm-node/hypen_engine_bg.wasm +0 -0
  84. package/wasm-node/hypen_engine_bg.wasm.d.ts +0 -37
  85. package/wasm-node/package.json +0 -22
package/dist/discovery.js DELETED
@@ -1,1334 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
18
-
19
- // src/logger.ts
20
- function isProduction() {
21
- if (typeof process !== "undefined" && process.env) {
22
- return false;
23
- }
24
- return false;
25
- }
26
- function setLogLevel(level) {
27
- config.level = level;
28
- }
29
- function getLogLevel() {
30
- return config.level;
31
- }
32
- function configureLogger(options) {
33
- config = { ...config, ...options };
34
- }
35
- function enableLogging() {
36
- config.level = "debug";
37
- }
38
- function disableLogging() {
39
- config.level = "none";
40
- }
41
- function setDebugMode(enabled) {
42
- config.level = enabled ? "debug" : "error";
43
- }
44
- function isDebugMode() {
45
- return config.level === "debug";
46
- }
47
- function shouldLog(level) {
48
- return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
49
- }
50
- function formatTag(tag, level) {
51
- const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
52
- if (config.colors && level !== "none") {
53
- const color = LOG_LEVEL_COLORS[level];
54
- return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
55
- }
56
- return `${timestamp}[${tag}]`;
57
- }
58
-
59
- class Logger {
60
- tag;
61
- constructor(tag) {
62
- this.tag = tag;
63
- }
64
- debug(...args) {
65
- if (!shouldLog("debug"))
66
- return;
67
- if (config.handler) {
68
- config.handler.debug(this.tag, ...args);
69
- } else {
70
- console.log(formatTag(this.tag, "debug"), ...args);
71
- }
72
- }
73
- info(...args) {
74
- if (!shouldLog("info"))
75
- return;
76
- if (config.handler) {
77
- config.handler.info(this.tag, ...args);
78
- } else {
79
- console.info(formatTag(this.tag, "info"), ...args);
80
- }
81
- }
82
- warn(...args) {
83
- if (!shouldLog("warn"))
84
- return;
85
- if (config.handler) {
86
- config.handler.warn(this.tag, ...args);
87
- } else {
88
- console.warn(formatTag(this.tag, "warn"), ...args);
89
- }
90
- }
91
- error(...args) {
92
- if (!shouldLog("error"))
93
- return;
94
- if (config.handler) {
95
- config.handler.error(this.tag, ...args);
96
- } else {
97
- console.error(formatTag(this.tag, "error"), ...args);
98
- }
99
- }
100
- time(label, fn) {
101
- if (!shouldLog("debug")) {
102
- return fn();
103
- }
104
- const start = performance.now();
105
- try {
106
- return fn();
107
- } finally {
108
- const duration = performance.now() - start;
109
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
110
- }
111
- }
112
- async timeAsync(label, fn) {
113
- if (!shouldLog("debug")) {
114
- return fn();
115
- }
116
- const start = performance.now();
117
- try {
118
- return await fn();
119
- } finally {
120
- const duration = performance.now() - start;
121
- this.debug(`${label}: ${duration.toFixed(2)}ms`);
122
- }
123
- }
124
- child(subTag) {
125
- return new Logger(`${this.tag}:${subTag}`);
126
- }
127
- debugIf(condition, ...args) {
128
- if (condition)
129
- this.debug(...args);
130
- }
131
- warnIf(condition, ...args) {
132
- if (condition)
133
- this.warn(...args);
134
- }
135
- errorIf(condition, ...args) {
136
- if (condition)
137
- this.error(...args);
138
- }
139
- loggedOnce = new Set;
140
- warnOnce(key, ...args) {
141
- if (this.loggedOnce.has(key))
142
- return;
143
- this.loggedOnce.add(key);
144
- this.warn(...args);
145
- }
146
- debugOnce(key, ...args) {
147
- if (this.loggedOnce.has(key))
148
- return;
149
- this.loggedOnce.add(key);
150
- this.debug(...args);
151
- }
152
- }
153
- function createLogger(tag) {
154
- return new Logger(tag);
155
- }
156
- var LOG_LEVEL_ORDER, LOG_LEVEL_COLORS, RESET_COLOR = "\x1B[0m", config, logger, log, frameworkLoggers;
157
- var init_logger = __esm(() => {
158
- LOG_LEVEL_ORDER = {
159
- debug: 0,
160
- info: 1,
161
- warn: 2,
162
- error: 3,
163
- none: 4
164
- };
165
- LOG_LEVEL_COLORS = {
166
- debug: "\x1B[36m",
167
- info: "\x1B[32m",
168
- warn: "\x1B[33m",
169
- error: "\x1B[31m"
170
- };
171
- config = {
172
- level: isProduction() ? "error" : "info",
173
- colors: true,
174
- timestamps: false
175
- };
176
- logger = createLogger("Hypen");
177
- log = {
178
- debug: (tag, ...args) => {
179
- if (!shouldLog("debug"))
180
- return;
181
- console.log(formatTag(tag, "debug"), ...args);
182
- },
183
- info: (tag, ...args) => {
184
- if (!shouldLog("info"))
185
- return;
186
- console.info(formatTag(tag, "info"), ...args);
187
- },
188
- warn: (tag, ...args) => {
189
- if (!shouldLog("warn"))
190
- return;
191
- console.warn(formatTag(tag, "warn"), ...args);
192
- },
193
- error: (tag, ...args) => {
194
- if (!shouldLog("error"))
195
- return;
196
- console.error(formatTag(tag, "error"), ...args);
197
- }
198
- };
199
- frameworkLoggers = {
200
- hypen: createLogger("Hypen"),
201
- engine: createLogger("Engine"),
202
- router: createLogger("Router"),
203
- state: createLogger("State"),
204
- events: createLogger("Events"),
205
- remote: createLogger("Remote"),
206
- renderer: createLogger("Renderer"),
207
- module: createLogger("Module"),
208
- lifecycle: createLogger("Lifecycle"),
209
- loader: createLogger("Loader"),
210
- context: createLogger("Context"),
211
- discovery: createLogger("Discovery"),
212
- plugin: createLogger("Plugin"),
213
- canvas: createLogger("Canvas"),
214
- debug: createLogger("Debug")
215
- };
216
- });
217
-
218
- // src/result.ts
219
- function Ok(value) {
220
- return { ok: true, value };
221
- }
222
- function Err(error) {
223
- return { ok: false, error };
224
- }
225
- function isOk(result) {
226
- return result.ok;
227
- }
228
- function isErr(result) {
229
- return !result.ok;
230
- }
231
- async function fromPromise(promise, mapError) {
232
- try {
233
- const value = await promise;
234
- return Ok(value);
235
- } catch (e) {
236
- if (mapError) {
237
- return Err(mapError(e));
238
- }
239
- return Err(e);
240
- }
241
- }
242
- function fromTry(fn, mapError) {
243
- try {
244
- return Ok(fn());
245
- } catch (e) {
246
- if (mapError) {
247
- return Err(mapError(e));
248
- }
249
- return Err(e);
250
- }
251
- }
252
- function map(result, fn) {
253
- if (result.ok) {
254
- return Ok(fn(result.value));
255
- }
256
- return result;
257
- }
258
- function mapErr(result, fn) {
259
- if (!result.ok) {
260
- return Err(fn(result.error));
261
- }
262
- return result;
263
- }
264
- function flatMap(result, fn) {
265
- if (result.ok) {
266
- return fn(result.value);
267
- }
268
- return result;
269
- }
270
- function unwrap(result) {
271
- if (result.ok) {
272
- return result.value;
273
- }
274
- throw result.error;
275
- }
276
- function unwrapOr(result, defaultValue) {
277
- if (result.ok) {
278
- return result.value;
279
- }
280
- return defaultValue;
281
- }
282
- function unwrapOrElse(result, fn) {
283
- if (result.ok) {
284
- return result.value;
285
- }
286
- return fn(result.error);
287
- }
288
- function match(result, handlers) {
289
- if (result.ok) {
290
- return handlers.ok(result.value);
291
- }
292
- return handlers.err(result.error);
293
- }
294
- function all(results) {
295
- const values = [];
296
- for (const result of results) {
297
- if (!result.ok) {
298
- return result;
299
- }
300
- values.push(result.value);
301
- }
302
- return Ok(values);
303
- }
304
- function classifyEngineError(err) {
305
- const message = err instanceof Error ? err.message : String(err);
306
- if (message.startsWith("Parse error:")) {
307
- return new ParseError(message);
308
- }
309
- if (message.startsWith("Invalid state:") || message.startsWith("Invalid state patch:")) {
310
- return new StateError(message);
311
- }
312
- if (message.startsWith("Parent node not found:")) {
313
- return new RenderError(message);
314
- }
315
- return new RenderError(message);
316
- }
317
- var HypenError, ActionError, ConnectionError, StateError, ParseError, RenderError;
318
- var init_result = __esm(() => {
319
- HypenError = class HypenError extends Error {
320
- code;
321
- context;
322
- cause;
323
- constructor(code, message, options) {
324
- super(message);
325
- this.name = "HypenError";
326
- this.code = code;
327
- this.context = options?.context;
328
- this.cause = options?.cause;
329
- Object.setPrototypeOf(this, new.target.prototype);
330
- }
331
- };
332
- ActionError = class ActionError extends HypenError {
333
- actionName;
334
- constructor(actionName, cause) {
335
- super("ACTION_ERROR", `Action handler "${actionName}" failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
336
- context: { actionName },
337
- cause: cause instanceof Error ? cause : undefined
338
- });
339
- this.name = "ActionError";
340
- this.actionName = actionName;
341
- }
342
- };
343
- ConnectionError = class ConnectionError extends HypenError {
344
- url;
345
- attempt;
346
- constructor(url, cause, attempt) {
347
- super("CONNECTION_ERROR", `Connection to "${url}" failed${attempt ? ` (attempt ${attempt})` : ""}: ${cause instanceof Error ? cause.message : String(cause)}`, {
348
- context: { url, attempt },
349
- cause: cause instanceof Error ? cause : undefined
350
- });
351
- this.name = "ConnectionError";
352
- this.url = url;
353
- this.attempt = attempt;
354
- }
355
- };
356
- StateError = class StateError extends HypenError {
357
- path;
358
- constructor(message, path, cause) {
359
- super("STATE_ERROR", message, {
360
- context: { path },
361
- cause: cause instanceof Error ? cause : undefined
362
- });
363
- this.name = "StateError";
364
- this.path = path;
365
- }
366
- };
367
- ParseError = class ParseError extends HypenError {
368
- source;
369
- constructor(message, source, cause) {
370
- super("PARSE_ERROR", message, {
371
- context: { source },
372
- cause: cause instanceof Error ? cause : undefined
373
- });
374
- this.name = "ParseError";
375
- this.source = source;
376
- }
377
- };
378
- RenderError = class RenderError extends HypenError {
379
- constructor(message, cause) {
380
- super("RENDER_ERROR", message, {
381
- cause: cause instanceof Error ? cause : undefined
382
- });
383
- this.name = "RenderError";
384
- }
385
- };
386
- });
387
-
388
- // src/datasource.ts
389
- class DataSourceManager {
390
- plugins = new Map;
391
- configs = new Map;
392
- state = new Map;
393
- engine;
394
- constructor(engine) {
395
- this.engine = engine;
396
- }
397
- async use(plugin, config2) {
398
- const { name } = plugin;
399
- this.state.set(name, {});
400
- this.plugins.set(name, plugin);
401
- this.configs.set(name, config2);
402
- await plugin.connect(config2, (change) => {
403
- const current = this.state.get(name) ?? {};
404
- for (const path of change.paths) {
405
- if (path in change.values) {
406
- current[path] = change.values[path];
407
- }
408
- }
409
- this.state.set(name, current);
410
- this.engine.setContext(name, current);
411
- });
412
- }
413
- get(name) {
414
- return this.plugins.get(name);
415
- }
416
- has(name) {
417
- return this.plugins.has(name);
418
- }
419
- getNames() {
420
- return Array.from(this.plugins.keys());
421
- }
422
- getStatus(name) {
423
- return this.plugins.get(name)?.status;
424
- }
425
- async remove(name) {
426
- const plugin = this.plugins.get(name);
427
- if (plugin) {
428
- await plugin.disconnect();
429
- this.plugins.delete(name);
430
- this.configs.delete(name);
431
- this.state.delete(name);
432
- this.engine.removeContext(name);
433
- }
434
- }
435
- async disconnectAll() {
436
- const names = Array.from(this.plugins.keys());
437
- await Promise.all(names.map((name) => this.remove(name)));
438
- }
439
- }
440
-
441
- // src/state.ts
442
- function deepClone(obj) {
443
- if (obj === null || typeof obj !== "object") {
444
- return obj;
445
- }
446
- if (typeof obj === "function") {
447
- return obj;
448
- }
449
- if (typeof obj.__getSnapshot === "function") {
450
- return obj.__getSnapshot();
451
- }
452
- if (obj instanceof WeakMap || obj instanceof WeakSet) {
453
- return obj;
454
- }
455
- const visited = new WeakMap;
456
- function cloneInternal(value) {
457
- if (value === null || typeof value !== "object") {
458
- return value;
459
- }
460
- if (typeof value === "function") {
461
- return value;
462
- }
463
- if (visited.has(value)) {
464
- return visited.get(value);
465
- }
466
- if (value instanceof WeakMap || value instanceof WeakSet) {
467
- return value;
468
- }
469
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
470
- try {
471
- return structuredClone(value);
472
- } catch {}
473
- }
474
- if (Array.isArray(value)) {
475
- const arrClone = [];
476
- visited.set(value, arrClone);
477
- for (let i = 0;i < value.length; i++) {
478
- arrClone[i] = cloneInternal(value[i]);
479
- }
480
- return arrClone;
481
- }
482
- const objClone = {};
483
- visited.set(value, objClone);
484
- for (const key in value) {
485
- if (Object.prototype.hasOwnProperty.call(value, key)) {
486
- objClone[key] = cloneInternal(value[key]);
487
- }
488
- }
489
- const symbolKeys = Object.getOwnPropertySymbols(value);
490
- for (const sym of symbolKeys) {
491
- objClone[sym] = cloneInternal(value[sym]);
492
- }
493
- return objClone;
494
- }
495
- return cloneInternal(obj);
496
- }
497
- function diffState(oldState, newState, basePath = "") {
498
- const paths = [];
499
- const newValues = {};
500
- function diff(oldVal, newVal, path) {
501
- if (oldVal === newVal)
502
- return;
503
- if (typeof oldVal !== "object" || typeof newVal !== "object" || oldVal === null || newVal === null) {
504
- if (oldVal !== newVal) {
505
- paths.push(path);
506
- newValues[path] = newVal;
507
- }
508
- return;
509
- }
510
- if (Array.isArray(oldVal) || Array.isArray(newVal)) {
511
- if (!Array.isArray(oldVal) || !Array.isArray(newVal) || oldVal.length !== newVal.length) {
512
- paths.push(path);
513
- newValues[path] = newVal;
514
- return;
515
- }
516
- for (let i = 0;i < newVal.length; i++) {
517
- const itemPath = path ? `${path}.${i}` : `${i}`;
518
- diff(oldVal[i], newVal[i], itemPath);
519
- }
520
- return;
521
- }
522
- const oldKeys = new Set(Object.keys(oldVal));
523
- const newKeys = new Set(Object.keys(newVal));
524
- for (const key of newKeys) {
525
- const propPath = path ? `${path}.${key}` : key;
526
- if (!oldKeys.has(key)) {
527
- paths.push(propPath);
528
- newValues[propPath] = newVal[key];
529
- } else {
530
- diff(oldVal[key], newVal[key], propPath);
531
- }
532
- }
533
- for (const key of oldKeys) {
534
- if (!newKeys.has(key)) {
535
- const propPath = path ? `${path}.${key}` : key;
536
- paths.push(propPath);
537
- newValues[propPath] = undefined;
538
- }
539
- }
540
- }
541
- diff(oldState, newState, basePath);
542
- return { paths, newValues };
543
- }
544
- function createObservableState(initialState, options) {
545
- const opts = options || { onChange: () => {} };
546
- if (initialState === null || initialState === undefined) {
547
- initialState = {};
548
- }
549
- if (initialState instanceof Number || initialState instanceof String || initialState instanceof Boolean) {
550
- throw new TypeError("Cannot create observable state from primitive wrapper objects (Number, String, Boolean). " + "Use plain primitives or regular objects instead.");
551
- }
552
- initialState = deepClone(initialState);
553
- let lastSnapshot = deepClone(initialState);
554
- const pathPrefix = opts.pathPrefix || "";
555
- let batchDepth = 0;
556
- let pendingChange = null;
557
- function notifyChange() {
558
- if (batchDepth > 0)
559
- return;
560
- const change = diffState(lastSnapshot, state, pathPrefix);
561
- if (change.paths.length > 0) {
562
- lastSnapshot = deepClone(state);
563
- if (pendingChange) {
564
- change.paths.push(...pendingChange.paths);
565
- Object.assign(change.newValues, pendingChange.newValues);
566
- pendingChange = null;
567
- }
568
- opts.onChange(change);
569
- }
570
- }
571
- let notificationPending = false;
572
- function scheduleBatch() {
573
- if (batchDepth === 0) {
574
- if (!notificationPending) {
575
- notificationPending = true;
576
- queueMicrotask(() => {
577
- notificationPending = false;
578
- if (batchDepth === 0) {
579
- notifyChange();
580
- } else {}
581
- });
582
- }
583
- } else {
584
- pendingChange = pendingChange || { paths: [], newValues: {} };
585
- }
586
- }
587
- const proxyCache = new WeakMap;
588
- function createProxy(target, basePath) {
589
- const cached = proxyCache.get(target);
590
- if (cached)
591
- return cached;
592
- const proxy = new Proxy(target, {
593
- get(obj, prop) {
594
- if (prop === IS_PROXY)
595
- return true;
596
- if (prop === RAW_TARGET)
597
- return obj;
598
- if (prop === "__beginBatch") {
599
- return () => {
600
- batchDepth++;
601
- };
602
- }
603
- if (prop === "__endBatch") {
604
- return () => {
605
- batchDepth--;
606
- if (batchDepth === 0) {
607
- notifyChange();
608
- }
609
- };
610
- }
611
- if (prop === "__getSnapshot") {
612
- return () => deepClone(obj);
613
- }
614
- const value = obj[prop];
615
- if (value && typeof value === "object") {
616
- if (value[IS_PROXY]) {
617
- return value;
618
- }
619
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
620
- return value;
621
- }
622
- const cachedNested = proxyCache.get(value);
623
- if (cachedNested) {
624
- return cachedNested;
625
- }
626
- const nestedProxy = createProxy(value, basePath ? `${basePath}.${String(prop)}` : String(prop));
627
- return nestedProxy;
628
- }
629
- return value;
630
- },
631
- set(obj, prop, value) {
632
- const oldValue = obj[prop];
633
- if (value && typeof value === "object" && value[IS_PROXY]) {
634
- value = value[RAW_TARGET];
635
- }
636
- obj[prop] = value;
637
- if (oldValue !== value) {
638
- scheduleBatch();
639
- }
640
- return true;
641
- },
642
- deleteProperty(obj, prop) {
643
- const existed = Object.prototype.hasOwnProperty.call(obj, prop);
644
- const result = delete obj[prop];
645
- if (existed) {
646
- scheduleBatch();
647
- }
648
- return result;
649
- }
650
- });
651
- proxyCache.set(target, proxy);
652
- return proxy;
653
- }
654
- const state = createProxy(initialState, pathPrefix);
655
- return state;
656
- }
657
- function batchStateUpdates(state, fn) {
658
- const s = state;
659
- if (s.__beginBatch && s.__endBatch) {
660
- s.__beginBatch();
661
- try {
662
- fn();
663
- } finally {
664
- s.__endBatch();
665
- }
666
- } else {
667
- fn();
668
- }
669
- }
670
- function getStateSnapshot(state) {
671
- const s = state;
672
- if (s.__getSnapshot) {
673
- return s.__getSnapshot();
674
- }
675
- return deepClone(state);
676
- }
677
- function isStateProxy(value) {
678
- return value !== null && typeof value === "object" && value[IS_PROXY] === true;
679
- }
680
- function unwrapProxy(value) {
681
- if (value !== null && typeof value === "object" && value[IS_PROXY]) {
682
- return value[RAW_TARGET];
683
- }
684
- return value;
685
- }
686
- var IS_PROXY, RAW_TARGET;
687
- var init_state = __esm(() => {
688
- IS_PROXY = Symbol.for("hypen.isProxy");
689
- RAW_TARGET = Symbol.for("hypen.rawTarget");
690
- });
691
-
692
- // src/app.ts
693
- var exports_app = {};
694
- __export(exports_app, {
695
- app: () => app,
696
- HypenModuleInstance: () => HypenModuleInstance,
697
- HypenAppBuilder: () => HypenAppBuilder,
698
- HypenApp: () => HypenApp
699
- });
700
-
701
- class HypenAppBuilder {
702
- initialState;
703
- options;
704
- createdHandler;
705
- actionHandlers = new Map;
706
- destroyedHandler;
707
- disconnectHandler;
708
- reconnectHandler;
709
- expireHandler;
710
- errorHandler;
711
- template;
712
- _registry;
713
- dataSourceEntries = [];
714
- constructor(initialState, options, registry) {
715
- this.initialState = initialState;
716
- this.options = options || {};
717
- this._registry = registry;
718
- }
719
- onCreated(fn) {
720
- this.createdHandler = fn;
721
- return this;
722
- }
723
- onAction(name, fn) {
724
- this.actionHandlers.set(name, fn);
725
- return this;
726
- }
727
- onDestroyed(fn) {
728
- this.destroyedHandler = fn;
729
- return this;
730
- }
731
- onDisconnect(fn) {
732
- this.disconnectHandler = fn;
733
- return this;
734
- }
735
- onReconnect(fn) {
736
- this.reconnectHandler = fn;
737
- return this;
738
- }
739
- onExpire(fn) {
740
- this.expireHandler = fn;
741
- return this;
742
- }
743
- onError(fn) {
744
- this.errorHandler = fn;
745
- return this;
746
- }
747
- useDataSource(plugin, config2) {
748
- this.dataSourceEntries.push({ plugin, config: config2 });
749
- return this;
750
- }
751
- ui(template) {
752
- this.template = template;
753
- return this.build();
754
- }
755
- uiFile(path) {
756
- const fs = __require("fs");
757
- this.template = fs.readFileSync(path, "utf-8").trim();
758
- return this.build();
759
- }
760
- build() {
761
- const stateKeys = this.initialState !== null && typeof this.initialState === "object" ? Object.keys(this.initialState) : [];
762
- const definition = {
763
- name: this.options.name,
764
- actions: Array.from(this.actionHandlers.keys()),
765
- stateKeys,
766
- persist: this.options.persist,
767
- version: this.options.version,
768
- initialState: this.initialState,
769
- template: this.template,
770
- dataSources: this.dataSourceEntries.length > 0 ? this.dataSourceEntries : undefined,
771
- handlers: {
772
- onCreated: this.createdHandler,
773
- onAction: this.actionHandlers,
774
- onDestroyed: this.destroyedHandler,
775
- onDisconnect: this.disconnectHandler,
776
- onReconnect: this.reconnectHandler,
777
- onExpire: this.expireHandler,
778
- onError: this.errorHandler
779
- }
780
- };
781
- if (this.options.name && this._registry) {
782
- this._registry.set(this.options.name, definition);
783
- }
784
- return definition;
785
- }
786
- }
787
-
788
- class HypenApp {
789
- _registry = new Map;
790
- defineState(initial, options) {
791
- return new HypenAppBuilder(initial, options, this._registry);
792
- }
793
- module(name) {
794
- const registry = this._registry;
795
- return {
796
- defineState: (initial, options) => {
797
- return new HypenAppBuilder(initial, { ...options, name }, registry);
798
- }
799
- };
800
- }
801
- get(name) {
802
- return this._registry.get(name);
803
- }
804
- has(name) {
805
- return this._registry.has(name);
806
- }
807
- get components() {
808
- return this._registry;
809
- }
810
- getNames() {
811
- return Array.from(this._registry.keys());
812
- }
813
- get size() {
814
- return this._registry.size;
815
- }
816
- unregister(name) {
817
- this._registry.delete(name);
818
- }
819
- clear() {
820
- this._registry.clear();
821
- }
822
- }
823
-
824
- class HypenModuleInstance {
825
- engine;
826
- definition;
827
- state;
828
- isDestroyed = false;
829
- router;
830
- globalContext;
831
- stateChangeCallbacks = [];
832
- dataSourceManager;
833
- dataSourceAccessor = {};
834
- constructor(engine, definition, router, globalContext) {
835
- this.engine = engine;
836
- this.definition = definition;
837
- this.router = router ?? null;
838
- this.globalContext = globalContext;
839
- const statePrefix = (definition.name || "").toLowerCase();
840
- this.state = createObservableState(definition.initialState, {
841
- onChange: (change) => {
842
- this.engine.notifyStateChange(change.paths, change.newValues);
843
- this.stateChangeCallbacks.forEach((cb) => cb());
844
- },
845
- pathPrefix: statePrefix || undefined
846
- });
847
- const snapshot = getStateSnapshot(this.state);
848
- const prefixedState = statePrefix ? { [statePrefix]: snapshot } : snapshot;
849
- this.engine.setModule(definition.name || "AnonymousModule", definition.actions, definition.stateKeys, prefixedState);
850
- for (const [actionName, handler] of definition.handlers.onAction) {
851
- log2.debug(`Registering action handler: ${actionName} for module ${definition.name}`);
852
- this.engine.onAction(actionName, async (action) => {
853
- log2.debug(`Action handler fired: ${actionName}`, action);
854
- const actionCtx = {
855
- name: action.name,
856
- payload: action.payload,
857
- sender: action.sender
858
- };
859
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
860
- const result = await this.executeAction(actionName, handler, {
861
- action: actionCtx,
862
- state: this.state,
863
- context,
864
- dataSources: this.dataSourceAccessor
865
- });
866
- if (!result.ok) {
867
- const shouldRethrow = await this.handleError(result.error, { actionName });
868
- if (shouldRethrow) {
869
- throw result.error;
870
- }
871
- } else {
872
- log2.debug(`Action handler completed: ${actionName}`);
873
- }
874
- });
875
- }
876
- this.engine.onAction("__hypen_bind", (action) => {
877
- const payload = action.payload;
878
- if (!payload?.path)
879
- return;
880
- const segments = payload.path.split(".");
881
- let target = this.state;
882
- for (let i = 0;i < segments.length - 1; i++) {
883
- const seg = segments[i];
884
- target = target?.[seg];
885
- if (target == null)
886
- return;
887
- }
888
- const lastSeg = segments[segments.length - 1];
889
- target[lastSeg] = payload.value;
890
- });
891
- this.callCreatedHandler();
892
- }
893
- createGlobalContextAPI() {
894
- if (!this.globalContext) {
895
- throw new Error("Global context not available");
896
- }
897
- const ctx = this.globalContext;
898
- const api = {
899
- getModule: (id) => ctx.getModule(id),
900
- hasModule: (id) => ctx.hasModule(id),
901
- getModuleIds: () => ctx.getModuleIds(),
902
- getGlobalState: () => ctx.getGlobalState(),
903
- emit: (event, payload) => ctx.emit(event, payload),
904
- on: (event, handler) => ctx.on(event, handler),
905
- router: this.router
906
- };
907
- const ctxRecord = ctx;
908
- if (ctxRecord.__hypenEngine) {
909
- api.__hypenEngine = ctxRecord.__hypenEngine;
910
- }
911
- return api;
912
- }
913
- async executeAction(actionName, handler, ctx) {
914
- try {
915
- const result = handler(ctx);
916
- await result;
917
- return Ok(undefined);
918
- } catch (e) {
919
- return Err(new ActionError(actionName, e));
920
- }
921
- }
922
- async handleError(error, context) {
923
- const errorCtx = {
924
- error,
925
- state: this.state,
926
- actionName: context.actionName,
927
- lifecycle: context.lifecycle
928
- };
929
- if (this.definition.handlers.onError) {
930
- try {
931
- const result = await this.definition.handlers.onError(errorCtx);
932
- if (result && typeof result === "object") {
933
- if ("handled" in result && result.handled) {
934
- return false;
935
- }
936
- if ("rethrow" in result && result.rethrow) {
937
- return true;
938
- }
939
- }
940
- } catch (handlerError) {
941
- log2.error("Error in onError handler:", handlerError);
942
- }
943
- }
944
- if (this.globalContext) {
945
- const eventContext = context.actionName ? `action:${context.actionName}` : context.lifecycle ? `lifecycle:${context.lifecycle}` : "unknown";
946
- this.globalContext.emit("error", {
947
- message: error.message,
948
- error,
949
- context: eventContext
950
- });
951
- }
952
- log2.error(`${context.actionName ? `Action "${context.actionName}"` : `Lifecycle "${context.lifecycle}"`} error:`, error);
953
- return false;
954
- }
955
- async callCreatedHandler() {
956
- if (this.definition.dataSources?.length) {
957
- const dsEngine = this.engine;
958
- this.dataSourceManager = new DataSourceManager(dsEngine);
959
- for (const { plugin, config: config2 } of this.definition.dataSources) {
960
- try {
961
- await this.dataSourceManager.use(plugin, config2);
962
- this.dataSourceAccessor[plugin.name] = new Proxy(plugin, {
963
- get(target, prop) {
964
- if (typeof prop === "string" && !(prop in target)) {
965
- return (...args) => target.call(prop, ...args);
966
- }
967
- return target[prop];
968
- }
969
- });
970
- } catch (e) {
971
- log2.error(`Failed to connect data source "${plugin.name}":`, e);
972
- }
973
- }
974
- }
975
- if (this.definition.handlers.onCreated) {
976
- const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
977
- try {
978
- await this.definition.handlers.onCreated(this.state, context);
979
- } catch (e) {
980
- const error = e instanceof HypenError ? e : new ActionError("onCreated", e);
981
- const shouldRethrow = await this.handleError(error, { lifecycle: "created" });
982
- if (shouldRethrow) {
983
- throw error;
984
- }
985
- }
986
- }
987
- }
988
- onStateChange(callback) {
989
- this.stateChangeCallbacks.push(callback);
990
- }
991
- async destroy() {
992
- if (this.isDestroyed)
993
- return;
994
- if (this.dataSourceManager) {
995
- try {
996
- await this.dataSourceManager.disconnectAll();
997
- } catch (e) {
998
- log2.error("Error disconnecting data sources:", e);
999
- }
1000
- this.dataSourceManager = undefined;
1001
- this.dataSourceAccessor = {};
1002
- }
1003
- if (this.definition.handlers.onDestroyed) {
1004
- try {
1005
- await this.definition.handlers.onDestroyed(this.state);
1006
- } catch (e) {
1007
- const error = e instanceof HypenError ? e : new ActionError("onDestroyed", e);
1008
- const shouldRethrow = await this.handleError(error, { lifecycle: "destroyed" });
1009
- if (shouldRethrow) {
1010
- throw error;
1011
- }
1012
- }
1013
- }
1014
- this.isDestroyed = true;
1015
- }
1016
- getState() {
1017
- return getStateSnapshot(this.state);
1018
- }
1019
- getLiveState() {
1020
- return this.state;
1021
- }
1022
- updateState(patch) {
1023
- Object.assign(this.state, patch);
1024
- }
1025
- }
1026
- var log2, app;
1027
- var init_app = __esm(() => {
1028
- init_result();
1029
- init_state();
1030
- init_logger();
1031
- log2 = createLogger("ModuleInstance");
1032
- app = new HypenApp;
1033
- });
1034
-
1035
- // src/discovery.ts
1036
- init_logger();
1037
- import { existsSync, readdirSync, readFileSync, watch } from "fs";
1038
- import { join, basename, resolve, relative } from "path";
1039
- async function discoverComponents(baseDir, options = {}) {
1040
- const {
1041
- patterns = ["single-file", "folder", "sibling", "index"],
1042
- recursive = true,
1043
- debug = false
1044
- } = options;
1045
- const log3 = debug ? (...args) => frameworkLoggers.discovery.debug(...args) : () => {};
1046
- const resolvedDir = resolve(baseDir);
1047
- const components = [];
1048
- const seen = new Set;
1049
- log3("Scanning directory:", resolvedDir);
1050
- log3("Patterns:", patterns);
1051
- const addTwoFileComponent = (name, hypenPath, modulePath) => {
1052
- if (seen.has(name)) {
1053
- log3(`Skipping duplicate: ${name}`);
1054
- return;
1055
- }
1056
- seen.add(name);
1057
- const templateRaw = readFileSync(hypenPath, "utf-8");
1058
- const template = templateRaw.trim();
1059
- components.push({
1060
- name,
1061
- hypenPath,
1062
- modulePath,
1063
- template,
1064
- hasModule: modulePath !== null,
1065
- isSingleFile: false
1066
- });
1067
- log3(`Found: ${name} (two-file, ${modulePath ? "with module" : "stateless"})`);
1068
- };
1069
- const addSingleFileComponent = (name, modulePath, template) => {
1070
- if (seen.has(name)) {
1071
- log3(`Skipping duplicate: ${name}`);
1072
- return;
1073
- }
1074
- seen.add(name);
1075
- components.push({
1076
- name,
1077
- hypenPath: null,
1078
- modulePath,
1079
- template,
1080
- hasModule: true,
1081
- isSingleFile: true
1082
- });
1083
- log3(`Found: ${name} (single-file with inline template)`);
1084
- };
1085
- const scanForFolderComponents = (dir) => {
1086
- if (!existsSync(dir))
1087
- return;
1088
- const entries = readdirSync(dir, { withFileTypes: true });
1089
- for (const entry of entries) {
1090
- if (!entry.isDirectory())
1091
- continue;
1092
- const folderPath = join(dir, entry.name);
1093
- const componentName = entry.name;
1094
- if (patterns.includes("folder")) {
1095
- const hypenPath = join(folderPath, "component.hypen");
1096
- if (existsSync(hypenPath)) {
1097
- const modulePath = join(folderPath, "component.ts");
1098
- addTwoFileComponent(componentName, hypenPath, existsSync(modulePath) ? modulePath : null);
1099
- continue;
1100
- }
1101
- }
1102
- if (patterns.includes("index")) {
1103
- const hypenPath = join(folderPath, "index.hypen");
1104
- if (existsSync(hypenPath)) {
1105
- const modulePath = join(folderPath, "index.ts");
1106
- addTwoFileComponent(componentName, hypenPath, existsSync(modulePath) ? modulePath : null);
1107
- continue;
1108
- }
1109
- }
1110
- if (recursive) {
1111
- scanForFolderComponents(folderPath);
1112
- }
1113
- }
1114
- };
1115
- const scanForSiblingComponents = (dir) => {
1116
- if (!existsSync(dir))
1117
- return;
1118
- const entries = readdirSync(dir, { withFileTypes: true });
1119
- for (const entry of entries) {
1120
- if (entry.isDirectory()) {
1121
- if (recursive) {
1122
- scanForSiblingComponents(join(dir, entry.name));
1123
- }
1124
- continue;
1125
- }
1126
- if (!entry.name.endsWith(".hypen"))
1127
- continue;
1128
- const hypenPath = join(dir, entry.name);
1129
- const baseName = basename(entry.name, ".hypen");
1130
- if (baseName === "component" || baseName === "index")
1131
- continue;
1132
- const modulePath = join(dir, `${baseName}.ts`);
1133
- addTwoFileComponent(baseName, hypenPath, existsSync(modulePath) ? modulePath : null);
1134
- }
1135
- };
1136
- const scanForSingleFileComponents = async (dir) => {
1137
- if (!existsSync(dir))
1138
- return;
1139
- const entries = readdirSync(dir, { withFileTypes: true });
1140
- for (const entry of entries) {
1141
- if (entry.isDirectory()) {
1142
- if (recursive) {
1143
- await scanForSingleFileComponents(join(dir, entry.name));
1144
- }
1145
- continue;
1146
- }
1147
- if (!entry.name.endsWith(".ts"))
1148
- continue;
1149
- if (entry.name.startsWith(".") || entry.name.includes(".test.") || entry.name.includes(".spec."))
1150
- continue;
1151
- const baseName = basename(entry.name, ".ts");
1152
- if (baseName === "component" || baseName === "index")
1153
- continue;
1154
- const hypenPath = join(dir, `${baseName}.hypen`);
1155
- if (existsSync(hypenPath))
1156
- continue;
1157
- const modulePath = join(dir, entry.name);
1158
- const content = readFileSync(modulePath, "utf-8");
1159
- if (content.includes(".ui(") || content.includes(".ui(hypen")) {
1160
- try {
1161
- const moduleExport = await import(modulePath);
1162
- const module = moduleExport.default;
1163
- if (module && typeof module === "object" && module.template) {
1164
- addSingleFileComponent(baseName, modulePath, module.template);
1165
- } else if (module && typeof module === "object") {
1166
- frameworkLoggers.discovery.warn(`Skipping "${entry.name}": has .ui() pattern but module has no .template property. Did you forget to call .ui(hypen\`...\`)?`);
1167
- }
1168
- } catch (e) {
1169
- log3(`Failed to import potential single-file component: ${entry.name}`, e);
1170
- }
1171
- }
1172
- }
1173
- };
1174
- if (patterns.includes("folder") || patterns.includes("index")) {
1175
- scanForFolderComponents(resolvedDir);
1176
- }
1177
- if (patterns.includes("sibling")) {
1178
- scanForSiblingComponents(resolvedDir);
1179
- }
1180
- if (patterns.includes("single-file")) {
1181
- await scanForSingleFileComponents(resolvedDir);
1182
- }
1183
- log3(`Discovered ${components.length} components`);
1184
- return components;
1185
- }
1186
- async function loadDiscoveredComponents(components) {
1187
- const { app: app2 } = await Promise.resolve().then(() => (init_app(), exports_app));
1188
- const loaded = new Map;
1189
- for (const component of components) {
1190
- let module;
1191
- let template = component.template;
1192
- if (component.modulePath) {
1193
- const moduleExport = await import(component.modulePath);
1194
- module = moduleExport.default;
1195
- if (component.isSingleFile && module.template) {
1196
- template = module.template;
1197
- }
1198
- } else {
1199
- module = app2.defineState({}).build();
1200
- }
1201
- loaded.set(component.name, {
1202
- name: component.name,
1203
- module,
1204
- template
1205
- });
1206
- }
1207
- return loaded;
1208
- }
1209
- function watchComponents(baseDir, options = {}) {
1210
- const resolvedDir = resolve(baseDir);
1211
- const {
1212
- onChange,
1213
- onAdd,
1214
- onRemove,
1215
- onUpdate,
1216
- debug = false,
1217
- ...discoveryOptions
1218
- } = options;
1219
- const log3 = debug ? (...args) => frameworkLoggers.discovery.debug("[watch]", ...args) : () => {};
1220
- let currentComponents = new Map;
1221
- let debounceTimer = null;
1222
- const initialScan = async () => {
1223
- const components = await discoverComponents(resolvedDir, discoveryOptions);
1224
- currentComponents = new Map(components.map((c) => [c.name, c]));
1225
- onChange?.(components);
1226
- };
1227
- const rescan = async () => {
1228
- if (debounceTimer) {
1229
- clearTimeout(debounceTimer);
1230
- }
1231
- debounceTimer = setTimeout(async () => {
1232
- log3("Rescanning...");
1233
- const newComponents = await discoverComponents(resolvedDir, discoveryOptions);
1234
- const newMap = new Map(newComponents.map((c) => [c.name, c]));
1235
- for (const [name, component] of newMap) {
1236
- const existing = currentComponents.get(name);
1237
- if (!existing) {
1238
- log3("Added:", name);
1239
- onAdd?.(component);
1240
- } else if (existing.template !== component.template || existing.modulePath !== component.modulePath) {
1241
- log3("Updated:", name);
1242
- onUpdate?.(component);
1243
- }
1244
- }
1245
- for (const name of currentComponents.keys()) {
1246
- if (!newMap.has(name)) {
1247
- log3("Removed:", name);
1248
- onRemove?.(name);
1249
- }
1250
- }
1251
- currentComponents = newMap;
1252
- onChange?.(newComponents);
1253
- }, 100);
1254
- };
1255
- const watcher = watch(resolvedDir, { recursive: true }, (event, filename) => {
1256
- if (!filename)
1257
- return;
1258
- if (filename.endsWith(".hypen") || filename.endsWith(".ts")) {
1259
- log3("File changed:", filename);
1260
- rescan();
1261
- }
1262
- });
1263
- initialScan();
1264
- return {
1265
- stop: () => {
1266
- watcher.close();
1267
- if (debounceTimer) {
1268
- clearTimeout(debounceTimer);
1269
- }
1270
- }
1271
- };
1272
- }
1273
- async function generateComponentsCode(baseDir, options = {}) {
1274
- const components = await discoverComponents(baseDir, options);
1275
- const resolvedDir = resolve(baseDir);
1276
- const outputBase = options.outputDir ? resolve(options.outputDir) : resolvedDir;
1277
- let code = `/**
1278
- * Auto-generated component imports
1279
- * Generated by @hypen-space/core discovery
1280
- */
1281
-
1282
- `;
1283
- for (const component of components) {
1284
- let importPath = null;
1285
- if (component.modulePath) {
1286
- const rel = relative(outputBase, component.modulePath).replace(/\.ts$/, ".js");
1287
- importPath = rel.startsWith(".") ? rel : "./" + rel;
1288
- }
1289
- if (importPath) {
1290
- code += `import ${component.name}Module from "${importPath}";
1291
- `;
1292
- }
1293
- }
1294
- code += `
1295
- import { app } from "@hypen-space/core";
1296
-
1297
- `;
1298
- for (const component of components) {
1299
- if (component.isSingleFile) {
1300
- code += `export const ${component.name} = {
1301
- module: ${component.name}Module,
1302
- template: ${component.name}Module.template,
1303
- };
1304
-
1305
- `;
1306
- } else if (component.hasModule) {
1307
- const templateJson = JSON.stringify(component.template);
1308
- code += `export const ${component.name} = {
1309
- module: ${component.name}Module,
1310
- template: ${templateJson},
1311
- };
1312
-
1313
- `;
1314
- } else {
1315
- const templateJson = JSON.stringify(component.template);
1316
- code += `const ${component.name}Module = app.defineState({}).build();
1317
- export const ${component.name} = {
1318
- module: ${component.name}Module,
1319
- template: ${templateJson},
1320
- };
1321
-
1322
- `;
1323
- }
1324
- }
1325
- return code;
1326
- }
1327
- export {
1328
- watchComponents,
1329
- loadDiscoveredComponents,
1330
- generateComponentsCode,
1331
- discoverComponents
1332
- };
1333
-
1334
- //# debugId=D8CFBCA4D5F7D1BB64756E2164756E21