@hypen-space/core 0.4.82 → 0.4.83
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 +10 -4
- package/dist/app.d.ts +78 -1
- package/dist/app.js +102 -46
- package/dist/app.js.map +6 -5
- package/dist/components/builtin.js +102 -46
- package/dist/components/builtin.js.map +6 -5
- package/dist/engine-base.d.ts +19 -0
- package/dist/engine-base.js +32 -1
- package/dist/engine-base.js.map +3 -3
- package/dist/index.browser.js +117 -85
- package/dist/index.browser.js.map +7 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.js +318 -85
- package/dist/index.js.map +9 -7
- package/dist/managed-router.d.ts +121 -5
- package/dist/portable.d.ts +62 -0
- package/dist/router.d.ts +7 -1
- package/dist/router.js +60 -81
- package/dist/router.js.map +6 -5
- package/dist/state.js +49 -46
- package/dist/state.js.map +5 -4
- package/dist/types.d.ts +12 -1
- package/package.json +7 -1
- package/src/app.ts +131 -1
- package/src/engine-base.ts +55 -0
- package/src/index.ts +13 -0
- package/src/managed-router.ts +285 -35
- package/src/portable.ts +113 -0
- package/src/router.ts +25 -50
- package/src/state.ts +11 -70
- package/src/types.ts +23 -1
package/dist/index.d.ts
CHANGED
|
@@ -50,10 +50,14 @@ export { DataSourceManager } from "./datasource.js";
|
|
|
50
50
|
export type { DataSourcePlugin, DataSourceStatus, DataSourceQuery, DataSourceSubscription, DataSourceChange, IDataSourceEngine, } from "./datasource.js";
|
|
51
51
|
export { createObservableState, batchStateUpdates, getStateSnapshot, isStateProxy, unwrapProxy, } from "./state.js";
|
|
52
52
|
export type { StatePath, StateChange, StateObserverOptions, } from "./state.js";
|
|
53
|
+
export { setPortableImpl, portable } from "./portable.js";
|
|
54
|
+
export type { PortableImpl } from "./portable.js";
|
|
53
55
|
export { BaseRenderer, ConsoleRenderer } from "./renderer.js";
|
|
54
56
|
export type { Renderer } from "./renderer.js";
|
|
55
57
|
export { HypenRouter } from "./router.js";
|
|
56
58
|
export type { RouteMatch, RouteState, RouteChangeCallback, } from "./router.js";
|
|
59
|
+
export { ManagedRouter } from "./managed-router.js";
|
|
60
|
+
export type { RouteDefinition } from "./managed-router.js";
|
|
57
61
|
export { TypedEventEmitter, createEventEmitter } from "./events.js";
|
|
58
62
|
export type { EventHandler, HypenFrameworkEvents } from "./events.js";
|
|
59
63
|
export { HypenGlobalContext } from "./context.js";
|
package/dist/index.js
CHANGED
|
@@ -602,6 +602,53 @@ class DataSourceManager {
|
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
+
// src/portable.ts
|
|
606
|
+
function notInstalled(name) {
|
|
607
|
+
throw new Error(`[@hypen-space/core] Portable helper "${name}" called before the engine was installed. ` + `Import @hypen-space/server, @hypen-space/web-engine, or call setPortableImpl() before use.`);
|
|
608
|
+
}
|
|
609
|
+
var current = {
|
|
610
|
+
diffState: () => notInstalled("diffState"),
|
|
611
|
+
matchPath: () => notInstalled("matchPath"),
|
|
612
|
+
pathGet: () => notInstalled("pathGet"),
|
|
613
|
+
pathHas: () => notInstalled("pathHas"),
|
|
614
|
+
pathSet: () => notInstalled("pathSet"),
|
|
615
|
+
pathDelete: () => notInstalled("pathDelete"),
|
|
616
|
+
encodeUriComponent: () => notInstalled("encodeUriComponent"),
|
|
617
|
+
decodeUriComponent: () => notInstalled("decodeUriComponent"),
|
|
618
|
+
parseQuery: () => notInstalled("parseQuery"),
|
|
619
|
+
buildUrl: () => notInstalled("buildUrl")
|
|
620
|
+
};
|
|
621
|
+
function setPortableImpl(impl) {
|
|
622
|
+
if (impl === null) {
|
|
623
|
+
current = {
|
|
624
|
+
diffState: () => notInstalled("diffState"),
|
|
625
|
+
matchPath: () => notInstalled("matchPath"),
|
|
626
|
+
pathGet: () => notInstalled("pathGet"),
|
|
627
|
+
pathHas: () => notInstalled("pathHas"),
|
|
628
|
+
pathSet: () => notInstalled("pathSet"),
|
|
629
|
+
pathDelete: () => notInstalled("pathDelete"),
|
|
630
|
+
encodeUriComponent: () => notInstalled("encodeUriComponent"),
|
|
631
|
+
decodeUriComponent: () => notInstalled("decodeUriComponent"),
|
|
632
|
+
parseQuery: () => notInstalled("parseQuery"),
|
|
633
|
+
buildUrl: () => notInstalled("buildUrl")
|
|
634
|
+
};
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
current = impl;
|
|
638
|
+
}
|
|
639
|
+
var portable = {
|
|
640
|
+
diffState: (o, n, b) => current.diffState(o, n, b),
|
|
641
|
+
matchPath: (p, path) => current.matchPath(p, path),
|
|
642
|
+
pathGet: (v, p) => current.pathGet(v, p),
|
|
643
|
+
pathHas: (v, p) => current.pathHas(v, p),
|
|
644
|
+
pathSet: (v, p, nv) => current.pathSet(v, p, nv),
|
|
645
|
+
pathDelete: (v, p) => current.pathDelete(v, p),
|
|
646
|
+
encodeUriComponent: (s) => current.encodeUriComponent(s),
|
|
647
|
+
decodeUriComponent: (s) => current.decodeUriComponent(s),
|
|
648
|
+
parseQuery: (f) => current.parseQuery(f),
|
|
649
|
+
buildUrl: (p, q) => current.buildUrl(p, q)
|
|
650
|
+
};
|
|
651
|
+
|
|
605
652
|
// src/state.ts
|
|
606
653
|
var IS_PROXY = Symbol.for("hypen.isProxy");
|
|
607
654
|
var RAW_TARGET = Symbol.for("hypen.rawTarget");
|
|
@@ -661,51 +708,7 @@ function deepClone(obj) {
|
|
|
661
708
|
return cloneInternal(obj);
|
|
662
709
|
}
|
|
663
710
|
function diffState(oldState, newState, basePath = "") {
|
|
664
|
-
|
|
665
|
-
const newValues = {};
|
|
666
|
-
function diff(oldVal, newVal, path) {
|
|
667
|
-
if (oldVal === newVal)
|
|
668
|
-
return;
|
|
669
|
-
if (typeof oldVal !== "object" || typeof newVal !== "object" || oldVal === null || newVal === null) {
|
|
670
|
-
if (oldVal !== newVal) {
|
|
671
|
-
paths.push(path);
|
|
672
|
-
newValues[path] = newVal;
|
|
673
|
-
}
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
if (Array.isArray(oldVal) || Array.isArray(newVal)) {
|
|
677
|
-
if (!Array.isArray(oldVal) || !Array.isArray(newVal) || oldVal.length !== newVal.length) {
|
|
678
|
-
paths.push(path);
|
|
679
|
-
newValues[path] = newVal;
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
for (let i = 0;i < newVal.length; i++) {
|
|
683
|
-
const itemPath = path ? `${path}.${i}` : `${i}`;
|
|
684
|
-
diff(oldVal[i], newVal[i], itemPath);
|
|
685
|
-
}
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
const oldKeys = new Set(Object.keys(oldVal));
|
|
689
|
-
const newKeys = new Set(Object.keys(newVal));
|
|
690
|
-
for (const key of newKeys) {
|
|
691
|
-
const propPath = path ? `${path}.${key}` : key;
|
|
692
|
-
if (!oldKeys.has(key)) {
|
|
693
|
-
paths.push(propPath);
|
|
694
|
-
newValues[propPath] = newVal[key];
|
|
695
|
-
} else {
|
|
696
|
-
diff(oldVal[key], newVal[key], propPath);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
for (const key of oldKeys) {
|
|
700
|
-
if (!newKeys.has(key)) {
|
|
701
|
-
const propPath = path ? `${path}.${key}` : key;
|
|
702
|
-
paths.push(propPath);
|
|
703
|
-
newValues[propPath] = undefined;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
diff(oldState, newState, basePath);
|
|
708
|
-
return { paths, newValues };
|
|
711
|
+
return portable.diffState(oldState, newState, basePath);
|
|
709
712
|
}
|
|
710
713
|
function createObservableState(initialState, options) {
|
|
711
714
|
const opts = options || { onChange: () => {} };
|
|
@@ -1054,6 +1057,8 @@ class HypenAppBuilder {
|
|
|
1054
1057
|
initialState;
|
|
1055
1058
|
options;
|
|
1056
1059
|
createdHandler;
|
|
1060
|
+
activatedHandler;
|
|
1061
|
+
deactivatedHandler;
|
|
1057
1062
|
actionHandlers = new Map;
|
|
1058
1063
|
destroyedHandler;
|
|
1059
1064
|
disconnectHandler;
|
|
@@ -1077,6 +1082,14 @@ class HypenAppBuilder {
|
|
|
1077
1082
|
this.actionHandlers.set(name, fn);
|
|
1078
1083
|
return this;
|
|
1079
1084
|
}
|
|
1085
|
+
onActivated(fn) {
|
|
1086
|
+
this.activatedHandler = fn;
|
|
1087
|
+
return this;
|
|
1088
|
+
}
|
|
1089
|
+
onDeactivated(fn) {
|
|
1090
|
+
this.deactivatedHandler = fn;
|
|
1091
|
+
return this;
|
|
1092
|
+
}
|
|
1080
1093
|
onDestroyed(fn) {
|
|
1081
1094
|
this.destroyedHandler = fn;
|
|
1082
1095
|
return this;
|
|
@@ -1128,6 +1141,8 @@ class HypenAppBuilder {
|
|
|
1128
1141
|
stateStore: this._stateStore,
|
|
1129
1142
|
handlers: {
|
|
1130
1143
|
onCreated: this.createdHandler,
|
|
1144
|
+
onActivated: this.activatedHandler,
|
|
1145
|
+
onDeactivated: this.deactivatedHandler,
|
|
1131
1146
|
onAction: this.actionHandlers,
|
|
1132
1147
|
onDestroyed: this.destroyedHandler,
|
|
1133
1148
|
onDisconnect: this.disconnectHandler,
|
|
@@ -1185,6 +1200,7 @@ class HypenModuleInstance {
|
|
|
1185
1200
|
definition;
|
|
1186
1201
|
state;
|
|
1187
1202
|
isDestroyed = false;
|
|
1203
|
+
isActive = false;
|
|
1188
1204
|
router;
|
|
1189
1205
|
globalContext;
|
|
1190
1206
|
stateChangeCallbacks = [];
|
|
@@ -1264,6 +1280,43 @@ class HypenModuleInstance {
|
|
|
1264
1280
|
async waitForReady() {
|
|
1265
1281
|
await this._readyPromise;
|
|
1266
1282
|
}
|
|
1283
|
+
async activate() {
|
|
1284
|
+
if (this.isDestroyed || this.isActive)
|
|
1285
|
+
return;
|
|
1286
|
+
await this._readyPromise;
|
|
1287
|
+
if (this.isDestroyed || this.isActive)
|
|
1288
|
+
return;
|
|
1289
|
+
this.isActive = true;
|
|
1290
|
+
if (this.definition.handlers.onActivated) {
|
|
1291
|
+
const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
|
|
1292
|
+
try {
|
|
1293
|
+
await this.definition.handlers.onActivated(this.state, context);
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
const error = e instanceof HypenError ? e : new ActionError("onActivated", e);
|
|
1296
|
+
const shouldRethrow = await this.handleError(error, { lifecycle: "activated" });
|
|
1297
|
+
if (shouldRethrow) {
|
|
1298
|
+
throw error;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
async deactivate() {
|
|
1304
|
+
if (this.isDestroyed || !this.isActive)
|
|
1305
|
+
return;
|
|
1306
|
+
this.isActive = false;
|
|
1307
|
+
if (this.definition.handlers.onDeactivated) {
|
|
1308
|
+
const context = this.globalContext ? this.createGlobalContextAPI() : undefined;
|
|
1309
|
+
try {
|
|
1310
|
+
await this.definition.handlers.onDeactivated(this.state, context);
|
|
1311
|
+
} catch (e) {
|
|
1312
|
+
const error = e instanceof HypenError ? e : new ActionError("onDeactivated", e);
|
|
1313
|
+
const shouldRethrow = await this.handleError(error, { lifecycle: "deactivated" });
|
|
1314
|
+
if (shouldRethrow) {
|
|
1315
|
+
throw error;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1267
1320
|
createGlobalContextAPI() {
|
|
1268
1321
|
if (!this.globalContext) {
|
|
1269
1322
|
throw new Error("Global context not available");
|
|
@@ -1412,6 +1465,9 @@ class HypenModuleInstance {
|
|
|
1412
1465
|
async destroy() {
|
|
1413
1466
|
if (this.isDestroyed)
|
|
1414
1467
|
return;
|
|
1468
|
+
if (this.isActive) {
|
|
1469
|
+
await this.deactivate();
|
|
1470
|
+
}
|
|
1415
1471
|
if (this.currentPersistKey && this.stateStore) {
|
|
1416
1472
|
clearTimeout(this.persistDebounceTimer);
|
|
1417
1473
|
const snapshot = getStateSnapshot(this.state);
|
|
@@ -1818,46 +1874,22 @@ class HypenRouter {
|
|
|
1818
1874
|
return getStateSnapshot(this.state);
|
|
1819
1875
|
}
|
|
1820
1876
|
matchPath(pattern, path) {
|
|
1821
|
-
if (!pattern || typeof pattern !== "string")
|
|
1877
|
+
if (!pattern || typeof pattern !== "string")
|
|
1822
1878
|
return null;
|
|
1823
|
-
|
|
1824
|
-
if (!path || typeof path !== "string") {
|
|
1879
|
+
if (!path || typeof path !== "string")
|
|
1825
1880
|
return null;
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
params: {},
|
|
1830
|
-
query: this.state.query,
|
|
1831
|
-
path
|
|
1832
|
-
};
|
|
1833
|
-
}
|
|
1834
|
-
if (pattern.endsWith("/*")) {
|
|
1835
|
-
const prefix = pattern.slice(0, -2);
|
|
1836
|
-
if (path === prefix || path.startsWith(prefix + "/")) {
|
|
1837
|
-
return {
|
|
1838
|
-
params: {},
|
|
1839
|
-
query: this.state.query,
|
|
1840
|
-
path
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
return null;
|
|
1844
|
-
}
|
|
1845
|
-
const paramNames = [];
|
|
1846
|
-
const regexPattern = pattern.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {
|
|
1847
|
-
paramNames.push(name);
|
|
1848
|
-
return "([^/]+)";
|
|
1849
|
-
}).replace(/\*/g, ".*");
|
|
1850
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
1851
|
-
const match2 = path.match(regex);
|
|
1852
|
-
if (!match2)
|
|
1881
|
+
const cleanPath = path.split("?")[0] ?? path;
|
|
1882
|
+
const result = portable.matchPath(pattern, cleanPath);
|
|
1883
|
+
if (!result)
|
|
1853
1884
|
return null;
|
|
1854
1885
|
const params = {};
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1886
|
+
for (const [name, raw] of Object.entries(result.params)) {
|
|
1887
|
+
try {
|
|
1888
|
+
params[name] = decodeURIComponent(raw);
|
|
1889
|
+
} catch {
|
|
1890
|
+
params[name] = raw;
|
|
1859
1891
|
}
|
|
1860
|
-
}
|
|
1892
|
+
}
|
|
1861
1893
|
return {
|
|
1862
1894
|
params,
|
|
1863
1895
|
query: this.state.query,
|
|
@@ -2332,13 +2364,13 @@ class RemoteEngine {
|
|
|
2332
2364
|
if (!state2 || typeof state2 !== "object")
|
|
2333
2365
|
return;
|
|
2334
2366
|
const parts = key.split(".");
|
|
2335
|
-
let
|
|
2367
|
+
let current2 = state2;
|
|
2336
2368
|
for (const part of parts) {
|
|
2337
|
-
if (
|
|
2369
|
+
if (current2 == null || typeof current2 !== "object")
|
|
2338
2370
|
return;
|
|
2339
|
-
|
|
2371
|
+
current2 = current2[part];
|
|
2340
2372
|
}
|
|
2341
|
-
return typeof
|
|
2373
|
+
return typeof current2 === "string" ? current2 : undefined;
|
|
2342
2374
|
}
|
|
2343
2375
|
dispatchAction(action, payload) {
|
|
2344
2376
|
if (this.state !== "connected" || !this.ws) {
|
|
@@ -2828,6 +2860,204 @@ var Link = app.defineState({
|
|
|
2828
2860
|
});
|
|
2829
2861
|
}
|
|
2830
2862
|
}).build();
|
|
2863
|
+
// src/managed-router.ts
|
|
2864
|
+
var log10 = createLogger("ManagedRouter");
|
|
2865
|
+
var DEFAULT_MAX_PERSISTED_MODULES = 10;
|
|
2866
|
+
|
|
2867
|
+
class ManagedRouter {
|
|
2868
|
+
router;
|
|
2869
|
+
engine;
|
|
2870
|
+
registry;
|
|
2871
|
+
globalContext;
|
|
2872
|
+
routes = [];
|
|
2873
|
+
activeModule = null;
|
|
2874
|
+
activeRoute = null;
|
|
2875
|
+
unsubscribe = null;
|
|
2876
|
+
persistedModules = new Map;
|
|
2877
|
+
maxPersistedModules;
|
|
2878
|
+
navPromise = Promise.resolve();
|
|
2879
|
+
constructor(router, engine, registry, globalContext, options = {}) {
|
|
2880
|
+
this.router = router;
|
|
2881
|
+
this.engine = engine;
|
|
2882
|
+
this.registry = registry;
|
|
2883
|
+
this.globalContext = globalContext;
|
|
2884
|
+
const cap = options.maxPersistedModules ?? DEFAULT_MAX_PERSISTED_MODULES;
|
|
2885
|
+
this.maxPersistedModules = cap > 0 ? cap : DEFAULT_MAX_PERSISTED_MODULES;
|
|
2886
|
+
}
|
|
2887
|
+
addRoute(route) {
|
|
2888
|
+
this.routes.push(route);
|
|
2889
|
+
return this;
|
|
2890
|
+
}
|
|
2891
|
+
start() {
|
|
2892
|
+
this.unsubscribe = this.router.onNavigate((routeState) => {
|
|
2893
|
+
this.handleRouteChange(routeState);
|
|
2894
|
+
});
|
|
2895
|
+
this.installRouterActions();
|
|
2896
|
+
}
|
|
2897
|
+
installRouterActions() {
|
|
2898
|
+
const router = this.router;
|
|
2899
|
+
const defer = (fn) => queueMicrotask(fn);
|
|
2900
|
+
const readTo = (action) => {
|
|
2901
|
+
const payload = action?.payload;
|
|
2902
|
+
const to = payload?.to;
|
|
2903
|
+
return typeof to === "string" && to.length > 0 ? to : null;
|
|
2904
|
+
};
|
|
2905
|
+
this.engine.onAction("router.push", (action) => {
|
|
2906
|
+
const to = readTo(action);
|
|
2907
|
+
if (to)
|
|
2908
|
+
defer(() => router.push(to));
|
|
2909
|
+
});
|
|
2910
|
+
this.engine.onAction("router.replace", (action) => {
|
|
2911
|
+
const to = readTo(action);
|
|
2912
|
+
if (to)
|
|
2913
|
+
defer(() => router.replace(to));
|
|
2914
|
+
});
|
|
2915
|
+
this.engine.onAction("router.back", () => {
|
|
2916
|
+
defer(() => router.back());
|
|
2917
|
+
});
|
|
2918
|
+
this.engine.onAction("router.forward", () => {
|
|
2919
|
+
defer(() => router.forward());
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
async stop() {
|
|
2923
|
+
if (this.unsubscribe) {
|
|
2924
|
+
this.unsubscribe();
|
|
2925
|
+
this.unsubscribe = null;
|
|
2926
|
+
}
|
|
2927
|
+
const cleanup = this.navPromise.catch(() => {}).then(async () => {
|
|
2928
|
+
await this.unmountActive();
|
|
2929
|
+
for (const [moduleId, instance] of this.persistedModules) {
|
|
2930
|
+
log10.debug(`Destroying persisted module on stop: ${moduleId}`);
|
|
2931
|
+
try {
|
|
2932
|
+
await instance.destroy();
|
|
2933
|
+
} catch (e) {
|
|
2934
|
+
log10.error(`Error destroying persisted module ${moduleId}:`, e);
|
|
2935
|
+
}
|
|
2936
|
+
this.globalContext.unregisterModule(moduleId);
|
|
2937
|
+
}
|
|
2938
|
+
this.persistedModules.clear();
|
|
2939
|
+
});
|
|
2940
|
+
this.navPromise = cleanup;
|
|
2941
|
+
await cleanup;
|
|
2942
|
+
this.router.dispose();
|
|
2943
|
+
}
|
|
2944
|
+
async waitForNavigation() {
|
|
2945
|
+
try {
|
|
2946
|
+
await this.navPromise;
|
|
2947
|
+
} catch {}
|
|
2948
|
+
}
|
|
2949
|
+
getActiveModule() {
|
|
2950
|
+
return this.activeModule;
|
|
2951
|
+
}
|
|
2952
|
+
getActiveRoute() {
|
|
2953
|
+
return this.activeRoute;
|
|
2954
|
+
}
|
|
2955
|
+
handleRouteChange(routeState) {
|
|
2956
|
+
this.navPromise = this.navPromise.catch((e) => {
|
|
2957
|
+
log10.error("Previous navigation failed:", e);
|
|
2958
|
+
}).then(() => this.processRouteChange(routeState));
|
|
2959
|
+
}
|
|
2960
|
+
async processRouteChange(routeState) {
|
|
2961
|
+
const path = routeState.currentPath;
|
|
2962
|
+
const matched = this.matchRoute(path);
|
|
2963
|
+
if (!matched) {
|
|
2964
|
+
log10.debug(`No route matched for path: ${path}`);
|
|
2965
|
+
await this.unmountActive();
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
if (this.activeRoute && this.activeRoute.path === matched.path) {
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
await this.unmountActive();
|
|
2972
|
+
await this.mount(matched);
|
|
2973
|
+
}
|
|
2974
|
+
matchRoute(path) {
|
|
2975
|
+
for (const route of this.routes) {
|
|
2976
|
+
if (this.router.matchPath(route.path, path) !== null) {
|
|
2977
|
+
return route;
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
return null;
|
|
2981
|
+
}
|
|
2982
|
+
async mount(route) {
|
|
2983
|
+
const definition = route.module || this.registry.get(route.component);
|
|
2984
|
+
if (!definition) {
|
|
2985
|
+
log10.debug(`No module definition found for component: ${route.component}`);
|
|
2986
|
+
this.activeRoute = route;
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
const namedDef = {
|
|
2990
|
+
...definition,
|
|
2991
|
+
name: definition.name || route.component.toLowerCase()
|
|
2992
|
+
};
|
|
2993
|
+
const moduleId = namedDef.name.toLowerCase();
|
|
2994
|
+
const persisted = this.persistedModules.get(moduleId);
|
|
2995
|
+
if (persisted) {
|
|
2996
|
+
log10.debug(`Restoring persisted module: ${moduleId} for route: ${route.path}`);
|
|
2997
|
+
this.activeModule = persisted;
|
|
2998
|
+
this.activeRoute = route;
|
|
2999
|
+
this.persistedModules.delete(moduleId);
|
|
3000
|
+
await persisted.activate();
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
log10.debug(`Mounting module: ${namedDef.name} for route: ${route.path}`);
|
|
3004
|
+
const instance = new HypenModuleInstance(this.engine, namedDef, this.router, this.globalContext);
|
|
3005
|
+
this.globalContext.registerModule(moduleId, instance);
|
|
3006
|
+
this.activeModule = instance;
|
|
3007
|
+
this.activeRoute = route;
|
|
3008
|
+
await instance.activate();
|
|
3009
|
+
}
|
|
3010
|
+
async unmountActive() {
|
|
3011
|
+
if (!this.activeModule || !this.activeRoute) {
|
|
3012
|
+
this.activeModule = null;
|
|
3013
|
+
this.activeRoute = null;
|
|
3014
|
+
return;
|
|
3015
|
+
}
|
|
3016
|
+
const active = this.activeModule;
|
|
3017
|
+
const route = this.activeRoute;
|
|
3018
|
+
const definition = route.module || this.registry.get(route.component);
|
|
3019
|
+
const moduleId = (definition?.name || route.component).toLowerCase();
|
|
3020
|
+
const persist = definition != null && definition.persist !== false;
|
|
3021
|
+
this.activeModule = null;
|
|
3022
|
+
this.activeRoute = null;
|
|
3023
|
+
try {
|
|
3024
|
+
await active.deactivate();
|
|
3025
|
+
} catch (e) {
|
|
3026
|
+
log10.error(`Error deactivating module ${moduleId}:`, e);
|
|
3027
|
+
}
|
|
3028
|
+
if (persist) {
|
|
3029
|
+
log10.debug(`Persisting module: ${moduleId}`);
|
|
3030
|
+
this.persistedModules.delete(moduleId);
|
|
3031
|
+
this.persistedModules.set(moduleId, active);
|
|
3032
|
+
await this.evictPersistedOverflow();
|
|
3033
|
+
} else {
|
|
3034
|
+
log10.debug(`Unmounting module: ${moduleId}`);
|
|
3035
|
+
try {
|
|
3036
|
+
await active.destroy();
|
|
3037
|
+
} catch (e) {
|
|
3038
|
+
log10.error(`Error destroying module ${moduleId}:`, e);
|
|
3039
|
+
}
|
|
3040
|
+
this.globalContext.unregisterModule(moduleId);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
async evictPersistedOverflow() {
|
|
3044
|
+
while (this.persistedModules.size > this.maxPersistedModules) {
|
|
3045
|
+
const oldest = this.persistedModules.keys().next();
|
|
3046
|
+
if (oldest.done)
|
|
3047
|
+
break;
|
|
3048
|
+
const oldestId = oldest.value;
|
|
3049
|
+
const evicted = this.persistedModules.get(oldestId);
|
|
3050
|
+
this.persistedModules.delete(oldestId);
|
|
3051
|
+
log10.debug(`Evicting persisted module (LRU): ${oldestId}`);
|
|
3052
|
+
try {
|
|
3053
|
+
await evicted.destroy();
|
|
3054
|
+
} catch (e) {
|
|
3055
|
+
log10.error(`Error destroying evicted module ${oldestId}:`, e);
|
|
3056
|
+
}
|
|
3057
|
+
this.globalContext.unregisterModule(oldestId);
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
2831
3061
|
export {
|
|
2832
3062
|
withRetry,
|
|
2833
3063
|
usingSync,
|
|
@@ -2837,10 +3067,12 @@ export {
|
|
|
2837
3067
|
unwrapOr,
|
|
2838
3068
|
unwrap,
|
|
2839
3069
|
state,
|
|
3070
|
+
setPortableImpl,
|
|
2840
3071
|
setLogLevel,
|
|
2841
3072
|
setDebugMode,
|
|
2842
3073
|
retryResult,
|
|
2843
3074
|
retry,
|
|
3075
|
+
portable,
|
|
2844
3076
|
match,
|
|
2845
3077
|
mapErr,
|
|
2846
3078
|
map,
|
|
@@ -2891,6 +3123,7 @@ export {
|
|
|
2891
3123
|
RemoteEngine,
|
|
2892
3124
|
ParseError,
|
|
2893
3125
|
Ok,
|
|
3126
|
+
ManagedRouter,
|
|
2894
3127
|
Logger,
|
|
2895
3128
|
Link,
|
|
2896
3129
|
HypenRouter,
|
|
@@ -2910,4 +3143,4 @@ export {
|
|
|
2910
3143
|
ActionError
|
|
2911
3144
|
};
|
|
2912
3145
|
|
|
2913
|
-
//# debugId=
|
|
3146
|
+
//# debugId=A9CE0B874F21F46D64756E2164756E21
|