specnav-next 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # @specnav/next
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial public release with trajectory prediction, 3-layer caching, DOM morphing, and all 19 audit bugs fixed.
8
+
9
+ Features:
10
+ - Trajectory-based prefetch with cursor prediction
11
+ - 3-layer cache (Memory/ServiceWorker/Edge)
12
+ - Surgical DOM morphing with scroll/focus preservation
13
+ - Speculative rendering in detached containers
14
+ - Navigation graph learning for pattern-based prefetch
15
+ - Adaptive mode with battery/network awareness
16
+ - Next.js Link component (drop-in replacement)
17
+ - Edge middleware with rate limiting and CSRF protection
18
+
19
+ Bug fixes:
20
+ - Fixed trajectory prediction actually triggering prefetch
21
+ - Fixed navigation graph self-to-self transitions
22
+ - Fixed cache blocking Next.js **NEXT_DATA** scripts
23
+ - Fixed onNavigateEnd callback implementation
24
+ - Fixed middleware same-origin bypass
25
+ - Fixed null engines on first render
26
+ - Fixed LRU cache duplicate entries
27
+ - Fixed cache exclusion substring matching
28
+ - Fixed async adaptive initialization race
29
+ - Fixed duplicate Link unregistration
30
+ - Fixed morph refocus without containment check
31
+ - Fixed navigation timing polling
32
+ - Fixed cache hit rate tracking
33
+ - And 6 more fixes (see BUG_FIXES.md)
34
+
35
+ ### Patch Changes
36
+
37
+ - Updated dependencies
38
+ - @specnav/core@0.2.0
package/dist/index.cjs ADDED
@@ -0,0 +1,552 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var specnavCore = require('specnav-core');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/prefetch.ts
18
+ var prefetch_exports = {};
19
+ __export(prefetch_exports, {
20
+ inflightRequests: () => inflightRequests,
21
+ prefetchPage: () => prefetchPage
22
+ });
23
+ async function prefetchPage(href, cache, speculator) {
24
+ if (inflightRequests.has(href)) {
25
+ await inflightRequests.get(href);
26
+ return;
27
+ }
28
+ const controller = new AbortController();
29
+ const fetchPromise = fetch(href, {
30
+ headers: { "x-specnav": "1" },
31
+ signal: controller.signal
32
+ }).then((res) => {
33
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
34
+ return res.text();
35
+ }).then((html) => {
36
+ if (cache) cache.set(href, html);
37
+ if (speculator) speculator.speculate(href, html);
38
+ return html;
39
+ }).finally(() => {
40
+ inflightRequests.delete(href);
41
+ });
42
+ inflightRequests.set(href, fetchPromise);
43
+ await fetchPromise;
44
+ }
45
+ var inflightRequests;
46
+ var init_prefetch = __esm({
47
+ "src/prefetch.ts"() {
48
+ inflightRequests = /* @__PURE__ */ new Map();
49
+ }
50
+ });
51
+ var NavigationContext = react.createContext(null);
52
+ function useNavigationContext() {
53
+ const ctx = react.useContext(NavigationContext);
54
+ if (!ctx) throw new Error("useNavigationContext must be used within NavigateProvider");
55
+ return ctx;
56
+ }
57
+ function NavigateProvider({
58
+ children,
59
+ strategy = "auto",
60
+ cache: cacheConfig,
61
+ prefetch: prefetchConfig,
62
+ progress: progressConfig,
63
+ morph: morphConfig,
64
+ graph: graphConfig,
65
+ onNavigateStart,
66
+ onNavigateEnd,
67
+ onCacheHit
68
+ }) {
69
+ const [isNavigating, setIsNavigating] = react.useState(false);
70
+ const [pendingHref, setPendingHref] = react.useState(null);
71
+ const [progress, setProgress] = react.useState(0);
72
+ const [cacheHits, setCacheHits] = react.useState(0);
73
+ const [cacheMisses, setCacheMisses] = react.useState(0);
74
+ const navigationStartTime = react.useRef(null);
75
+ const [trajectory, setTrajectory] = react.useState(null);
76
+ const [cache, setCache] = react.useState(null);
77
+ const [morpher, setMorpher] = react.useState(null);
78
+ const [speculator, setSpeculator] = react.useState(null);
79
+ const [graph, setGraph] = react.useState(null);
80
+ const [adaptive, setAdaptive] = react.useState(null);
81
+ const wrappedSetNavigating = (href) => {
82
+ if (href) {
83
+ navigationStartTime.current = Date.now();
84
+ onNavigateStart?.(href);
85
+ } else if (navigationStartTime.current) {
86
+ const duration = Date.now() - navigationStartTime.current;
87
+ if (pendingHref) {
88
+ onNavigateEnd?.(pendingHref, duration);
89
+ }
90
+ navigationStartTime.current = null;
91
+ }
92
+ setIsNavigating(!!href);
93
+ setPendingHref(href);
94
+ };
95
+ react.useEffect(() => {
96
+ const adaptiveEngine = specnavCore.createAdaptiveMode();
97
+ const cacheEngine = specnavCore.createCacheManager(cacheConfig, {
98
+ onCacheHit: (href, layer) => {
99
+ setCacheHits((prev) => prev + 1);
100
+ onCacheHit?.(href, layer);
101
+ }
102
+ });
103
+ const morpherEngine = specnavCore.createMorpher(morphConfig);
104
+ const speculatorEngine = specnavCore.createSpeculativeRenderer(3);
105
+ const graphEngine = specnavCore.createNavigationGraphLearner(graphConfig);
106
+ adaptiveEngine.waitForInit().then(() => {
107
+ setAdaptive(adaptiveEngine);
108
+ setCache(cacheEngine);
109
+ setMorpher(morpherEngine);
110
+ setSpeculator(speculatorEngine);
111
+ setGraph(graphEngine);
112
+ const effectiveStrategy = adaptiveEngine.getStrategy(strategy);
113
+ if (effectiveStrategy !== "off" && prefetchConfig?.mode === "trajectory") {
114
+ const trajectoryEngine = specnavCore.createTrajectoryEngine(prefetchConfig.trajectory, {
115
+ onPrediction: async (href) => {
116
+ if (!adaptiveEngine?.shouldPrefetch()) return;
117
+ const { prefetchPage: prefetchPage2 } = await Promise.resolve().then(() => (init_prefetch(), prefetch_exports));
118
+ await prefetchPage2(href, cacheEngine, speculatorEngine);
119
+ },
120
+ onCancel: (href) => {
121
+ speculatorEngine?.cancel(href);
122
+ }
123
+ });
124
+ trajectoryEngine.start();
125
+ setTrajectory(trajectoryEngine);
126
+ }
127
+ });
128
+ const handlePopState = async (e) => {
129
+ if (!e.state?.specnav) return;
130
+ const href = window.location.pathname;
131
+ wrappedSetNavigating(href);
132
+ setProgress(0.3);
133
+ try {
134
+ const html = await cache?.get(href);
135
+ if (html && morpher) {
136
+ setProgress(0.7);
137
+ const parser = new DOMParser();
138
+ const doc = parser.parseFromString(html, "text/html");
139
+ const newContent = doc.body;
140
+ morpher.morph(document.body, newContent);
141
+ setProgress(1);
142
+ setTimeout(() => wrappedSetNavigating(null), 100);
143
+ } else {
144
+ window.location.reload();
145
+ }
146
+ } catch (error) {
147
+ console.error("Popstate navigation failed:", error);
148
+ window.location.reload();
149
+ }
150
+ };
151
+ window.addEventListener("popstate", handlePopState);
152
+ return () => {
153
+ trajectory?.stop();
154
+ cache?.destroy();
155
+ speculator?.cancelAll();
156
+ window.removeEventListener("popstate", handlePopState);
157
+ };
158
+ }, [strategy, cacheConfig, prefetchConfig, morphConfig, graphConfig, onCacheHit, onNavigateEnd]);
159
+ const value = {
160
+ trajectory,
161
+ cache,
162
+ morpher,
163
+ speculator,
164
+ graph,
165
+ adaptive,
166
+ isNavigating,
167
+ pendingHref,
168
+ progress,
169
+ cacheHits,
170
+ cacheMisses,
171
+ setNavigating: wrappedSetNavigating,
172
+ setProgress,
173
+ incrementCacheMiss: () => setCacheMisses((prev) => prev + 1)
174
+ };
175
+ return /* @__PURE__ */ jsxRuntime.jsxs(NavigationContext.Provider, { value, children: [
176
+ progressConfig?.enabled !== false && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { config: progressConfig, progress, isNavigating }),
177
+ children
178
+ ] });
179
+ }
180
+ function ProgressBar({
181
+ config,
182
+ progress,
183
+ isNavigating
184
+ }) {
185
+ const color = config?.color ?? "#6366f1";
186
+ const height = config?.height ?? 3;
187
+ const position = config?.position ?? "top";
188
+ return /* @__PURE__ */ jsxRuntime.jsx(
189
+ "div",
190
+ {
191
+ style: {
192
+ position: "fixed",
193
+ [position]: 0,
194
+ left: 0,
195
+ right: 0,
196
+ height: `${height}px`,
197
+ zIndex: 9999,
198
+ pointerEvents: "none"
199
+ },
200
+ children: /* @__PURE__ */ jsxRuntime.jsx(
201
+ "div",
202
+ {
203
+ style: {
204
+ height: "100%",
205
+ width: `${progress * 100}%`,
206
+ background: color,
207
+ transition: isNavigating ? "width 200ms ease" : "opacity 200ms ease",
208
+ opacity: isNavigating ? 1 : 0
209
+ }
210
+ }
211
+ )
212
+ }
213
+ );
214
+ }
215
+ init_prefetch();
216
+ function Link({
217
+ href,
218
+ prefetch = "trajectory",
219
+ morph = true,
220
+ cache = true,
221
+ replace = false,
222
+ scroll = true,
223
+ children,
224
+ ...props
225
+ }) {
226
+ const ctx = useNavigationContext();
227
+ const linkRef = react.useRef(null);
228
+ const abortControllerRef = react.useRef(null);
229
+ const isSafeUrl = (url) => {
230
+ try {
231
+ const parsed = new URL(url, window.location.origin);
232
+ return parsed.origin === window.location.origin;
233
+ } catch {
234
+ return false;
235
+ }
236
+ };
237
+ react.useEffect(() => {
238
+ if (!linkRef.current || !ctx.trajectory || prefetch === false) return;
239
+ const element = linkRef.current;
240
+ ctx.trajectory.registerLink(href, element);
241
+ return () => {
242
+ ctx.trajectory?.unregisterLink(element);
243
+ abortControllerRef.current?.abort();
244
+ };
245
+ }, [href, ctx.trajectory, prefetch]);
246
+ const handleMouseEnter = async () => {
247
+ if (prefetch === "hover" && ctx.adaptive?.shouldPrefetch()) {
248
+ await prefetchPage2(href);
249
+ }
250
+ };
251
+ const handleMouseLeave = () => {
252
+ };
253
+ const handleFocus = async () => {
254
+ if (ctx.adaptive?.shouldPrefetch()) {
255
+ await prefetchPage2(href);
256
+ }
257
+ };
258
+ const prefetchPage2 = async (url) => {
259
+ if (!isSafeUrl(url) || !ctx.cache) return;
260
+ const cached = await ctx.cache.get(url);
261
+ if (cached) return;
262
+ if (inflightRequests.has(url)) {
263
+ await inflightRequests.get(url);
264
+ return;
265
+ }
266
+ abortControllerRef.current = new AbortController();
267
+ const fetchPromise = fetch(url, {
268
+ headers: { "x-specnav": "1" },
269
+ signal: abortControllerRef.current.signal
270
+ }).then((res) => res.text()).then((html) => {
271
+ ctx.cache?.set(url, html);
272
+ if (ctx.speculator && ctx.adaptive?.shouldSpeculate()) {
273
+ ctx.speculator.speculate(url, html);
274
+ }
275
+ return html;
276
+ }).catch((err) => {
277
+ if (err.name !== "AbortError") {
278
+ console.warn("Prefetch failed:", err);
279
+ }
280
+ throw err;
281
+ }).finally(() => {
282
+ inflightRequests.delete(url);
283
+ });
284
+ inflightRequests.set(url, fetchPromise);
285
+ await fetchPromise;
286
+ };
287
+ const handleClick = async (e) => {
288
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
289
+ e.preventDefault();
290
+ if (!isSafeUrl(href)) {
291
+ window.location.href = href;
292
+ return;
293
+ }
294
+ if (!morph || !ctx.morpher || !ctx.cache) {
295
+ window.location.href = href;
296
+ return;
297
+ }
298
+ ctx.setNavigating(href);
299
+ ctx.setProgress(0.3);
300
+ const timeoutId = setTimeout(() => {
301
+ console.error("Navigation timeout");
302
+ ctx.setNavigating(null);
303
+ window.location.href = href;
304
+ }, 1e4);
305
+ try {
306
+ let newContent = ctx.speculator?.get(href);
307
+ if (!newContent) {
308
+ let html = cache ? await ctx.cache.get(href) : null;
309
+ if (!html) {
310
+ ctx.incrementCacheMiss();
311
+ ctx.setProgress(0.5);
312
+ if (inflightRequests.has(href)) {
313
+ html = await inflightRequests.get(href);
314
+ } else {
315
+ const controller = new AbortController();
316
+ const fetchPromise = fetch(href, {
317
+ headers: { "x-specnav": "1" },
318
+ signal: controller.signal
319
+ }).then((res) => {
320
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
321
+ return res.text();
322
+ });
323
+ inflightRequests.set(href, fetchPromise);
324
+ html = await fetchPromise;
325
+ inflightRequests.delete(href);
326
+ }
327
+ if (cache) {
328
+ await ctx.cache.set(href, html);
329
+ }
330
+ }
331
+ ctx.setProgress(0.7);
332
+ const parser = new DOMParser();
333
+ const doc = parser.parseFromString(html, "text/html");
334
+ newContent = doc.body;
335
+ }
336
+ ctx.setProgress(0.9);
337
+ if ("startViewTransition" in document && ctx.adaptive?.shouldUseTransitions()) {
338
+ await document.startViewTransition(() => {
339
+ ctx.morpher?.morph(document.body, newContent);
340
+ }).finished;
341
+ } else {
342
+ ctx.morpher?.morph(document.body, newContent);
343
+ }
344
+ const currentHref = window.location.pathname;
345
+ if (replace) {
346
+ window.history.replaceState({ specnav: true }, "", href);
347
+ } else {
348
+ window.history.pushState({ specnav: true }, "", href);
349
+ }
350
+ ctx.graph?.recordNavigation(currentHref, href);
351
+ if (scroll) {
352
+ window.scrollTo(0, 0);
353
+ }
354
+ clearTimeout(timeoutId);
355
+ ctx.setProgress(1);
356
+ setTimeout(() => ctx.setNavigating(null), 200);
357
+ } catch (error) {
358
+ clearTimeout(timeoutId);
359
+ console.error("Navigation failed:", error);
360
+ ctx.setNavigating(null);
361
+ window.location.href = href;
362
+ }
363
+ };
364
+ return /* @__PURE__ */ jsxRuntime.jsx(
365
+ "a",
366
+ {
367
+ ref: linkRef,
368
+ href,
369
+ onClick: handleClick,
370
+ onMouseEnter: handleMouseEnter,
371
+ onMouseLeave: handleMouseLeave,
372
+ onFocus: handleFocus,
373
+ ...props,
374
+ children
375
+ }
376
+ );
377
+ }
378
+
379
+ // src/useNavigate.ts
380
+ init_prefetch();
381
+ function useNavigate() {
382
+ const ctx = useNavigationContext();
383
+ const isSafeUrl = (url) => {
384
+ try {
385
+ const parsed = new URL(url, window.location.origin);
386
+ return parsed.origin === window.location.origin;
387
+ } catch {
388
+ return false;
389
+ }
390
+ };
391
+ const navigate = async (href, options = {}) => {
392
+ const {
393
+ replace = false,
394
+ scroll = true,
395
+ morph = true,
396
+ cache: useCache = true
397
+ } = options;
398
+ if (!isSafeUrl(href)) {
399
+ window.location.href = href;
400
+ return;
401
+ }
402
+ if (!morph || !ctx.morpher || !ctx.cache) {
403
+ window.location.href = href;
404
+ return;
405
+ }
406
+ ctx.setNavigating(href);
407
+ ctx.setProgress(0.3);
408
+ try {
409
+ let newContent = ctx.speculator?.get(href);
410
+ if (!newContent) {
411
+ let html = useCache ? await ctx.cache.get(href) : null;
412
+ if (!html) {
413
+ ctx.setProgress(0.5);
414
+ if (inflightRequests.has(href)) {
415
+ html = await inflightRequests.get(href);
416
+ } else {
417
+ const controller = new AbortController();
418
+ const fetchPromise = fetch(href, {
419
+ headers: { "x-specnav": "1" },
420
+ signal: controller.signal
421
+ }).then((res) => {
422
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
423
+ return res.text();
424
+ });
425
+ inflightRequests.set(href, fetchPromise);
426
+ html = await fetchPromise;
427
+ inflightRequests.delete(href);
428
+ }
429
+ if (useCache) {
430
+ await ctx.cache.set(href, html);
431
+ }
432
+ }
433
+ ctx.setProgress(0.7);
434
+ const parser = new DOMParser();
435
+ const doc = parser.parseFromString(html, "text/html");
436
+ newContent = doc.body;
437
+ }
438
+ ctx.setProgress(0.9);
439
+ if ("startViewTransition" in document && ctx.adaptive?.shouldUseTransitions()) {
440
+ await document.startViewTransition(() => {
441
+ ctx.morpher?.morph(document.body, newContent);
442
+ }).finished;
443
+ } else {
444
+ ctx.morpher?.morph(document.body, newContent);
445
+ }
446
+ const currentHref = window.location.pathname;
447
+ if (replace) {
448
+ window.history.replaceState({ specnav: true }, "", href);
449
+ } else {
450
+ window.history.pushState({ specnav: true }, "", href);
451
+ }
452
+ ctx.graph?.recordNavigation(currentHref, href);
453
+ if (scroll) {
454
+ window.scrollTo(0, 0);
455
+ }
456
+ ctx.setProgress(1);
457
+ setTimeout(() => ctx.setNavigating(null), 200);
458
+ } catch (error) {
459
+ console.error("Navigation failed:", error);
460
+ ctx.setNavigating(null);
461
+ window.location.href = href;
462
+ }
463
+ };
464
+ const back = () => {
465
+ window.history.back();
466
+ };
467
+ const forward = () => {
468
+ window.history.forward();
469
+ };
470
+ const prefetch = async (href) => {
471
+ if (!ctx.cache || !isSafeUrl(href)) return;
472
+ try {
473
+ if (inflightRequests.has(href)) {
474
+ await inflightRequests.get(href);
475
+ return;
476
+ }
477
+ const controller = new AbortController();
478
+ const fetchPromise = fetch(href, {
479
+ headers: { "x-specnav": "1" },
480
+ signal: controller.signal
481
+ }).then((res) => res.text()).then((html) => {
482
+ ctx.cache?.set(href, html);
483
+ if (ctx.speculator && ctx.adaptive?.shouldSpeculate()) {
484
+ ctx.speculator.speculate(href, html);
485
+ }
486
+ return html;
487
+ }).finally(() => {
488
+ inflightRequests.delete(href);
489
+ });
490
+ inflightRequests.set(href, fetchPromise);
491
+ await fetchPromise;
492
+ } catch (error) {
493
+ if (error.name !== "AbortError") {
494
+ console.warn("Prefetch failed:", error);
495
+ }
496
+ }
497
+ };
498
+ const clearCache = (href) => {
499
+ ctx.cache?.clear(href);
500
+ if (href) {
501
+ ctx.speculator?.cancel(href);
502
+ } else {
503
+ ctx.speculator?.cancelAll();
504
+ }
505
+ };
506
+ return {
507
+ navigate,
508
+ back,
509
+ forward,
510
+ prefetch,
511
+ clearCache,
512
+ isNavigating: ctx.isNavigating,
513
+ pendingHref: ctx.pendingHref
514
+ };
515
+ }
516
+ function useNavigationState() {
517
+ const ctx = useNavigationContext();
518
+ const [previousHref, setPreviousHref] = react.useState(null);
519
+ const [lastNavigationMs, setLastNavigationMs] = react.useState(0);
520
+ const [startTime, setStartTime] = react.useState(null);
521
+ react.useEffect(() => {
522
+ if (ctx.isNavigating && ctx.pendingHref) {
523
+ setPreviousHref(window.location.pathname);
524
+ setStartTime(Date.now());
525
+ }
526
+ }, [ctx.isNavigating, ctx.pendingHref]);
527
+ react.useEffect(() => {
528
+ if (!ctx.isNavigating && startTime !== null) {
529
+ setLastNavigationMs(Date.now() - startTime);
530
+ setStartTime(null);
531
+ }
532
+ }, [ctx.isNavigating, startTime]);
533
+ const cacheSize = ctx.cache?.getSize() ?? 0;
534
+ const totalRequests = ctx.cacheHits + ctx.cacheMisses;
535
+ const cacheHitRate = totalRequests > 0 ? ctx.cacheHits / totalRequests : 0;
536
+ return {
537
+ isNavigating: ctx.isNavigating,
538
+ pendingHref: ctx.pendingHref,
539
+ previousHref,
540
+ cacheSize,
541
+ cacheHitRate,
542
+ lastNavigationMs,
543
+ progress: ctx.progress
544
+ };
545
+ }
546
+
547
+ exports.Link = Link;
548
+ exports.NavigateProvider = NavigateProvider;
549
+ exports.useNavigate = useNavigate;
550
+ exports.useNavigationState = useNavigationState;
551
+ //# sourceMappingURL=index.cjs.map
552
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prefetch.ts","../src/NavigateProvider.tsx","../src/Link.tsx","../src/useNavigate.ts","../src/useNavigationState.ts"],"names":["createContext","useContext","useState","useRef","useEffect","createAdaptiveMode","createCacheManager","createMorpher","createSpeculativeRenderer","createNavigationGraphLearner","createTrajectoryEngine","prefetchPage","jsxs","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["// Shared prefetch logic and request deduplication\n\nexport const inflightRequests = new Map<string, Promise<string>>();\n\nexport async function prefetchPage(\n href: string,\n cache: any,\n speculator: any\n): Promise<void> {\n if (inflightRequests.has(href)) {\n await inflightRequests.get(href);\n return;\n }\n\n const controller = new AbortController();\n const fetchPromise = fetch(href, {\n headers: { \"x-specnav\": \"1\" },\n signal: controller.signal,\n })\n .then((res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return res.text();\n })\n .then((html) => {\n if (cache) cache.set(href, html);\n if (speculator) speculator.speculate(href, html);\n return html;\n })\n .finally(() => {\n inflightRequests.delete(href);\n });\n\n inflightRequests.set(href, fetchPromise);\n await fetchPromise;\n}\n","\"use client\";\n\nimport { createContext, useContext, useEffect, useState, useRef } from \"react\";\nimport {\n createTrajectoryEngine,\n createCacheManager,\n createMorpher,\n createSpeculativeRenderer,\n createNavigationGraphLearner,\n createAdaptiveMode,\n type TrajectoryEngine,\n type CacheManager,\n type DOMmorpher,\n type SpeculativeRenderer,\n type NavigationGraphLearner,\n type AdaptiveMode,\n} from \"specnav-core\";\nimport type { NavigateProviderProps } from \"./types\";\n\ninterface NavigationContextValue {\n trajectory: TrajectoryEngine | null;\n cache: CacheManager | null;\n morpher: DOMmorpher | null;\n speculator: SpeculativeRenderer | null;\n graph: NavigationGraphLearner | null;\n adaptive: AdaptiveMode | null;\n isNavigating: boolean;\n pendingHref: string | null;\n progress: number;\n cacheHits: number;\n cacheMisses: number;\n setNavigating: (href: string | null) => void;\n setProgress: (progress: number) => void;\n incrementCacheMiss: () => void;\n}\n\nconst NavigationContext = createContext<NavigationContextValue | null>(null);\n\nexport function useNavigationContext() {\n const ctx = useContext(NavigationContext);\n if (!ctx) throw new Error(\"useNavigationContext must be used within NavigateProvider\");\n return ctx;\n}\n\nexport function NavigateProvider({\n children,\n strategy = \"auto\",\n cache: cacheConfig,\n prefetch: prefetchConfig,\n progress: progressConfig,\n morph: morphConfig,\n graph: graphConfig,\n onNavigateStart,\n onNavigateEnd,\n onCacheHit,\n}: NavigateProviderProps) {\n const [isNavigating, setIsNavigating] = useState(false);\n const [pendingHref, setPendingHref] = useState<string | null>(null);\n const [progress, setProgress] = useState(0);\n const [cacheHits, setCacheHits] = useState(0);\n const [cacheMisses, setCacheMisses] = useState(0);\n const navigationStartTime = useRef<number | null>(null);\n\n const [trajectory, setTrajectory] = useState<TrajectoryEngine | null>(null);\n const [cache, setCache] = useState<CacheManager | null>(null);\n const [morpher, setMorpher] = useState<DOMmorpher | null>(null);\n const [speculator, setSpeculator] = useState<SpeculativeRenderer | null>(null);\n const [graph, setGraph] = useState<NavigationGraphLearner | null>(null);\n const [adaptive, setAdaptive] = useState<AdaptiveMode | null>(null);\n\n const wrappedSetNavigating = (href: string | null) => {\n if (href) {\n navigationStartTime.current = Date.now();\n onNavigateStart?.(href);\n } else if (navigationStartTime.current) {\n const duration = Date.now() - navigationStartTime.current;\n if (pendingHref) {\n onNavigateEnd?.(pendingHref, duration);\n }\n navigationStartTime.current = null;\n }\n setIsNavigating(!!href);\n setPendingHref(href);\n };\n\n useEffect(() => {\n // Initialize engines\n const adaptiveEngine = createAdaptiveMode();\n \n const cacheEngine = createCacheManager(cacheConfig, {\n onCacheHit: (href, layer) => {\n setCacheHits(prev => prev + 1);\n onCacheHit?.(href, layer);\n },\n });\n\n const morpherEngine = createMorpher(morphConfig);\n const speculatorEngine = createSpeculativeRenderer(3);\n const graphEngine = createNavigationGraphLearner(graphConfig);\n\n // Wait for adaptive to initialize before setting state\n adaptiveEngine.waitForInit().then(() => {\n setAdaptive(adaptiveEngine);\n setCache(cacheEngine);\n setMorpher(morpherEngine);\n setSpeculator(speculatorEngine);\n setGraph(graphEngine);\n\n const effectiveStrategy = adaptiveEngine.getStrategy(strategy);\n\n if (effectiveStrategy !== \"off\" && prefetchConfig?.mode === \"trajectory\") {\n const trajectoryEngine = createTrajectoryEngine(prefetchConfig.trajectory, {\n onPrediction: async (href: string) => {\n if (!adaptiveEngine?.shouldPrefetch()) return;\n const { prefetchPage } = await import(\"./prefetch\");\n await prefetchPage(href, cacheEngine, speculatorEngine);\n },\n onCancel: (href) => {\n speculatorEngine?.cancel(href);\n },\n });\n\n trajectoryEngine.start();\n setTrajectory(trajectoryEngine);\n }\n });\n\n // Handle browser back/forward\n const handlePopState = async (e: PopStateEvent) => {\n if (!e.state?.specnav) return;\n\n const href = window.location.pathname;\n wrappedSetNavigating(href);\n setProgress(0.3);\n\n try {\n // Try cache first (should be instant)\n const html = await cache?.get(href);\n \n if (html && morpher) {\n setProgress(0.7);\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, \"text/html\");\n const newContent = doc.body;\n\n morpher.morph(document.body, newContent);\n setProgress(1);\n setTimeout(() => wrappedSetNavigating(null), 100);\n } else {\n // Fallback to full reload\n window.location.reload();\n }\n } catch (error) {\n console.error(\"Popstate navigation failed:\", error);\n window.location.reload();\n }\n };\n\n window.addEventListener(\"popstate\", handlePopState);\n\n return () => {\n trajectory?.stop();\n cache?.destroy();\n speculator?.cancelAll();\n window.removeEventListener(\"popstate\", handlePopState);\n };\n }, [strategy, cacheConfig, prefetchConfig, morphConfig, graphConfig, onCacheHit, onNavigateEnd]);\n\n const value: NavigationContextValue = {\n trajectory,\n cache,\n morpher,\n speculator,\n graph,\n adaptive,\n isNavigating,\n pendingHref,\n progress,\n cacheHits,\n cacheMisses,\n setNavigating: wrappedSetNavigating,\n setProgress,\n incrementCacheMiss: () => setCacheMisses(prev => prev + 1),\n };\n\n return (\n <NavigationContext.Provider value={value}>\n {progressConfig?.enabled !== false && (\n <ProgressBar config={progressConfig} progress={progress} isNavigating={isNavigating} />\n )}\n {children}\n </NavigationContext.Provider>\n );\n}\n\nfunction ProgressBar({\n config,\n progress,\n isNavigating,\n}: {\n config: any;\n progress: number;\n isNavigating: boolean;\n}) {\n const color = config?.color ?? \"#6366f1\";\n const height = config?.height ?? 3;\n const position = config?.position ?? \"top\";\n\n return (\n <div\n style={{\n position: \"fixed\",\n [position]: 0,\n left: 0,\n right: 0,\n height: `${height}px`,\n zIndex: 9999,\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${progress * 100}%`,\n background: color,\n transition: isNavigating ? \"width 200ms ease\" : \"opacity 200ms ease\",\n opacity: isNavigating ? 1 : 0,\n }}\n />\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { useNavigationContext } from \"./NavigateProvider\";\nimport type { LinkProps } from \"./types\";\nimport { inflightRequests } from \"./prefetch\";\n\nexport function Link({\n href,\n prefetch = \"trajectory\",\n morph = true,\n cache = true,\n replace = false,\n scroll = true,\n children,\n ...props\n}: LinkProps) {\n const ctx = useNavigationContext();\n const linkRef = useRef<HTMLAnchorElement>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n // Validate URL is same-origin for security\n const isSafeUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url, window.location.origin);\n return parsed.origin === window.location.origin;\n } catch {\n return false;\n }\n };\n\n useEffect(() => {\n if (!linkRef.current || !ctx.trajectory || prefetch === false) return;\n\n const element = linkRef.current;\n ctx.trajectory.registerLink(href, element);\n\n return () => {\n ctx.trajectory?.unregisterLink(element);\n abortControllerRef.current?.abort();\n };\n }, [href, ctx.trajectory, prefetch]);\n\n // Hover prefetch\n const handleMouseEnter = async () => {\n if (prefetch === \"hover\" && ctx.adaptive?.shouldPrefetch()) {\n await prefetchPage(href);\n }\n };\n\n const handleMouseLeave = () => {\n // Cleanup if needed\n };\n\n // Focus prefetch (keyboard navigation)\n const handleFocus = async () => {\n if (ctx.adaptive?.shouldPrefetch()) {\n await prefetchPage(href);\n }\n };\n\n const prefetchPage = async (url: string): Promise<void> => {\n if (!isSafeUrl(url) || !ctx.cache) return;\n\n // Check if already cached\n const cached = await ctx.cache.get(url);\n if (cached) return;\n\n // Check if already in-flight\n if (inflightRequests.has(url)) {\n await inflightRequests.get(url);\n return;\n }\n\n // Start new request\n abortControllerRef.current = new AbortController();\n const fetchPromise = fetch(url, {\n headers: { \"x-specnav\": \"1\" },\n signal: abortControllerRef.current.signal,\n })\n .then((res) => res.text())\n .then((html) => {\n ctx.cache?.set(url, html);\n // Speculative render if enabled\n if (ctx.speculator && ctx.adaptive?.shouldSpeculate()) {\n ctx.speculator.speculate(url, html);\n }\n return html;\n })\n .catch((err) => {\n if (err.name !== \"AbortError\") {\n console.warn(\"Prefetch failed:\", err);\n }\n throw err;\n })\n .finally(() => {\n inflightRequests.delete(url);\n });\n\n inflightRequests.set(url, fetchPromise);\n await fetchPromise;\n };\n\n const handleClick = async (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Allow default behavior for modified clicks\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n \n e.preventDefault();\n\n if (!isSafeUrl(href)) {\n window.location.href = href;\n return;\n }\n\n if (!morph || !ctx.morpher || !ctx.cache) {\n window.location.href = href;\n return;\n }\n\n ctx.setNavigating(href);\n ctx.setProgress(0.3);\n\n // Timeout to prevent infinite hangs\n const timeoutId = setTimeout(() => {\n console.error(\"Navigation timeout\");\n ctx.setNavigating(null);\n window.location.href = href;\n }, 10000); // 10 second timeout\n\n try {\n // Check speculative render first\n let newContent = ctx.speculator?.get(href);\n \n if (!newContent) {\n // Check cache\n let html = cache ? await ctx.cache.get(href) : null;\n\n if (!html) {\n ctx.incrementCacheMiss();\n ctx.setProgress(0.5);\n // Deduplicate requests\n if (inflightRequests.has(href)) {\n html = await inflightRequests.get(href)!;\n } else {\n const controller = new AbortController();\n const fetchPromise = fetch(href, {\n headers: { \"x-specnav\": \"1\" },\n signal: controller.signal,\n }).then((res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return res.text();\n });\n \n inflightRequests.set(href, fetchPromise);\n html = await fetchPromise;\n inflightRequests.delete(href);\n }\n\n if (cache) {\n await ctx.cache.set(href, html);\n }\n }\n\n ctx.setProgress(0.7);\n\n // Parse HTML\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, \"text/html\");\n newContent = doc.body;\n }\n\n ctx.setProgress(0.9);\n\n // Morph DOM with optional View Transitions\n if (\n \"startViewTransition\" in document &&\n ctx.adaptive?.shouldUseTransitions()\n ) {\n await (document as any).startViewTransition(() => {\n ctx.morpher?.morph(document.body, newContent!);\n }).finished;\n } else {\n ctx.morpher?.morph(document.body, newContent);\n }\n\n // Record navigation in graph (capture before URL change)\n const currentHref = window.location.pathname;\n\n // Update URL\n if (replace) {\n window.history.replaceState({ specnav: true }, \"\", href);\n } else {\n window.history.pushState({ specnav: true }, \"\", href);\n }\n\n ctx.graph?.recordNavigation(currentHref, href);\n\n // Scroll to top if requested\n if (scroll) {\n window.scrollTo(0, 0);\n }\n\n clearTimeout(timeoutId);\n ctx.setProgress(1);\n setTimeout(() => ctx.setNavigating(null), 200);\n } catch (error) {\n clearTimeout(timeoutId);\n console.error(\"Navigation failed:\", error);\n ctx.setNavigating(null);\n window.location.href = href;\n }\n };\n\n return (\n <a\n ref={linkRef}\n href={href}\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onFocus={handleFocus}\n {...props}\n >\n {children}\n </a>\n );\n}\n","\"use client\";\n\nimport { useNavigationContext } from \"./NavigateProvider\";\nimport type { UseNavigateReturn, NavigateOptions } from \"./types\";\nimport { inflightRequests } from \"./prefetch\";\n\nexport function useNavigate(): UseNavigateReturn {\n const ctx = useNavigationContext();\n\n const isSafeUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url, window.location.origin);\n return parsed.origin === window.location.origin;\n } catch {\n return false;\n }\n };\n\n const navigate = async (href: string, options: NavigateOptions = {}) => {\n const {\n replace = false,\n scroll = true,\n morph = true,\n cache: useCache = true,\n } = options;\n\n if (!isSafeUrl(href)) {\n window.location.href = href;\n return;\n }\n\n if (!morph || !ctx.morpher || !ctx.cache) {\n window.location.href = href;\n return;\n }\n\n ctx.setNavigating(href);\n ctx.setProgress(0.3);\n\n try {\n // Check speculative render first\n let newContent = ctx.speculator?.get(href);\n\n if (!newContent) {\n let html = useCache ? await ctx.cache.get(href) : null;\n\n if (!html) {\n ctx.setProgress(0.5);\n \n // Deduplicate requests\n if (inflightRequests.has(href)) {\n html = await inflightRequests.get(href)!;\n } else {\n const controller = new AbortController();\n const fetchPromise = fetch(href, {\n headers: { \"x-specnav\": \"1\" },\n signal: controller.signal,\n }).then((res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return res.text();\n });\n\n inflightRequests.set(href, fetchPromise);\n html = await fetchPromise;\n inflightRequests.delete(href);\n }\n\n if (useCache) {\n await ctx.cache.set(href, html);\n }\n }\n\n ctx.setProgress(0.7);\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, \"text/html\");\n newContent = doc.body;\n }\n\n ctx.setProgress(0.9);\n\n if (\n \"startViewTransition\" in document &&\n ctx.adaptive?.shouldUseTransitions()\n ) {\n await (document as any).startViewTransition(() => {\n ctx.morpher?.morph(document.body, newContent!);\n }).finished;\n } else {\n ctx.morpher?.morph(document.body, newContent);\n }\n\n const currentHref = window.location.pathname;\n\n if (replace) {\n window.history.replaceState({ specnav: true }, \"\", href);\n } else {\n window.history.pushState({ specnav: true }, \"\", href);\n }\n\n ctx.graph?.recordNavigation(currentHref, href);\n\n if (scroll) {\n window.scrollTo(0, 0);\n }\n\n ctx.setProgress(1);\n setTimeout(() => ctx.setNavigating(null), 200);\n } catch (error) {\n console.error(\"Navigation failed:\", error);\n ctx.setNavigating(null);\n window.location.href = href;\n }\n };\n\n const back = () => {\n window.history.back();\n };\n\n const forward = () => {\n window.history.forward();\n };\n\n const prefetch = async (href: string) => {\n if (!ctx.cache || !isSafeUrl(href)) return;\n\n try {\n // Check if already in-flight\n if (inflightRequests.has(href)) {\n await inflightRequests.get(href);\n return;\n }\n\n const controller = new AbortController();\n const fetchPromise = fetch(href, {\n headers: { \"x-specnav\": \"1\" },\n signal: controller.signal,\n })\n .then((res) => res.text())\n .then((html) => {\n ctx.cache?.set(href, html);\n // Speculative render if enabled\n if (ctx.speculator && ctx.adaptive?.shouldSpeculate()) {\n ctx.speculator.speculate(href, html);\n }\n return html;\n })\n .finally(() => {\n inflightRequests.delete(href);\n });\n\n inflightRequests.set(href, fetchPromise);\n await fetchPromise;\n } catch (error) {\n if ((error as Error).name !== \"AbortError\") {\n console.warn(\"Prefetch failed:\", error);\n }\n }\n };\n\n const clearCache = (href?: string) => {\n ctx.cache?.clear(href);\n if (href) {\n ctx.speculator?.cancel(href);\n } else {\n ctx.speculator?.cancelAll();\n }\n };\n\n return {\n navigate,\n back,\n forward,\n prefetch,\n clearCache,\n isNavigating: ctx.isNavigating,\n pendingHref: ctx.pendingHref,\n };\n}\n","\"use client\";\n\nimport { useState, useEffect } from \"react\";\nimport { useNavigationContext } from \"./NavigateProvider\";\nimport type { UseNavigationStateReturn } from \"./types\";\n\nexport function useNavigationState(): UseNavigationStateReturn {\n const ctx = useNavigationContext();\n const [previousHref, setPreviousHref] = useState<string | null>(null);\n const [lastNavigationMs, setLastNavigationMs] = useState(0);\n const [startTime, setStartTime] = useState<number | null>(null);\n\n // Track navigation start\n useEffect(() => {\n if (ctx.isNavigating && ctx.pendingHref) {\n setPreviousHref(window.location.pathname);\n setStartTime(Date.now());\n }\n }, [ctx.isNavigating, ctx.pendingHref]);\n\n // Track navigation end (event-driven)\n useEffect(() => {\n if (!ctx.isNavigating && startTime !== null) {\n setLastNavigationMs(Date.now() - startTime);\n setStartTime(null);\n }\n }, [ctx.isNavigating, startTime]);\n\n const cacheSize = ctx.cache?.getSize() ?? 0;\n const totalRequests = ctx.cacheHits + ctx.cacheMisses;\n const cacheHitRate = totalRequests > 0 ? ctx.cacheHits / totalRequests : 0;\n\n return {\n isNavigating: ctx.isNavigating,\n pendingHref: ctx.pendingHref,\n previousHref,\n cacheSize,\n cacheHitRate,\n lastNavigationMs,\n progress: ctx.progress,\n };\n}\n"]}