@hypen-space/core 0.2.11 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -11
- package/dist/src/app.js +470 -44
- package/dist/src/app.js.map +7 -5
- package/dist/src/components/builtin.js +470 -44
- package/dist/src/components/builtin.js.map +7 -5
- package/dist/src/discovery.js +559 -65
- package/dist/src/discovery.js.map +8 -6
- package/dist/src/engine.browser.js +2 -2
- package/dist/src/engine.browser.js.map +2 -2
- package/dist/src/engine.js +18 -9
- package/dist/src/engine.js.map +3 -3
- package/dist/src/index.browser.js +863 -82
- package/dist/src/index.browser.js.map +11 -7
- package/dist/src/index.js +1591 -125
- package/dist/src/index.js.map +17 -10
- package/dist/src/remote/client.js +525 -35
- package/dist/src/remote/client.js.map +7 -4
- package/dist/src/remote/index.js +1796 -35
- package/dist/src/remote/index.js.map +13 -4
- package/dist/src/router.js +55 -29
- package/dist/src/router.js.map +3 -3
- package/dist/src/state.js +57 -29
- package/dist/src/state.js.map +3 -3
- package/package.json +8 -2
- package/src/app.ts +292 -13
- package/src/discovery.ts +123 -18
- package/src/disposable.ts +281 -0
- package/src/engine.browser.ts +1 -1
- package/src/engine.ts +29 -10
- package/src/hypen.ts +209 -0
- package/src/index.ts +147 -11
- package/src/logger.ts +338 -0
- package/src/remote/client.ts +263 -56
- package/src/remote/index.ts +25 -1
- package/src/remote/server.ts +652 -0
- package/src/remote/session.ts +256 -0
- package/src/remote/types.ts +68 -1
- package/src/result.ts +260 -0
- package/src/retry.ts +306 -0
- package/src/state.ts +103 -45
- package/wasm-browser/README.md +4 -0
- package/wasm-browser/hypen_engine_bg.wasm +0 -0
- package/wasm-browser/package.json +1 -1
- package/wasm-node/README.md +4 -0
- package/wasm-node/hypen_engine_bg.wasm +0 -0
- package/wasm-node/package.json +1 -1
- package/wasm-browser/hypen_engine_bg.js +0 -736
- package/wasm-node/hypen_engine_bg.js +0 -736
package/dist/src/discovery.js
CHANGED
|
@@ -15,39 +15,34 @@ function deepClone(obj) {
|
|
|
15
15
|
if (obj === null || typeof obj !== "object") {
|
|
16
16
|
return obj;
|
|
17
17
|
}
|
|
18
|
+
if (typeof obj === "function") {
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
if (typeof obj.__getSnapshot === "function") {
|
|
22
|
+
return obj.__getSnapshot();
|
|
23
|
+
}
|
|
24
|
+
if (obj instanceof WeakMap || obj instanceof WeakSet) {
|
|
25
|
+
return obj;
|
|
26
|
+
}
|
|
18
27
|
const visited = new WeakMap;
|
|
19
28
|
function cloneInternal(value) {
|
|
20
29
|
if (value === null || typeof value !== "object") {
|
|
21
30
|
return value;
|
|
22
31
|
}
|
|
32
|
+
if (typeof value === "function") {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
23
35
|
if (visited.has(value)) {
|
|
24
36
|
return visited.get(value);
|
|
25
37
|
}
|
|
26
|
-
if (value instanceof Date) {
|
|
27
|
-
return new Date(value.getTime());
|
|
28
|
-
}
|
|
29
|
-
if (value instanceof RegExp) {
|
|
30
|
-
return new RegExp(value.source, value.flags);
|
|
31
|
-
}
|
|
32
|
-
if (value instanceof Map) {
|
|
33
|
-
const mapClone = new Map;
|
|
34
|
-
visited.set(value, mapClone);
|
|
35
|
-
for (const [k, v] of value.entries()) {
|
|
36
|
-
mapClone.set(cloneInternal(k), cloneInternal(v));
|
|
37
|
-
}
|
|
38
|
-
return mapClone;
|
|
39
|
-
}
|
|
40
|
-
if (value instanceof Set) {
|
|
41
|
-
const setClone = new Set;
|
|
42
|
-
visited.set(value, setClone);
|
|
43
|
-
for (const item of value.values()) {
|
|
44
|
-
setClone.add(cloneInternal(item));
|
|
45
|
-
}
|
|
46
|
-
return setClone;
|
|
47
|
-
}
|
|
48
38
|
if (value instanceof WeakMap || value instanceof WeakSet) {
|
|
49
39
|
return value;
|
|
50
40
|
}
|
|
41
|
+
if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
42
|
+
try {
|
|
43
|
+
return structuredClone(value);
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
51
46
|
if (Array.isArray(value)) {
|
|
52
47
|
const arrClone = [];
|
|
53
48
|
visited.set(value, arrClone);
|
|
@@ -59,7 +54,7 @@ function deepClone(obj) {
|
|
|
59
54
|
const objClone = {};
|
|
60
55
|
visited.set(value, objClone);
|
|
61
56
|
for (const key in value) {
|
|
62
|
-
if (
|
|
57
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
63
58
|
objClone[key] = cloneInternal(value[key]);
|
|
64
59
|
}
|
|
65
60
|
}
|
|
@@ -161,12 +156,15 @@ function createObservableState(initialState, options) {
|
|
|
161
156
|
}
|
|
162
157
|
const proxyCache = new WeakMap;
|
|
163
158
|
function createProxy(target, basePath) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
159
|
+
const cached = proxyCache.get(target);
|
|
160
|
+
if (cached)
|
|
161
|
+
return cached;
|
|
167
162
|
const proxy = new Proxy(target, {
|
|
168
163
|
get(obj, prop) {
|
|
169
|
-
|
|
164
|
+
if (prop === IS_PROXY)
|
|
165
|
+
return true;
|
|
166
|
+
if (prop === RAW_TARGET)
|
|
167
|
+
return obj;
|
|
170
168
|
if (prop === "__beginBatch") {
|
|
171
169
|
return () => {
|
|
172
170
|
batchDepth++;
|
|
@@ -183,16 +181,28 @@ function createObservableState(initialState, options) {
|
|
|
183
181
|
if (prop === "__getSnapshot") {
|
|
184
182
|
return () => deepClone(obj);
|
|
185
183
|
}
|
|
184
|
+
const value = obj[prop];
|
|
186
185
|
if (value && typeof value === "object") {
|
|
186
|
+
if (value[IS_PROXY]) {
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
187
189
|
if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
|
|
188
190
|
return value;
|
|
189
191
|
}
|
|
190
|
-
|
|
192
|
+
const cachedNested = proxyCache.get(value);
|
|
193
|
+
if (cachedNested) {
|
|
194
|
+
return cachedNested;
|
|
195
|
+
}
|
|
196
|
+
const nestedProxy = createProxy(value, basePath ? `${basePath}.${String(prop)}` : String(prop));
|
|
197
|
+
return nestedProxy;
|
|
191
198
|
}
|
|
192
199
|
return value;
|
|
193
200
|
},
|
|
194
201
|
set(obj, prop, value) {
|
|
195
202
|
const oldValue = obj[prop];
|
|
203
|
+
if (value && typeof value === "object" && value[IS_PROXY]) {
|
|
204
|
+
value = value[RAW_TARGET];
|
|
205
|
+
}
|
|
196
206
|
obj[prop] = value;
|
|
197
207
|
if (oldValue !== value) {
|
|
198
208
|
scheduleBatch();
|
|
@@ -233,6 +243,344 @@ function getStateSnapshot(state) {
|
|
|
233
243
|
}
|
|
234
244
|
return deepClone(state);
|
|
235
245
|
}
|
|
246
|
+
function isStateProxy(value) {
|
|
247
|
+
return value !== null && typeof value === "object" && value[IS_PROXY] === true;
|
|
248
|
+
}
|
|
249
|
+
function unwrapProxy(value) {
|
|
250
|
+
if (value !== null && typeof value === "object" && value[IS_PROXY]) {
|
|
251
|
+
return value[RAW_TARGET];
|
|
252
|
+
}
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
var IS_PROXY, RAW_TARGET;
|
|
256
|
+
var init_state = __esm(() => {
|
|
257
|
+
IS_PROXY = Symbol.for("hypen.isProxy");
|
|
258
|
+
RAW_TARGET = Symbol.for("hypen.rawTarget");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// src/result.ts
|
|
262
|
+
function Ok(value) {
|
|
263
|
+
return { ok: true, value };
|
|
264
|
+
}
|
|
265
|
+
function Err(error) {
|
|
266
|
+
return { ok: false, error };
|
|
267
|
+
}
|
|
268
|
+
function isOk(result) {
|
|
269
|
+
return result.ok;
|
|
270
|
+
}
|
|
271
|
+
function isErr(result) {
|
|
272
|
+
return !result.ok;
|
|
273
|
+
}
|
|
274
|
+
async function fromPromise(promise, mapError) {
|
|
275
|
+
try {
|
|
276
|
+
const value = await promise;
|
|
277
|
+
return Ok(value);
|
|
278
|
+
} catch (e) {
|
|
279
|
+
if (mapError) {
|
|
280
|
+
return Err(mapError(e));
|
|
281
|
+
}
|
|
282
|
+
return Err(e);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function fromTry(fn, mapError) {
|
|
286
|
+
try {
|
|
287
|
+
return Ok(fn());
|
|
288
|
+
} catch (e) {
|
|
289
|
+
if (mapError) {
|
|
290
|
+
return Err(mapError(e));
|
|
291
|
+
}
|
|
292
|
+
return Err(e);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function map(result, fn) {
|
|
296
|
+
if (result.ok) {
|
|
297
|
+
return Ok(fn(result.value));
|
|
298
|
+
}
|
|
299
|
+
return result;
|
|
300
|
+
}
|
|
301
|
+
function mapErr(result, fn) {
|
|
302
|
+
if (!result.ok) {
|
|
303
|
+
return Err(fn(result.error));
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
function flatMap(result, fn) {
|
|
308
|
+
if (result.ok) {
|
|
309
|
+
return fn(result.value);
|
|
310
|
+
}
|
|
311
|
+
return result;
|
|
312
|
+
}
|
|
313
|
+
function unwrap(result) {
|
|
314
|
+
if (result.ok) {
|
|
315
|
+
return result.value;
|
|
316
|
+
}
|
|
317
|
+
throw result.error;
|
|
318
|
+
}
|
|
319
|
+
function unwrapOr(result, defaultValue) {
|
|
320
|
+
if (result.ok) {
|
|
321
|
+
return result.value;
|
|
322
|
+
}
|
|
323
|
+
return defaultValue;
|
|
324
|
+
}
|
|
325
|
+
function unwrapOrElse(result, fn) {
|
|
326
|
+
if (result.ok) {
|
|
327
|
+
return result.value;
|
|
328
|
+
}
|
|
329
|
+
return fn(result.error);
|
|
330
|
+
}
|
|
331
|
+
function match(result, handlers) {
|
|
332
|
+
if (result.ok) {
|
|
333
|
+
return handlers.ok(result.value);
|
|
334
|
+
}
|
|
335
|
+
return handlers.err(result.error);
|
|
336
|
+
}
|
|
337
|
+
function all(results) {
|
|
338
|
+
const values = [];
|
|
339
|
+
for (const result of results) {
|
|
340
|
+
if (!result.ok) {
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
values.push(result.value);
|
|
344
|
+
}
|
|
345
|
+
return Ok(values);
|
|
346
|
+
}
|
|
347
|
+
var HypenError, ActionError, ConnectionError, StateError;
|
|
348
|
+
var init_result = __esm(() => {
|
|
349
|
+
HypenError = class HypenError extends Error {
|
|
350
|
+
code;
|
|
351
|
+
context;
|
|
352
|
+
cause;
|
|
353
|
+
constructor(code, message, options) {
|
|
354
|
+
super(message);
|
|
355
|
+
this.name = "HypenError";
|
|
356
|
+
this.code = code;
|
|
357
|
+
this.context = options?.context;
|
|
358
|
+
this.cause = options?.cause;
|
|
359
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
ActionError = class ActionError extends HypenError {
|
|
363
|
+
actionName;
|
|
364
|
+
constructor(actionName, cause) {
|
|
365
|
+
super("ACTION_ERROR", `Action handler "${actionName}" failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
|
|
366
|
+
context: { actionName },
|
|
367
|
+
cause: cause instanceof Error ? cause : undefined
|
|
368
|
+
});
|
|
369
|
+
this.name = "ActionError";
|
|
370
|
+
this.actionName = actionName;
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
ConnectionError = class ConnectionError extends HypenError {
|
|
374
|
+
url;
|
|
375
|
+
attempt;
|
|
376
|
+
constructor(url, cause, attempt) {
|
|
377
|
+
super("CONNECTION_ERROR", `Connection to "${url}" failed${attempt ? ` (attempt ${attempt})` : ""}: ${cause instanceof Error ? cause.message : String(cause)}`, {
|
|
378
|
+
context: { url, attempt },
|
|
379
|
+
cause: cause instanceof Error ? cause : undefined
|
|
380
|
+
});
|
|
381
|
+
this.name = "ConnectionError";
|
|
382
|
+
this.url = url;
|
|
383
|
+
this.attempt = attempt;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
StateError = class StateError extends HypenError {
|
|
387
|
+
path;
|
|
388
|
+
constructor(message, path, cause) {
|
|
389
|
+
super("STATE_ERROR", message, {
|
|
390
|
+
context: { path },
|
|
391
|
+
cause: cause instanceof Error ? cause : undefined
|
|
392
|
+
});
|
|
393
|
+
this.name = "StateError";
|
|
394
|
+
this.path = path;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// src/logger.ts
|
|
400
|
+
function isProduction() {
|
|
401
|
+
if (typeof process !== "undefined" && process.env) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
function setLogLevel(level) {
|
|
407
|
+
config.level = level;
|
|
408
|
+
}
|
|
409
|
+
function getLogLevel() {
|
|
410
|
+
return config.level;
|
|
411
|
+
}
|
|
412
|
+
function configureLogger(options) {
|
|
413
|
+
config = { ...config, ...options };
|
|
414
|
+
}
|
|
415
|
+
function enableLogging() {
|
|
416
|
+
config.level = "debug";
|
|
417
|
+
}
|
|
418
|
+
function disableLogging() {
|
|
419
|
+
config.level = "none";
|
|
420
|
+
}
|
|
421
|
+
function shouldLog(level) {
|
|
422
|
+
return LOG_LEVEL_ORDER[level] >= LOG_LEVEL_ORDER[config.level];
|
|
423
|
+
}
|
|
424
|
+
function formatTag(tag, level) {
|
|
425
|
+
const timestamp = config.timestamps ? `${new Date().toISOString()} ` : "";
|
|
426
|
+
if (config.colors && level !== "none") {
|
|
427
|
+
const color = LOG_LEVEL_COLORS[level];
|
|
428
|
+
return `${timestamp}${color}[${tag}]${RESET_COLOR}`;
|
|
429
|
+
}
|
|
430
|
+
return `${timestamp}[${tag}]`;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
class Logger {
|
|
434
|
+
tag;
|
|
435
|
+
constructor(tag) {
|
|
436
|
+
this.tag = tag;
|
|
437
|
+
}
|
|
438
|
+
debug(...args) {
|
|
439
|
+
if (!shouldLog("debug"))
|
|
440
|
+
return;
|
|
441
|
+
if (config.handler) {
|
|
442
|
+
config.handler.debug(this.tag, ...args);
|
|
443
|
+
} else {
|
|
444
|
+
console.log(formatTag(this.tag, "debug"), ...args);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
info(...args) {
|
|
448
|
+
if (!shouldLog("info"))
|
|
449
|
+
return;
|
|
450
|
+
if (config.handler) {
|
|
451
|
+
config.handler.info(this.tag, ...args);
|
|
452
|
+
} else {
|
|
453
|
+
console.info(formatTag(this.tag, "info"), ...args);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
warn(...args) {
|
|
457
|
+
if (!shouldLog("warn"))
|
|
458
|
+
return;
|
|
459
|
+
if (config.handler) {
|
|
460
|
+
config.handler.warn(this.tag, ...args);
|
|
461
|
+
} else {
|
|
462
|
+
console.warn(formatTag(this.tag, "warn"), ...args);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
error(...args) {
|
|
466
|
+
if (!shouldLog("error"))
|
|
467
|
+
return;
|
|
468
|
+
if (config.handler) {
|
|
469
|
+
config.handler.error(this.tag, ...args);
|
|
470
|
+
} else {
|
|
471
|
+
console.error(formatTag(this.tag, "error"), ...args);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
time(label, fn) {
|
|
475
|
+
if (!shouldLog("debug")) {
|
|
476
|
+
return fn();
|
|
477
|
+
}
|
|
478
|
+
const start = performance.now();
|
|
479
|
+
try {
|
|
480
|
+
return fn();
|
|
481
|
+
} finally {
|
|
482
|
+
const duration = performance.now() - start;
|
|
483
|
+
this.debug(`${label}: ${duration.toFixed(2)}ms`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
async timeAsync(label, fn) {
|
|
487
|
+
if (!shouldLog("debug")) {
|
|
488
|
+
return fn();
|
|
489
|
+
}
|
|
490
|
+
const start = performance.now();
|
|
491
|
+
try {
|
|
492
|
+
return await fn();
|
|
493
|
+
} finally {
|
|
494
|
+
const duration = performance.now() - start;
|
|
495
|
+
this.debug(`${label}: ${duration.toFixed(2)}ms`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
child(subTag) {
|
|
499
|
+
return new Logger(`${this.tag}:${subTag}`);
|
|
500
|
+
}
|
|
501
|
+
debugIf(condition, ...args) {
|
|
502
|
+
if (condition)
|
|
503
|
+
this.debug(...args);
|
|
504
|
+
}
|
|
505
|
+
warnIf(condition, ...args) {
|
|
506
|
+
if (condition)
|
|
507
|
+
this.warn(...args);
|
|
508
|
+
}
|
|
509
|
+
errorIf(condition, ...args) {
|
|
510
|
+
if (condition)
|
|
511
|
+
this.error(...args);
|
|
512
|
+
}
|
|
513
|
+
loggedOnce = new Set;
|
|
514
|
+
warnOnce(key, ...args) {
|
|
515
|
+
if (this.loggedOnce.has(key))
|
|
516
|
+
return;
|
|
517
|
+
this.loggedOnce.add(key);
|
|
518
|
+
this.warn(...args);
|
|
519
|
+
}
|
|
520
|
+
debugOnce(key, ...args) {
|
|
521
|
+
if (this.loggedOnce.has(key))
|
|
522
|
+
return;
|
|
523
|
+
this.loggedOnce.add(key);
|
|
524
|
+
this.debug(...args);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function createLogger(tag) {
|
|
528
|
+
return new Logger(tag);
|
|
529
|
+
}
|
|
530
|
+
var LOG_LEVEL_ORDER, LOG_LEVEL_COLORS, RESET_COLOR = "\x1B[0m", config, logger, log, frameworkLoggers;
|
|
531
|
+
var init_logger = __esm(() => {
|
|
532
|
+
LOG_LEVEL_ORDER = {
|
|
533
|
+
debug: 0,
|
|
534
|
+
info: 1,
|
|
535
|
+
warn: 2,
|
|
536
|
+
error: 3,
|
|
537
|
+
none: 4
|
|
538
|
+
};
|
|
539
|
+
LOG_LEVEL_COLORS = {
|
|
540
|
+
debug: "\x1B[36m",
|
|
541
|
+
info: "\x1B[32m",
|
|
542
|
+
warn: "\x1B[33m",
|
|
543
|
+
error: "\x1B[31m"
|
|
544
|
+
};
|
|
545
|
+
config = {
|
|
546
|
+
level: isProduction() ? "error" : "debug",
|
|
547
|
+
colors: true,
|
|
548
|
+
timestamps: false
|
|
549
|
+
};
|
|
550
|
+
logger = createLogger("Hypen");
|
|
551
|
+
log = {
|
|
552
|
+
debug: (tag, ...args) => {
|
|
553
|
+
if (!shouldLog("debug"))
|
|
554
|
+
return;
|
|
555
|
+
console.log(formatTag(tag, "debug"), ...args);
|
|
556
|
+
},
|
|
557
|
+
info: (tag, ...args) => {
|
|
558
|
+
if (!shouldLog("info"))
|
|
559
|
+
return;
|
|
560
|
+
console.info(formatTag(tag, "info"), ...args);
|
|
561
|
+
},
|
|
562
|
+
warn: (tag, ...args) => {
|
|
563
|
+
if (!shouldLog("warn"))
|
|
564
|
+
return;
|
|
565
|
+
console.warn(formatTag(tag, "warn"), ...args);
|
|
566
|
+
},
|
|
567
|
+
error: (tag, ...args) => {
|
|
568
|
+
if (!shouldLog("error"))
|
|
569
|
+
return;
|
|
570
|
+
console.error(formatTag(tag, "error"), ...args);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
frameworkLoggers = {
|
|
574
|
+
engine: createLogger("Engine"),
|
|
575
|
+
router: createLogger("Router"),
|
|
576
|
+
state: createLogger("State"),
|
|
577
|
+
events: createLogger("Events"),
|
|
578
|
+
remote: createLogger("Remote"),
|
|
579
|
+
renderer: createLogger("Renderer"),
|
|
580
|
+
module: createLogger("Module"),
|
|
581
|
+
lifecycle: createLogger("Lifecycle")
|
|
582
|
+
};
|
|
583
|
+
});
|
|
236
584
|
|
|
237
585
|
// src/app.ts
|
|
238
586
|
var exports_app = {};
|
|
@@ -249,6 +597,11 @@ class HypenAppBuilder {
|
|
|
249
597
|
createdHandler;
|
|
250
598
|
actionHandlers = new Map;
|
|
251
599
|
destroyedHandler;
|
|
600
|
+
disconnectHandler;
|
|
601
|
+
reconnectHandler;
|
|
602
|
+
expireHandler;
|
|
603
|
+
errorHandler;
|
|
604
|
+
template;
|
|
252
605
|
constructor(initialState, options) {
|
|
253
606
|
this.initialState = initialState;
|
|
254
607
|
this.options = options || {};
|
|
@@ -265,6 +618,26 @@ class HypenAppBuilder {
|
|
|
265
618
|
this.destroyedHandler = fn;
|
|
266
619
|
return this;
|
|
267
620
|
}
|
|
621
|
+
onDisconnect(fn) {
|
|
622
|
+
this.disconnectHandler = fn;
|
|
623
|
+
return this;
|
|
624
|
+
}
|
|
625
|
+
onReconnect(fn) {
|
|
626
|
+
this.reconnectHandler = fn;
|
|
627
|
+
return this;
|
|
628
|
+
}
|
|
629
|
+
onExpire(fn) {
|
|
630
|
+
this.expireHandler = fn;
|
|
631
|
+
return this;
|
|
632
|
+
}
|
|
633
|
+
onError(fn) {
|
|
634
|
+
this.errorHandler = fn;
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
ui(template) {
|
|
638
|
+
this.template = template;
|
|
639
|
+
return this.build();
|
|
640
|
+
}
|
|
268
641
|
build() {
|
|
269
642
|
const stateKeys = this.initialState !== null && typeof this.initialState === "object" ? Object.keys(this.initialState) : [];
|
|
270
643
|
return {
|
|
@@ -274,10 +647,15 @@ class HypenAppBuilder {
|
|
|
274
647
|
persist: this.options.persist,
|
|
275
648
|
version: this.options.version,
|
|
276
649
|
initialState: this.initialState,
|
|
650
|
+
template: this.template,
|
|
277
651
|
handlers: {
|
|
278
652
|
onCreated: this.createdHandler,
|
|
279
653
|
onAction: this.actionHandlers,
|
|
280
|
-
onDestroyed: this.destroyedHandler
|
|
654
|
+
onDestroyed: this.destroyedHandler,
|
|
655
|
+
onDisconnect: this.disconnectHandler,
|
|
656
|
+
onReconnect: this.reconnectHandler,
|
|
657
|
+
onExpire: this.expireHandler,
|
|
658
|
+
onError: this.errorHandler
|
|
281
659
|
}
|
|
282
660
|
};
|
|
283
661
|
}
|
|
@@ -310,9 +688,9 @@ class HypenModuleInstance {
|
|
|
310
688
|
});
|
|
311
689
|
this.engine.setModule(definition.name || "AnonymousModule", definition.actions, definition.stateKeys, getStateSnapshot(this.state));
|
|
312
690
|
for (const [actionName, handler] of definition.handlers.onAction) {
|
|
313
|
-
|
|
691
|
+
log2.debug(`Registering action handler: ${actionName} for module ${definition.name}`);
|
|
314
692
|
this.engine.onAction(actionName, async (action) => {
|
|
315
|
-
|
|
693
|
+
log2.debug(`Action handler fired: ${actionName}`, action);
|
|
316
694
|
const actionCtx = {
|
|
317
695
|
name: action.name,
|
|
318
696
|
payload: action.payload,
|
|
@@ -322,17 +700,19 @@ class HypenModuleInstance {
|
|
|
322
700
|
router: this.routerContext?.root || null
|
|
323
701
|
};
|
|
324
702
|
const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
703
|
+
const result = await this.executeAction(actionName, handler, {
|
|
704
|
+
action: actionCtx,
|
|
705
|
+
state: this.state,
|
|
706
|
+
next,
|
|
707
|
+
context
|
|
708
|
+
});
|
|
709
|
+
if (!result.ok) {
|
|
710
|
+
const shouldRethrow = await this.handleError(result.error, { actionName });
|
|
711
|
+
if (shouldRethrow) {
|
|
712
|
+
throw result.error;
|
|
713
|
+
}
|
|
714
|
+
} else {
|
|
715
|
+
log2.debug(`Action handler completed: ${actionName}`);
|
|
336
716
|
}
|
|
337
717
|
});
|
|
338
718
|
}
|
|
@@ -359,6 +739,48 @@ class HypenModuleInstance {
|
|
|
359
739
|
}
|
|
360
740
|
return api;
|
|
361
741
|
}
|
|
742
|
+
async executeAction(actionName, handler, ctx) {
|
|
743
|
+
try {
|
|
744
|
+
const result = handler(ctx);
|
|
745
|
+
await result;
|
|
746
|
+
return Ok(undefined);
|
|
747
|
+
} catch (e) {
|
|
748
|
+
return Err(new ActionError(actionName, e));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
async handleError(error, context) {
|
|
752
|
+
const errorCtx = {
|
|
753
|
+
error,
|
|
754
|
+
state: this.state,
|
|
755
|
+
actionName: context.actionName,
|
|
756
|
+
lifecycle: context.lifecycle
|
|
757
|
+
};
|
|
758
|
+
if (this.definition.handlers.onError) {
|
|
759
|
+
try {
|
|
760
|
+
const result = await this.definition.handlers.onError(errorCtx);
|
|
761
|
+
if (result && typeof result === "object") {
|
|
762
|
+
if ("handled" in result && result.handled) {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
if ("rethrow" in result && result.rethrow) {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
} catch (handlerError) {
|
|
770
|
+
log2.error("Error in onError handler:", handlerError);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (this.globalContext) {
|
|
774
|
+
const eventContext = context.actionName ? `action:${context.actionName}` : context.lifecycle ? `lifecycle:${context.lifecycle}` : "unknown";
|
|
775
|
+
this.globalContext.emit("error", {
|
|
776
|
+
message: error.message,
|
|
777
|
+
error,
|
|
778
|
+
context: eventContext
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
log2.error(`${context.actionName ? `Action "${context.actionName}"` : `Lifecycle "${context.lifecycle}"`} error:`, error);
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
362
784
|
async callCreatedHandler() {
|
|
363
785
|
if (this.definition.handlers.onCreated) {
|
|
364
786
|
const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
|
|
@@ -386,8 +808,12 @@ class HypenModuleInstance {
|
|
|
386
808
|
Object.assign(this.state, patch);
|
|
387
809
|
}
|
|
388
810
|
}
|
|
389
|
-
var app;
|
|
811
|
+
var log2, app;
|
|
390
812
|
var init_app = __esm(() => {
|
|
813
|
+
init_result();
|
|
814
|
+
init_state();
|
|
815
|
+
init_logger();
|
|
816
|
+
log2 = createLogger("ModuleInstance");
|
|
391
817
|
app = new HypenApp;
|
|
392
818
|
});
|
|
393
819
|
|
|
@@ -399,19 +825,19 @@ function removeImports(text) {
|
|
|
399
825
|
}
|
|
400
826
|
async function discoverComponents(baseDir, options = {}) {
|
|
401
827
|
const {
|
|
402
|
-
patterns = ["folder", "sibling", "index"],
|
|
828
|
+
patterns = ["single-file", "folder", "sibling", "index"],
|
|
403
829
|
recursive = false,
|
|
404
830
|
debug = false
|
|
405
831
|
} = options;
|
|
406
|
-
const
|
|
832
|
+
const log3 = debug ? (...args) => console.log("[discovery]", ...args) : () => {};
|
|
407
833
|
const resolvedDir = resolve(baseDir);
|
|
408
834
|
const components = [];
|
|
409
835
|
const seen = new Set;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const
|
|
836
|
+
log3("Scanning directory:", resolvedDir);
|
|
837
|
+
log3("Patterns:", patterns);
|
|
838
|
+
const addTwoFileComponent = (name, hypenPath, modulePath) => {
|
|
413
839
|
if (seen.has(name)) {
|
|
414
|
-
|
|
840
|
+
log3(`Skipping duplicate: ${name}`);
|
|
415
841
|
return;
|
|
416
842
|
}
|
|
417
843
|
seen.add(name);
|
|
@@ -422,9 +848,26 @@ async function discoverComponents(baseDir, options = {}) {
|
|
|
422
848
|
hypenPath,
|
|
423
849
|
modulePath,
|
|
424
850
|
template,
|
|
425
|
-
hasModule: modulePath !== null
|
|
851
|
+
hasModule: modulePath !== null,
|
|
852
|
+
isSingleFile: false
|
|
426
853
|
});
|
|
427
|
-
|
|
854
|
+
log3(`Found: ${name} (two-file, ${modulePath ? "with module" : "stateless"})`);
|
|
855
|
+
};
|
|
856
|
+
const addSingleFileComponent = (name, modulePath, template) => {
|
|
857
|
+
if (seen.has(name)) {
|
|
858
|
+
log3(`Skipping duplicate: ${name}`);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
seen.add(name);
|
|
862
|
+
components.push({
|
|
863
|
+
name,
|
|
864
|
+
hypenPath: null,
|
|
865
|
+
modulePath,
|
|
866
|
+
template,
|
|
867
|
+
hasModule: true,
|
|
868
|
+
isSingleFile: true
|
|
869
|
+
});
|
|
870
|
+
log3(`Found: ${name} (single-file with inline template)`);
|
|
428
871
|
};
|
|
429
872
|
const scanForFolderComponents = (dir) => {
|
|
430
873
|
if (!existsSync(dir))
|
|
@@ -439,7 +882,7 @@ async function discoverComponents(baseDir, options = {}) {
|
|
|
439
882
|
const hypenPath = join(folderPath, "component.hypen");
|
|
440
883
|
if (existsSync(hypenPath)) {
|
|
441
884
|
const modulePath = join(folderPath, "component.ts");
|
|
442
|
-
|
|
885
|
+
addTwoFileComponent(componentName, hypenPath, existsSync(modulePath) ? modulePath : null);
|
|
443
886
|
continue;
|
|
444
887
|
}
|
|
445
888
|
}
|
|
@@ -447,7 +890,7 @@ async function discoverComponents(baseDir, options = {}) {
|
|
|
447
890
|
const hypenPath = join(folderPath, "index.hypen");
|
|
448
891
|
if (existsSync(hypenPath)) {
|
|
449
892
|
const modulePath = join(folderPath, "index.ts");
|
|
450
|
-
|
|
893
|
+
addTwoFileComponent(componentName, hypenPath, existsSync(modulePath) ? modulePath : null);
|
|
451
894
|
continue;
|
|
452
895
|
}
|
|
453
896
|
}
|
|
@@ -474,7 +917,43 @@ async function discoverComponents(baseDir, options = {}) {
|
|
|
474
917
|
if (baseName === "component" || baseName === "index")
|
|
475
918
|
continue;
|
|
476
919
|
const modulePath = join(dir, `${baseName}.ts`);
|
|
477
|
-
|
|
920
|
+
addTwoFileComponent(baseName, hypenPath, existsSync(modulePath) ? modulePath : null);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
const scanForSingleFileComponents = async (dir) => {
|
|
924
|
+
if (!existsSync(dir))
|
|
925
|
+
return;
|
|
926
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
927
|
+
for (const entry of entries) {
|
|
928
|
+
if (entry.isDirectory()) {
|
|
929
|
+
if (recursive) {
|
|
930
|
+
await scanForSingleFileComponents(join(dir, entry.name));
|
|
931
|
+
}
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
if (!entry.name.endsWith(".ts"))
|
|
935
|
+
continue;
|
|
936
|
+
if (entry.name.startsWith(".") || entry.name.includes(".test.") || entry.name.includes(".spec."))
|
|
937
|
+
continue;
|
|
938
|
+
const baseName = basename(entry.name, ".ts");
|
|
939
|
+
if (baseName === "component" || baseName === "index")
|
|
940
|
+
continue;
|
|
941
|
+
const hypenPath = join(dir, `${baseName}.hypen`);
|
|
942
|
+
if (existsSync(hypenPath))
|
|
943
|
+
continue;
|
|
944
|
+
const modulePath = join(dir, entry.name);
|
|
945
|
+
const content = readFileSync(modulePath, "utf-8");
|
|
946
|
+
if (content.includes(".ui(") || content.includes(".ui(hypen")) {
|
|
947
|
+
try {
|
|
948
|
+
const moduleExport = await import(modulePath);
|
|
949
|
+
const module = moduleExport.default;
|
|
950
|
+
if (module && typeof module === "object" && module.template) {
|
|
951
|
+
addSingleFileComponent(baseName, modulePath, module.template);
|
|
952
|
+
}
|
|
953
|
+
} catch (e) {
|
|
954
|
+
log3(`Failed to import potential single-file component: ${entry.name}`, e);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
478
957
|
}
|
|
479
958
|
};
|
|
480
959
|
if (patterns.includes("folder") || patterns.includes("index")) {
|
|
@@ -483,7 +962,10 @@ async function discoverComponents(baseDir, options = {}) {
|
|
|
483
962
|
if (patterns.includes("sibling")) {
|
|
484
963
|
scanForSiblingComponents(resolvedDir);
|
|
485
964
|
}
|
|
486
|
-
|
|
965
|
+
if (patterns.includes("single-file")) {
|
|
966
|
+
await scanForSingleFileComponents(resolvedDir);
|
|
967
|
+
}
|
|
968
|
+
log3(`Discovered ${components.length} components`);
|
|
487
969
|
return components;
|
|
488
970
|
}
|
|
489
971
|
async function loadDiscoveredComponents(components) {
|
|
@@ -491,16 +973,20 @@ async function loadDiscoveredComponents(components) {
|
|
|
491
973
|
const loaded = new Map;
|
|
492
974
|
for (const component of components) {
|
|
493
975
|
let module;
|
|
976
|
+
let template = component.template;
|
|
494
977
|
if (component.modulePath) {
|
|
495
978
|
const moduleExport = await import(component.modulePath);
|
|
496
979
|
module = moduleExport.default;
|
|
980
|
+
if (component.isSingleFile && module.template) {
|
|
981
|
+
template = module.template;
|
|
982
|
+
}
|
|
497
983
|
} else {
|
|
498
984
|
module = app2.defineState({}).build();
|
|
499
985
|
}
|
|
500
986
|
loaded.set(component.name, {
|
|
501
987
|
name: component.name,
|
|
502
988
|
module,
|
|
503
|
-
template
|
|
989
|
+
template
|
|
504
990
|
});
|
|
505
991
|
}
|
|
506
992
|
return loaded;
|
|
@@ -515,7 +1001,7 @@ function watchComponents(baseDir, options = {}) {
|
|
|
515
1001
|
debug = false,
|
|
516
1002
|
...discoveryOptions
|
|
517
1003
|
} = options;
|
|
518
|
-
const
|
|
1004
|
+
const log3 = debug ? (...args) => console.log("[discovery:watch]", ...args) : () => {};
|
|
519
1005
|
let currentComponents = new Map;
|
|
520
1006
|
let debounceTimer = null;
|
|
521
1007
|
const initialScan = async () => {
|
|
@@ -528,22 +1014,22 @@ function watchComponents(baseDir, options = {}) {
|
|
|
528
1014
|
clearTimeout(debounceTimer);
|
|
529
1015
|
}
|
|
530
1016
|
debounceTimer = setTimeout(async () => {
|
|
531
|
-
|
|
1017
|
+
log3("Rescanning...");
|
|
532
1018
|
const newComponents = await discoverComponents(resolvedDir, discoveryOptions);
|
|
533
1019
|
const newMap = new Map(newComponents.map((c) => [c.name, c]));
|
|
534
1020
|
for (const [name, component] of newMap) {
|
|
535
1021
|
const existing = currentComponents.get(name);
|
|
536
1022
|
if (!existing) {
|
|
537
|
-
|
|
1023
|
+
log3("Added:", name);
|
|
538
1024
|
onAdd?.(component);
|
|
539
1025
|
} else if (existing.template !== component.template || existing.modulePath !== component.modulePath) {
|
|
540
|
-
|
|
1026
|
+
log3("Updated:", name);
|
|
541
1027
|
onUpdate?.(component);
|
|
542
1028
|
}
|
|
543
1029
|
}
|
|
544
1030
|
for (const name of currentComponents.keys()) {
|
|
545
1031
|
if (!newMap.has(name)) {
|
|
546
|
-
|
|
1032
|
+
log3("Removed:", name);
|
|
547
1033
|
onRemove?.(name);
|
|
548
1034
|
}
|
|
549
1035
|
}
|
|
@@ -555,7 +1041,7 @@ function watchComponents(baseDir, options = {}) {
|
|
|
555
1041
|
if (!filename)
|
|
556
1042
|
return;
|
|
557
1043
|
if (filename.endsWith(".hypen") || filename.endsWith(".ts")) {
|
|
558
|
-
|
|
1044
|
+
log3("File changed:", filename);
|
|
559
1045
|
rescan();
|
|
560
1046
|
}
|
|
561
1047
|
});
|
|
@@ -590,8 +1076,15 @@ import { app } from "@hypen-space/core";
|
|
|
590
1076
|
|
|
591
1077
|
`;
|
|
592
1078
|
for (const component of components) {
|
|
593
|
-
|
|
594
|
-
|
|
1079
|
+
if (component.isSingleFile) {
|
|
1080
|
+
code += `export const ${component.name} = {
|
|
1081
|
+
module: ${component.name}Module,
|
|
1082
|
+
template: ${component.name}Module.template,
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
`;
|
|
1086
|
+
} else if (component.hasModule) {
|
|
1087
|
+
const templateJson = JSON.stringify(component.template);
|
|
595
1088
|
code += `export const ${component.name} = {
|
|
596
1089
|
module: ${component.name}Module,
|
|
597
1090
|
template: ${templateJson},
|
|
@@ -599,6 +1092,7 @@ import { app } from "@hypen-space/core";
|
|
|
599
1092
|
|
|
600
1093
|
`;
|
|
601
1094
|
} else {
|
|
1095
|
+
const templateJson = JSON.stringify(component.template);
|
|
602
1096
|
code += `const ${component.name}Module = app.defineState({}).build();
|
|
603
1097
|
export const ${component.name} = {
|
|
604
1098
|
module: ${component.name}Module,
|
|
@@ -617,4 +1111,4 @@ export {
|
|
|
617
1111
|
discoverComponents
|
|
618
1112
|
};
|
|
619
1113
|
|
|
620
|
-
//# debugId=
|
|
1114
|
+
//# debugId=8B91C0622F0CDB2064756E2164756E21
|