@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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +621 -0
  3. package/dist/index.d.ts +29 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +49 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/router/core/config.d.ts +22 -0
  8. package/dist/router/core/config.d.ts.map +1 -0
  9. package/dist/router/core/config.js +54 -0
  10. package/dist/router/core/config.js.map +1 -0
  11. package/dist/router/core/constants.d.ts +89 -0
  12. package/dist/router/core/constants.d.ts.map +1 -0
  13. package/dist/router/core/constants.js +95 -0
  14. package/dist/router/core/constants.js.map +1 -0
  15. package/dist/router/core/history.d.ts +54 -0
  16. package/dist/router/core/history.d.ts.map +1 -0
  17. package/dist/router/core/history.js +89 -0
  18. package/dist/router/core/history.js.map +1 -0
  19. package/dist/router/core/matcher.d.ts +43 -0
  20. package/dist/router/core/matcher.d.ts.map +1 -0
  21. package/dist/router/core/matcher.js +242 -0
  22. package/dist/router/core/matcher.js.map +1 -0
  23. package/dist/router/core/params.d.ts +88 -0
  24. package/dist/router/core/params.d.ts.map +1 -0
  25. package/dist/router/core/params.js +150 -0
  26. package/dist/router/core/params.js.map +1 -0
  27. package/dist/router/core/pipeline.d.ts +90 -0
  28. package/dist/router/core/pipeline.d.ts.map +1 -0
  29. package/dist/router/core/pipeline.js +323 -0
  30. package/dist/router/core/pipeline.js.map +1 -0
  31. package/dist/router/core/route-tree.d.ts +76 -0
  32. package/dist/router/core/route-tree.d.ts.map +1 -0
  33. package/dist/router/core/route-tree.js +143 -0
  34. package/dist/router/core/route-tree.js.map +1 -0
  35. package/dist/router/core/router.d.ts +229 -0
  36. package/dist/router/core/router.d.ts.map +1 -0
  37. package/dist/router/core/router.js +762 -0
  38. package/dist/router/core/router.js.map +1 -0
  39. package/dist/router/core/types.d.ts +387 -0
  40. package/dist/router/core/types.d.ts.map +1 -0
  41. package/dist/router/core/types.js +22 -0
  42. package/dist/router/core/types.js.map +1 -0
  43. package/dist/router/core/utils.d.ts +66 -0
  44. package/dist/router/core/utils.d.ts.map +1 -0
  45. package/dist/router/core/utils.js +152 -0
  46. package/dist/router/core/utils.js.map +1 -0
  47. package/dist/router/features/coordinator.d.ts +75 -0
  48. package/dist/router/features/coordinator.d.ts.map +1 -0
  49. package/dist/router/features/coordinator.js +203 -0
  50. package/dist/router/features/coordinator.js.map +1 -0
  51. package/dist/router/features/errors/error-codes.d.ts +107 -0
  52. package/dist/router/features/errors/error-codes.d.ts.map +1 -0
  53. package/dist/router/features/errors/error-codes.js +247 -0
  54. package/dist/router/features/errors/error-codes.js.map +1 -0
  55. package/dist/router/features/errors/error-resolution.d.ts +31 -0
  56. package/dist/router/features/errors/error-resolution.d.ts.map +1 -0
  57. package/dist/router/features/errors/error-resolution.js +47 -0
  58. package/dist/router/features/errors/error-resolution.js.map +1 -0
  59. package/dist/router/features/errors/error-types.d.ts +60 -0
  60. package/dist/router/features/errors/error-types.d.ts.map +1 -0
  61. package/dist/router/features/errors/error-types.js +57 -0
  62. package/dist/router/features/errors/error-types.js.map +1 -0
  63. package/dist/router/features/errors/global-error-fallback.d.ts +33 -0
  64. package/dist/router/features/errors/global-error-fallback.d.ts.map +1 -0
  65. package/dist/router/features/errors/global-error-fallback.js +182 -0
  66. package/dist/router/features/errors/global-error-fallback.js.map +1 -0
  67. package/dist/router/features/errors/index.d.ts +15 -0
  68. package/dist/router/features/errors/index.d.ts.map +1 -0
  69. package/dist/router/features/errors/index.js +18 -0
  70. package/dist/router/features/errors/index.js.map +1 -0
  71. package/dist/router/features/errors/router-errors.d.ts +44 -0
  72. package/dist/router/features/errors/router-errors.d.ts.map +1 -0
  73. package/dist/router/features/errors/router-errors.js +53 -0
  74. package/dist/router/features/errors/router-errors.js.map +1 -0
  75. package/dist/router/features/guards/engine.d.ts +40 -0
  76. package/dist/router/features/guards/engine.d.ts.map +1 -0
  77. package/dist/router/features/guards/engine.js +67 -0
  78. package/dist/router/features/guards/engine.js.map +1 -0
  79. package/dist/router/features/guards/index.d.ts +52 -0
  80. package/dist/router/features/guards/index.d.ts.map +1 -0
  81. package/dist/router/features/guards/index.js +95 -0
  82. package/dist/router/features/guards/index.js.map +1 -0
  83. package/dist/router/features/loaders/cache.d.ts +60 -0
  84. package/dist/router/features/loaders/cache.d.ts.map +1 -0
  85. package/dist/router/features/loaders/cache.js +80 -0
  86. package/dist/router/features/loaders/cache.js.map +1 -0
  87. package/dist/router/features/loaders/engine.d.ts +17 -0
  88. package/dist/router/features/loaders/engine.d.ts.map +1 -0
  89. package/dist/router/features/loaders/engine.js +27 -0
  90. package/dist/router/features/loaders/engine.js.map +1 -0
  91. package/dist/router/features/loaders/index.d.ts +49 -0
  92. package/dist/router/features/loaders/index.d.ts.map +1 -0
  93. package/dist/router/features/loaders/index.js +112 -0
  94. package/dist/router/features/loaders/index.js.map +1 -0
  95. package/dist/router/features/loading-ui-manager.d.ts +69 -0
  96. package/dist/router/features/loading-ui-manager.d.ts.map +1 -0
  97. package/dist/router/features/loading-ui-manager.js +209 -0
  98. package/dist/router/features/loading-ui-manager.js.map +1 -0
  99. package/dist/router/features/module-loader.d.ts +50 -0
  100. package/dist/router/features/module-loader.d.ts.map +1 -0
  101. package/dist/router/features/module-loader.js +121 -0
  102. package/dist/router/features/module-loader.js.map +1 -0
  103. package/dist/router/features/outlet/errors.d.ts +24 -0
  104. package/dist/router/features/outlet/errors.d.ts.map +1 -0
  105. package/dist/router/features/outlet/errors.js +96 -0
  106. package/dist/router/features/outlet/errors.js.map +1 -0
  107. package/dist/router/features/outlet/index.d.ts +45 -0
  108. package/dist/router/features/outlet/index.d.ts.map +1 -0
  109. package/dist/router/features/outlet/index.js +95 -0
  110. package/dist/router/features/outlet/index.js.map +1 -0
  111. package/dist/router/features/outlet/mount.d.ts +38 -0
  112. package/dist/router/features/outlet/mount.d.ts.map +1 -0
  113. package/dist/router/features/outlet/mount.js +301 -0
  114. package/dist/router/features/outlet/mount.js.map +1 -0
  115. package/dist/router/features/outlet/segment-chain.d.ts +16 -0
  116. package/dist/router/features/outlet/segment-chain.d.ts.map +1 -0
  117. package/dist/router/features/outlet/segment-chain.js +62 -0
  118. package/dist/router/features/outlet/segment-chain.js.map +1 -0
  119. package/dist/router/features/prefetch/index.d.ts +97 -0
  120. package/dist/router/features/prefetch/index.d.ts.map +1 -0
  121. package/dist/router/features/prefetch/index.js +345 -0
  122. package/dist/router/features/prefetch/index.js.map +1 -0
  123. package/dist/router/features/ux/focus.d.ts +62 -0
  124. package/dist/router/features/ux/focus.d.ts.map +1 -0
  125. package/dist/router/features/ux/focus.js +136 -0
  126. package/dist/router/features/ux/focus.js.map +1 -0
  127. package/dist/router/features/ux/live-region.d.ts +81 -0
  128. package/dist/router/features/ux/live-region.d.ts.map +1 -0
  129. package/dist/router/features/ux/live-region.js +166 -0
  130. package/dist/router/features/ux/live-region.js.map +1 -0
  131. package/dist/router/features/ux/scroll-focus.d.ts +105 -0
  132. package/dist/router/features/ux/scroll-focus.d.ts.map +1 -0
  133. package/dist/router/features/ux/scroll-focus.js +111 -0
  134. package/dist/router/features/ux/scroll-focus.js.map +1 -0
  135. package/dist/router/features/ux/scroll.d.ts +71 -0
  136. package/dist/router/features/ux/scroll.d.ts.map +1 -0
  137. package/dist/router/features/ux/scroll.js +137 -0
  138. package/dist/router/features/ux/scroll.js.map +1 -0
  139. package/dist/router/features/ux/transitions.d.ts +120 -0
  140. package/dist/router/features/ux/transitions.d.ts.map +1 -0
  141. package/dist/router/features/ux/transitions.js +235 -0
  142. package/dist/router/features/ux/transitions.js.map +1 -0
  143. package/dist/router/integration/directive-binder.d.ts +20 -0
  144. package/dist/router/integration/directive-binder.d.ts.map +1 -0
  145. package/dist/router/integration/directive-binder.js +139 -0
  146. package/dist/router/integration/directive-binder.js.map +1 -0
  147. package/dist/router/integration/directives.d.ts +42 -0
  148. package/dist/router/integration/directives.d.ts.map +1 -0
  149. package/dist/router/integration/directives.js +109 -0
  150. package/dist/router/integration/directives.js.map +1 -0
  151. package/dist/router/integration/history-adapter.d.ts +76 -0
  152. package/dist/router/integration/history-adapter.d.ts.map +1 -0
  153. package/dist/router/integration/history-adapter.js +157 -0
  154. package/dist/router/integration/history-adapter.js.map +1 -0
  155. package/dist/router/integration/hmr.d.ts +83 -0
  156. package/dist/router/integration/hmr.d.ts.map +1 -0
  157. package/dist/router/integration/hmr.js +160 -0
  158. package/dist/router/integration/hmr.js.map +1 -0
  159. package/dist/router/integration/link-interceptor.d.ts +49 -0
  160. package/dist/router/integration/link-interceptor.d.ts.map +1 -0
  161. package/dist/router/integration/link-interceptor.js +94 -0
  162. package/dist/router/integration/link-interceptor.js.map +1 -0
  163. package/package.json +47 -0
@@ -0,0 +1,209 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.features.loading-ui",
4
+ "title": "Loading UI Manager - Atomic Swap and Overlay Loading States",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ import { extractElement } from '../core/utils';
9
+ import { LOADING_UI } from '../core/constants';
10
+ import { loadRouteModule, getRouteModuleKey } from './module-loader';
11
+ /**
12
+ * Loading UI Manager
13
+ * Handles atomic swap, overlay, and progress-only loading policies
14
+ *
15
+ * Supports two loading strategies:
16
+ * 1. Atomic Swap - Replace entire outlet content with loading UI
17
+ * 2. Overlay - Show loading UI on top of existing content
18
+ *
19
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"LoadingUIManager","stability":"stable","signature":"class LoadingUIManager"}
20
+ */
21
+ export class LoadingUIManager {
22
+ constructor() {
23
+ this.outletSnapshot = null;
24
+ this.mountedElement = null;
25
+ }
26
+ /**
27
+ * Set the mounted element (outlet)
28
+ */
29
+ setMountedElement(element) {
30
+ this.mountedElement = element;
31
+ }
32
+ /**
33
+ * Show atomic loading UI (replace outlet content)
34
+ * Creates a container with router-loading-atomic class that replaces all outlet content
35
+ *
36
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"showAtomic","stability":"stable","signature":"async showAtomic(pattern: string, navId: NavigationId, outlet: HTMLElement, routes: RouteNode[]): Promise<void>"}
37
+ */
38
+ async showAtomic(pattern, navId, outlet, routes) {
39
+ // Resolve route-specific loading content or fall back to default
40
+ const contentEl = await this.buildForRoute(pattern, routes);
41
+ // Wrap the content in a removable atomic container (ALWAYS)
42
+ const container = document.createElement('div');
43
+ container.className = 'router-loading-atomic';
44
+ container.setAttribute('data-nav-id', navId.toString());
45
+ container.appendChild(contentEl);
46
+ // Atomic replace: no intermediate empty state
47
+ // Don't use View Transition for loading UI to prevent spinner from getting stuck
48
+ const frag = document.createDocumentFragment();
49
+ frag.appendChild(container);
50
+ outlet.replaceChildren(frag);
51
+ }
52
+ /**
53
+ * Show custom overlay loading UI with route-specific content
54
+ *
55
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"showCustomOverlay","stability":"stable","signature":"async showCustomOverlay(pattern: string, navId: NavigationId, outlet: HTMLElement, routes: RouteNode[]): Promise<void>"}
56
+ */
57
+ async showCustomOverlay(pattern, navId, outlet, routes) {
58
+ // Resolve route-specific loading content or default
59
+ const content = await this.buildForRoute(pattern, routes);
60
+ this.mountOverlay(outlet, navId, content, true);
61
+ }
62
+ /**
63
+ * Internal helper to mount an overlay with content
64
+ * Consolidates overlay creation logic
65
+ */
66
+ mountOverlay(outlet, navId, content, isCustom) {
67
+ // Make outlet a positioning context
68
+ if (!outlet.style.position || outlet.style.position === 'static') {
69
+ outlet.style.position = 'relative';
70
+ }
71
+ // Remove any previous overlay for safety
72
+ this.removeOverlay(outlet);
73
+ const overlay = document.createElement('div');
74
+ overlay.className = isCustom
75
+ ? 'router-loading-overlay router-loading-overlay--custom'
76
+ : 'router-loading-overlay';
77
+ overlay.setAttribute('data-nav-id', String(navId));
78
+ // Base styles for all overlays
79
+ Object.assign(overlay.style, {
80
+ position: 'absolute',
81
+ inset: '0',
82
+ display: 'flex',
83
+ justifyContent: 'center',
84
+ alignItems: 'center',
85
+ zIndex: String(LOADING_UI.OVERLAY_Z_INDEX),
86
+ pointerEvents: 'none',
87
+ });
88
+ // Add background for default overlay only
89
+ if (!isCustom) {
90
+ Object.assign(overlay.style, {
91
+ backgroundColor: 'rgba(255, 255, 255, 0.9)',
92
+ backdropFilter: 'blur(2px)',
93
+ });
94
+ }
95
+ overlay.appendChild(content);
96
+ outlet.appendChild(overlay);
97
+ }
98
+ /**
99
+ * Remove loading overlay from outlet
100
+ *
101
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"removeOverlay","stability":"stable","signature":"removeOverlay(outlet: HTMLElement): void"}
102
+ */
103
+ removeOverlay(outlet) {
104
+ const overlays = outlet.querySelectorAll('.router-loading-overlay');
105
+ overlays.forEach(overlay => {
106
+ overlay.remove();
107
+ });
108
+ }
109
+ /**
110
+ * Clear all loading UI from outlet (handles both overlays and atomic swap loading)
111
+ *
112
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"clearAll","stability":"stable","signature":"clearAll(): void"}
113
+ */
114
+ clearAll() {
115
+ if (!this.mountedElement)
116
+ return;
117
+ // Remove overlay-style loading UI
118
+ this.removeOverlay(this.mountedElement);
119
+ // Remove atomic swap loading UI (elements with router-loading-atomic class)
120
+ const atomicLoadingElements = this.mountedElement.querySelectorAll('.router-loading-atomic');
121
+ atomicLoadingElements.forEach(element => {
122
+ element.remove();
123
+ });
124
+ // If outlet is now empty after clearing loading UI, restore snapshot
125
+ if (this.mountedElement.children.length === 0 && this.outletSnapshot) {
126
+ this.mountedElement.appendChild(this.outletSnapshot.cloneNode(true));
127
+ }
128
+ }
129
+ /**
130
+ * Build default loading content (spinner + "Loading..." text)
131
+ *
132
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"buildDefault","stability":"stable","signature":"buildDefault(): HTMLElement"}
133
+ */
134
+ buildDefault() {
135
+ const wrap = document.createElement('div');
136
+ wrap.className = 'router-loading-content';
137
+ wrap.innerHTML = `
138
+ <div class="spinner"></div>
139
+ <p>Loading…</p>
140
+ <style>
141
+ .router-loading-content {
142
+ text-align: center;
143
+ background: white;
144
+ padding: 2rem;
145
+ border-radius: 8px;
146
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
147
+ }
148
+ .spinner {
149
+ width: ${LOADING_UI.SPINNER_SIZE}px;
150
+ height: ${LOADING_UI.SPINNER_SIZE}px;
151
+ border: ${LOADING_UI.SPINNER_BORDER}px solid #eee;
152
+ border-top-color: #3498db;
153
+ border-radius: 50%;
154
+ animation: spin 1s linear infinite;
155
+ margin: 0 auto 0.5rem;
156
+ }
157
+ @keyframes spin {
158
+ to { transform: rotate(${LOADING_UI.SPINNER_ROTATION}deg) }
159
+ }
160
+ </style>
161
+ `;
162
+ return wrap;
163
+ }
164
+ /**
165
+ * Build loading content for a specific route (supports many export shapes)
166
+ *
167
+ * @codexApi {"parent":"pithy.router.features.loading-ui","name":"buildForRoute","stability":"stable","signature":"async buildForRoute(pattern: string, routes: RouteNode[]): Promise<HTMLElement>"}
168
+ */
169
+ async buildForRoute(pattern, routes) {
170
+ const route = routes.find(r => r.pattern === pattern);
171
+ if (!route || !route.imports.loading) {
172
+ return this.buildDefault();
173
+ }
174
+ try {
175
+ // Load through shared module cache
176
+ const mod = await loadRouteModule(getRouteModuleKey(pattern, 'loading'), route.imports.loading);
177
+ // candidates to inspect
178
+ const modRecord = mod;
179
+ const candidates = [
180
+ modRecord?.default,
181
+ modRecord?.loading,
182
+ modRecord?.Loading,
183
+ mod,
184
+ ];
185
+ for (const c of candidates) {
186
+ if (!c)
187
+ continue;
188
+ // If it's a function, call it (sync or async)
189
+ if (typeof c === 'function') {
190
+ const out = await Promise.resolve(c());
191
+ const el = extractElement(out);
192
+ if (el)
193
+ return el;
194
+ }
195
+ // If it's already an element-like or HTML string/object
196
+ const el = extractElement(c);
197
+ if (el)
198
+ return el;
199
+ }
200
+ // Fallback
201
+ return this.buildDefault();
202
+ }
203
+ catch (e) {
204
+ console.warn('[Router] Failed to load loading component:', e);
205
+ return this.buildDefault();
206
+ }
207
+ }
208
+ }
209
+ //# sourceMappingURL=loading-ui-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading-ui-manager.js","sourceRoot":"","sources":["../../../src/router/features/loading-ui-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.module-loader",
4
+ "title": "Route Module Loader with Shared Cache Integration",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ /**
9
+ * Module Loader Utility
10
+ *
11
+ * Provides integration with @pithyjs/core's shared module cache for route imports.
12
+ * Falls back to direct imports if core is not available.
13
+ *
14
+ * @module router/features/module-loader
15
+ */
16
+ import { type RouteModuleType } from '../core/constants';
17
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"loadRouteModule","stability":"stable","signature":"<T>(key: string, loader: () => Promise<T>) => Promise<T>"} */
18
+ /**
19
+ * Load a route module through the shared cache
20
+ *
21
+ * @param key - Cache key for deduplication (e.g., "route:/users:page")
22
+ * @param loader - Dynamic import function
23
+ * @returns The loaded module
24
+ */
25
+ export declare function loadRouteModule<T>(key: string, loader: () => Promise<T>): Promise<T>;
26
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"getRouteModuleKey","stability":"stable","signature":"(pattern: string, type: RouteModuleType) => string"} */
27
+ /**
28
+ * Generate a cache key for a route module
29
+ *
30
+ * @param pattern - Route pattern (e.g., "/users/:id")
31
+ * @param type - Module type ("page", "layout", "loading", "error", "loader")
32
+ * @returns Cache key (e.g., "route:/users/:id:page")
33
+ */
34
+ export declare function getRouteModuleKey(pattern: string, type: RouteModuleType): string;
35
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"invalidateAllRouteModules","stability":"stable","signature":"(routes: Array<{ pattern: string }>) => Promise<void>"} */
36
+ /**
37
+ * Invalidate all route modules for a list of routes (for HMR full refresh)
38
+ *
39
+ * @param routes - Array of route nodes to invalidate
40
+ */
41
+ export declare function invalidateAllRouteModules(routes: Array<{
42
+ pattern: string;
43
+ }>): Promise<void>;
44
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"clearAllModuleCache","stability":"stable","signature":"() => Promise<void>"} */
45
+ /**
46
+ * Clear all route modules from the shared cache (for testing)
47
+ * This clears both the loader cache and the @pithyjs/core module cache
48
+ */
49
+ export declare function clearAllModuleCache(): Promise<void>;
50
+ //# sourceMappingURL=module-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-loader.d.ts","sourceRoot":"","sources":["../../../src/router/features/module-loader.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAoC7E,6KAA6K;AAC7K;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAGZ;AAED,yKAAyK;AACzK;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,GACpB,MAAM,CAER;AA2BD,oLAAoL;AACpL;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,4IAA4I;AAC5I;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAazD"}
@@ -0,0 +1,121 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.module-loader",
4
+ "title": "Route Module Loader with Shared Cache Integration",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ /**
9
+ * Module Loader Utility
10
+ *
11
+ * Provides integration with @pithyjs/core's shared module cache for route imports.
12
+ * Falls back to direct imports if core is not available.
13
+ *
14
+ * @module router/features/module-loader
15
+ */
16
+ import { ROUTE_MODULE_TYPES } from '../core/constants';
17
+ /**
18
+ * Cached reference to the module loader function
19
+ */
20
+ let cachedLoader = null;
21
+ /**
22
+ * Get the module loader function from @pithyjs/core
23
+ * Caches the result for performance
24
+ */
25
+ async function getModuleLoader() {
26
+ if (cachedLoader) {
27
+ return cachedLoader;
28
+ }
29
+ try {
30
+ const core = await import('@pithyjs/core');
31
+ if (core.loadModule) {
32
+ const loader = core.loadModule;
33
+ cachedLoader = loader;
34
+ return loader;
35
+ }
36
+ }
37
+ catch {
38
+ // Core not available
39
+ }
40
+ // Fallback: direct import without caching
41
+ cachedLoader = (_key, loader) => loader();
42
+ return cachedLoader;
43
+ }
44
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"loadRouteModule","stability":"stable","signature":"<T>(key: string, loader: () => Promise<T>) => Promise<T>"} */
45
+ /**
46
+ * Load a route module through the shared cache
47
+ *
48
+ * @param key - Cache key for deduplication (e.g., "route:/users:page")
49
+ * @param loader - Dynamic import function
50
+ * @returns The loaded module
51
+ */
52
+ export async function loadRouteModule(key, loader) {
53
+ const moduleLoader = await getModuleLoader();
54
+ return moduleLoader(key, loader);
55
+ }
56
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"getRouteModuleKey","stability":"stable","signature":"(pattern: string, type: RouteModuleType) => string"} */
57
+ /**
58
+ * Generate a cache key for a route module
59
+ *
60
+ * @param pattern - Route pattern (e.g., "/users/:id")
61
+ * @param type - Module type ("page", "layout", "loading", "error", "loader")
62
+ * @returns Cache key (e.g., "route:/users/:id:page")
63
+ */
64
+ export function getRouteModuleKey(pattern, type) {
65
+ return `route:${pattern}:${type}`;
66
+ }
67
+ /**
68
+ * Invalidate a route module in the cache (for HMR)
69
+ */
70
+ async function invalidateRouteModule(key) {
71
+ try {
72
+ const core = await import('@pithyjs/core');
73
+ if (core.invalidateModule) {
74
+ return core.invalidateModule(key);
75
+ }
76
+ }
77
+ catch {
78
+ // Core not available
79
+ }
80
+ return false;
81
+ }
82
+ /**
83
+ * Invalidate all cached modules for a route pattern (for HMR)
84
+ * Clears page, layout, loading, error, and loader cache entries
85
+ */
86
+ async function invalidateRouteModules(pattern) {
87
+ for (const type of ROUTE_MODULE_TYPES) {
88
+ await invalidateRouteModule(getRouteModuleKey(pattern, type));
89
+ }
90
+ }
91
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"invalidateAllRouteModules","stability":"stable","signature":"(routes: Array<{ pattern: string }>) => Promise<void>"} */
92
+ /**
93
+ * Invalidate all route modules for a list of routes (for HMR full refresh)
94
+ *
95
+ * @param routes - Array of route nodes to invalidate
96
+ */
97
+ export async function invalidateAllRouteModules(routes) {
98
+ for (const route of routes) {
99
+ await invalidateRouteModules(route.pattern);
100
+ }
101
+ }
102
+ /** @codexApi {"parent":"pithy.router.module-loader","name":"clearAllModuleCache","stability":"stable","signature":"() => Promise<void>"} */
103
+ /**
104
+ * Clear all route modules from the shared cache (for testing)
105
+ * This clears both the loader cache and the @pithyjs/core module cache
106
+ */
107
+ export async function clearAllModuleCache() {
108
+ // Reset the local loader cache
109
+ cachedLoader = null;
110
+ // Clear the @pithyjs/core module cache if available
111
+ try {
112
+ const core = await import('@pithyjs/core');
113
+ if (core.clearModuleCache) {
114
+ core.clearModuleCache();
115
+ }
116
+ }
117
+ catch {
118
+ // Core not available
119
+ }
120
+ }
121
+ //# sourceMappingURL=module-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-loader.js","sourceRoot":"","sources":["../../../src/router/features/module-loader.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAwB,MAAM,mBAAmB,CAAC;AAE7E;;GAEG;AACH,IAAI,YAAY,GAEL,IAAI,CAAC;AAEhB;;;GAGG;AACH,KAAK,UAAU,eAAe;IAG5B,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;YAC/B,YAAY,GAAG,MAAM,CAAC;YACtB,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,0CAA0C;IAC1C,YAAY,GAAG,CAAC,IAAY,EAAE,MAA8B,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;IAC1E,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,6KAA6K;AAC7K;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,MAAwB;IAExB,MAAM,YAAY,GAAG,MAAM,eAAe,EAAE,CAAC;IAC7C,OAAO,YAAY,CAAC,GAAG,EAAE,MAAM,CAAe,CAAC;AACjD,CAAC;AAED,yKAAyK;AACzK;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAqB;IAErB,OAAO,SAAS,OAAO,IAAI,IAAI,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,qBAAqB,CAAC,GAAW;IAC9C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,OAAe;IACnD,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,MAAM,qBAAqB,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,oLAAoL;AACpL;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAkC;IAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,4IAA4I;AAC5I;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,+BAA+B;IAC/B,YAAY,GAAG,IAAI,CAAC;IAEpB,oDAAoD;IACpD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.outlet.errors",
4
+ "title": "Outlet Error Boundary System",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ import type { RouteSegmentChain, NavigationId } from '../../core/types';
9
+ import { type RouterError } from '../errors';
10
+ /** @codexApi {"parent":"pithy.router.outlet.errors","name":"buildErrorUI","stability":"experimental","signature":"(segment: RouteSegmentChain, navId: NavigationId, error: any, retryHandler: () => void) => Promise<HTMLElement>"} */
11
+ /**
12
+ * Build error UI for a route segment
13
+ * Returns an HTMLElement with error component or global fallback
14
+ *
15
+ * Tries to resolve error component from route hierarchy, falls back to global error UI
16
+ */
17
+ export declare function buildErrorUI(segment: RouteSegmentChain, navId: NavigationId, error: Error & Partial<RouterError>, retryHandler: () => void): Promise<HTMLElement>;
18
+ /** @codexApi {"parent":"pithy.router.outlet.errors","name":"createRetryHandler","stability":"experimental","signature":"() => () => void"} */
19
+ /**
20
+ * Create a retry handler for route navigation
21
+ * Simple URL-level refresh for v0
22
+ */
23
+ export declare function createRetryHandler(): () => void;
24
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/router/features/outlet/errors.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EAEb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEpE,uOAAuO;AACvO;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,EACnC,YAAY,EAAE,MAAM,IAAI,GACvB,OAAO,CAAC,WAAW,CAAC,CAiEtB;AAaD,8IAA8I;AAC9I;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,IAAI,CAM/C"}
@@ -0,0 +1,96 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.outlet.errors",
4
+ "title": "Outlet Error Boundary System",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ import { resolveErrorImport } from '../errors/error-resolution';
9
+ import { GlobalErrorFallback } from '../errors/global-error-fallback';
10
+ import { ErrorRecoveryStrategy } from '../errors';
11
+ /** @codexApi {"parent":"pithy.router.outlet.errors","name":"buildErrorUI","stability":"experimental","signature":"(segment: RouteSegmentChain, navId: NavigationId, error: any, retryHandler: () => void) => Promise<HTMLElement>"} */
12
+ /**
13
+ * Build error UI for a route segment
14
+ * Returns an HTMLElement with error component or global fallback
15
+ *
16
+ * Tries to resolve error component from route hierarchy, falls back to global error UI
17
+ */
18
+ export async function buildErrorUI(segment, navId, error, retryHandler) {
19
+ const { node } = segment;
20
+ // Check recovery strategy - silent fail errors don't show UI
21
+ const strategy = error?.getRecoveryStrategy?.();
22
+ if (strategy === ErrorRecoveryStrategy.SILENT_FAIL) {
23
+ console.log('[Router] Silent fail - error will not display UI:', error);
24
+ // Return empty hidden placeholder
25
+ const placeholder = document.createElement('div');
26
+ placeholder.style.display = 'none';
27
+ placeholder.setAttribute('data-silent-error', 'true');
28
+ return placeholder;
29
+ }
30
+ // Build a node-to-segment map for parent lookups
31
+ // This allows us to traverse the parent chain to find error boundaries
32
+ const nodeToSegment = new Map();
33
+ let currentSegment = segment;
34
+ while (currentSegment) {
35
+ nodeToSegment.set(currentSegment.node, currentSegment);
36
+ currentSegment = currentSegment.parent;
37
+ }
38
+ // Try to resolve error component from route hierarchy
39
+ // Walk up the parent chain until we find an error component
40
+ const errorImport = resolveErrorImport(node, n => {
41
+ const seg = nodeToSegment.get(n);
42
+ return seg?.parent?.node;
43
+ });
44
+ // If route has error component, use it
45
+ if (errorImport) {
46
+ try {
47
+ const errorModule = (await errorImport());
48
+ const candidate = errorModule.default ?? errorModule;
49
+ if (typeof candidate === 'function') {
50
+ const errorFactory = candidate;
51
+ const errorInstance = errorFactory({
52
+ error,
53
+ retry: retryHandler,
54
+ });
55
+ if (errorInstance && errorInstance.el) {
56
+ return toElement(errorInstance.el);
57
+ }
58
+ }
59
+ else {
60
+ console.warn('[Router] Route error component default export is not a function; falling back to global error UI.');
61
+ }
62
+ }
63
+ catch (errorLoadError) {
64
+ console.warn('[Router] Failed to load error component:', errorLoadError);
65
+ // Fall through to global fallback
66
+ }
67
+ }
68
+ // Use global fallback
69
+ const fallbackInstance = GlobalErrorFallback({
70
+ error,
71
+ retry: retryHandler,
72
+ });
73
+ return toElement(fallbackInstance.el);
74
+ }
75
+ // Wrap fragments in a div — appendChild moves the nodes (preserving listeners)
76
+ // so callers that hold the returned element keep a live, non-empty handle.
77
+ function toElement(node) {
78
+ if (node instanceof DocumentFragment) {
79
+ const wrapper = document.createElement('div');
80
+ wrapper.appendChild(node);
81
+ return wrapper;
82
+ }
83
+ return node;
84
+ }
85
+ /** @codexApi {"parent":"pithy.router.outlet.errors","name":"createRetryHandler","stability":"experimental","signature":"() => () => void"} */
86
+ /**
87
+ * Create a retry handler for route navigation
88
+ * Simple URL-level refresh for v0
89
+ */
90
+ export function createRetryHandler() {
91
+ return () => {
92
+ const currentUrl = window.location.pathname + window.location.search + window.location.hash;
93
+ window.location.href = currentUrl;
94
+ };
95
+ }
96
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../src/router/features/outlet/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.router.outlet",
4
+ "title": "Router Outlet Mounting System",
5
+ "category": "runtime"
6
+ }
7
+ */
8
+ import type { RouteSegmentChain, NavigationId } from '../../core/types';
9
+ import { type RouterInstance } from './mount';
10
+ /** @codexApi {"parent":"pithy.router.outlet","name":"OutletManager","stability":"experimental","signature":"class OutletManager"} */
11
+ /**
12
+ * Enhanced outlet mounting system
13
+ * Implements segment diff mounting with robust outlet resolution
14
+ * Fixed memory leak with proper two-phase mounting and cleanup
15
+ */
16
+ export declare class OutletManager {
17
+ private mountedComponents;
18
+ private loadingStates;
19
+ private outletElements;
20
+ private router;
21
+ private disposers;
22
+ /** @codexApi {"parent":"pithy.router.outlet","name":"mountSegments","stability":"experimental","signature":"(segmentChain: RouteSegmentChain[], navId: NavigationId, rootElement: HTMLElement) => Promise<boolean>"} */
23
+ /**
24
+ * Mount route segments with two-phase mounting and rollback
25
+ * Phase 1: Build everything off-DOM, Phase 2: Atomic commit
26
+ * Only remounts changed segments, preserves parent layouts
27
+ */
28
+ mountSegments(segmentChain: RouteSegmentChain[], navId: NavigationId, rootElement: HTMLElement): Promise<boolean>;
29
+ /** @codexApi {"parent":"pithy.router.outlet","name":"setRouter","stability":"experimental","signature":"(router: RouterInstance) => void"} */
30
+ /**
31
+ * Set router instance for navigation checking
32
+ */
33
+ setRouter(router: RouterInstance): void;
34
+ /** @codexApi {"parent":"pithy.router.outlet","name":"dispose","stability":"experimental","signature":"() => void"} */
35
+ /**
36
+ * Clean up all mounted components and state
37
+ */
38
+ dispose(): void;
39
+ /**
40
+ * Generate unique key for outlet element
41
+ */
42
+ private getOutletKey;
43
+ }
44
+ export type { RouterInstance };
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/router/features/outlet/index.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EACV,iBAAiB,EAGjB,YAAY,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAEjB,qIAAqI;AACrI;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,iBAAiB,CAA6C;IACtE,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,SAAS,CAAwC;IAEzD,wNAAwN;IACxN;;;;OAIG;IACG,aAAa,CACjB,YAAY,EAAE,iBAAiB,EAAE,EACjC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,OAAO,CAAC;IAoDnB,8IAA8I;IAC9I;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIvC,sHAAsH;IACtH;;OAEG;IACH,OAAO,IAAI,IAAI;IAmBf;;OAEG;IACH,OAAO,CAAC,YAAY;CAGrB;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}