@pithyjs/router 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +621 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/router/core/config.d.ts +22 -0
- package/dist/router/core/config.d.ts.map +1 -0
- package/dist/router/core/config.js +54 -0
- package/dist/router/core/config.js.map +1 -0
- package/dist/router/core/constants.d.ts +89 -0
- package/dist/router/core/constants.d.ts.map +1 -0
- package/dist/router/core/constants.js +95 -0
- package/dist/router/core/constants.js.map +1 -0
- package/dist/router/core/history.d.ts +54 -0
- package/dist/router/core/history.d.ts.map +1 -0
- package/dist/router/core/history.js +89 -0
- package/dist/router/core/history.js.map +1 -0
- package/dist/router/core/matcher.d.ts +43 -0
- package/dist/router/core/matcher.d.ts.map +1 -0
- package/dist/router/core/matcher.js +242 -0
- package/dist/router/core/matcher.js.map +1 -0
- package/dist/router/core/params.d.ts +88 -0
- package/dist/router/core/params.d.ts.map +1 -0
- package/dist/router/core/params.js +150 -0
- package/dist/router/core/params.js.map +1 -0
- package/dist/router/core/pipeline.d.ts +90 -0
- package/dist/router/core/pipeline.d.ts.map +1 -0
- package/dist/router/core/pipeline.js +323 -0
- package/dist/router/core/pipeline.js.map +1 -0
- package/dist/router/core/route-tree.d.ts +76 -0
- package/dist/router/core/route-tree.d.ts.map +1 -0
- package/dist/router/core/route-tree.js +143 -0
- package/dist/router/core/route-tree.js.map +1 -0
- package/dist/router/core/router.d.ts +229 -0
- package/dist/router/core/router.d.ts.map +1 -0
- package/dist/router/core/router.js +762 -0
- package/dist/router/core/router.js.map +1 -0
- package/dist/router/core/types.d.ts +387 -0
- package/dist/router/core/types.d.ts.map +1 -0
- package/dist/router/core/types.js +22 -0
- package/dist/router/core/types.js.map +1 -0
- package/dist/router/core/utils.d.ts +66 -0
- package/dist/router/core/utils.d.ts.map +1 -0
- package/dist/router/core/utils.js +152 -0
- package/dist/router/core/utils.js.map +1 -0
- package/dist/router/features/coordinator.d.ts +75 -0
- package/dist/router/features/coordinator.d.ts.map +1 -0
- package/dist/router/features/coordinator.js +203 -0
- package/dist/router/features/coordinator.js.map +1 -0
- package/dist/router/features/errors/error-codes.d.ts +107 -0
- package/dist/router/features/errors/error-codes.d.ts.map +1 -0
- package/dist/router/features/errors/error-codes.js +247 -0
- package/dist/router/features/errors/error-codes.js.map +1 -0
- package/dist/router/features/errors/error-resolution.d.ts +31 -0
- package/dist/router/features/errors/error-resolution.d.ts.map +1 -0
- package/dist/router/features/errors/error-resolution.js +47 -0
- package/dist/router/features/errors/error-resolution.js.map +1 -0
- package/dist/router/features/errors/error-types.d.ts +60 -0
- package/dist/router/features/errors/error-types.d.ts.map +1 -0
- package/dist/router/features/errors/error-types.js +57 -0
- package/dist/router/features/errors/error-types.js.map +1 -0
- package/dist/router/features/errors/global-error-fallback.d.ts +33 -0
- package/dist/router/features/errors/global-error-fallback.d.ts.map +1 -0
- package/dist/router/features/errors/global-error-fallback.js +182 -0
- package/dist/router/features/errors/global-error-fallback.js.map +1 -0
- package/dist/router/features/errors/index.d.ts +15 -0
- package/dist/router/features/errors/index.d.ts.map +1 -0
- package/dist/router/features/errors/index.js +18 -0
- package/dist/router/features/errors/index.js.map +1 -0
- package/dist/router/features/errors/router-errors.d.ts +44 -0
- package/dist/router/features/errors/router-errors.d.ts.map +1 -0
- package/dist/router/features/errors/router-errors.js +53 -0
- package/dist/router/features/errors/router-errors.js.map +1 -0
- package/dist/router/features/guards/engine.d.ts +40 -0
- package/dist/router/features/guards/engine.d.ts.map +1 -0
- package/dist/router/features/guards/engine.js +67 -0
- package/dist/router/features/guards/engine.js.map +1 -0
- package/dist/router/features/guards/index.d.ts +52 -0
- package/dist/router/features/guards/index.d.ts.map +1 -0
- package/dist/router/features/guards/index.js +95 -0
- package/dist/router/features/guards/index.js.map +1 -0
- package/dist/router/features/loaders/cache.d.ts +60 -0
- package/dist/router/features/loaders/cache.d.ts.map +1 -0
- package/dist/router/features/loaders/cache.js +80 -0
- package/dist/router/features/loaders/cache.js.map +1 -0
- package/dist/router/features/loaders/engine.d.ts +17 -0
- package/dist/router/features/loaders/engine.d.ts.map +1 -0
- package/dist/router/features/loaders/engine.js +27 -0
- package/dist/router/features/loaders/engine.js.map +1 -0
- package/dist/router/features/loaders/index.d.ts +49 -0
- package/dist/router/features/loaders/index.d.ts.map +1 -0
- package/dist/router/features/loaders/index.js +112 -0
- package/dist/router/features/loaders/index.js.map +1 -0
- package/dist/router/features/loading-ui-manager.d.ts +69 -0
- package/dist/router/features/loading-ui-manager.d.ts.map +1 -0
- package/dist/router/features/loading-ui-manager.js +209 -0
- package/dist/router/features/loading-ui-manager.js.map +1 -0
- package/dist/router/features/module-loader.d.ts +50 -0
- package/dist/router/features/module-loader.d.ts.map +1 -0
- package/dist/router/features/module-loader.js +121 -0
- package/dist/router/features/module-loader.js.map +1 -0
- package/dist/router/features/outlet/errors.d.ts +24 -0
- package/dist/router/features/outlet/errors.d.ts.map +1 -0
- package/dist/router/features/outlet/errors.js +96 -0
- package/dist/router/features/outlet/errors.js.map +1 -0
- package/dist/router/features/outlet/index.d.ts +45 -0
- package/dist/router/features/outlet/index.d.ts.map +1 -0
- package/dist/router/features/outlet/index.js +95 -0
- package/dist/router/features/outlet/index.js.map +1 -0
- package/dist/router/features/outlet/mount.d.ts +38 -0
- package/dist/router/features/outlet/mount.d.ts.map +1 -0
- package/dist/router/features/outlet/mount.js +301 -0
- package/dist/router/features/outlet/mount.js.map +1 -0
- package/dist/router/features/outlet/segment-chain.d.ts +16 -0
- package/dist/router/features/outlet/segment-chain.d.ts.map +1 -0
- package/dist/router/features/outlet/segment-chain.js +62 -0
- package/dist/router/features/outlet/segment-chain.js.map +1 -0
- package/dist/router/features/prefetch/index.d.ts +97 -0
- package/dist/router/features/prefetch/index.d.ts.map +1 -0
- package/dist/router/features/prefetch/index.js +345 -0
- package/dist/router/features/prefetch/index.js.map +1 -0
- package/dist/router/features/ux/focus.d.ts +62 -0
- package/dist/router/features/ux/focus.d.ts.map +1 -0
- package/dist/router/features/ux/focus.js +136 -0
- package/dist/router/features/ux/focus.js.map +1 -0
- package/dist/router/features/ux/live-region.d.ts +81 -0
- package/dist/router/features/ux/live-region.d.ts.map +1 -0
- package/dist/router/features/ux/live-region.js +166 -0
- package/dist/router/features/ux/live-region.js.map +1 -0
- package/dist/router/features/ux/scroll-focus.d.ts +105 -0
- package/dist/router/features/ux/scroll-focus.d.ts.map +1 -0
- package/dist/router/features/ux/scroll-focus.js +111 -0
- package/dist/router/features/ux/scroll-focus.js.map +1 -0
- package/dist/router/features/ux/scroll.d.ts +71 -0
- package/dist/router/features/ux/scroll.d.ts.map +1 -0
- package/dist/router/features/ux/scroll.js +137 -0
- package/dist/router/features/ux/scroll.js.map +1 -0
- package/dist/router/features/ux/transitions.d.ts +120 -0
- package/dist/router/features/ux/transitions.d.ts.map +1 -0
- package/dist/router/features/ux/transitions.js +235 -0
- package/dist/router/features/ux/transitions.js.map +1 -0
- package/dist/router/integration/directive-binder.d.ts +20 -0
- package/dist/router/integration/directive-binder.d.ts.map +1 -0
- package/dist/router/integration/directive-binder.js +139 -0
- package/dist/router/integration/directive-binder.js.map +1 -0
- package/dist/router/integration/directives.d.ts +42 -0
- package/dist/router/integration/directives.d.ts.map +1 -0
- package/dist/router/integration/directives.js +109 -0
- package/dist/router/integration/directives.js.map +1 -0
- package/dist/router/integration/history-adapter.d.ts +76 -0
- package/dist/router/integration/history-adapter.d.ts.map +1 -0
- package/dist/router/integration/history-adapter.js +157 -0
- package/dist/router/integration/history-adapter.js.map +1 -0
- package/dist/router/integration/hmr.d.ts +83 -0
- package/dist/router/integration/hmr.d.ts.map +1 -0
- package/dist/router/integration/hmr.js +160 -0
- package/dist/router/integration/hmr.js.map +1 -0
- package/dist/router/integration/link-interceptor.d.ts +49 -0
- package/dist/router/integration/link-interceptor.d.ts.map +1 -0
- package/dist/router/integration/link-interceptor.js +94 -0
- package/dist/router/integration/link-interceptor.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.outlet",
|
|
4
|
+
"title": "Router Outlet Mounting System",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import { buildSegmentsOffDOM, commitSegmentsToDOM, } from './mount';
|
|
9
|
+
/** @codexApi {"parent":"pithy.router.outlet","name":"OutletManager","stability":"experimental","signature":"class OutletManager"} */
|
|
10
|
+
/**
|
|
11
|
+
* Enhanced outlet mounting system
|
|
12
|
+
* Implements segment diff mounting with robust outlet resolution
|
|
13
|
+
* Fixed memory leak with proper two-phase mounting and cleanup
|
|
14
|
+
*/
|
|
15
|
+
export class OutletManager {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.mountedComponents = new Map();
|
|
18
|
+
this.loadingStates = new Map();
|
|
19
|
+
this.outletElements = new Map();
|
|
20
|
+
this.router = null;
|
|
21
|
+
this.disposers = new Map();
|
|
22
|
+
}
|
|
23
|
+
/** @codexApi {"parent":"pithy.router.outlet","name":"mountSegments","stability":"experimental","signature":"(segmentChain: RouteSegmentChain[], navId: NavigationId, rootElement: HTMLElement) => Promise<boolean>"} */
|
|
24
|
+
/**
|
|
25
|
+
* Mount route segments with two-phase mounting and rollback
|
|
26
|
+
* Phase 1: Build everything off-DOM, Phase 2: Atomic commit
|
|
27
|
+
* Only remounts changed segments, preserves parent layouts
|
|
28
|
+
*/
|
|
29
|
+
async mountSegments(segmentChain, navId, rootElement) {
|
|
30
|
+
try {
|
|
31
|
+
// Find the first changed segment to determine mount point
|
|
32
|
+
const firstChangedIndex = segmentChain.findIndex(segment => segment.hasChanged);
|
|
33
|
+
if (firstChangedIndex === -1) {
|
|
34
|
+
// No changes needed
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
// Phase 1: Build everything off-DOM first
|
|
38
|
+
const buildResult = await buildSegmentsOffDOM(segmentChain, firstChangedIndex, navId, this.router);
|
|
39
|
+
if (!buildResult.success) {
|
|
40
|
+
// Run disposers to clean up any partial work
|
|
41
|
+
buildResult.disposers.forEach(fn => fn());
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// Phase 2: Atomic commit (replaces old nodes in one shot)
|
|
45
|
+
const commitResult = commitSegmentsToDOM(buildResult.fragment, buildResult.firstChangedIndex, segmentChain, rootElement, this.outletElements);
|
|
46
|
+
if (!commitResult.success) {
|
|
47
|
+
// Run disposers to clean up
|
|
48
|
+
buildResult.disposers.forEach(fn => fn());
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// Register disposers on the outlet for future cleanup
|
|
52
|
+
const outletKey = this.getOutletKey(rootElement);
|
|
53
|
+
this.disposers.set(outletKey, buildResult.disposers);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error('[Router] Failed to mount segments:', error);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** @codexApi {"parent":"pithy.router.outlet","name":"setRouter","stability":"experimental","signature":"(router: RouterInstance) => void"} */
|
|
62
|
+
/**
|
|
63
|
+
* Set router instance for navigation checking
|
|
64
|
+
*/
|
|
65
|
+
setRouter(router) {
|
|
66
|
+
this.router = router;
|
|
67
|
+
}
|
|
68
|
+
/** @codexApi {"parent":"pithy.router.outlet","name":"dispose","stability":"experimental","signature":"() => void"} */
|
|
69
|
+
/**
|
|
70
|
+
* Clean up all mounted components and state
|
|
71
|
+
*/
|
|
72
|
+
dispose() {
|
|
73
|
+
// Clean up all mounted components
|
|
74
|
+
for (const component of this.mountedComponents.values()) {
|
|
75
|
+
if (component.cleanup) {
|
|
76
|
+
component.cleanup();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Clean up all disposers
|
|
80
|
+
for (const disposers of this.disposers.values()) {
|
|
81
|
+
disposers.forEach(fn => fn());
|
|
82
|
+
}
|
|
83
|
+
this.mountedComponents.clear();
|
|
84
|
+
this.loadingStates.clear();
|
|
85
|
+
this.outletElements.clear();
|
|
86
|
+
this.disposers.clear();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generate unique key for outlet element
|
|
90
|
+
*/
|
|
91
|
+
getOutletKey(element) {
|
|
92
|
+
return element.id || element.className || element.tagName;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/router/features/outlet/index.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAQF,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAEpB,MAAM,SAAS,CAAC;AAEjB,qIAAqI;AACrI;;;;GAIG;AACH,MAAM,OAAO,aAAa;IAA1B;QACU,sBAAiB,GAAG,IAAI,GAAG,EAAkC,CAAC;QAC9D,kBAAa,GAAG,IAAI,GAAG,EAA6B,CAAC;QACrD,mBAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;QAChD,WAAM,GAA0B,IAAI,CAAC;QACrC,cAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IAqG3D,CAAC;IAnGC,wNAAwN;IACxN;;;;OAIG;IACH,KAAK,CAAC,aAAa,CACjB,YAAiC,EACjC,KAAmB,EACnB,WAAwB;QAExB,IAAI,CAAC;YACH,0DAA0D;YAC1D,MAAM,iBAAiB,GAAG,YAAY,CAAC,SAAS,CAC9C,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAC9B,CAAC;YAEF,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC7B,oBAAoB;gBACpB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,0CAA0C;YAC1C,MAAM,WAAW,GAAG,MAAM,mBAAmB,CAC3C,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,IAAI,CAAC,MAAM,CACZ,CAAC;YAEF,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACzB,6CAA6C;gBAC7C,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACf,CAAC;YAED,0DAA0D;YAC1D,MAAM,YAAY,GAAG,mBAAmB,CACtC,WAAW,CAAC,QAAQ,EACpB,WAAW,CAAC,iBAAiB,EAC7B,YAAY,EACZ,WAAW,EACX,IAAI,CAAC,cAAc,CACpB,CAAC;YAEF,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;gBAC1B,4BAA4B;gBAC5B,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACf,CAAC;YAED,sDAAsD;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;YAErD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC3D,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,8IAA8I;IAC9I;;OAEG;IACH,SAAS,CAAC,MAAsB;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,sHAAsH;IACtH;;OAEG;IACH,OAAO;QACL,kCAAkC;QAClC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC;YACxD,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,SAAS,CAAC,OAAO,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;QAED,yBAAyB;QACzB,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YAChD,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,OAAoB;QACvC,OAAO,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAC5D,CAAC;CACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.outlet.mount",
|
|
4
|
+
"title": "Outlet Component Mounting System",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import type { RouteSegmentChain, NavigationId, ResourceState } from '../../core/types';
|
|
9
|
+
/**
|
|
10
|
+
* Router interface for navigation checking
|
|
11
|
+
*/
|
|
12
|
+
export interface RouterInstance {
|
|
13
|
+
getActiveNavId(): NavigationId;
|
|
14
|
+
isNavActive(navId: NavigationId): boolean;
|
|
15
|
+
loaderData(): () => ResourceState | null;
|
|
16
|
+
}
|
|
17
|
+
/** @codexApi {"parent":"pithy.router.outlet.mount","name":"buildSegmentsOffDOM","stability":"experimental","signature":"(segmentChain: RouteSegmentChain[], firstChangedIndex: number, navId: NavigationId, router: RouterInstance | null) => Promise<BuildResult>"} */
|
|
18
|
+
/**
|
|
19
|
+
* Build segments off-DOM first (Phase 1 of two-phase mounting)
|
|
20
|
+
* Returns a document fragment with all segments built, along with disposers for cleanup
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildSegmentsOffDOM(segmentChain: RouteSegmentChain[], firstChangedIndex: number, navId: NavigationId, router: RouterInstance | null): Promise<{
|
|
23
|
+
success: boolean;
|
|
24
|
+
reason?: string | undefined;
|
|
25
|
+
fragment: DocumentFragment;
|
|
26
|
+
firstChangedIndex: number;
|
|
27
|
+
disposers: Array<() => void>;
|
|
28
|
+
}>;
|
|
29
|
+
/** @codexApi {"parent":"pithy.router.outlet.mount","name":"commitSegmentsToDOM","stability":"experimental","signature":"(fragment: DocumentFragment, firstChangedIndex: number, segmentChain: RouteSegmentChain[], rootElement: HTMLElement, outletElements: Map<string, HTMLElement>) => CommitResult"} */
|
|
30
|
+
/**
|
|
31
|
+
* Commit segments to DOM atomically (Phase 2 of two-phase mounting)
|
|
32
|
+
* Replaces the container's children with the new fragment in one operation
|
|
33
|
+
*/
|
|
34
|
+
export declare function commitSegmentsToDOM(fragment: DocumentFragment, firstChangedIndex: number, segmentChain: RouteSegmentChain[], rootElement: HTMLElement, outletElements: Map<string, HTMLElement>): {
|
|
35
|
+
success: boolean;
|
|
36
|
+
reason?: string | undefined;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../../src/router/features/outlet/mount.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EACV,iBAAiB,EAEjB,YAAY,EACZ,aAAa,EACd,MAAM,kBAAkB,CAAC;AAe1B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,cAAc,IAAI,YAAY,CAAC;IAC/B,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;IAC1C,UAAU,IAAI,MAAM,aAAa,GAAG,IAAI,CAAC;CAC1C;AAED,wQAAwQ;AACxQ;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,iBAAiB,EAAE,EACjC,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,GAAG,IAAI,GAC5B,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;CAC9B,CAAC,CAuDD;AAgRD,4SAA4S;AAC5S;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,iBAAiB,EAAE,MAAM,EACzB,YAAY,EAAE,iBAAiB,EAAE,EACjC,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GACvC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CA0BnD"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.outlet.mount",
|
|
4
|
+
"title": "Outlet Component Mounting System",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import { ROUTER_CONFIG } from '../../core/constants';
|
|
9
|
+
import { routeErrors } from '../errors/router-errors';
|
|
10
|
+
import { buildErrorUI, createRetryHandler } from './errors';
|
|
11
|
+
import { loadRouteModule, getRouteModuleKey } from '../module-loader';
|
|
12
|
+
/** @codexApi {"parent":"pithy.router.outlet.mount","name":"buildSegmentsOffDOM","stability":"experimental","signature":"(segmentChain: RouteSegmentChain[], firstChangedIndex: number, navId: NavigationId, router: RouterInstance | null) => Promise<BuildResult>"} */
|
|
13
|
+
/**
|
|
14
|
+
* Build segments off-DOM first (Phase 1 of two-phase mounting)
|
|
15
|
+
* Returns a document fragment with all segments built, along with disposers for cleanup
|
|
16
|
+
*/
|
|
17
|
+
export async function buildSegmentsOffDOM(segmentChain, firstChangedIndex, navId, router) {
|
|
18
|
+
const fragment = document.createDocumentFragment();
|
|
19
|
+
const disposers = [];
|
|
20
|
+
for (let i = firstChangedIndex; i < segmentChain.length; i++) {
|
|
21
|
+
const segment = segmentChain[i];
|
|
22
|
+
if (!segment)
|
|
23
|
+
continue;
|
|
24
|
+
// Check if navigation is still active
|
|
25
|
+
if (!isNavigationActive(navId, router)) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
reason: 'superseded',
|
|
29
|
+
fragment,
|
|
30
|
+
firstChangedIndex,
|
|
31
|
+
disposers,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Build this segment (pass null for outlet since we're building off-DOM)
|
|
35
|
+
const buildResult = await buildSegmentOffDOM(segment, navId, router);
|
|
36
|
+
if (!buildResult.success) {
|
|
37
|
+
const result = {
|
|
38
|
+
success: false,
|
|
39
|
+
fragment,
|
|
40
|
+
firstChangedIndex,
|
|
41
|
+
disposers,
|
|
42
|
+
};
|
|
43
|
+
if (buildResult.reason) {
|
|
44
|
+
result.reason = buildResult.reason;
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
// Add to fragment
|
|
49
|
+
fragment.appendChild(buildResult.element);
|
|
50
|
+
// Collect disposers
|
|
51
|
+
if (buildResult.dispose) {
|
|
52
|
+
disposers.push(buildResult.dispose);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
fragment,
|
|
58
|
+
firstChangedIndex,
|
|
59
|
+
disposers,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build a single segment off-DOM
|
|
64
|
+
* Handles both layout + page composition and standalone page components
|
|
65
|
+
*/
|
|
66
|
+
async function buildSegmentOffDOM(segment, navId, router) {
|
|
67
|
+
try {
|
|
68
|
+
const { node } = segment;
|
|
69
|
+
const cleanups = [];
|
|
70
|
+
// Check if route has a layout
|
|
71
|
+
if (node.imports.layout) {
|
|
72
|
+
// Load layout component through shared module cache
|
|
73
|
+
const layoutModule = await loadRouteModule(getRouteModuleKey(node.pattern, 'layout'), node.imports.layout);
|
|
74
|
+
const layoutCandidate = layoutModule.default || layoutModule;
|
|
75
|
+
if (typeof layoutCandidate !== 'function') {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
reason: 'layout load failed',
|
|
79
|
+
element: document.createElement('div'),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const layoutFactory = layoutCandidate;
|
|
83
|
+
const layoutInstance = layoutFactory();
|
|
84
|
+
if (!layoutInstance || !layoutInstance.el) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
reason: 'layout load failed',
|
|
88
|
+
element: document.createElement('div'),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
cleanups.push(layoutInstance.destroy);
|
|
92
|
+
// Find outlet in layout
|
|
93
|
+
const outlet = layoutInstance.el.querySelector('[data-router-outlet]');
|
|
94
|
+
// Load page component
|
|
95
|
+
const pageComponent = await loadComponent(segment, navId, outlet, router);
|
|
96
|
+
if (!pageComponent) {
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
reason: 'page load failed',
|
|
100
|
+
element: document.createElement('div'),
|
|
101
|
+
dispose: () => cleanups.forEach(fn => fn?.()),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
cleanups.push(pageComponent.cleanup);
|
|
105
|
+
// Insert page into layout's outlet
|
|
106
|
+
if (outlet) {
|
|
107
|
+
outlet.appendChild(pageComponent.element);
|
|
108
|
+
}
|
|
109
|
+
// Return the layout element (which now contains the page)
|
|
110
|
+
return {
|
|
111
|
+
success: true,
|
|
112
|
+
element: layoutInstance.el,
|
|
113
|
+
dispose: () => cleanups.forEach(fn => fn?.()),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// No layout - just load the page component
|
|
117
|
+
const component = await loadComponent(segment, navId, null, router);
|
|
118
|
+
if (!component) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
reason: 'component load failed',
|
|
122
|
+
element: document.createElement('div'),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Check if this is an error placeholder
|
|
126
|
+
if (component.element instanceof HTMLElement &&
|
|
127
|
+
component.element.classList.contains('router-error-placeholder')) {
|
|
128
|
+
return {
|
|
129
|
+
success: true,
|
|
130
|
+
element: component.element,
|
|
131
|
+
dispose: component.cleanup,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
element: component.element,
|
|
137
|
+
dispose: component.cleanup,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error('[Router] Failed to build segment:', error);
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
reason: 'build failed',
|
|
145
|
+
element: document.createElement('div'),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Load component with error handling
|
|
151
|
+
* Handles route errors, dynamic imports, component instantiation, and error UI
|
|
152
|
+
*/
|
|
153
|
+
async function loadComponent(segment, navId, outletElement, router) {
|
|
154
|
+
const { node } = segment;
|
|
155
|
+
if (!node.imports.page) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
// Check for route errors first
|
|
159
|
+
const errors = routeErrors();
|
|
160
|
+
const routeError = errors.get(node.id);
|
|
161
|
+
if (routeError) {
|
|
162
|
+
// Show error UI
|
|
163
|
+
const errorElement = await buildErrorUI(segment, navId, routeError, createRetryHandler());
|
|
164
|
+
return {
|
|
165
|
+
element: errorElement,
|
|
166
|
+
cleanup: undefined,
|
|
167
|
+
navId,
|
|
168
|
+
route: node,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
// Dynamic import through shared module cache
|
|
173
|
+
const componentModule = await loadRouteModule(getRouteModuleKey(node.pattern, 'page'), node.imports.page);
|
|
174
|
+
// Check if navigation is still active
|
|
175
|
+
if (!isNavigationActive(navId, router)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
// Create component instance with error handling
|
|
179
|
+
const componentCandidate = componentModule.default || componentModule;
|
|
180
|
+
if (typeof componentCandidate !== 'function') {
|
|
181
|
+
throw new Error('Component factory did not return valid instance');
|
|
182
|
+
}
|
|
183
|
+
const componentFactory = componentCandidate;
|
|
184
|
+
// Get loader data for this route
|
|
185
|
+
const loaderDataGetter = router?.loaderData();
|
|
186
|
+
const loaderState = loaderDataGetter ? loaderDataGetter() : null;
|
|
187
|
+
const loaderData = loaderState?.data;
|
|
188
|
+
// Build component props with both params and loader data
|
|
189
|
+
const componentProps = {
|
|
190
|
+
...segment.params,
|
|
191
|
+
loaderData,
|
|
192
|
+
};
|
|
193
|
+
let componentInstance;
|
|
194
|
+
try {
|
|
195
|
+
componentInstance = componentFactory(componentProps);
|
|
196
|
+
}
|
|
197
|
+
catch (componentError) {
|
|
198
|
+
console.error('[Router] Component instantiation failed:', componentError);
|
|
199
|
+
// Set route error for component instantiation failures
|
|
200
|
+
const { RouterError, RouterErrorCode } = await import('../errors');
|
|
201
|
+
const { setRouteError } = await import('../errors/router-errors');
|
|
202
|
+
const err = new RouterError(`Component error: ${componentError instanceof Error ? componentError.message : String(componentError)}`, {
|
|
203
|
+
navId: String(navId),
|
|
204
|
+
routeId: node.id,
|
|
205
|
+
parentRouteId: undefined,
|
|
206
|
+
routePath: node.pattern,
|
|
207
|
+
ts: Date.now(),
|
|
208
|
+
}, componentError, RouterErrorCode.COMPONENT_RENDER_ERROR);
|
|
209
|
+
setRouteError(node.id, err);
|
|
210
|
+
// Show error UI instead of throwing
|
|
211
|
+
const errorElement = await buildErrorUI(segment, navId, err, createRetryHandler());
|
|
212
|
+
return {
|
|
213
|
+
element: errorElement,
|
|
214
|
+
cleanup: undefined,
|
|
215
|
+
navId,
|
|
216
|
+
route: node,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
if (!componentInstance || !componentInstance.el) {
|
|
220
|
+
throw new Error('Component factory did not return valid instance');
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
element: componentInstance.el,
|
|
224
|
+
cleanup: componentInstance.destroy,
|
|
225
|
+
navId,
|
|
226
|
+
route: node,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.error('[Router] Failed to load component:', error);
|
|
231
|
+
// For other types of errors (import errors, validation errors, etc.)
|
|
232
|
+
// Set route error and show error UI
|
|
233
|
+
const { RouterError, RouterErrorCode } = await import('../errors');
|
|
234
|
+
const { setRouteError } = await import('../errors/router-errors');
|
|
235
|
+
const err = new RouterError(`Component load error: ${error instanceof Error ? error.message : String(error)}`, {
|
|
236
|
+
navId: String(navId),
|
|
237
|
+
routeId: node.id,
|
|
238
|
+
parentRouteId: undefined,
|
|
239
|
+
routePath: node.pattern,
|
|
240
|
+
ts: Date.now(),
|
|
241
|
+
}, error, RouterErrorCode.COMPONENT_LOAD_ERROR);
|
|
242
|
+
setRouteError(node.id, err);
|
|
243
|
+
// Show error UI instead of throwing
|
|
244
|
+
const errorElement = await buildErrorUI(segment, navId, err, createRetryHandler());
|
|
245
|
+
return {
|
|
246
|
+
element: errorElement,
|
|
247
|
+
cleanup: undefined,
|
|
248
|
+
navId,
|
|
249
|
+
route: node,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/** @codexApi {"parent":"pithy.router.outlet.mount","name":"commitSegmentsToDOM","stability":"experimental","signature":"(fragment: DocumentFragment, firstChangedIndex: number, segmentChain: RouteSegmentChain[], rootElement: HTMLElement, outletElements: Map<string, HTMLElement>) => CommitResult"} */
|
|
254
|
+
/**
|
|
255
|
+
* Commit segments to DOM atomically (Phase 2 of two-phase mounting)
|
|
256
|
+
* Replaces the container's children with the new fragment in one operation
|
|
257
|
+
*/
|
|
258
|
+
export function commitSegmentsToDOM(fragment, firstChangedIndex, segmentChain, rootElement, outletElements) {
|
|
259
|
+
try {
|
|
260
|
+
// Find the container to replace (the first changed segment's container)
|
|
261
|
+
let containerToReplace = rootElement;
|
|
262
|
+
// If we have previous segments, find the container of the first changed segment
|
|
263
|
+
if (firstChangedIndex > 0) {
|
|
264
|
+
const previousSegment = segmentChain[firstChangedIndex - 1];
|
|
265
|
+
if (previousSegment) {
|
|
266
|
+
const previousSegmentKey = getSegmentKey(previousSegment);
|
|
267
|
+
const previousOutlet = outletElements.get(previousSegmentKey);
|
|
268
|
+
if (previousOutlet) {
|
|
269
|
+
containerToReplace = previousOutlet;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Atomic replace: clear and append fragment in one operation
|
|
274
|
+
containerToReplace.replaceChildren(fragment);
|
|
275
|
+
return { success: true };
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
console.error('[Router] Atomic commit failed:', error);
|
|
279
|
+
return { success: false, reason: 'commit failed' };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Check if navigation is still active
|
|
284
|
+
* This is now integrated with the router's navigation transaction system
|
|
285
|
+
*/
|
|
286
|
+
function isNavigationActive(navId, router) {
|
|
287
|
+
if (navId === ROUTER_CONFIG.INITIAL_NAV_ID)
|
|
288
|
+
return true; // [OutletManager] initial mount has no transaction
|
|
289
|
+
if (router) {
|
|
290
|
+
return router.isNavActive(navId);
|
|
291
|
+
}
|
|
292
|
+
// Fallback: assume navigation is active if no router is set
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Generate unique key for route segment
|
|
297
|
+
*/
|
|
298
|
+
function getSegmentKey(segment) {
|
|
299
|
+
return `${segment.node.id}-${JSON.stringify(segment.params)}`;
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../../../../src/router/features/outlet/mount.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.outlet.segment-chain",
|
|
4
|
+
"title": "Route Segment Chain Builder",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import type { RouteNode, RouteSegmentChain, RouteParams } from '../../core/types';
|
|
9
|
+
/** @codexApi {"parent":"pithy.router.outlet.segment-chain","name":"buildSegmentChain","stability":"experimental","signature":"(routes: RouteNode[], matchedPath: string, params: RouteParams, previousChain?: RouteSegmentChain[]) => RouteSegmentChain[]"} */
|
|
10
|
+
/**
|
|
11
|
+
* Build route segment chain from route match
|
|
12
|
+
* Supports hierarchical nested routes with layouts
|
|
13
|
+
* Determines which segments have changed for efficient diff mounting
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildSegmentChain(routes: RouteNode[], matchedPath: string, params: RouteParams, previousChain?: RouteSegmentChain[]): RouteSegmentChain[];
|
|
16
|
+
//# sourceMappingURL=segment-chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segment-chain.d.ts","sourceRoot":"","sources":["../../../../src/router/features/outlet/segment-chain.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAU1B,+PAA+P;AAC/P;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,aAAa,CAAC,EAAE,iBAAiB,EAAE,GAClC,iBAAiB,EAAE,CA6DrB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.outlet.segment-chain",
|
|
4
|
+
"title": "Route Segment Chain Builder",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
import { flattenRouteTree, buildRouteMap, getAncestorChain, extractAncestorParams, mergeAncestorParams, findMatchingEntry, } from '../../core/route-tree';
|
|
9
|
+
/** @codexApi {"parent":"pithy.router.outlet.segment-chain","name":"buildSegmentChain","stability":"experimental","signature":"(routes: RouteNode[], matchedPath: string, params: RouteParams, previousChain?: RouteSegmentChain[]) => RouteSegmentChain[]"} */
|
|
10
|
+
/**
|
|
11
|
+
* Build route segment chain from route match
|
|
12
|
+
* Supports hierarchical nested routes with layouts
|
|
13
|
+
* Determines which segments have changed for efficient diff mounting
|
|
14
|
+
*/
|
|
15
|
+
export function buildSegmentChain(routes, matchedPath, params, previousChain) {
|
|
16
|
+
// Flatten the route tree to enable ancestor lookup
|
|
17
|
+
const flatRoutes = flattenRouteTree(routes);
|
|
18
|
+
const routeMap = buildRouteMap(flatRoutes);
|
|
19
|
+
// Find the exact matching route from the flat route list
|
|
20
|
+
const matchingEntry = findMatchingEntry(matchedPath, flatRoutes);
|
|
21
|
+
if (!matchingEntry) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
// Get full ancestor chain (includes layouts)
|
|
25
|
+
const ancestorChain = getAncestorChain(matchingEntry.node.id, routeMap);
|
|
26
|
+
// Extract params for each ancestor level
|
|
27
|
+
const paramsByLevel = extractAncestorParams(matchedPath, ancestorChain);
|
|
28
|
+
// Merge params cumulatively (child params inherit + override parent params)
|
|
29
|
+
const mergedParams = mergeAncestorParams(paramsByLevel);
|
|
30
|
+
// Build segment chain from ancestors
|
|
31
|
+
const segments = [];
|
|
32
|
+
let previousSegment;
|
|
33
|
+
for (let i = 0; i < ancestorChain.length; i++) {
|
|
34
|
+
const routeNode = ancestorChain[i];
|
|
35
|
+
// Skip if routeNode is undefined (should not happen, but TypeScript safety)
|
|
36
|
+
if (!routeNode) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const segmentParams = mergedParams[i] || {};
|
|
40
|
+
// Check if this segment has changed compared to previous navigation
|
|
41
|
+
const prevChainSegment = previousChain?.[i];
|
|
42
|
+
const hasChanged = !prevChainSegment ||
|
|
43
|
+
prevChainSegment.node.id !== routeNode.id ||
|
|
44
|
+
JSON.stringify(prevChainSegment.params) !== JSON.stringify(segmentParams);
|
|
45
|
+
// Create segment chain entry
|
|
46
|
+
const segment = {
|
|
47
|
+
node: routeNode,
|
|
48
|
+
params: segmentParams,
|
|
49
|
+
hasChanged,
|
|
50
|
+
parent: previousSegment,
|
|
51
|
+
children: [],
|
|
52
|
+
};
|
|
53
|
+
// Link parent-child relationship
|
|
54
|
+
if (previousSegment) {
|
|
55
|
+
previousSegment.children.push(segment);
|
|
56
|
+
}
|
|
57
|
+
segments.push(segment);
|
|
58
|
+
previousSegment = segment;
|
|
59
|
+
}
|
|
60
|
+
return segments;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=segment-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segment-chain.js","sourceRoot":"","sources":["../../../../src/router/features/outlet/segment-chain.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAOF,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,+PAA+P;AAC/P;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,WAAmB,EACnB,MAAmB,EACnB,aAAmC;IAEnC,mDAAmD;IACnD,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAE3C,yDAAyD;IACzD,MAAM,aAAa,GAAG,iBAAiB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAEjE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,6CAA6C;IAC7C,MAAM,aAAa,GAAG,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAExE,yCAAyC;IACzC,MAAM,aAAa,GAAG,qBAAqB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAExE,4EAA4E;IAC5E,MAAM,YAAY,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAExD,qCAAqC;IACrC,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,IAAI,eAA8C,CAAC;IAEnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAEnC,4EAA4E;QAC5E,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,MAAM,aAAa,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5C,oEAAoE;QACpE,MAAM,gBAAgB,GAAG,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,UAAU,GACd,CAAC,gBAAgB;YACjB,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE;YACzC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAE5E,6BAA6B;QAC7B,MAAM,OAAO,GAAsB;YACjC,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,aAAa;YACrB,UAAU;YACV,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,iCAAiC;QACjC,IAAI,eAAe,EAAE,CAAC;YACpB,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,eAAe,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** @codex
|
|
2
|
+
{
|
|
3
|
+
"id": "pithy.router.prefetch",
|
|
4
|
+
"title": "Enhanced Prefetch System with Intelligent Heuristics",
|
|
5
|
+
"category": "runtime"
|
|
6
|
+
}
|
|
7
|
+
*/
|
|
8
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PrefetchStrategy","stability":"stable","signature":"type PrefetchStrategy","description":"Strategy options controlling when routes are prefetched"} */
|
|
9
|
+
/**
|
|
10
|
+
* Prefetch strategy options for intelligent resource loading
|
|
11
|
+
* Controls when and how routes are prefetched before user navigation
|
|
12
|
+
*/
|
|
13
|
+
export type PrefetchStrategy = 'none' | 'hover' | 'visible' | 'intent';
|
|
14
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PREFETCH_STRATEGIES","stability":"stable","signature":"readonly PrefetchStrategy[]","description":"Runtime list of valid PrefetchStrategy values for enum validation"} */
|
|
15
|
+
export declare const PREFETCH_STRATEGIES: readonly PrefetchStrategy[];
|
|
16
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PrefetchConfig","stability":"stable","signature":"interface PrefetchConfig","description":"Fine-tune prefetch behavior with delays, thresholds, and caching"} */
|
|
17
|
+
/**
|
|
18
|
+
* Prefetch configuration options
|
|
19
|
+
* Fine-tune prefetch behavior with delays, thresholds, and caching settings
|
|
20
|
+
*/
|
|
21
|
+
export interface PrefetchConfig {
|
|
22
|
+
/** Hover intent delay in milliseconds */
|
|
23
|
+
hoverDelay?: number;
|
|
24
|
+
/** Intersection observer margin for visible strategy */
|
|
25
|
+
visibleMargin?: string;
|
|
26
|
+
/** Cache TTL for prefetched resources */
|
|
27
|
+
cacheTTL?: number;
|
|
28
|
+
/** Pointer velocity threshold for intent detection */
|
|
29
|
+
intentVelocityThreshold?: number;
|
|
30
|
+
/** Pointer direction consistency required for intent */
|
|
31
|
+
intentDirectionSamples?: number;
|
|
32
|
+
}
|
|
33
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"PrefetchManager","stability":"stable","signature":"class PrefetchManager","description":"Intelligent resource prefetching with enhanced heuristics"} */
|
|
34
|
+
/**
|
|
35
|
+
* Prefetch manager for intelligent resource prefetching
|
|
36
|
+
* Implements enhanced prefetch policy & cache layer from architectural improvements
|
|
37
|
+
*/
|
|
38
|
+
export declare class PrefetchManager {
|
|
39
|
+
private config;
|
|
40
|
+
private activeRequests;
|
|
41
|
+
private hoverTimers;
|
|
42
|
+
private intentTracking;
|
|
43
|
+
/** Track when each route was last prefetched with its TTL to avoid repeated prefetches */
|
|
44
|
+
private prefetchedAt;
|
|
45
|
+
constructor(config?: PrefetchConfig);
|
|
46
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"registerLink","stability":"stable","signature":"(element: HTMLElement, strategy: PrefetchStrategy) => void","description":"Register a link element for prefetching with a given strategy"} */
|
|
47
|
+
/**
|
|
48
|
+
* Register a link for prefetching with specified strategy
|
|
49
|
+
*/
|
|
50
|
+
registerLink(element: HTMLElement, strategy: PrefetchStrategy): void;
|
|
51
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"unregisterLink","stability":"stable","signature":"(element: HTMLElement) => void","description":"Unregister a link and clean up its prefetch listeners"} */
|
|
52
|
+
/**
|
|
53
|
+
* Unregister a link from prefetching
|
|
54
|
+
*/
|
|
55
|
+
unregisterLink(element: HTMLElement): void;
|
|
56
|
+
/**
|
|
57
|
+
* Setup hover-based prefetching with intent delay
|
|
58
|
+
*/
|
|
59
|
+
private setupHoverPrefetch;
|
|
60
|
+
/**
|
|
61
|
+
* Setup visibility-based prefetching using shared observer pool from @pithyjs/shared
|
|
62
|
+
*/
|
|
63
|
+
private setupVisiblePrefetch;
|
|
64
|
+
/**
|
|
65
|
+
* Setup intent-based prefetching with pointer tracking
|
|
66
|
+
*/
|
|
67
|
+
private setupIntentPrefetch;
|
|
68
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"prefetchRoute","stability":"stable","signature":"(href: string, strategy: PrefetchStrategy) => Promise<void>","description":"Prefetch a route with priority handling and deduplication"} */
|
|
69
|
+
/**
|
|
70
|
+
* Prefetch a route with priority handling
|
|
71
|
+
*/
|
|
72
|
+
prefetchRoute(href: string, _strategy: PrefetchStrategy): Promise<void>;
|
|
73
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"cancelPrefetch","stability":"stable","signature":"(href: string) => void","description":"Cancel an in-flight prefetch for a specific route"} */
|
|
74
|
+
/**
|
|
75
|
+
* Cancel prefetch for a specific route
|
|
76
|
+
*/
|
|
77
|
+
cancelPrefetch(href: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Prefetch module code (dynamic imports)
|
|
80
|
+
*/
|
|
81
|
+
private prefetchModuleCode;
|
|
82
|
+
/**
|
|
83
|
+
* Prefetch loader data
|
|
84
|
+
*/
|
|
85
|
+
private prefetchLoaderData;
|
|
86
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"dispose","stability":"stable","signature":"() => void","description":"Clean up all prefetch resources, requests, and timers"} */
|
|
87
|
+
/**
|
|
88
|
+
* Cleanup all prefetch resources
|
|
89
|
+
*/
|
|
90
|
+
dispose(): void;
|
|
91
|
+
}
|
|
92
|
+
/** @codexApi {"parent":"pithy.router.prefetch","name":"getPrefetchManager","stability":"stable","signature":"() => PrefetchManager","description":"Get the lazy-initialized global prefetch manager"} */
|
|
93
|
+
/**
|
|
94
|
+
* Get the global prefetch manager
|
|
95
|
+
*/
|
|
96
|
+
export declare function getPrefetchManager(): PrefetchManager;
|
|
97
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/router/features/prefetch/index.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAiBF,8MAA8M;AAC9M;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvE,iOAAiO;AACjO,eAAO,MAAM,mBAAmB,EAAE,SAAS,gBAAgB,EAKjD,CAAC;AAEX,wNAAwN;AACxN;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wDAAwD;IACxD,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,+MAA+M;AAC/M;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,WAAW,CAAyD;IAC5E,OAAO,CAAC,cAAc,CAA0C;IAChE,0FAA0F;IAC1F,OAAO,CAAC,YAAY,CAAyD;gBAEjE,MAAM,GAAE,cAAmB;IAcvC,qPAAqP;IACrP;;OAEG;IACI,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAmB3E,mNAAmN;IACnN;;OAEG;IACI,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAyBjD;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkD3B,mPAAmP;IACnP;;OAEG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,gBAAgB,GAC1B,OAAO,CAAC,IAAI,CAAC;IA0DhB,uMAAuM;IACvM;;OAEG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQzC;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;YACW,kBAAkB;IAmBhC,wLAAwL;IACxL;;OAEG;IACI,OAAO,IAAI,IAAI;CAsBvB;AAyED,yMAAyM;AACzM;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAKpD"}
|