@hypen-space/core 0.4.92 → 0.4.941
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/dist/app.js +1 -1
- package/dist/app.js.map +1 -1
- package/dist/components/builtin.js +1 -1
- package/dist/components/builtin.js.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.js +224 -223
- package/dist/index.js.map +5 -5
- package/dist/managed-router.js +1372 -0
- package/dist/managed-router.js.map +16 -0
- package/dist/persistence.js +2 -0
- package/dist/persistence.js.map +9 -0
- package/dist/portable.js +75 -0
- package/dist/portable.js.map +10 -0
- package/dist/router.js +1 -1
- package/dist/router.js.map +1 -1
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1941,8 +1941,207 @@ class HypenRouter {
|
|
|
1941
1941
|
}
|
|
1942
1942
|
}
|
|
1943
1943
|
|
|
1944
|
+
// src/managed-router.ts
|
|
1945
|
+
var log6 = createLogger("ManagedRouter");
|
|
1946
|
+
var DEFAULT_MAX_PERSISTED_MODULES = 10;
|
|
1947
|
+
|
|
1948
|
+
class ManagedRouter {
|
|
1949
|
+
router;
|
|
1950
|
+
engine;
|
|
1951
|
+
registry;
|
|
1952
|
+
globalContext;
|
|
1953
|
+
routes = [];
|
|
1954
|
+
activeModule = null;
|
|
1955
|
+
activeRoute = null;
|
|
1956
|
+
unsubscribe = null;
|
|
1957
|
+
persistedModules = new Map;
|
|
1958
|
+
maxPersistedModules;
|
|
1959
|
+
navPromise = Promise.resolve();
|
|
1960
|
+
constructor(router, engine, registry, globalContext, options = {}) {
|
|
1961
|
+
this.router = router;
|
|
1962
|
+
this.engine = engine;
|
|
1963
|
+
this.registry = registry;
|
|
1964
|
+
this.globalContext = globalContext;
|
|
1965
|
+
const cap = options.maxPersistedModules ?? DEFAULT_MAX_PERSISTED_MODULES;
|
|
1966
|
+
this.maxPersistedModules = cap > 0 ? cap : DEFAULT_MAX_PERSISTED_MODULES;
|
|
1967
|
+
}
|
|
1968
|
+
addRoute(route) {
|
|
1969
|
+
this.routes.push(route);
|
|
1970
|
+
return this;
|
|
1971
|
+
}
|
|
1972
|
+
start() {
|
|
1973
|
+
this.unsubscribe = this.router.onNavigate((routeState) => {
|
|
1974
|
+
this.handleRouteChange(routeState);
|
|
1975
|
+
});
|
|
1976
|
+
this.installRouterActions();
|
|
1977
|
+
}
|
|
1978
|
+
installRouterActions() {
|
|
1979
|
+
const router = this.router;
|
|
1980
|
+
const defer = (fn) => queueMicrotask(fn);
|
|
1981
|
+
const readTo = (action) => {
|
|
1982
|
+
const payload = action?.payload;
|
|
1983
|
+
const to = payload?.to;
|
|
1984
|
+
return typeof to === "string" && to.length > 0 ? to : null;
|
|
1985
|
+
};
|
|
1986
|
+
this.engine.onAction("router.push", (action) => {
|
|
1987
|
+
const to = readTo(action);
|
|
1988
|
+
if (to)
|
|
1989
|
+
defer(() => router.push(to));
|
|
1990
|
+
});
|
|
1991
|
+
this.engine.onAction("router.replace", (action) => {
|
|
1992
|
+
const to = readTo(action);
|
|
1993
|
+
if (to)
|
|
1994
|
+
defer(() => router.replace(to));
|
|
1995
|
+
});
|
|
1996
|
+
this.engine.onAction("router.back", () => {
|
|
1997
|
+
defer(() => router.back());
|
|
1998
|
+
});
|
|
1999
|
+
this.engine.onAction("router.forward", () => {
|
|
2000
|
+
defer(() => router.forward());
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
async stop() {
|
|
2004
|
+
if (this.unsubscribe) {
|
|
2005
|
+
this.unsubscribe();
|
|
2006
|
+
this.unsubscribe = null;
|
|
2007
|
+
}
|
|
2008
|
+
const cleanup = this.navPromise.catch(() => {}).then(async () => {
|
|
2009
|
+
await this.unmountActive();
|
|
2010
|
+
for (const [moduleId, instance] of this.persistedModules) {
|
|
2011
|
+
log6.debug(`Destroying persisted module on stop: ${moduleId}`);
|
|
2012
|
+
try {
|
|
2013
|
+
await instance.destroy();
|
|
2014
|
+
} catch (e) {
|
|
2015
|
+
log6.error(`Error destroying persisted module ${moduleId}:`, e);
|
|
2016
|
+
}
|
|
2017
|
+
this.globalContext.unregisterModule(moduleId);
|
|
2018
|
+
}
|
|
2019
|
+
this.persistedModules.clear();
|
|
2020
|
+
});
|
|
2021
|
+
this.navPromise = cleanup;
|
|
2022
|
+
await cleanup;
|
|
2023
|
+
this.router.dispose();
|
|
2024
|
+
}
|
|
2025
|
+
async waitForNavigation() {
|
|
2026
|
+
try {
|
|
2027
|
+
await this.navPromise;
|
|
2028
|
+
} catch {}
|
|
2029
|
+
}
|
|
2030
|
+
getActiveModule() {
|
|
2031
|
+
return this.activeModule;
|
|
2032
|
+
}
|
|
2033
|
+
getActiveRoute() {
|
|
2034
|
+
return this.activeRoute;
|
|
2035
|
+
}
|
|
2036
|
+
handleRouteChange(routeState) {
|
|
2037
|
+
this.navPromise = this.navPromise.catch((e) => {
|
|
2038
|
+
log6.error("Previous navigation failed:", e);
|
|
2039
|
+
}).then(() => this.processRouteChange(routeState));
|
|
2040
|
+
}
|
|
2041
|
+
async processRouteChange(routeState) {
|
|
2042
|
+
const path = routeState.currentPath;
|
|
2043
|
+
const matched = this.matchRoute(path);
|
|
2044
|
+
if (!matched) {
|
|
2045
|
+
log6.debug(`No route matched for path: ${path}`);
|
|
2046
|
+
await this.unmountActive();
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
if (this.activeRoute && this.activeRoute.path === matched.path) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
await this.unmountActive();
|
|
2053
|
+
await this.mount(matched);
|
|
2054
|
+
}
|
|
2055
|
+
matchRoute(path) {
|
|
2056
|
+
for (const route of this.routes) {
|
|
2057
|
+
if (this.router.matchPath(route.path, path) !== null) {
|
|
2058
|
+
return route;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
return null;
|
|
2062
|
+
}
|
|
2063
|
+
async mount(route) {
|
|
2064
|
+
const definition = route.module || this.registry.get(route.component);
|
|
2065
|
+
if (!definition) {
|
|
2066
|
+
log6.debug(`No module definition found for component: ${route.component}`);
|
|
2067
|
+
this.activeRoute = route;
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
const namedDef = {
|
|
2071
|
+
...definition,
|
|
2072
|
+
name: definition.name || route.component.toLowerCase()
|
|
2073
|
+
};
|
|
2074
|
+
const moduleId = namedDef.name.toLowerCase();
|
|
2075
|
+
const persisted = this.persistedModules.get(moduleId);
|
|
2076
|
+
if (persisted) {
|
|
2077
|
+
log6.debug(`Restoring persisted module: ${moduleId} for route: ${route.path}`);
|
|
2078
|
+
this.activeModule = persisted;
|
|
2079
|
+
this.activeRoute = route;
|
|
2080
|
+
this.persistedModules.delete(moduleId);
|
|
2081
|
+
await persisted.activate();
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
log6.debug(`Mounting module: ${namedDef.name} for route: ${route.path}`);
|
|
2085
|
+
const instance = new HypenModuleInstance(this.engine, namedDef, this.router, this.globalContext);
|
|
2086
|
+
this.globalContext.registerModule(moduleId, instance);
|
|
2087
|
+
this.activeModule = instance;
|
|
2088
|
+
this.activeRoute = route;
|
|
2089
|
+
await instance.activate();
|
|
2090
|
+
}
|
|
2091
|
+
async unmountActive() {
|
|
2092
|
+
if (!this.activeModule || !this.activeRoute) {
|
|
2093
|
+
this.activeModule = null;
|
|
2094
|
+
this.activeRoute = null;
|
|
2095
|
+
return;
|
|
2096
|
+
}
|
|
2097
|
+
const active = this.activeModule;
|
|
2098
|
+
const route = this.activeRoute;
|
|
2099
|
+
const definition = route.module || this.registry.get(route.component);
|
|
2100
|
+
const moduleId = (definition?.name || route.component).toLowerCase();
|
|
2101
|
+
const persist = definition != null && definition.persist !== false;
|
|
2102
|
+
this.activeModule = null;
|
|
2103
|
+
this.activeRoute = null;
|
|
2104
|
+
try {
|
|
2105
|
+
await active.deactivate();
|
|
2106
|
+
} catch (e) {
|
|
2107
|
+
log6.error(`Error deactivating module ${moduleId}:`, e);
|
|
2108
|
+
}
|
|
2109
|
+
if (persist) {
|
|
2110
|
+
log6.debug(`Persisting module: ${moduleId}`);
|
|
2111
|
+
this.persistedModules.delete(moduleId);
|
|
2112
|
+
this.persistedModules.set(moduleId, active);
|
|
2113
|
+
await this.evictPersistedOverflow();
|
|
2114
|
+
} else {
|
|
2115
|
+
log6.debug(`Unmounting module: ${moduleId}`);
|
|
2116
|
+
try {
|
|
2117
|
+
await active.destroy();
|
|
2118
|
+
} catch (e) {
|
|
2119
|
+
log6.error(`Error destroying module ${moduleId}:`, e);
|
|
2120
|
+
}
|
|
2121
|
+
this.globalContext.unregisterModule(moduleId);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
async evictPersistedOverflow() {
|
|
2125
|
+
while (this.persistedModules.size > this.maxPersistedModules) {
|
|
2126
|
+
const oldest = this.persistedModules.keys().next();
|
|
2127
|
+
if (oldest.done)
|
|
2128
|
+
break;
|
|
2129
|
+
const oldestId = oldest.value;
|
|
2130
|
+
const evicted = this.persistedModules.get(oldestId);
|
|
2131
|
+
this.persistedModules.delete(oldestId);
|
|
2132
|
+
log6.debug(`Evicting persisted module (LRU): ${oldestId}`);
|
|
2133
|
+
try {
|
|
2134
|
+
await evicted.destroy();
|
|
2135
|
+
} catch (e) {
|
|
2136
|
+
log6.error(`Error destroying evicted module ${oldestId}:`, e);
|
|
2137
|
+
}
|
|
2138
|
+
this.globalContext.unregisterModule(oldestId);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
|
|
1944
2143
|
// src/events.ts
|
|
1945
|
-
var
|
|
2144
|
+
var log7 = frameworkLoggers.events;
|
|
1946
2145
|
|
|
1947
2146
|
class TypedEventEmitter {
|
|
1948
2147
|
eventBus = new Map;
|
|
@@ -1955,7 +2154,7 @@ class TypedEventEmitter {
|
|
|
1955
2154
|
try {
|
|
1956
2155
|
handler(payload);
|
|
1957
2156
|
} catch (error) {
|
|
1958
|
-
|
|
2157
|
+
log7.error(`Error in event handler for "${String(event)}":`, error);
|
|
1959
2158
|
}
|
|
1960
2159
|
});
|
|
1961
2160
|
}
|
|
@@ -2007,7 +2206,7 @@ function createEventEmitter() {
|
|
|
2007
2206
|
}
|
|
2008
2207
|
|
|
2009
2208
|
// src/context.ts
|
|
2010
|
-
var
|
|
2209
|
+
var log8 = frameworkLoggers.context;
|
|
2011
2210
|
|
|
2012
2211
|
class HypenGlobalContext {
|
|
2013
2212
|
modules = new Map;
|
|
@@ -2020,14 +2219,14 @@ class HypenGlobalContext {
|
|
|
2020
2219
|
}
|
|
2021
2220
|
registerModule(id, instance) {
|
|
2022
2221
|
if (this.modules.has(id)) {
|
|
2023
|
-
|
|
2222
|
+
log8.warn(`Module "${id}" is already registered. Overwriting.`);
|
|
2024
2223
|
}
|
|
2025
2224
|
this.modules.set(id, instance);
|
|
2026
|
-
|
|
2225
|
+
log8.debug(`Registered module: ${id}`);
|
|
2027
2226
|
}
|
|
2028
2227
|
unregisterModule(id) {
|
|
2029
2228
|
this.modules.delete(id);
|
|
2030
|
-
|
|
2229
|
+
log8.debug(`Unregistered module: ${id}`);
|
|
2031
2230
|
}
|
|
2032
2231
|
getModule(id) {
|
|
2033
2232
|
const module = this.modules.get(id);
|
|
@@ -2055,14 +2254,14 @@ class HypenGlobalContext {
|
|
|
2055
2254
|
}
|
|
2056
2255
|
emit(event, payload) {
|
|
2057
2256
|
if (this.typedEvents.listenerCount(event) === 0) {
|
|
2058
|
-
|
|
2257
|
+
log8.debug(`Event "${event}" emitted but no listeners`);
|
|
2059
2258
|
return;
|
|
2060
2259
|
}
|
|
2061
|
-
|
|
2260
|
+
log8.debug(`Emitting event: ${event}`, payload);
|
|
2062
2261
|
this.typedEvents.emit(event, payload);
|
|
2063
2262
|
}
|
|
2064
2263
|
on(event, handler) {
|
|
2065
|
-
|
|
2264
|
+
log8.debug(`Listening to event: ${event}`);
|
|
2066
2265
|
return this.typedEvents.on(event, handler);
|
|
2067
2266
|
}
|
|
2068
2267
|
off(event, handler) {
|
|
@@ -2209,7 +2408,7 @@ var RetryPresets = {
|
|
|
2209
2408
|
};
|
|
2210
2409
|
|
|
2211
2410
|
// src/remote/client.ts
|
|
2212
|
-
var
|
|
2411
|
+
var log9 = frameworkLoggers.remote;
|
|
2213
2412
|
|
|
2214
2413
|
class RemoteEngine {
|
|
2215
2414
|
ws = null;
|
|
@@ -2338,7 +2537,7 @@ class RemoteEngine {
|
|
|
2338
2537
|
this.navigationDisposable = disposableListener(window, "popstate", () => {
|
|
2339
2538
|
if (this.handlingPopState)
|
|
2340
2539
|
return;
|
|
2341
|
-
|
|
2540
|
+
log9.debug("Back navigation detected, dispatching:", nav.backAction);
|
|
2342
2541
|
this.handlingPopState = true;
|
|
2343
2542
|
this.dispatchAction(nav.backAction);
|
|
2344
2543
|
});
|
|
@@ -2374,7 +2573,7 @@ class RemoteEngine {
|
|
|
2374
2573
|
}
|
|
2375
2574
|
dispatchAction(action, payload) {
|
|
2376
2575
|
if (this.state !== "connected" || !this.ws) {
|
|
2377
|
-
|
|
2576
|
+
log9.warn("Cannot dispatch action: not connected");
|
|
2378
2577
|
return;
|
|
2379
2578
|
}
|
|
2380
2579
|
const message = {
|
|
@@ -2387,7 +2586,7 @@ class RemoteEngine {
|
|
|
2387
2586
|
}
|
|
2388
2587
|
subscribeState() {
|
|
2389
2588
|
if (this.state !== "connected" || !this.ws) {
|
|
2390
|
-
|
|
2589
|
+
log9.warn("Cannot subscribe to state: not connected");
|
|
2391
2590
|
return;
|
|
2392
2591
|
}
|
|
2393
2592
|
const message = { type: "subscribeState" };
|
|
@@ -2395,7 +2594,7 @@ class RemoteEngine {
|
|
|
2395
2594
|
}
|
|
2396
2595
|
updateState(state2) {
|
|
2397
2596
|
if (this.state !== "connected" || !this.ws) {
|
|
2398
|
-
|
|
2597
|
+
log9.warn("Cannot update state: not connected");
|
|
2399
2598
|
return;
|
|
2400
2599
|
}
|
|
2401
2600
|
const message = {
|
|
@@ -2468,7 +2667,7 @@ class RemoteEngine {
|
|
|
2468
2667
|
break;
|
|
2469
2668
|
}
|
|
2470
2669
|
} catch (e) {
|
|
2471
|
-
|
|
2670
|
+
log9.error("Error handling remote message:", e);
|
|
2472
2671
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
2473
2672
|
this.errorCallbacks.forEach((cb) => cb(error));
|
|
2474
2673
|
}
|
|
@@ -2502,7 +2701,7 @@ class RemoteEngine {
|
|
|
2502
2701
|
}
|
|
2503
2702
|
handlePatch(message) {
|
|
2504
2703
|
if (message.revision <= this.currentRevision) {
|
|
2505
|
-
|
|
2704
|
+
log9.warn(`Out of order patch: expected > ${this.currentRevision}, got ${message.revision}`);
|
|
2506
2705
|
return;
|
|
2507
2706
|
}
|
|
2508
2707
|
this.currentRevision = message.revision;
|
|
@@ -2528,10 +2727,10 @@ class RemoteEngine {
|
|
|
2528
2727
|
maxDelayMs: 30000,
|
|
2529
2728
|
jitter: 0.1,
|
|
2530
2729
|
onRetry: (attempt, error) => {
|
|
2531
|
-
|
|
2730
|
+
log9.debug(`Reconnection attempt ${attempt}/${this.options.maxReconnectAttempts} failed: ${error.message}`);
|
|
2532
2731
|
}
|
|
2533
2732
|
}).catch((error) => {
|
|
2534
|
-
|
|
2733
|
+
log9.error("Max reconnection attempts reached:", error.message);
|
|
2535
2734
|
this.errorCallbacks.forEach((cb) => cb(new ConnectionError(this.url, error, this.options.maxReconnectAttempts)));
|
|
2536
2735
|
});
|
|
2537
2736
|
}, this.options.reconnectInterval);
|
|
@@ -2784,7 +2983,7 @@ class ComponentResolver {
|
|
|
2784
2983
|
}
|
|
2785
2984
|
|
|
2786
2985
|
// src/components/builtin.ts
|
|
2787
|
-
var
|
|
2986
|
+
var log10 = frameworkLoggers.router;
|
|
2788
2987
|
async function updateRouteVisibility(currentPath, engine, doc) {
|
|
2789
2988
|
const targetDoc = doc ?? document;
|
|
2790
2989
|
const routeElements = targetDoc.querySelectorAll('[data-hypen-type="route"]');
|
|
@@ -2805,13 +3004,13 @@ async function updateRouteVisibility(currentPath, engine, doc) {
|
|
|
2805
3004
|
try {
|
|
2806
3005
|
await engine.renderLazyRoute(routePath, componentName, htmlEl);
|
|
2807
3006
|
} catch (err) {
|
|
2808
|
-
|
|
3007
|
+
log10.error(`Failed to render route ${routePath}:`, err);
|
|
2809
3008
|
}
|
|
2810
3009
|
}
|
|
2811
3010
|
}
|
|
2812
3011
|
}
|
|
2813
3012
|
if (!matchFound) {
|
|
2814
|
-
|
|
3013
|
+
log10.warn(`No route matched path: ${currentPath}. Available routes:`, Array.from(routeElements).map((el) => el.dataset.routePath));
|
|
2815
3014
|
}
|
|
2816
3015
|
}
|
|
2817
3016
|
var Router = app.defineState({
|
|
@@ -2820,12 +3019,12 @@ var Router = app.defineState({
|
|
|
2820
3019
|
routeParams: {}
|
|
2821
3020
|
}, { name: "__Router" }).onCreated((state2, context) => {
|
|
2822
3021
|
if (!context) {
|
|
2823
|
-
|
|
3022
|
+
log10.error("Requires global context");
|
|
2824
3023
|
return;
|
|
2825
3024
|
}
|
|
2826
3025
|
const router = context.router;
|
|
2827
3026
|
if (!router) {
|
|
2828
|
-
|
|
3027
|
+
log10.error("Router not found in context");
|
|
2829
3028
|
return;
|
|
2830
3029
|
}
|
|
2831
3030
|
const hypenEngine = context.__hypenEngine;
|
|
@@ -2845,7 +3044,7 @@ var Link = app.defineState({
|
|
|
2845
3044
|
}, { name: "__Link" }).onAction("navigate", ({ state: state2, context }) => {
|
|
2846
3045
|
const router = context?.router;
|
|
2847
3046
|
if (!router) {
|
|
2848
|
-
|
|
3047
|
+
log10.error("Link requires router context");
|
|
2849
3048
|
return;
|
|
2850
3049
|
}
|
|
2851
3050
|
const targetPath = state2.to;
|
|
@@ -2860,204 +3059,6 @@ var Link = app.defineState({
|
|
|
2860
3059
|
});
|
|
2861
3060
|
}
|
|
2862
3061
|
}).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
|
-
}
|
|
3061
3062
|
export {
|
|
3062
3063
|
withRetry,
|
|
3063
3064
|
usingSync,
|
|
@@ -3143,4 +3144,4 @@ export {
|
|
|
3143
3144
|
ActionError
|
|
3144
3145
|
};
|
|
3145
3146
|
|
|
3146
|
-
//# debugId=
|
|
3147
|
+
//# debugId=6ED7F94267EF229064756E2164756E21
|