stx-router 0.2.10 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable prefer-const, no-console, style/max-statements-per-line, general/prefer-template */
1
2
  /**
2
3
  * STX Router - Canonical SPA Router
3
4
  *
package/dist/codegen.d.ts CHANGED
@@ -1,2 +1,9 @@
1
1
  import type { Route } from './types';
2
2
  export declare function generateRouteTypes(routes: Route[], outputDir: string): void;
3
+ /**
4
+ * Generate a route manifest file (.stx/routes.ts).
5
+ *
6
+ * Produces a TypeScript module exporting the full route array with patterns,
7
+ * file paths, params, and layout references. Similar to Nuxt's .nuxt/routes.mjs.
8
+ */
9
+ export declare function generateRouteManifest(routes: Route[], outputDir: string, pagesDir: string): void;
package/dist/index.d.ts CHANGED
@@ -46,6 +46,6 @@ export {
46
46
  // Nested layouts
47
47
  export { resolveLayoutChain } from './nested-layouts';
48
48
  // Route type generation
49
- export { generateRouteTypes } from './codegen';
49
+ export { generateRouteTypes, generateRouteManifest } from './codegen';
50
50
  // Client-side SPA navigation
51
51
  export { getRouterScript } from './client';
package/dist/index.js CHANGED
@@ -26,6 +26,29 @@ function generateRouteTypes(routes, outputDir) {
26
26
  fs.writeFileSync(path.join(outputDir, "route-types.d.ts"), lines.join(`
27
27
  `));
28
28
  }
29
+ function generateRouteManifest(routes, outputDir, pagesDir) {
30
+ const cwd = process.cwd();
31
+ const relativePages = path.relative(cwd, pagesDir);
32
+ const excludeDirs = ["components", "layouts", "partials"];
33
+ const pageRoutes = routes.filter((r) => !excludeDirs.some((dir) => r.pattern.startsWith(`/${dir}/`) || r.pattern === `/${dir}`));
34
+ const lines = [
35
+ "// Auto-generated by stx \u2014 do not edit",
36
+ `// Source: ${relativePages || "pages"}/`,
37
+ "",
38
+ "export const routes = ["
39
+ ];
40
+ for (const route of pageRoutes) {
41
+ const relFile = path.relative(cwd, route.filePath).replace(/\\/g, "/");
42
+ const params = JSON.stringify(route.params);
43
+ const layoutStr = route.layout ? `, layout: '${path.relative(cwd, route.layout).replace(/\\/g, "/")}'` : "";
44
+ lines.push(` { pattern: '${route.pattern}', filePath: '${relFile}', isDynamic: ${route.isDynamic}, params: ${params}${layoutStr} },`);
45
+ }
46
+ lines.push("] as const", "");
47
+ lines.push("export type RouteName = typeof routes[number]['pattern']", "");
48
+ fs.mkdirSync(outputDir, { recursive: true });
49
+ fs.writeFileSync(path.join(outputDir, "routes.ts"), lines.join(`
50
+ `));
51
+ }
29
52
 
30
53
  // src/matcher.ts
31
54
  import path2 from "path";
@@ -160,6 +183,7 @@ class Router {
160
183
  });
161
184
  const stxDir = path4.join(baseDir, ".stx");
162
185
  generateRouteTypes(this.routes, stxDir);
186
+ generateRouteManifest(this.routes, stxDir, this.pagesDir);
163
187
  }
164
188
  match(pathname) {
165
189
  const normalizedPath = pathname === "" ? "/" : pathname;
@@ -546,27 +570,145 @@ function getRouterScript() {
546
570
  if(window.__stxRouter)return;
547
571
 
548
572
  // \u2500\u2500 Configuration \u2500\u2500
549
- var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true};
573
+ var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true,progress:true,progressColor:'#78dce8',progressHeight:'2px'};
550
574
  var o=Object.assign({},defaults,window.__stxRouterConfig||{},window.STX_ROUTER_OPTIONS||{});
551
575
  var containerSel=o.container;
552
576
 
577
+ // \u2500\u2500 Progress bar (0\u2192100% at top of viewport) \u2500\u2500
578
+ // Native loading indicator baked into the router. Starts when navigation
579
+ // begins, trickles up to ~90% during fetch, snaps to 100% + fades on
580
+ // completion. Opt-out via window.__stxRouterConfig={progress:false}.
581
+ var progEl=null;
582
+ var progVal=0;
583
+ var progTimer=null;
584
+ function setProgress(v){
585
+ progVal=v<0?0:(v>100?100:v);
586
+ if(!progEl)return;
587
+ progEl.style.opacity=progVal>0?'1':'0';
588
+ progEl.style.transform='scaleX('+(progVal/100)+')';
589
+ }
590
+ function startProgress(){
591
+ if(!o.progress||!progEl)return;
592
+ if(progTimer){clearInterval(progTimer);progTimer=null}
593
+ setProgress(8);
594
+ progTimer=setInterval(function(){
595
+ if(progVal>=90)return;
596
+ // Asymptotic trickle \u2014 fast at first, slower near 90%
597
+ var inc=Math.max(0.4,(90-progVal)*0.08);
598
+ setProgress(progVal+inc);
599
+ },160);
600
+ }
601
+ function finishProgress(){
602
+ if(!o.progress||!progEl)return;
603
+ if(progTimer){clearInterval(progTimer);progTimer=null}
604
+ setProgress(100);
605
+ // Fade out, then reset. Delays chosen so the "full" state is briefly
606
+ // visible before the bar disappears.
607
+ setTimeout(function(){
608
+ if(!progEl)return;
609
+ progEl.style.opacity='0';
610
+ setTimeout(function(){progVal=0;if(progEl)progEl.style.transform='scaleX(0)'},260);
611
+ },180);
612
+ }
613
+
553
614
  var cache={};
554
615
  var prefetching={};
555
616
  var isNavigating=false;
556
617
 
618
+ // Extract top-level CSS blocks (rules AND @media blocks with nested braces).
619
+ // The old regex ([^{}]+{[^{}]*}) silently dropped @media blocks because
620
+ // it couldn't handle nested braces \u2014 causing responsive classes (lg:, md:)
621
+ // to vanish after SPA navigation.
622
+ function extractCssBlocks(css){
623
+ var blocks=[];
624
+ var i=0;
625
+ var len=css.length;
626
+ while(i<len){
627
+ // Skip whitespace
628
+ while(i<len&&(css[i]===' '||css[i]==='\\n'||css[i]==='\\r'||css[i]==='\\t'))i++;
629
+ if(i>=len)break;
630
+ // Find the start of a block (first {)
631
+ var blockStart=i;
632
+ var bracePos=css.indexOf('{',i);
633
+ if(bracePos===-1)break;
634
+ // Walk forward tracking brace depth to find the matching close
635
+ var depth=0;
636
+ var j=bracePos;
637
+ while(j<len){
638
+ if(css[j]==='{')depth++;
639
+ else if(css[j]==='}'){depth--;if(depth===0){j++;break}}
640
+ j++;
641
+ }
642
+ if(depth!==0)break;
643
+ blocks.push(css.slice(blockStart,j).trim());
644
+ i=j;
645
+ }
646
+ return blocks;
647
+ }
648
+
649
+ function mergeCrosswindCSS(existing,incoming){
650
+ var blocks=extractCssBlocks(incoming);
651
+ var newBlocks=[];
652
+ for(var bi=0;bi<blocks.length;bi++){
653
+ if(existing.indexOf(blocks[bi])===-1)newBlocks.push(blocks[bi]);
654
+ }
655
+ if(newBlocks.length>0)return existing+'\\n'+newBlocks.join('\\n');
656
+ return null;
657
+ }
658
+
557
659
  function getContainer(){
558
660
  return document.querySelector(containerSel)||document.querySelector('[data-stx-content]')||document.querySelector('main');
559
661
  }
560
662
 
561
663
  // \u2500\u2500 Navigation \u2500\u2500
562
- function navigate(url,pushState){
664
+ // Layout group detection \u2014 layouts in the same group share a <main> container.
665
+ // Only truly different layout groups trigger a full page reload.
666
+ var layoutCache={};
667
+ // Track executed script hashes to prevent redeclaration errors on navigation.
668
+ // Layout-level scripts (theme, nav setup) execute on initial page load and
669
+ // should NOT re-execute when navigating to another page with the same layout.
670
+ var executedScriptHashes={};
671
+ function hashScript(code){
672
+ var h=0;for(var i=0;i<code.length;i++){h=((h<<5)-h)+code.charCodeAt(i);h|=0}
673
+ return h;
674
+ }
675
+ // Record scripts from the initial page load
676
+ document.querySelectorAll('script').forEach(function(s){
677
+ var text=s.textContent||'';
678
+ if(text.trim()&&!s.hasAttribute('src'))executedScriptHashes[hashScript(text)]=1;
679
+ });
680
+ function getLayoutGroup(layout){
681
+ if(!layout)return 'app';
682
+ if(layout.indexOf('auth')!==-1||layout.indexOf('guest')!==-1)return 'auth';
683
+ return 'app';
684
+ }
685
+ function checkLayoutChange(newLayout,targetUrl){
686
+ var currentLayout=document.querySelector('meta[name="stx-layout"]');
687
+ var curLayoutName=currentLayout?currentLayout.getAttribute('content'):'';
688
+ var curGroup=getLayoutGroup(curLayoutName);
689
+ var newGroup=getLayoutGroup(newLayout);
690
+ console.log('[router] layout check: current='+curLayoutName+'('+curGroup+') new='+(newLayout||'')+'('+newGroup+')');
691
+ // Different layout GROUP (e.g. app \u2192 auth): full reload
692
+ if(curGroup!==newGroup){
693
+ console.log('[router] layout group change:',curGroup,'\u2192',newGroup,'\u2014 full reload to:',targetUrl);
694
+ return true;
695
+ }
696
+ // Same group but different SPECIFIC layout (e.g. layouts/app \u2192 layouts/coach):
697
+ // full body swap so nav, sidebar, and other layout-level elements update
698
+ if(curLayoutName && newLayout && curLayoutName!==newLayout){
699
+ console.log('[router] layout name change:',curLayoutName,'\u2192',newLayout,'\u2014 full body swap');
700
+ return true;
701
+ }
702
+ return false;
703
+ }
704
+
705
+ function navigate(url,pushState,force){
706
+ console.log('[router] navigate() called:',url,'isNavigating:',isNavigating);
563
707
  if(isNavigating)return;
564
708
  var t=new URL(url,location.origin);
565
709
 
566
- // Different origin \u2192 full navigation
567
710
  if(t.origin!==location.origin){location.href=url;return}
568
711
 
569
- // Hash-only navigation on same page
570
712
  if(t.pathname===location.pathname&&t.hash){
571
713
  if(pushState!==false)history.pushState({},'',t.href);
572
714
  var el=document.querySelector(t.hash);
@@ -574,40 +716,152 @@ function getRouterScript() {
574
716
  return;
575
717
  }
576
718
 
577
- // Same page, no hash \u2192 skip
578
- if(t.href===location.href&&!t.hash)return;
719
+ if(t.href===location.href&&!t.hash&&!force)return;
579
720
 
580
721
  isNavigating=true;
581
722
  document.body.classList.add(o.loadingClass);
723
+ startProgress();
582
724
 
583
725
  var targetHref=t.href;
584
726
  var targetPath=t.pathname;
585
727
  var targetHash=t.hash;
586
728
 
587
- function done(){isNavigating=false;document.body.classList.remove(o.loadingClass)}
729
+ function done(){isNavigating=false;document.body.classList.remove(o.loadingClass);finishProgress()}
588
730
 
589
- if(o.cache&&cache[targetPath]){
731
+ if(o.cache&&cache[targetPath]&&!force){
732
+ if(checkLayoutChange(layoutCache[targetPath],url)){
733
+ // Layout changed \u2014 fetch full page and do full document swap
734
+ console.log('[router] cache hit but layout changed \u2014 fetching full page');
735
+ fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
736
+ if(!r.ok)throw new Error(r.status);
737
+ return r.text();
738
+ }).then(function(html){
739
+ console.log('[router] full page fetched from cache path, len:',html.length);
740
+ swap(html,targetPath,pushState,targetHash);
741
+ }).catch(function(err){
742
+ console.error('[router] full page fetch error:',err);
743
+ location.href=url;
744
+ }).finally(done);
745
+ return;
746
+ }
590
747
  swap(cache[targetPath],targetPath,pushState,targetHash);
591
748
  done();
592
- }else{
749
+ }
750
+ else {
751
+ if(force&&cache[targetPath])delete cache[targetPath];
752
+ // First fetch as fragment (SPA mode)
593
753
  fetch(url,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){
594
754
  if(!r.ok)throw new Error(r.status);
595
- return r.text();
596
- }).then(function(html){
597
- if(o.cache)cache[targetPath]=html;
598
- swap(html,targetPath,pushState,targetHash);
599
- }).catch(function(){
755
+ var isFragment=r.headers.get('X-STX-Fragment')==='true';
756
+ var newLayout=r.headers.get('X-STX-Layout')||'';
757
+ // Layout change? Fetch the FULL page (no X-STX-Router header) and do full document swap
758
+ if(isFragment&&checkLayoutChange(newLayout,url)){
759
+ console.log('[router] layout change \u2014 fetching full page for document swap');
760
+ return fetch(url,{headers:{'Accept':'text/html'}}).then(function(fullRes){
761
+ console.log('[router] full page fetched:',fullRes.status,'ok:',fullRes.ok);
762
+ if(!fullRes.ok)throw new Error(fullRes.status);
763
+ return fullRes.text().then(function(html){
764
+ console.log('[router] full page html length:',html.length);
765
+ return{html:html,isFragment:false,layout:newLayout};
766
+ });
767
+ });
768
+ }
769
+ return r.text().then(function(html){return{html:html,isFragment:isFragment,layout:newLayout}});
770
+ }).then(function(result){
771
+ if(!result)return;
772
+ if(result.isFragment)result.html='<!--stx-fragment-->'+result.html;
773
+ if(o.cache){cache[targetPath]=result.html;layoutCache[targetPath]=result.layout}
774
+ swap(result.html,targetPath,pushState,targetHash);
775
+ }).catch(function(err){
776
+ console.error('[router] fetch error:',err);
600
777
  location.href=url;
601
778
  }).finally(done);
602
779
  }
603
780
  }
604
781
 
605
782
  function swap(html,url,pushState,hash){
783
+ var isFragment=html.indexOf('<!--stx-fragment-->')===0;
784
+ if(isFragment)html=html.slice('<!--stx-fragment-->'.length);
785
+ var currentContent=getContainer();
786
+ console.log('[router] swap: isFragment='+isFragment+' container='+!!currentContent+' htmlLen='+html.length);
787
+ if(!currentContent){console.log('[router] no container \u2014 falling back');location.href=url;return}
788
+
789
+ // Fragment mode: server returned just the page content (no document wrapper)
790
+ if(isFragment){
791
+ if(window.stx&&window.stx._cleanupContainer)window.stx._cleanupContainer(currentContent);
792
+ function doFragSwap(){
793
+ // Extract scripts from fragment before injecting HTML
794
+ var fragScripts=[];
795
+ var fragStyles=[];
796
+ var fragCrosswindCSS=null;
797
+ var cleanFrag=html.replace(new RegExp('<scr'+'ipt\\\\b[^>]*>([\\\\s\\\\S]*?)<\\\\/scr'+'ipt>','gi'),function(m,code){
798
+ if(code&&code.trim())fragScripts.push(code);
799
+ return '';
800
+ });
801
+ cleanFrag=cleanFrag.replace(new RegExp('<sty'+'le\\\\b([^>]*)>([\\\\s\\\\S]*?)<\\\\/sty'+'le>','gi'),function(m,attrs,css){
802
+ if(attrs.indexOf('data-crosswind')!==-1){
803
+ fragCrosswindCSS=css;
804
+ }else{
805
+ fragStyles.push({attrs:attrs,css:css});
806
+ }
807
+ return '';
808
+ });
809
+ // Remove old page styles (not crosswind \u2014 that gets merged)
810
+ document.querySelectorAll('style[data-stx-page]').forEach(function(s){s.remove()});
811
+ // Merge crosswind CSS from fragment into existing crosswind style
812
+ if(fragCrosswindCSS){
813
+ var curCrosswind=document.querySelector('head style[data-crosswind]');
814
+ if(curCrosswind){
815
+ var merged=mergeCrosswindCSS(curCrosswind.textContent||'',fragCrosswindCSS);
816
+ if(merged)curCrosswind.textContent=merged;
817
+ }else{
818
+ var cw=document.createElement('style');
819
+ cw.setAttribute('data-crosswind','generated');
820
+ cw.textContent=fragCrosswindCSS;
821
+ document.head.appendChild(cw);
822
+ }
823
+ }
824
+ // Add new page styles
825
+ fragStyles.forEach(function(s){
826
+ var el=document.createElement('style');
827
+ el.textContent=s.css;
828
+ el.setAttribute('data-stx-page','');
829
+ document.head.appendChild(el);
830
+ });
831
+ // Swap content
832
+ currentContent.innerHTML=cleanFrag;
833
+ // Remove old page scripts
834
+ document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});
835
+ if(pushState!==false)history.pushState({},'',url+(hash||''));
836
+ updateNav(url);
837
+ updateActiveLinks();
838
+ if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});
839
+ else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}
840
+ window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));
841
+ // Execute page scripts FIRST \u2014 they define setup functions and set _latestSetup
842
+ console.log('[router] frag scripts:', fragScripts.length);
843
+ document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});
844
+ fragScripts.forEach(function(code){
845
+ console.log('[router] exec script len:', code.length, 'has __stx_setup:', code.indexOf('__stx_setup')>-1);
846
+ var ns=document.createElement('script');
847
+ ns.textContent=code;
848
+ ns.setAttribute('data-stx-page','');
849
+ document.body.appendChild(ns);
850
+ });
851
+ console.log('[router] scripts done. _latestSetup:', !!window.stx._latestSetup);
852
+ // THEN fire stx:load \u2014 now _latestSetup is set and processElement has the right scope
853
+ window.dispatchEvent(new Event('stx:load'));
854
+ }
855
+ if(o.viewTransitions&&document.startViewTransition){document.startViewTransition(doFragSwap)}
856
+ else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){doFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}
857
+ return;
858
+ }
859
+
860
+ // Full document mode: parse with DOMParser and extract container content
606
861
  var parser=new DOMParser();
607
862
  var doc=parser.parseFromString(html,'text/html');
608
863
  var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');
609
- var currentContent=getContainer();
610
- if(!newContent||!currentContent){location.href=url;return}
864
+ if(!newContent){location.href=url;return}
611
865
 
612
866
  // Clean up existing signals/effects
613
867
  if(window.stx&&window.stx._cleanupContainer){
@@ -621,27 +875,74 @@ function getRouterScript() {
621
875
  var curStyles=document.querySelectorAll('head style');
622
876
  var newStyles=doc.querySelectorAll('head style');
623
877
 
878
+ // Merge crosswind styles instead of replacing \u2014 persistent elements
879
+ // (nav, footer) outside <main> still need their utility classes
880
+ var curCrosswind=document.querySelector('head style[data-crosswind]');
881
+ var newCrosswind=null;
882
+ newStyles.forEach(function(s){if(s.getAttribute('data-crosswind'))newCrosswind=s});
883
+
884
+ if(curCrosswind&&newCrosswind){
885
+ var merged=mergeCrosswindCSS(curCrosswind.textContent||'',newCrosswind.textContent||'');
886
+ if(merged)curCrosswind.textContent=merged;
887
+ }
888
+
624
889
  var incoming=[];
625
890
  newStyles.forEach(function(s){
626
- if(!keepIds[s.id]){
891
+ if(!keepIds[s.id]&&!s.getAttribute('data-crosswind')){
627
892
  var ns=document.createElement('style');
628
893
  ns.textContent=s.textContent;
629
894
  ns.setAttribute('data-stx-incoming','');
630
- if(s.getAttribute('data-crosswind'))ns.setAttribute('data-crosswind',s.getAttribute('data-crosswind'));
631
895
  document.head.appendChild(ns);
632
896
  incoming.push(ns);
633
897
  }
634
898
  });
635
899
 
636
- // Remove old styles (except persistent ones and incoming)
900
+ // If no existing crosswind but new page has one, add it
901
+ if(!curCrosswind&&newCrosswind){
902
+ var ns=document.createElement('style');
903
+ ns.textContent=newCrosswind.textContent;
904
+ ns.setAttribute('data-crosswind',newCrosswind.getAttribute('data-crosswind'));
905
+ document.head.appendChild(ns);
906
+ }
907
+
908
+ // Remove old styles (except persistent ones, crosswind, and incoming)
637
909
  curStyles.forEach(function(s){
638
- if(!keepIds[s.id]&&!s.hasAttribute('data-stx-incoming'))s.remove();
910
+ if(!keepIds[s.id]&&!s.hasAttribute('data-stx-incoming')&&!s.hasAttribute('data-crosswind'))s.remove();
639
911
  });
640
912
 
641
913
  incoming.forEach(function(s){s.removeAttribute('data-stx-incoming')});
642
914
 
643
- // \u2500\u2500 Swap main content \u2500\u2500
644
- currentContent.innerHTML=newContent.innerHTML;
915
+ // \u2500\u2500 Swap content \u2500\u2500
916
+ // For layout changes: swap the entire <body> to replace layout chrome (nav, footer, etc.)
917
+ // For same-layout: swap only the container (<main>)
918
+ var newBody=doc.querySelector('body');
919
+ var isLayoutChange=false;
920
+ if(newBody){
921
+ var newMeta=doc.querySelector('meta[name="stx-layout"]');
922
+ var curMeta=document.querySelector('meta[name="stx-layout"]');
923
+ var curGroup=getLayoutGroup(curMeta?curMeta.getAttribute('content'):'');
924
+ var newGroup=getLayoutGroup(newMeta?newMeta.getAttribute('content'):'');
925
+ isLayoutChange=curGroup!==newGroup;
926
+ }
927
+ if(isLayoutChange&&newBody){
928
+ console.log('[router] full body swap for layout change');
929
+ // Replace entire body content \u2014 layout chrome and all
930
+ var bodyHTML=newBody.innerHTML.replace(new RegExp('<scr'+'ipt\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/scr'+'ipt\\\\s*>','gi'),'');
931
+ document.body.innerHTML=bodyHTML;
932
+ // Copy body attributes (class, data-stx, etc.)
933
+ Array.from(newBody.attributes).forEach(function(attr){document.body.setAttribute(attr.name,attr.value)});
934
+ // Update layout meta tag
935
+ var oldMeta=document.querySelector('meta[name="stx-layout"]');
936
+ var freshMeta=doc.querySelector('meta[name="stx-layout"]');
937
+ if(oldMeta&&freshMeta)oldMeta.setAttribute('content',freshMeta.getAttribute('content')||'');
938
+ else if(freshMeta){var m=document.createElement('meta');m.name='stx-layout';m.content=freshMeta.getAttribute('content')||'';document.head.appendChild(m)}
939
+ // Update container reference for script execution below
940
+ currentContent=document.querySelector(containerSel)||document.querySelector('main')||document.body;
941
+ } else {
942
+ // Same layout \u2014 swap only container content
943
+ var cleanHTML=newContent.innerHTML.replace(new RegExp('<scr'+'ipt\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/scr'+'ipt\\\\s*>','gi'),'');
944
+ currentContent.innerHTML=cleanHTML;
945
+ }
645
946
 
646
947
  // \u2500\u2500 Load new external <head> scripts \u2500\u2500
647
948
  var loadedSrcs={};
@@ -665,35 +966,59 @@ function getRouterScript() {
665
966
  document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});
666
967
 
667
968
  var scripts=[];
668
- doc.querySelectorAll('script').forEach(function(s){
669
- var text=s.textContent||'';
670
- // Skip the signals runtime
671
- if(text.indexOf('let activeEffect')!==-1)return;
672
- // Skip the router
673
- if(text.indexOf('__stxRouter')!==-1)return;
674
- // Skip layout shell scripts
675
- if(text.indexOf('__stxDashboardInit')!==-1||text.indexOf('__stxLayoutInit')!==-1)return;
676
- // Skip external scripts
677
- if(s.hasAttribute('src'))return;
678
- // Skip empty
679
- if(!text.trim())return;
680
- scripts.push(text);
681
- });
682
-
683
- function execScripts(){
684
- scripts.forEach(function(text){
685
- var ns=document.createElement('script');
686
- ns.textContent=text;
687
- ns.setAttribute('data-stx-page','');
688
- document.body.appendChild(ns);
969
+ if(isLayoutChange){
970
+ // Layout change: collect ALL scripts from the new document body
971
+ // (layout scripts, component mounts, setup functions \u2014 everything)
972
+ var newBodyEl=doc.querySelector('body');
973
+ if(newBodyEl){
974
+ newBodyEl.querySelectorAll('script').forEach(function(s){
975
+ var text=s.textContent||'';
976
+ if(s.hasAttribute('src'))return;
977
+ if(!text.trim())return;
978
+ // Skip the signals runtime IIFE \u2014 it's already loaded
979
+ if(text.indexOf("'use strict';var cloakStyle")!==-1)return;
980
+ if(text.indexOf('__stxRouter')!==-1)return;
981
+ scripts.push(text);
982
+ });
983
+ }
984
+ // Also collect setup functions from <head>
985
+ doc.querySelectorAll('head script').forEach(function(s){
986
+ var text=s.textContent||'';
987
+ if(s.hasAttribute('src'))return;
988
+ if(!text.trim())return;
989
+ if(text.indexOf('__stx_setup_')!==-1)scripts.push(text);
990
+ });
991
+ } else {
992
+ // Same layout: collect scripts from the container
993
+ newContent.querySelectorAll('script').forEach(function(s){
994
+ var text=s.textContent||'';
995
+ if(s.hasAttribute('src'))return;
996
+ if(!text.trim())return;
997
+ scripts.push(text);
998
+ });
999
+ // Collect setup scripts from <head> AND <body> (outside container).
1000
+ // SSG builds place the setup function in <body> before <main>, not
1001
+ // in <head>. Without this, SPA navigation on static sites never
1002
+ // runs the setup and reactive data stays empty.
1003
+ var seenSetups={};
1004
+ scripts.forEach(function(t){if(t.indexOf('__stx_setup_')!==-1)seenSetups[t.substring(0,80)]=1});
1005
+ doc.querySelectorAll('script').forEach(function(s){
1006
+ var text=s.textContent||'';
1007
+ if(s.hasAttribute('src'))return;
1008
+ if(!text.trim())return;
1009
+ if(text.indexOf('__stx_setup_')===-1)return;
1010
+ // Skip signals runtime and router (they contain __stx_setup references but aren't setup functions)
1011
+ if(text.indexOf("'use strict';var cloakStyle")!==-1)return;
1012
+ if(text.indexOf('__stxRouter')!==-1)return;
1013
+ var key=text.substring(0,80);
1014
+ if(seenSetups[key])return;
1015
+ seenSetups[key]=1;
1016
+ scripts.push(text);
689
1017
  });
690
1018
  }
691
1019
 
692
- if(extPromises.length>0){
693
- Promise.all(extPromises).then(execScripts).catch(execScripts);
694
- }else{
695
- execScripts();
696
- }
1020
+ // Push history state (before active link updates so location.pathname is current)
1021
+ if(pushState!==false)history.pushState({},'',url+(hash||''));
697
1022
 
698
1023
  // Update active nav links
699
1024
  updateNav(url);
@@ -707,17 +1032,47 @@ function getRouterScript() {
707
1032
  var newTitle=doc.querySelector('title');
708
1033
  if(newTitle)document.title=newTitle.textContent;
709
1034
 
710
- // Push history state
711
- if(pushState!==false)history.pushState({},'',url+(hash||''));
712
-
713
- // Dispatch navigation events
714
1035
  window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));
715
- window.dispatchEvent(new Event('stx:load'));
1036
+
1037
+ // Execute page scripts FIRST \u2014 they define setup functions and set _latestSetup
1038
+ function execScripts(){
1039
+ scripts.forEach(function(text){
1040
+ // Skip scripts that were already executed (layout-level partials
1041
+ // like theme.stx). Their top-level const/function declarations
1042
+ // would throw "Identifier has already been declared" on re-execution.
1043
+ // Exception: setup functions (__stx_setup_) must always re-execute
1044
+ // because each page has its own setup, and import statements
1045
+ // need special handling.
1046
+ var h=hashScript(text);
1047
+ var isSetup=text.indexOf('__stx_setup_')!==-1;
1048
+ var hasImport=text.indexOf('import ')!==-1;
1049
+ if(!isSetup&&executedScriptHashes[h])return;
1050
+ executedScriptHashes[h]=1;
1051
+ // Wrap scripts with import statements as modules (Bug 3 fix)
1052
+ var ns=document.createElement('script');
1053
+ if(hasImport){
1054
+ ns.type='module';
1055
+ }
1056
+ ns.textContent=text;
1057
+ ns.setAttribute('data-stx-page','');
1058
+ document.body.appendChild(ns);
1059
+ });
1060
+ // THEN fire stx:load \u2014 now _latestSetup is set and processElement has the right scope
1061
+ window.dispatchEvent(new Event('stx:load'));
1062
+ }
1063
+
1064
+ if(extPromises.length>0){
1065
+ Promise.all(extPromises).then(execScripts).catch(execScripts);
1066
+ }
1067
+ else {
1068
+ execScripts();
1069
+ }
716
1070
  }
717
1071
 
718
1072
  if(o.viewTransitions&&document.startViewTransition){
719
1073
  document.startViewTransition(doSwap);
720
- }else{
1074
+ }
1075
+ else {
721
1076
  // Fallback fade for browsers without View Transitions API
722
1077
  currentContent.style.transition='opacity 0.12s ease-out';
723
1078
  currentContent.style.opacity='0';
@@ -742,14 +1097,22 @@ function getRouterScript() {
742
1097
  return true;
743
1098
  }
744
1099
 
1100
+ // SPA click handling \u2014 only [data-stx-link] elements get SPA navigation.
1101
+ // Regular <a href> does native full page reload (no interception).
1102
+ // StxLink builtin renders <a data-stx-link href="...">, so we intercept those.
745
1103
  document.addEventListener('click',function(e){
746
1104
  if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0)return;
747
1105
  if(!e.target||!e.target.closest)return;
748
- var link=e.target.closest('a[href]');
749
- if(!shouldIntercept(link))return;
1106
+ var link=e.target.closest('[data-stx-link]');
1107
+ if(!link){return}
1108
+ var href=link.getAttribute('href');
1109
+ console.log('[router] click intercepted:',href,'container:',!!getContainer(),'defaultPrevented:',e.defaultPrevented);
1110
+ if(!href||href.startsWith('http')||href.startsWith('#')||href.startsWith('mailto:')||href.startsWith('tel:')){console.log('[router] skipped:',href);return}
1111
+ if(link.target==='_blank'||link.hasAttribute('download'))return;
750
1112
  e.preventDefault();
751
1113
  e.stopPropagation();
752
- navigate(link.getAttribute('href'));
1114
+ console.log('[router] navigating to:',href);
1115
+ navigate(href);
753
1116
  },true);
754
1117
 
755
1118
  // \u2500\u2500 Back/forward \u2500\u2500
@@ -761,14 +1124,17 @@ function getRouterScript() {
761
1124
  if(o.prefetch){
762
1125
  document.addEventListener('mouseover',function(e){
763
1126
  if(!e.target||!e.target.closest)return;
764
- var link=e.target.closest('a[href]');
765
- if(!shouldIntercept(link))return;
766
- // Only prefetch links with data-stx-prefetch or all internal links
1127
+ var link=e.target.closest('[data-stx-link]');
1128
+ if(!link)return;
767
1129
  var href=link.getAttribute('href');
768
1130
  if(cache[href]||prefetching[href])return;
769
1131
  prefetching[href]=true;
770
- fetch(href,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){return r.text()}).then(function(html){
771
- if(o.cache)cache[href]=html;
1132
+ fetch(href,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){
1133
+ var isFrag=r.headers.get('X-STX-Fragment')==='true';
1134
+ var pLayout=r.headers.get('X-STX-Layout')||'';
1135
+ return r.text().then(function(html){return{html:isFrag?'<!--stx-fragment-->'+html:html,layout:pLayout}});
1136
+ }).then(function(result){
1137
+ if(o.cache){cache[href]=result.html;layoutCache[href]=result.layout}
772
1138
  }).catch(function(){}).finally(function(){delete prefetching[href]});
773
1139
  },true);
774
1140
  }
@@ -779,23 +1145,21 @@ function getRouterScript() {
779
1145
  var href=a.getAttribute('href');
780
1146
  if(!href||href.startsWith('#')||href.startsWith('http'))return;
781
1147
  var isActive=(href===url)||(href==='/'&&url==='/');
782
- a.style.background=isActive?'var(--nav-active-bg, rgba(0,0,0,0.06))':'';
783
- a.style.color=isActive?'var(--text-primary, inherit)':'var(--text-nav, inherit)';
784
- a.style.fontWeight=isActive?'500':'';
785
1148
  if(a.hasAttribute('data-stx-link')){
786
1149
  var ac=a.getAttribute('data-stx-active-class')||'active';
787
- if(isActive)a.classList.add(ac);else a.classList.remove(ac);
1150
+ if(isActive)ac.split(' ').forEach(function(cls){if(cls)a.classList.add(cls)});else ac.split(' ').forEach(function(cls){if(cls)a.classList.remove(cls)});
788
1151
  }
789
1152
  });
790
1153
  }
791
1154
 
792
1155
  function updateActiveLinks(){
1156
+ // Update active classes on <stx-link> elements (and legacy data-stx-link)
793
1157
  var links=document.querySelectorAll('[data-stx-link]');
794
1158
  var cur=location.pathname;
795
1159
  links.forEach(function(link){
796
- var href=link.getAttribute('href')||'';
797
- var ac=link.getAttribute('data-stx-active-class')||'active';
798
- var eac=link.getAttribute('data-stx-exact-active-class')||'exact-active';
1160
+ var href=link.getAttribute('to')||link.getAttribute('href')||'';
1161
+ var ac=link.getAttribute('active-class')||link.getAttribute('data-stx-active-class')||'active';
1162
+ var eac=link.getAttribute('exact-active-class')||link.getAttribute('data-stx-exact-active-class')||'exact-active';
799
1163
  ac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});
800
1164
  eac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});
801
1165
  var isExact=cur===href;
@@ -805,12 +1169,47 @@ function getRouterScript() {
805
1169
  });
806
1170
  }
807
1171
 
808
- // \u2500\u2500 Loading bar + View Transitions CSS \u2500\u2500
1172
+ // \u2500\u2500 Progress bar DOM + style \u2500\u2500
1173
+ // Injects a fixed-position element at the top of the viewport plus the
1174
+ // minimal CSS for its transform/opacity transitions. Kept idempotent so
1175
+ // repeated init() calls (e.g. after full-body swaps) don't duplicate.
1176
+ // Also ships the default View Transitions fade+slide CSS when
1177
+ // viewTransitions is enabled and the browser supports it. Apps can
1178
+ // override by defining more specific ::view-transition-* rules later in
1179
+ // the cascade, or opt out entirely with viewTransitions:false.
809
1180
  function injectStyles(){
810
- if(document.getElementById('stx-r-css'))return;
811
- var s=document.createElement('style');s.id='stx-r-css';
812
- s.textContent='.stx-navigating{cursor:wait}.stx-navigating *{pointer-events:none}@keyframes stx-l{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.stx-navigating::before{content:\\'\\';position:fixed;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,#78dce8,transparent);animation:stx-l 1s ease-in-out infinite;z-index:99999}';
813
- document.head.appendChild(s);
1181
+ if(!document.getElementById('stx-r-css')){
1182
+ var s=document.createElement('style');s.id='stx-r-css';
1183
+ // Strip characters that could escape our CSS block and inject new
1184
+ // declarations: ; { } ( ) " ' \\ < > plus whitespace control chars.
1185
+ // This keeps the value safe to concat into a stylesheet even if a
1186
+ // caller wires the config from an untrusted source.
1187
+ var sanitize=function(v){return String(v).replace(/[;{}()"'\\\\<>\\n\\r\\t]/g,'')};
1188
+ var pc=sanitize(o.progressColor);
1189
+ var ph=sanitize(o.progressHeight);
1190
+ var css='.stx-navigating{cursor:wait}.stx-navigating a,.stx-navigating button{pointer-events:none}#stx-router-progress{position:fixed;top:0;left:0;right:0;height:'+ph+';background:'+pc+';box-shadow:0 0 8px '+pc+',0 0 4px '+pc+';transform:scaleX(0);transform-origin:left;transition:transform .18s ease-out,opacity .26s ease;opacity:0;pointer-events:none;z-index:999999}';
1191
+ if(o.viewTransitions&&'startViewTransition' in document){
1192
+ var dur=(o.viewTransitionDuration||220)+'ms';
1193
+ var ease=o.viewTransitionEasing||'cubic-bezier(0.16, 1, 0.3, 1)';
1194
+ css+='::view-transition-old(root),::view-transition-new(root){animation-duration:'+dur+';animation-timing-function:'+ease+'}';
1195
+ css+='::view-transition-old(root){animation-name:stx-r-fade-out}::view-transition-new(root){animation-name:stx-r-fade-in}';
1196
+ css+='@keyframes stx-r-fade-out{from{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}';
1197
+ css+='@keyframes stx-r-fade-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}';
1198
+ css+='@media (prefers-reduced-motion: reduce){::view-transition-old(root),::view-transition-new(root){animation-duration:0s;animation-name:none}}';
1199
+ }
1200
+ s.textContent=css;
1201
+ document.head.appendChild(s);
1202
+ }
1203
+ if(o.progress&&!document.getElementById('stx-router-progress')){
1204
+ var el=document.createElement('div');
1205
+ el.id='stx-router-progress';
1206
+ el.setAttribute('role','progressbar');
1207
+ el.setAttribute('aria-hidden','true');
1208
+ (document.body||document.documentElement).appendChild(el);
1209
+ progEl=el;
1210
+ } else if(o.progress){
1211
+ progEl=document.getElementById('stx-router-progress');
1212
+ }
814
1213
  }
815
1214
 
816
1215
  function injectViewTransitionCSS(){
@@ -826,7 +1225,7 @@ function getRouterScript() {
826
1225
  navigateTo:navigate,
827
1226
  prefetch:function(url){
828
1227
  if(!cache[url]){
829
- fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){return r.text()}).then(function(html){cache[url]=html}).catch(function(){});
1228
+ fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){var isFrag=r.headers.get('X-STX-Fragment')==='true';return r.text().then(function(html){return isFrag?'<!--stx-fragment-->'+html:html})}).then(function(html){cache[url]=html}).catch(function(){});
830
1229
  }
831
1230
  },
832
1231
  clearCache:function(){for(var k in cache)delete cache[k]},
@@ -867,6 +1266,7 @@ export {
867
1266
  getMiddlewareNames,
868
1267
  getMiddleware,
869
1268
  generateRouteTypes,
1269
+ generateRouteManifest,
870
1270
  formatRoutes,
871
1271
  findErrorPage,
872
1272
  filePathToPattern,
@@ -884,4 +1284,4 @@ export {
884
1284
  Router
885
1285
  };
886
1286
 
887
- //# debugId=3C52557F9211FAA564756E2164756E21
1287
+ //# debugId=F05C3AD3376ECE0E64756E2164756E21
package/dist/index.js.map CHANGED
@@ -2,15 +2,15 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/file-router.ts", "../src/codegen.ts", "../src/matcher.ts", "../src/nested-layouts.ts", "../src/named-routes.ts", "../src/middleware.ts", "../src/client.ts"],
4
4
  "sourcesContent": [
5
- "import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route, RouteMatch, RouterConfig } from './types'\nimport { generateRouteTypes } from './codegen'\nimport { filePathToPattern, patternToRegex } from './matcher'\nimport { resolveLayoutChain } from './nested-layouts'\n\nfunction scanDirectory(dir: string, extensions: string[]): string[] {\n const files: string[] = []\n\n if (!fs.existsSync(dir)) {\n return files\n }\n\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name.startsWith('.')) {\n continue\n }\n files.push(...scanDirectory(fullPath, extensions))\n }\n else if (entry.isFile()) {\n const ext = path.extname(entry.name)\n if (extensions.includes(ext)) {\n // Skip layout files from being routes themselves\n if (entry.name.startsWith('_') && entry.name !== '_layout.stx') {\n continue\n }\n // Don't register _layout.stx as a route\n if (entry.name === '_layout.stx') {\n continue\n }\n files.push(fullPath)\n }\n }\n }\n\n return files\n}\n\nexport class Router {\n routes: Route[]\n private pagesDir: string\n private config: RouterConfig\n\n constructor(baseDir: string, config: RouterConfig = {}) {\n this.config = config\n this.pagesDir = path.resolve(baseDir, config.pagesDir || 'pages')\n const extensions = config.extensions || ['.stx']\n\n const files = scanDirectory(this.pagesDir, extensions)\n\n this.routes = files.map((filePath) => {\n const pattern = filePathToPattern(filePath, this.pagesDir)\n const { regex, params } = patternToRegex(pattern)\n const layouts = config.layouts !== false ? resolveLayoutChain(filePath, this.pagesDir) : []\n\n return {\n pattern,\n regex,\n params,\n filePath,\n isDynamic: params.length > 0,\n layout: layouts.length > 0 ? layouts[layouts.length - 1] : undefined,\n }\n })\n\n // Sort: static before dynamic, more segments first\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n const aSegments = a.pattern.split('/').length\n const bSegments = b.pattern.split('/').length\n if (aSegments !== bSegments) return bSegments - aSegments\n return a.pattern.localeCompare(b.pattern)\n })\n\n // Generate type declarations\n const stxDir = path.join(baseDir, '.stx')\n generateRouteTypes(this.routes, stxDir)\n }\n\n match(pathname: string): RouteMatch | null {\n const normalizedPath = pathname === '' ? '/' : pathname\n\n for (const route of this.routes) {\n const m = normalizedPath.match(route.regex)\n if (m) {\n const params: Record<string, string> = {}\n route.params.forEach((name, index) => {\n params[name] = m[index + 1]\n })\n return { route, params }\n }\n }\n\n return null\n }\n\n resolve(name: string, params?: Record<string, string>): string {\n const route = this.routes.find(r => r.pattern === name || r.filePath.includes(name))\n if (!route) return '#not-found'\n\n let resolved = route.pattern\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n resolved = resolved.replace(`:${key}`, encodeURIComponent(value))\n }\n }\n return resolved\n }\n\n addRoute(route: Route): void {\n this.routes.push(route)\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n return a.pattern.localeCompare(b.pattern)\n })\n }\n\n getLayout(route: Route): string | null {\n return route.layout ?? null\n }\n}\n\nexport function createRouter(baseDir: string, config?: RouterConfig): Router {\n return new Router(baseDir, config)\n}\n\nexport function findErrorPage(pagesDir: string, statusCode: number): string | null {\n const candidates = [`${statusCode}.stx`, 'error.stx']\n for (const candidate of candidates) {\n const filePath = path.join(pagesDir, candidate)\n if (fs.existsSync(filePath)) return filePath\n }\n return null\n}\n\nexport function formatRoutes(routes: Route[], baseDir: string): string[] {\n return routes.map((route) => {\n const relativePath = path.relative(baseDir, route.filePath)\n const dynamicLabel = route.isDynamic ? ' (dynamic)' : ''\n return `${route.pattern} → ${relativePath}${dynamicLabel}`\n })\n}\n",
6
- "import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route } from './types'\n\nexport function generateRouteTypes(routes: Route[], outputDir: string): void {\n const lines = [\n '// Auto-generated by STX - do not edit',\n 'declare module \"stx/routes\" {',\n ' interface RouteMap {',\n ]\n\n for (const route of routes) {\n const paramEntries: string[] = []\n for (const p of route.params) {\n const type = route.pattern.includes(`:${p}*`) ? 'string[]' : 'string'\n paramEntries.push(`${p}: ${type}`)\n }\n const paramsStr = paramEntries.join('; ')\n lines.push(` '${route.pattern}': { ${paramsStr} }`)\n }\n\n lines.push(' }', '}', '')\n\n fs.mkdirSync(outputDir, { recursive: true })\n fs.writeFileSync(path.join(outputDir, 'route-types.d.ts'), lines.join('\\n'))\n}\n",
5
+ "import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route, RouteMatch, RouterConfig } from './types'\nimport { generateRouteTypes, generateRouteManifest } from './codegen'\nimport { filePathToPattern, patternToRegex } from './matcher'\nimport { resolveLayoutChain } from './nested-layouts'\n\nfunction scanDirectory(dir: string, extensions: string[]): string[] {\n const files: string[] = []\n\n if (!fs.existsSync(dir)) {\n return files\n }\n\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name.startsWith('.')) {\n continue\n }\n files.push(...scanDirectory(fullPath, extensions))\n }\n else if (entry.isFile()) {\n const ext = path.extname(entry.name)\n if (extensions.includes(ext)) {\n // Skip layout files from being routes themselves\n if (entry.name.startsWith('_') && entry.name !== '_layout.stx') {\n continue\n }\n // Don't register _layout.stx as a route\n if (entry.name === '_layout.stx') {\n continue\n }\n files.push(fullPath)\n }\n }\n }\n\n return files\n}\n\nexport class Router {\n routes: Route[]\n private pagesDir: string\n private config: RouterConfig\n\n constructor(baseDir: string, config: RouterConfig = {}) {\n this.config = config\n this.pagesDir = path.resolve(baseDir, config.pagesDir || 'pages')\n const extensions = config.extensions || ['.stx']\n\n const files = scanDirectory(this.pagesDir, extensions)\n\n this.routes = files.map((filePath) => {\n const pattern = filePathToPattern(filePath, this.pagesDir)\n const { regex, params } = patternToRegex(pattern)\n const layouts = config.layouts !== false ? resolveLayoutChain(filePath, this.pagesDir) : []\n\n return {\n pattern,\n regex,\n params,\n filePath,\n isDynamic: params.length > 0,\n layout: layouts.length > 0 ? layouts[layouts.length - 1] : undefined,\n }\n })\n\n // Sort: static before dynamic, more segments first\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n const aSegments = a.pattern.split('/').length\n const bSegments = b.pattern.split('/').length\n if (aSegments !== bSegments) return bSegments - aSegments\n return a.pattern.localeCompare(b.pattern)\n })\n\n // Generate type declarations and route manifest into .stx/\n const stxDir = path.join(baseDir, '.stx')\n generateRouteTypes(this.routes, stxDir)\n generateRouteManifest(this.routes, stxDir, this.pagesDir)\n }\n\n match(pathname: string): RouteMatch | null {\n const normalizedPath = pathname === '' ? '/' : pathname\n\n for (const route of this.routes) {\n const m = normalizedPath.match(route.regex)\n if (m) {\n const params: Record<string, string> = {}\n route.params.forEach((name, index) => {\n params[name] = m[index + 1]\n })\n return { route, params }\n }\n }\n\n return null\n }\n\n resolve(name: string, params?: Record<string, string>): string {\n const route = this.routes.find(r => r.pattern === name || r.filePath.includes(name))\n if (!route) return '#not-found'\n\n let resolved = route.pattern\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n resolved = resolved.replace(`:${key}`, encodeURIComponent(value))\n }\n }\n return resolved\n }\n\n addRoute(route: Route): void {\n this.routes.push(route)\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n return a.pattern.localeCompare(b.pattern)\n })\n }\n\n getLayout(route: Route): string | null {\n return route.layout ?? null\n }\n}\n\nexport function createRouter(baseDir: string, config?: RouterConfig): Router {\n return new Router(baseDir, config)\n}\n\nexport function findErrorPage(pagesDir: string, statusCode: number): string | null {\n const candidates = [`${statusCode}.stx`, 'error.stx']\n for (const candidate of candidates) {\n const filePath = path.join(pagesDir, candidate)\n if (fs.existsSync(filePath)) return filePath\n }\n return null\n}\n\nexport function formatRoutes(routes: Route[], baseDir: string): string[] {\n return routes.map((route) => {\n const relativePath = path.relative(baseDir, route.filePath)\n const dynamicLabel = route.isDynamic ? ' (dynamic)' : ''\n return `${route.pattern} → ${relativePath}${dynamicLabel}`\n })\n}\n",
6
+ "import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route } from './types'\n\nexport function generateRouteTypes(routes: Route[], outputDir: string): void {\n const lines = [\n '// Auto-generated by STX - do not edit',\n 'declare module \"stx/routes\" {',\n ' interface RouteMap {',\n ]\n\n for (const route of routes) {\n const paramEntries: string[] = []\n for (const p of route.params) {\n const type = route.pattern.includes(`:${p}*`) ? 'string[]' : 'string'\n paramEntries.push(`${p}: ${type}`)\n }\n const paramsStr = paramEntries.join('; ')\n lines.push(` '${route.pattern}': { ${paramsStr} }`)\n }\n\n lines.push(' }', '}', '')\n\n fs.mkdirSync(outputDir, { recursive: true })\n fs.writeFileSync(path.join(outputDir, 'route-types.d.ts'), lines.join('\\n'))\n}\n\n/**\n * Generate a route manifest file (.stx/routes.ts).\n *\n * Produces a TypeScript module exporting the full route array with patterns,\n * file paths, params, and layout references. Similar to Nuxt's .nuxt/routes.mjs.\n */\nexport function generateRouteManifest(routes: Route[], outputDir: string, pagesDir: string): void {\n const cwd = process.cwd()\n const relativePages = path.relative(cwd, pagesDir)\n\n // Filter out non-page files (components, layouts, partials)\n const excludeDirs = ['components', 'layouts', 'partials']\n const pageRoutes = routes.filter(r =>\n !excludeDirs.some(dir => r.pattern.startsWith(`/${dir}/`) || r.pattern === `/${dir}`),\n )\n\n const lines = [\n '// Auto-generated by stx — do not edit',\n `// Source: ${relativePages || 'pages'}/`,\n '',\n 'export const routes = [',\n ]\n\n for (const route of pageRoutes) {\n const relFile = path.relative(cwd, route.filePath).replace(/\\\\/g, '/')\n const params = JSON.stringify(route.params)\n const layoutStr = route.layout\n ? `, layout: '${path.relative(cwd, route.layout).replace(/\\\\/g, '/')}'`\n : ''\n lines.push(` { pattern: '${route.pattern}', filePath: '${relFile}', isDynamic: ${route.isDynamic}, params: ${params}${layoutStr} },`)\n }\n\n lines.push('] as const', '')\n lines.push('export type RouteName = typeof routes[number][\\'pattern\\']', '')\n\n fs.mkdirSync(outputDir, { recursive: true })\n fs.writeFileSync(path.join(outputDir, 'routes.ts'), lines.join('\\n'))\n}\n",
7
7
  "import path from 'node:path'\n\nexport function filePathToPattern(filePath: string, pagesDir: string): string {\n const relativePath = path.relative(pagesDir, filePath)\n let route = relativePath.replace(/\\.(stx|md)$/, '')\n\n route = route.split(path.sep).join('/')\n\n if (route === 'index') {\n return '/'\n }\n if (route.endsWith('/index')) {\n route = route.slice(0, -6)\n }\n\n // Convert [[param]] to :param? (optional) — BEFORE required params\n route = route.replace(/\\[\\[([^\\]]+)\\]\\]/g, ':$1?')\n\n // Convert [param] to :param\n route = route.replace(/\\[([^\\]]+)\\]/g, ':$1')\n\n // Convert [...param] to :param* (catch-all)\n route = route.replace(/:\\.\\.\\.([^/]+)/g, ':$1*')\n\n return `/${route}`\n}\n\nexport function patternToRegex(pattern: string): { regex: RegExp, params: string[] } {\n const params: string[] = []\n\n let regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\n // Handle optional params (/:param?)\n regexStr = regexStr.replace(/\\/:([^/]+)\\?/g, (_, name) => {\n params.push(name)\n return '(?:/([^/]+))?'\n })\n\n // Handle catch-all params (:param*)\n regexStr = regexStr.replace(/:([^/]+)\\*/g, (_, name) => {\n params.push(name)\n return '(.+)'\n })\n\n // Handle regular params (:param)\n regexStr = regexStr.replace(/:([^/]+)/g, (_, name) => {\n params.push(name)\n return '([^/]+)'\n })\n\n regexStr = `^${regexStr}$`\n\n return { regex: new RegExp(regexStr), params }\n}\n\nexport function matchRoute(pathname: string, routes: { pattern: string, regex: RegExp, params: string[] }[]): { route: typeof routes[0], params: Record<string, string> } | null {\n const normalizedPath = pathname === '' ? '/' : pathname\n\n for (const route of routes) {\n const match = normalizedPath.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, index) => {\n params[name] = match[index + 1]\n })\n return { route, params }\n }\n }\n\n return null\n}\n",
8
8
  "import fs from 'node:fs'\nimport path from 'node:path'\n\nexport function resolveLayoutChain(routeFilePath: string, pagesDir: string): string[] {\n const layouts: string[] = []\n let dir = path.dirname(routeFilePath)\n\n // Walk up from the route's directory to the pages root, collecting _layout.stx files\n while (dir.startsWith(pagesDir) || dir === pagesDir) {\n const layoutFile = path.join(dir, '_layout.stx')\n if (fs.existsSync(layoutFile)) {\n layouts.unshift(layoutFile) // Prepend so root layout is first\n }\n\n if (dir === pagesDir) break\n dir = path.dirname(dir)\n }\n\n return layouts\n}\n",
9
9
  "interface RouteDefinition {\n path: string\n name?: string\n params?: Record<string, any>\n}\n\nconst routes: Record<string, RouteDefinition> = {}\nlet appUrl: string = ''\n\nexport function setAppUrl(url: string): void {\n appUrl = url.replace(/\\/$/, '')\n}\n\nexport function defineRoute(name: string, routePath: string, params: Record<string, any> = {}): void {\n routes[name] = { path: routePath, name, params }\n}\n\nexport function defineRoutes(routeDefinitions: Record<string, string | RouteDefinition>): void {\n for (const [name, definition] of Object.entries(routeDefinitions)) {\n if (typeof definition === 'string') {\n routes[name] = { path: definition, name }\n }\n else {\n routes[name] = { ...definition, name }\n }\n }\n}\n\nexport function route(\n name: string,\n params: Record<string, any> = {},\n absolute = false,\n): string {\n const r = routes[name]\n\n if (!r) {\n console.warn(`Route [${name}] not defined.`)\n return '#undefined-route'\n }\n\n const mergedParams = { ...r.params, ...params }\n let routePath = r.path\n\n routePath = routePath.replace(/:(\\w+)/g, (_, paramName) => {\n const value = mergedParams[paramName]\n\n if (value === undefined) {\n console.warn(`Missing parameter [${paramName}] for route [${name}].`)\n return `:${paramName}`\n }\n\n delete mergedParams[paramName]\n return encodeURIComponent(String(value))\n })\n\n const remainingParams = Object.entries(mergedParams)\n if (remainingParams.length > 0) {\n const queryString = remainingParams\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&')\n\n routePath += (routePath.includes('?') ? '&' : '?') + queryString\n }\n\n return absolute && appUrl ? `${appUrl}${routePath}` : routePath\n}\n\nexport function resetRoutes(): void {\n for (const key of Object.keys(routes)) {\n delete routes[key]\n }\n appUrl = ''\n}\n",
10
10
  "import fs from 'node:fs'\nimport path from 'node:path'\nimport type {\n AbortNavigationResult,\n CookieManager,\n CookieOptions,\n MiddlewareContext,\n MiddlewareMode,\n MiddlewareOptions,\n MiddlewareResult,\n NavigateToOptions,\n NavigateToResult,\n NavigationError,\n NavigationResult,\n RouteLocation,\n RouteMiddlewareDefinition,\n RouteMiddlewareHandler,\n StorageManager,\n} from './types'\n\n// =============================================================================\n// Navigation Helpers\n// =============================================================================\n\nexport function navigateTo(navPath: string, options: NavigateToOptions = {}): NavigateToResult {\n return {\n type: 'redirect',\n path: navPath,\n options: {\n replace: options.replace ?? false,\n external: options.external ?? false,\n redirectCode: options.redirectCode ?? 302,\n },\n }\n}\n\nexport function abortNavigation(error: string | NavigationError): AbortNavigationResult {\n const normalizedError: NavigationError\n = typeof error === 'string' ? { statusCode: 500, message: error } : error\n\n return {\n type: 'abort',\n error: normalizedError,\n }\n}\n\n// =============================================================================\n// Middleware Definition\n// =============================================================================\n\nexport function defineMiddleware(\n handler: RouteMiddlewareHandler,\n options: MiddlewareOptions = {},\n): RouteMiddlewareDefinition {\n return {\n handler,\n mode: options.mode ?? 'universal',\n }\n}\n\n// =============================================================================\n// Cookie Manager\n// =============================================================================\n\nfunction parseCookies(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {}\n if (!cookieHeader) return cookies\n\n const pairs = cookieHeader.split(';')\n for (const pair of pairs) {\n const [name, ...rest] = pair.split('=')\n if (name) {\n const key = name.trim()\n const value = rest.join('=').trim()\n if (key) {\n cookies[key] = decodeURIComponent(value)\n }\n }\n }\n return cookies\n}\n\nfunction serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n\n if (options.expires) {\n const expires\n = typeof options.expires === 'number'\n ? new Date(Date.now() + options.expires * 1000)\n : options.expires\n cookie += `; Expires=${expires.toUTCString()}`\n }\n\n if (options.path) cookie += `; Path=${options.path}`\n if (options.domain) cookie += `; Domain=${options.domain}`\n if (options.secure) cookie += '; Secure'\n if (options.httpOnly) cookie += '; HttpOnly'\n if (options.sameSite) cookie += `; SameSite=${options.sameSite}`\n\n return cookie\n}\n\nexport function createServerCookieManager(\n request: Request,\n responseHeaders: Headers,\n): CookieManager {\n const cookieHeader = request.headers.get('cookie') || ''\n const cookies = parseCookies(cookieHeader)\n\n return {\n get(name: string): string | undefined {\n return cookies[name]\n },\n set(name: string, value: string, options: CookieOptions = {}): void {\n cookies[name] = value\n responseHeaders.append('Set-Cookie', serializeCookie(name, value, options))\n },\n delete(name: string): void {\n delete cookies[name]\n responseHeaders.append(\n 'Set-Cookie',\n serializeCookie(name, '', { expires: new Date(0), path: '/' }),\n )\n },\n getAll(): Record<string, string> {\n return { ...cookies }\n },\n }\n}\n\nexport function createClientCookieManager(): CookieManager {\n return {\n get(name: string): string | undefined {\n if (typeof document === 'undefined') return undefined\n const cookies = parseCookies(document.cookie)\n return cookies[name]\n },\n set(name: string, value: string, options: CookieOptions = {}): void {\n if (typeof document === 'undefined') return\n document.cookie = serializeCookie(name, value, options)\n },\n delete(name: string): void {\n if (typeof document === 'undefined') return\n document.cookie = serializeCookie(name, '', { expires: new Date(0), path: '/' })\n },\n getAll(): Record<string, string> {\n if (typeof document === 'undefined') return {}\n return parseCookies(document.cookie)\n },\n }\n}\n\n// =============================================================================\n// Storage Manager\n// =============================================================================\n\nexport function createStorageManager(): StorageManager {\n const available\n = typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n\n return {\n get(key: string): string | null {\n if (!available) return null\n try { return window.localStorage.getItem(key) }\n catch { return null }\n },\n set(key: string, value: string): void {\n if (!available) return\n try { window.localStorage.setItem(key, value) }\n catch { /* storage full or blocked */ }\n },\n remove(key: string): void {\n if (!available) return\n try { window.localStorage.removeItem(key) }\n catch { /* ignore */ }\n },\n isAvailable(): boolean {\n return available\n },\n }\n}\n\n// =============================================================================\n// Middleware Registry\n// =============================================================================\n\nconst middlewareRegistry = new Map<string, RouteMiddlewareDefinition>()\n\nexport function registerMiddleware(name: string, middleware: RouteMiddlewareDefinition): void {\n middlewareRegistry.set(name, middleware)\n}\n\nexport function getMiddleware(name: string): RouteMiddlewareDefinition | undefined {\n return middlewareRegistry.get(name)\n}\n\nexport function hasMiddleware(name: string): boolean {\n return middlewareRegistry.has(name)\n}\n\nexport function clearMiddleware(): void {\n middlewareRegistry.clear()\n}\n\nexport function getMiddlewareNames(): string[] {\n return Array.from(middlewareRegistry.keys())\n}\n\n// =============================================================================\n// Middleware Loading\n// =============================================================================\n\nexport async function loadMiddlewareFromDirectory(\n baseDir: string,\n middlewareDir: string = 'middleware',\n): Promise<void> {\n const fullPath = path.resolve(baseDir, middlewareDir)\n\n if (!fs.existsSync(fullPath)) {\n return\n }\n\n const files = fs.readdirSync(fullPath)\n\n for (const file of files) {\n if (!file.endsWith('.ts') && !file.endsWith('.js')) continue\n if (file.includes('.test.') || file.includes('.spec.')) continue\n\n const name = file.replace(/\\.(ts|js)$/, '')\n const filePath = path.join(fullPath, file)\n\n try {\n const mod = await import(filePath)\n const mw = mod.default\n\n if (mw && typeof mw.handler === 'function') {\n registerMiddleware(name, mw)\n }\n else if (typeof mw === 'function') {\n registerMiddleware(name, { handler: mw, mode: 'universal' })\n }\n }\n catch (error) {\n console.warn(`Failed to load middleware '${name}' from ${filePath}:`, error)\n }\n }\n}\n\n// =============================================================================\n// Middleware Context & Execution\n// =============================================================================\n\nfunction parseQuery(search: string): Record<string, string> {\n const query: Record<string, string> = {}\n if (!search) return query\n\n const params = new URLSearchParams(search)\n for (const [key, value] of params) {\n query[key] = value\n }\n return query\n}\n\nexport function createRouteLocation(\n pathname: string,\n params: Record<string, string>,\n meta: Record<string, unknown>,\n search: string = '',\n): RouteLocation {\n return {\n path: pathname,\n params,\n query: parseQuery(search),\n fullPath: search ? `${pathname}?${search}` : pathname,\n meta,\n }\n}\n\nexport function createMiddlewareContext(\n to: RouteLocation,\n from: RouteLocation | null,\n request?: Request,\n): MiddlewareContext {\n const isServer = typeof window === 'undefined'\n const isClient = !isServer\n const responseHeaders = new Headers()\n\n return {\n to,\n from,\n isClient,\n isServer,\n cookies: isServer && request\n ? createServerCookieManager(request, responseHeaders)\n : createClientCookieManager(),\n storage: createStorageManager(),\n state: {},\n request,\n responseHeaders,\n }\n}\n\nexport async function runMiddleware(\n middlewareNames: string | string[],\n context: MiddlewareContext,\n): Promise<MiddlewareResult> {\n const names = Array.isArray(middlewareNames) ? middlewareNames : [middlewareNames]\n const isServer = context.isServer\n\n for (const name of names) {\n const middleware = getMiddleware(name)\n\n if (!middleware) {\n console.warn(`Middleware '${name}' not found`)\n continue\n }\n\n if (middleware.mode === 'server' && !isServer) continue\n if (middleware.mode === 'client' && isServer) continue\n\n try {\n const result = await middleware.handler(context)\n\n if (result) {\n if (result.type === 'redirect') {\n return {\n passed: false,\n redirect: result,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n\n if (result.type === 'abort') {\n return {\n passed: false,\n abort: result,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n }\n }\n catch (error) {\n console.error(`Error in middleware '${name}':`, error)\n return {\n passed: false,\n abort: {\n type: 'abort',\n error: {\n statusCode: 500,\n message: error instanceof Error ? error.message : 'Middleware error',\n },\n },\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n }\n\n return {\n passed: true,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n}\n",
11
- "/**\n * STX Router - Canonical SPA Router\n *\n * Single source of truth for client-side navigation.\n * Injected via @stxRouter directive or auto-loaded with the signals runtime.\n *\n * Features:\n * - Click interception for internal links\n * - History API pushState navigation\n * - View Transitions API with CSS fade fallback\n * - <head> style swapping (prevents unstyled flash)\n * - Smart script filtering (skip signals runtime, layout guards)\n * - Page prefetching on hover\n * - Response caching (5-minute TTL)\n * - Active link class management (data-stx-link)\n * - Loading indicator bar\n * - Configurable via window.STX_ROUTER_OPTIONS or window.__stxRouterConfig\n */\nexport function getRouterScript(): string {\n return `\n;(function(){\n 'use strict';\n if(window.__stxRouter)return;\n\n // ── Configuration ──\n var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true};\n var o=Object.assign({},defaults,window.__stxRouterConfig||{},window.STX_ROUTER_OPTIONS||{});\n var containerSel=o.container;\n\n var cache={};\n var prefetching={};\n var isNavigating=false;\n\n function getContainer(){\n return document.querySelector(containerSel)||document.querySelector('[data-stx-content]')||document.querySelector('main');\n }\n\n // ── Navigation ──\n function navigate(url,pushState){\n if(isNavigating)return;\n var t=new URL(url,location.origin);\n\n // Different origin → full navigation\n if(t.origin!==location.origin){location.href=url;return}\n\n // Hash-only navigation on same page\n if(t.pathname===location.pathname&&t.hash){\n if(pushState!==false)history.pushState({},'',t.href);\n var el=document.querySelector(t.hash);\n if(el)el.scrollIntoView({behavior:'smooth'});\n return;\n }\n\n // Same page, no hash → skip\n if(t.href===location.href&&!t.hash)return;\n\n isNavigating=true;\n document.body.classList.add(o.loadingClass);\n\n var targetHref=t.href;\n var targetPath=t.pathname;\n var targetHash=t.hash;\n\n function done(){isNavigating=false;document.body.classList.remove(o.loadingClass)}\n\n if(o.cache&&cache[targetPath]){\n swap(cache[targetPath],targetPath,pushState,targetHash);\n done();\n }else{\n fetch(url,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){\n if(!r.ok)throw new Error(r.status);\n return r.text();\n }).then(function(html){\n if(o.cache)cache[targetPath]=html;\n swap(html,targetPath,pushState,targetHash);\n }).catch(function(){\n location.href=url;\n }).finally(done);\n }\n }\n\n function swap(html,url,pushState,hash){\n var parser=new DOMParser();\n var doc=parser.parseFromString(html,'text/html');\n var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');\n var currentContent=getContainer();\n if(!newContent||!currentContent){location.href=url;return}\n\n // Clean up existing signals/effects\n if(window.stx&&window.stx._cleanupContainer){\n window.stx._cleanupContainer(currentContent);\n }\n\n function doSwap(){\n // ── Swap <head> styles ──\n // Inject new styles FIRST, then remove old to prevent unstyled flash\n var keepIds={'stx-view-transitions':1,'stx-r-css':1};\n var curStyles=document.querySelectorAll('head style');\n var newStyles=doc.querySelectorAll('head style');\n\n var incoming=[];\n newStyles.forEach(function(s){\n if(!keepIds[s.id]){\n var ns=document.createElement('style');\n ns.textContent=s.textContent;\n ns.setAttribute('data-stx-incoming','');\n if(s.getAttribute('data-crosswind'))ns.setAttribute('data-crosswind',s.getAttribute('data-crosswind'));\n document.head.appendChild(ns);\n incoming.push(ns);\n }\n });\n\n // Remove old styles (except persistent ones and incoming)\n curStyles.forEach(function(s){\n if(!keepIds[s.id]&&!s.hasAttribute('data-stx-incoming'))s.remove();\n });\n\n incoming.forEach(function(s){s.removeAttribute('data-stx-incoming')});\n\n // ── Swap main content ──\n currentContent.innerHTML=newContent.innerHTML;\n\n // ── Load new external <head> scripts ──\n var loadedSrcs={};\n document.querySelectorAll('head script[src]').forEach(function(s){loadedSrcs[s.src]=1});\n var extPromises=[];\n doc.querySelectorAll('head script[src]').forEach(function(s){\n var src=new URL(s.getAttribute('src'),location.origin).href;\n if(loadedSrcs[src])return;\n loadedSrcs[src]=1;\n extPromises.push(new Promise(function(resolve,reject){\n var ns=document.createElement('script');\n ns.src=src;\n ns.onload=resolve;\n ns.onerror=reject;\n document.head.appendChild(ns);\n }));\n });\n\n // ── Script re-execution ──\n // Remove previously injected page scripts\n document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});\n\n var scripts=[];\n doc.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n // Skip the signals runtime\n if(text.indexOf('let activeEffect')!==-1)return;\n // Skip the router\n if(text.indexOf('__stxRouter')!==-1)return;\n // Skip layout shell scripts\n if(text.indexOf('__stxDashboardInit')!==-1||text.indexOf('__stxLayoutInit')!==-1)return;\n // Skip external scripts\n if(s.hasAttribute('src'))return;\n // Skip empty\n if(!text.trim())return;\n scripts.push(text);\n });\n\n function execScripts(){\n scripts.forEach(function(text){\n var ns=document.createElement('script');\n ns.textContent=text;\n ns.setAttribute('data-stx-page','');\n document.body.appendChild(ns);\n });\n }\n\n if(extPromises.length>0){\n Promise.all(extPromises).then(execScripts).catch(execScripts);\n }else{\n execScripts();\n }\n\n // Update active nav links\n updateNav(url);\n updateActiveLinks();\n\n // Scroll\n if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});\n else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}\n\n // Update title\n var newTitle=doc.querySelector('title');\n if(newTitle)document.title=newTitle.textContent;\n\n // Push history state\n if(pushState!==false)history.pushState({},'',url+(hash||''));\n\n // Dispatch navigation events\n window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));\n window.dispatchEvent(new Event('stx:load'));\n }\n\n if(o.viewTransitions&&document.startViewTransition){\n document.startViewTransition(doSwap);\n }else{\n // Fallback fade for browsers without View Transitions API\n currentContent.style.transition='opacity 0.12s ease-out';\n currentContent.style.opacity='0';\n setTimeout(function(){\n doSwap();\n currentContent.style.opacity='1';\n setTimeout(function(){currentContent.style.transition=''},150);\n },120);\n }\n }\n\n // ── Link interception ──\n function shouldIntercept(link){\n if(!link)return false;\n var href=link.getAttribute('href');\n if(!href)return false;\n if(href.startsWith('http')||href.startsWith('#')||href.startsWith('mailto:')||href.startsWith('tel:')||href.startsWith('javascript:'))return false;\n if(link.target==='_blank')return false;\n if(link.hasAttribute('data-stx-no-router')||link.hasAttribute('data-no-router')||link.hasAttribute('download'))return false;\n if(href===location.pathname)return false;\n if(!getContainer())return false;\n return true;\n }\n\n document.addEventListener('click',function(e){\n if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0)return;\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('a[href]');\n if(!shouldIntercept(link))return;\n e.preventDefault();\n e.stopPropagation();\n navigate(link.getAttribute('href'));\n },true);\n\n // ── Back/forward ──\n window.addEventListener('popstate',function(){\n navigate(location.pathname+location.search+location.hash,false);\n });\n\n // ── Prefetch on hover ──\n if(o.prefetch){\n document.addEventListener('mouseover',function(e){\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('a[href]');\n if(!shouldIntercept(link))return;\n // Only prefetch links with data-stx-prefetch or all internal links\n var href=link.getAttribute('href');\n if(cache[href]||prefetching[href])return;\n prefetching[href]=true;\n fetch(href,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){return r.text()}).then(function(html){\n if(o.cache)cache[href]=html;\n }).catch(function(){}).finally(function(){delete prefetching[href]});\n },true);\n }\n\n // ── Active link management ──\n function updateNav(url){\n document.querySelectorAll('nav a[href], #mobileNav a[href], [data-stx-nav] a[href]').forEach(function(a){\n var href=a.getAttribute('href');\n if(!href||href.startsWith('#')||href.startsWith('http'))return;\n var isActive=(href===url)||(href==='/'&&url==='/');\n a.style.background=isActive?'var(--nav-active-bg, rgba(0,0,0,0.06))':'';\n a.style.color=isActive?'var(--text-primary, inherit)':'var(--text-nav, inherit)';\n a.style.fontWeight=isActive?'500':'';\n if(a.hasAttribute('data-stx-link')){\n var ac=a.getAttribute('data-stx-active-class')||'active';\n if(isActive)a.classList.add(ac);else a.classList.remove(ac);\n }\n });\n }\n\n function updateActiveLinks(){\n var links=document.querySelectorAll('[data-stx-link]');\n var cur=location.pathname;\n links.forEach(function(link){\n var href=link.getAttribute('href')||'';\n var ac=link.getAttribute('data-stx-active-class')||'active';\n var eac=link.getAttribute('data-stx-exact-active-class')||'exact-active';\n ac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n eac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n var isExact=cur===href;\n var isActive=href!=='/'?cur.startsWith(href):cur==='/';\n if(isExact)eac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n if(isActive)ac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n });\n }\n\n // ── Loading bar + View Transitions CSS ──\n function injectStyles(){\n if(document.getElementById('stx-r-css'))return;\n var s=document.createElement('style');s.id='stx-r-css';\n s.textContent='.stx-navigating{cursor:wait}.stx-navigating *{pointer-events:none}@keyframes stx-l{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.stx-navigating::before{content:\\\\'\\\\';position:fixed;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,#78dce8,transparent);animation:stx-l 1s ease-in-out infinite;z-index:99999}';\n document.head.appendChild(s);\n }\n\n function injectViewTransitionCSS(){\n if(document.getElementById('stx-view-transitions'))return;\n var s=document.createElement('style');s.id='stx-view-transitions';\n s.textContent='::view-transition-group(root){animation:none}::view-transition-old(root){animation:none}::view-transition-new(root){animation:none}#app-content,[data-stx-content]{view-transition-name:stx-content}::view-transition-old(stx-content){animation:stx-fade-out .15s ease-out both}::view-transition-new(stx-content){animation:stx-fade-in .15s ease-in .1s both}@keyframes stx-fade-out{from{opacity:1}to{opacity:0}}@keyframes stx-fade-in{from{opacity:0}to{opacity:1}}::view-transition{background:transparent}::view-transition-group(stx-content){background:inherit;overflow:hidden}';\n (document.head||document.documentElement).appendChild(s);\n }\n\n // ── Public API ──\n var router={\n navigate:navigate,\n navigateTo:navigate,\n prefetch:function(url){\n if(!cache[url]){\n fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){return r.text()}).then(function(html){cache[url]=html}).catch(function(){});\n }\n },\n clearCache:function(){for(var k in cache)delete cache[k]},\n cache:cache,\n swap:swap,\n updateNav:updateNav\n };\n\n window.__stxRouter=router;\n window.stxRouter=router;\n if(window.stx)window.stx.router=router;\n\n // ── Initialize ──\n function init(){\n injectStyles();\n injectViewTransitionCSS();\n updateActiveLinks();\n updateNav(location.pathname);\n }\n\n if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();\n})();\n`\n}\n"
11
+ "/* eslint-disable prefer-const, no-console, style/max-statements-per-line, general/prefer-template */\n/**\n * STX Router - Canonical SPA Router\n *\n * Single source of truth for client-side navigation.\n * Injected via @stxRouter directive or auto-loaded with the signals runtime.\n *\n * Features:\n * - Click interception for internal links\n * - History API pushState navigation\n * - View Transitions API with CSS fade fallback\n * - <head> style swapping (prevents unstyled flash)\n * - Smart script filtering (skip signals runtime, layout guards)\n * - Page prefetching on hover\n * - Response caching (5-minute TTL)\n * - Active link class management (data-stx-link)\n * - Loading indicator bar\n * - Configurable via window.STX_ROUTER_OPTIONS or window.__stxRouterConfig\n */\nexport function getRouterScript(): string {\n return `\n;(function(){\n 'use strict';\n if(window.__stxRouter)return;\n\n // ── Configuration ──\n var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true,progress:true,progressColor:'#78dce8',progressHeight:'2px'};\n var o=Object.assign({},defaults,window.__stxRouterConfig||{},window.STX_ROUTER_OPTIONS||{});\n var containerSel=o.container;\n\n // ── Progress bar (0→100% at top of viewport) ──\n // Native loading indicator baked into the router. Starts when navigation\n // begins, trickles up to ~90% during fetch, snaps to 100% + fades on\n // completion. Opt-out via window.__stxRouterConfig={progress:false}.\n var progEl=null;\n var progVal=0;\n var progTimer=null;\n function setProgress(v){\n progVal=v<0?0:(v>100?100:v);\n if(!progEl)return;\n progEl.style.opacity=progVal>0?'1':'0';\n progEl.style.transform='scaleX('+(progVal/100)+')';\n }\n function startProgress(){\n if(!o.progress||!progEl)return;\n if(progTimer){clearInterval(progTimer);progTimer=null}\n setProgress(8);\n progTimer=setInterval(function(){\n if(progVal>=90)return;\n // Asymptotic trickle — fast at first, slower near 90%\n var inc=Math.max(0.4,(90-progVal)*0.08);\n setProgress(progVal+inc);\n },160);\n }\n function finishProgress(){\n if(!o.progress||!progEl)return;\n if(progTimer){clearInterval(progTimer);progTimer=null}\n setProgress(100);\n // Fade out, then reset. Delays chosen so the \"full\" state is briefly\n // visible before the bar disappears.\n setTimeout(function(){\n if(!progEl)return;\n progEl.style.opacity='0';\n setTimeout(function(){progVal=0;if(progEl)progEl.style.transform='scaleX(0)'},260);\n },180);\n }\n\n var cache={};\n var prefetching={};\n var isNavigating=false;\n\n // Extract top-level CSS blocks (rules AND @media blocks with nested braces).\n // The old regex ([^{}]+\\{[^{}]*\\}) silently dropped @media blocks because\n // it couldn't handle nested braces — causing responsive classes (lg:, md:)\n // to vanish after SPA navigation.\n function extractCssBlocks(css){\n var blocks=[];\n var i=0;\n var len=css.length;\n while(i<len){\n // Skip whitespace\n while(i<len&&(css[i]===' '||css[i]==='\\\\n'||css[i]==='\\\\r'||css[i]==='\\\\t'))i++;\n if(i>=len)break;\n // Find the start of a block (first {)\n var blockStart=i;\n var bracePos=css.indexOf('{',i);\n if(bracePos===-1)break;\n // Walk forward tracking brace depth to find the matching close\n var depth=0;\n var j=bracePos;\n while(j<len){\n if(css[j]==='{')depth++;\n else if(css[j]==='}'){depth--;if(depth===0){j++;break}}\n j++;\n }\n if(depth!==0)break;\n blocks.push(css.slice(blockStart,j).trim());\n i=j;\n }\n return blocks;\n }\n\n function mergeCrosswindCSS(existing,incoming){\n var blocks=extractCssBlocks(incoming);\n var newBlocks=[];\n for(var bi=0;bi<blocks.length;bi++){\n if(existing.indexOf(blocks[bi])===-1)newBlocks.push(blocks[bi]);\n }\n if(newBlocks.length>0)return existing+'\\\\n'+newBlocks.join('\\\\n');\n return null;\n }\n\n function getContainer(){\n return document.querySelector(containerSel)||document.querySelector('[data-stx-content]')||document.querySelector('main');\n }\n\n // ── Navigation ──\n // Layout group detection — layouts in the same group share a <main> container.\n // Only truly different layout groups trigger a full page reload.\n var layoutCache={};\n // Track executed script hashes to prevent redeclaration errors on navigation.\n // Layout-level scripts (theme, nav setup) execute on initial page load and\n // should NOT re-execute when navigating to another page with the same layout.\n var executedScriptHashes={};\n function hashScript(code){\n var h=0;for(var i=0;i<code.length;i++){h=((h<<5)-h)+code.charCodeAt(i);h|=0}\n return h;\n }\n // Record scripts from the initial page load\n document.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n if(text.trim()&&!s.hasAttribute('src'))executedScriptHashes[hashScript(text)]=1;\n });\n function getLayoutGroup(layout){\n if(!layout)return 'app';\n if(layout.indexOf('auth')!==-1||layout.indexOf('guest')!==-1)return 'auth';\n return 'app';\n }\n function checkLayoutChange(newLayout,targetUrl){\n var currentLayout=document.querySelector('meta[name=\"stx-layout\"]');\n var curLayoutName=currentLayout?currentLayout.getAttribute('content'):'';\n var curGroup=getLayoutGroup(curLayoutName);\n var newGroup=getLayoutGroup(newLayout);\n console.log('[router] layout check: current='+curLayoutName+'('+curGroup+') new='+(newLayout||'')+'('+newGroup+')');\n // Different layout GROUP (e.g. app → auth): full reload\n if(curGroup!==newGroup){\n console.log('[router] layout group change:',curGroup,'→',newGroup,'— full reload to:',targetUrl);\n return true;\n }\n // Same group but different SPECIFIC layout (e.g. layouts/app → layouts/coach):\n // full body swap so nav, sidebar, and other layout-level elements update\n if(curLayoutName && newLayout && curLayoutName!==newLayout){\n console.log('[router] layout name change:',curLayoutName,'→',newLayout,'— full body swap');\n return true;\n }\n return false;\n }\n\n function navigate(url,pushState,force){\n console.log('[router] navigate() called:',url,'isNavigating:',isNavigating);\n if(isNavigating)return;\n var t=new URL(url,location.origin);\n\n if(t.origin!==location.origin){location.href=url;return}\n\n if(t.pathname===location.pathname&&t.hash){\n if(pushState!==false)history.pushState({},'',t.href);\n var el=document.querySelector(t.hash);\n if(el)el.scrollIntoView({behavior:'smooth'});\n return;\n }\n\n if(t.href===location.href&&!t.hash&&!force)return;\n\n isNavigating=true;\n document.body.classList.add(o.loadingClass);\n startProgress();\n\n var targetHref=t.href;\n var targetPath=t.pathname;\n var targetHash=t.hash;\n\n function done(){isNavigating=false;document.body.classList.remove(o.loadingClass);finishProgress()}\n\n if(o.cache&&cache[targetPath]&&!force){\n if(checkLayoutChange(layoutCache[targetPath],url)){\n // Layout changed — fetch full page and do full document swap\n console.log('[router] cache hit but layout changed — fetching full page');\n fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){\n if(!r.ok)throw new Error(r.status);\n return r.text();\n }).then(function(html){\n console.log('[router] full page fetched from cache path, len:',html.length);\n swap(html,targetPath,pushState,targetHash);\n }).catch(function(err){\n console.error('[router] full page fetch error:',err);\n location.href=url;\n }).finally(done);\n return;\n }\n swap(cache[targetPath],targetPath,pushState,targetHash);\n done();\n }\nelse {\n if(force&&cache[targetPath])delete cache[targetPath];\n // First fetch as fragment (SPA mode)\n fetch(url,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){\n if(!r.ok)throw new Error(r.status);\n var isFragment=r.headers.get('X-STX-Fragment')==='true';\n var newLayout=r.headers.get('X-STX-Layout')||'';\n // Layout change? Fetch the FULL page (no X-STX-Router header) and do full document swap\n if(isFragment&&checkLayoutChange(newLayout,url)){\n console.log('[router] layout change — fetching full page for document swap');\n return fetch(url,{headers:{'Accept':'text/html'}}).then(function(fullRes){\n console.log('[router] full page fetched:',fullRes.status,'ok:',fullRes.ok);\n if(!fullRes.ok)throw new Error(fullRes.status);\n return fullRes.text().then(function(html){\n console.log('[router] full page html length:',html.length);\n return{html:html,isFragment:false,layout:newLayout};\n });\n });\n }\n return r.text().then(function(html){return{html:html,isFragment:isFragment,layout:newLayout}});\n }).then(function(result){\n if(!result)return;\n if(result.isFragment)result.html='<!--stx-fragment-->'+result.html;\n if(o.cache){cache[targetPath]=result.html;layoutCache[targetPath]=result.layout}\n swap(result.html,targetPath,pushState,targetHash);\n }).catch(function(err){\n console.error('[router] fetch error:',err);\n location.href=url;\n }).finally(done);\n }\n }\n\n function swap(html,url,pushState,hash){\n var isFragment=html.indexOf('<!--stx-fragment-->')===0;\n if(isFragment)html=html.slice('<!--stx-fragment-->'.length);\n var currentContent=getContainer();\n console.log('[router] swap: isFragment='+isFragment+' container='+!!currentContent+' htmlLen='+html.length);\n if(!currentContent){console.log('[router] no container — falling back');location.href=url;return}\n\n // Fragment mode: server returned just the page content (no document wrapper)\n if(isFragment){\n if(window.stx&&window.stx._cleanupContainer)window.stx._cleanupContainer(currentContent);\n function doFragSwap(){\n // Extract scripts from fragment before injecting HTML\n var fragScripts=[];\n var fragStyles=[];\n var fragCrosswindCSS=null;\n var cleanFrag=html.replace(new RegExp('<scr'+'ipt\\\\\\\\b[^>]*>([\\\\\\\\s\\\\\\\\S]*?)<\\\\\\\\/scr'+'ipt>','gi'),function(m,code){\n if(code&&code.trim())fragScripts.push(code);\n return '';\n });\n cleanFrag=cleanFrag.replace(new RegExp('<sty'+'le\\\\\\\\b([^>]*)>([\\\\\\\\s\\\\\\\\S]*?)<\\\\\\\\/sty'+'le>','gi'),function(m,attrs,css){\n if(attrs.indexOf('data-crosswind')!==-1){\n fragCrosswindCSS=css;\n }else{\n fragStyles.push({attrs:attrs,css:css});\n }\n return '';\n });\n // Remove old page styles (not crosswind — that gets merged)\n document.querySelectorAll('style[data-stx-page]').forEach(function(s){s.remove()});\n // Merge crosswind CSS from fragment into existing crosswind style\n if(fragCrosswindCSS){\n var curCrosswind=document.querySelector('head style[data-crosswind]');\n if(curCrosswind){\n var merged=mergeCrosswindCSS(curCrosswind.textContent||'',fragCrosswindCSS);\n if(merged)curCrosswind.textContent=merged;\n }else{\n var cw=document.createElement('style');\n cw.setAttribute('data-crosswind','generated');\n cw.textContent=fragCrosswindCSS;\n document.head.appendChild(cw);\n }\n }\n // Add new page styles\n fragStyles.forEach(function(s){\n var el=document.createElement('style');\n el.textContent=s.css;\n el.setAttribute('data-stx-page','');\n document.head.appendChild(el);\n });\n // Swap content\n currentContent.innerHTML=cleanFrag;\n // Remove old page scripts\n document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});\n if(pushState!==false)history.pushState({},'',url+(hash||''));\n updateNav(url);\n updateActiveLinks();\n if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});\n else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}\n window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));\n // Execute page scripts FIRST — they define setup functions and set _latestSetup\n console.log('[router] frag scripts:', fragScripts.length);\n document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});\n fragScripts.forEach(function(code){\n console.log('[router] exec script len:', code.length, 'has __stx_setup:', code.indexOf('__stx_setup')>-1);\n var ns=document.createElement('script');\n ns.textContent=code;\n ns.setAttribute('data-stx-page','');\n document.body.appendChild(ns);\n });\n console.log('[router] scripts done. _latestSetup:', !!window.stx._latestSetup);\n // THEN fire stx:load — now _latestSetup is set and processElement has the right scope\n window.dispatchEvent(new Event('stx:load'));\n }\n if(o.viewTransitions&&document.startViewTransition){document.startViewTransition(doFragSwap)}\n else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){doFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}\n return;\n }\n\n // Full document mode: parse with DOMParser and extract container content\n var parser=new DOMParser();\n var doc=parser.parseFromString(html,'text/html');\n var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');\n if(!newContent){location.href=url;return}\n\n // Clean up existing signals/effects\n if(window.stx&&window.stx._cleanupContainer){\n window.stx._cleanupContainer(currentContent);\n }\n\n function doSwap(){\n // ── Swap <head> styles ──\n // Inject new styles FIRST, then remove old to prevent unstyled flash\n var keepIds={'stx-view-transitions':1,'stx-r-css':1};\n var curStyles=document.querySelectorAll('head style');\n var newStyles=doc.querySelectorAll('head style');\n\n // Merge crosswind styles instead of replacing — persistent elements\n // (nav, footer) outside <main> still need their utility classes\n var curCrosswind=document.querySelector('head style[data-crosswind]');\n var newCrosswind=null;\n newStyles.forEach(function(s){if(s.getAttribute('data-crosswind'))newCrosswind=s});\n\n if(curCrosswind&&newCrosswind){\n var merged=mergeCrosswindCSS(curCrosswind.textContent||'',newCrosswind.textContent||'');\n if(merged)curCrosswind.textContent=merged;\n }\n\n var incoming=[];\n newStyles.forEach(function(s){\n if(!keepIds[s.id]&&!s.getAttribute('data-crosswind')){\n var ns=document.createElement('style');\n ns.textContent=s.textContent;\n ns.setAttribute('data-stx-incoming','');\n document.head.appendChild(ns);\n incoming.push(ns);\n }\n });\n\n // If no existing crosswind but new page has one, add it\n if(!curCrosswind&&newCrosswind){\n var ns=document.createElement('style');\n ns.textContent=newCrosswind.textContent;\n ns.setAttribute('data-crosswind',newCrosswind.getAttribute('data-crosswind'));\n document.head.appendChild(ns);\n }\n\n // Remove old styles (except persistent ones, crosswind, and incoming)\n curStyles.forEach(function(s){\n if(!keepIds[s.id]&&!s.hasAttribute('data-stx-incoming')&&!s.hasAttribute('data-crosswind'))s.remove();\n });\n\n incoming.forEach(function(s){s.removeAttribute('data-stx-incoming')});\n\n // ── Swap content ──\n // For layout changes: swap the entire <body> to replace layout chrome (nav, footer, etc.)\n // For same-layout: swap only the container (<main>)\n var newBody=doc.querySelector('body');\n var isLayoutChange=false;\n if(newBody){\n var newMeta=doc.querySelector('meta[name=\"stx-layout\"]');\n var curMeta=document.querySelector('meta[name=\"stx-layout\"]');\n var curGroup=getLayoutGroup(curMeta?curMeta.getAttribute('content'):'');\n var newGroup=getLayoutGroup(newMeta?newMeta.getAttribute('content'):'');\n isLayoutChange=curGroup!==newGroup;\n }\n if(isLayoutChange&&newBody){\n console.log('[router] full body swap for layout change');\n // Replace entire body content — layout chrome and all\n var bodyHTML=newBody.innerHTML.replace(new RegExp('<scr'+'ipt\\\\\\\\b[^>]*>[\\\\\\\\s\\\\\\\\S]*?<\\\\\\\\/scr'+'ipt\\\\\\\\s*>','gi'),'');\n document.body.innerHTML=bodyHTML;\n // Copy body attributes (class, data-stx, etc.)\n Array.from(newBody.attributes).forEach(function(attr){document.body.setAttribute(attr.name,attr.value)});\n // Update layout meta tag\n var oldMeta=document.querySelector('meta[name=\"stx-layout\"]');\n var freshMeta=doc.querySelector('meta[name=\"stx-layout\"]');\n if(oldMeta&&freshMeta)oldMeta.setAttribute('content',freshMeta.getAttribute('content')||'');\n else if(freshMeta){var m=document.createElement('meta');m.name='stx-layout';m.content=freshMeta.getAttribute('content')||'';document.head.appendChild(m)}\n // Update container reference for script execution below\n currentContent=document.querySelector(containerSel)||document.querySelector('main')||document.body;\n } else {\n // Same layout — swap only container content\n var cleanHTML=newContent.innerHTML.replace(new RegExp('<scr'+'ipt\\\\\\\\b[^>]*>[\\\\\\\\s\\\\\\\\S]*?<\\\\\\\\/scr'+'ipt\\\\\\\\s*>','gi'),'');\n currentContent.innerHTML=cleanHTML;\n }\n\n // ── Load new external <head> scripts ──\n var loadedSrcs={};\n document.querySelectorAll('head script[src]').forEach(function(s){loadedSrcs[s.src]=1});\n var extPromises=[];\n doc.querySelectorAll('head script[src]').forEach(function(s){\n var src=new URL(s.getAttribute('src'),location.origin).href;\n if(loadedSrcs[src])return;\n loadedSrcs[src]=1;\n extPromises.push(new Promise(function(resolve,reject){\n var ns=document.createElement('script');\n ns.src=src;\n ns.onload=resolve;\n ns.onerror=reject;\n document.head.appendChild(ns);\n }));\n });\n\n // ── Script re-execution ──\n // Remove previously injected page scripts\n document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});\n\n var scripts=[];\n if(isLayoutChange){\n // Layout change: collect ALL scripts from the new document body\n // (layout scripts, component mounts, setup functions — everything)\n var newBodyEl=doc.querySelector('body');\n if(newBodyEl){\n newBodyEl.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n if(s.hasAttribute('src'))return;\n if(!text.trim())return;\n // Skip the signals runtime IIFE — it's already loaded\n if(text.indexOf(\"'use strict';var cloakStyle\")!==-1)return;\n if(text.indexOf('__stxRouter')!==-1)return;\n scripts.push(text);\n });\n }\n // Also collect setup functions from <head>\n doc.querySelectorAll('head script').forEach(function(s){\n var text=s.textContent||'';\n if(s.hasAttribute('src'))return;\n if(!text.trim())return;\n if(text.indexOf('__stx_setup_')!==-1)scripts.push(text);\n });\n } else {\n // Same layout: collect scripts from the container\n newContent.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n if(s.hasAttribute('src'))return;\n if(!text.trim())return;\n scripts.push(text);\n });\n // Collect setup scripts from <head> AND <body> (outside container).\n // SSG builds place the setup function in <body> before <main>, not\n // in <head>. Without this, SPA navigation on static sites never\n // runs the setup and reactive data stays empty.\n var seenSetups={};\n scripts.forEach(function(t){if(t.indexOf('__stx_setup_')!==-1)seenSetups[t.substring(0,80)]=1});\n doc.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n if(s.hasAttribute('src'))return;\n if(!text.trim())return;\n if(text.indexOf('__stx_setup_')===-1)return;\n // Skip signals runtime and router (they contain __stx_setup references but aren't setup functions)\n if(text.indexOf(\"'use strict';var cloakStyle\")!==-1)return;\n if(text.indexOf('__stxRouter')!==-1)return;\n var key=text.substring(0,80);\n if(seenSetups[key])return;\n seenSetups[key]=1;\n scripts.push(text);\n });\n }\n\n // Push history state (before active link updates so location.pathname is current)\n if(pushState!==false)history.pushState({},'',url+(hash||''));\n\n // Update active nav links\n updateNav(url);\n updateActiveLinks();\n\n // Scroll\n if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});\n else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}\n\n // Update title\n var newTitle=doc.querySelector('title');\n if(newTitle)document.title=newTitle.textContent;\n\n window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));\n\n // Execute page scripts FIRST — they define setup functions and set _latestSetup\n function execScripts(){\n scripts.forEach(function(text){\n // Skip scripts that were already executed (layout-level partials\n // like theme.stx). Their top-level const/function declarations\n // would throw \"Identifier has already been declared\" on re-execution.\n // Exception: setup functions (__stx_setup_) must always re-execute\n // because each page has its own setup, and import statements\n // need special handling.\n var h=hashScript(text);\n var isSetup=text.indexOf('__stx_setup_')!==-1;\n var hasImport=text.indexOf('import ')!==-1;\n if(!isSetup&&executedScriptHashes[h])return;\n executedScriptHashes[h]=1;\n // Wrap scripts with import statements as modules (Bug 3 fix)\n var ns=document.createElement('script');\n if(hasImport){\n ns.type='module';\n }\n ns.textContent=text;\n ns.setAttribute('data-stx-page','');\n document.body.appendChild(ns);\n });\n // THEN fire stx:load — now _latestSetup is set and processElement has the right scope\n window.dispatchEvent(new Event('stx:load'));\n }\n\n if(extPromises.length>0){\n Promise.all(extPromises).then(execScripts).catch(execScripts);\n }\nelse {\n execScripts();\n }\n }\n\n if(o.viewTransitions&&document.startViewTransition){\n document.startViewTransition(doSwap);\n }\nelse {\n // Fallback fade for browsers without View Transitions API\n currentContent.style.transition='opacity 0.12s ease-out';\n currentContent.style.opacity='0';\n setTimeout(function(){\n doSwap();\n currentContent.style.opacity='1';\n setTimeout(function(){currentContent.style.transition=''},150);\n },120);\n }\n }\n\n // ── Link interception ──\n function shouldIntercept(link){\n if(!link)return false;\n var href=link.getAttribute('href');\n if(!href)return false;\n if(href.startsWith('http')||href.startsWith('#')||href.startsWith('mailto:')||href.startsWith('tel:')||href.startsWith('javascript:'))return false;\n if(link.target==='_blank')return false;\n if(link.hasAttribute('data-stx-no-router')||link.hasAttribute('data-no-router')||link.hasAttribute('download'))return false;\n if(href===location.pathname)return false;\n if(!getContainer())return false;\n return true;\n }\n\n // SPA click handling — only [data-stx-link] elements get SPA navigation.\n // Regular <a href> does native full page reload (no interception).\n // StxLink builtin renders <a data-stx-link href=\"...\">, so we intercept those.\n document.addEventListener('click',function(e){\n if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0)return;\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('[data-stx-link]');\n if(!link){return}\n var href=link.getAttribute('href');\n console.log('[router] click intercepted:',href,'container:',!!getContainer(),'defaultPrevented:',e.defaultPrevented);\n if(!href||href.startsWith('http')||href.startsWith('#')||href.startsWith('mailto:')||href.startsWith('tel:')){console.log('[router] skipped:',href);return}\n if(link.target==='_blank'||link.hasAttribute('download'))return;\n e.preventDefault();\n e.stopPropagation();\n console.log('[router] navigating to:',href);\n navigate(href);\n },true);\n\n // ── Back/forward ──\n window.addEventListener('popstate',function(){\n navigate(location.pathname+location.search+location.hash,false);\n });\n\n // ── Prefetch on hover ──\n if(o.prefetch){\n document.addEventListener('mouseover',function(e){\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('[data-stx-link]');\n if(!link)return;\n var href=link.getAttribute('href');\n if(cache[href]||prefetching[href])return;\n prefetching[href]=true;\n fetch(href,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){\n var isFrag=r.headers.get('X-STX-Fragment')==='true';\n var pLayout=r.headers.get('X-STX-Layout')||'';\n return r.text().then(function(html){return{html:isFrag?'<!--stx-fragment-->'+html:html,layout:pLayout}});\n }).then(function(result){\n if(o.cache){cache[href]=result.html;layoutCache[href]=result.layout}\n }).catch(function(){}).finally(function(){delete prefetching[href]});\n },true);\n }\n\n // ── Active link management ──\n function updateNav(url){\n document.querySelectorAll('nav a[href], #mobileNav a[href], [data-stx-nav] a[href]').forEach(function(a){\n var href=a.getAttribute('href');\n if(!href||href.startsWith('#')||href.startsWith('http'))return;\n var isActive=(href===url)||(href==='/'&&url==='/');\n if(a.hasAttribute('data-stx-link')){\n var ac=a.getAttribute('data-stx-active-class')||'active';\n if(isActive)ac.split(' ').forEach(function(cls){if(cls)a.classList.add(cls)});else ac.split(' ').forEach(function(cls){if(cls)a.classList.remove(cls)});\n }\n });\n }\n\n function updateActiveLinks(){\n // Update active classes on <stx-link> elements (and legacy data-stx-link)\n var links=document.querySelectorAll('[data-stx-link]');\n var cur=location.pathname;\n links.forEach(function(link){\n var href=link.getAttribute('to')||link.getAttribute('href')||'';\n var ac=link.getAttribute('active-class')||link.getAttribute('data-stx-active-class')||'active';\n var eac=link.getAttribute('exact-active-class')||link.getAttribute('data-stx-exact-active-class')||'exact-active';\n ac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n eac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n var isExact=cur===href;\n var isActive=href!=='/'?cur.startsWith(href):cur==='/';\n if(isExact)eac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n if(isActive)ac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n });\n }\n\n // ── Progress bar DOM + style ──\n // Injects a fixed-position element at the top of the viewport plus the\n // minimal CSS for its transform/opacity transitions. Kept idempotent so\n // repeated init() calls (e.g. after full-body swaps) don't duplicate.\n // Also ships the default View Transitions fade+slide CSS when\n // viewTransitions is enabled and the browser supports it. Apps can\n // override by defining more specific ::view-transition-* rules later in\n // the cascade, or opt out entirely with viewTransitions:false.\n function injectStyles(){\n if(!document.getElementById('stx-r-css')){\n var s=document.createElement('style');s.id='stx-r-css';\n // Strip characters that could escape our CSS block and inject new\n // declarations: ; { } ( ) \" ' \\\\ < > plus whitespace control chars.\n // This keeps the value safe to concat into a stylesheet even if a\n // caller wires the config from an untrusted source.\n var sanitize=function(v){return String(v).replace(/[;{}()\"'\\\\\\\\<>\\\\n\\\\r\\\\t]/g,'')};\n var pc=sanitize(o.progressColor);\n var ph=sanitize(o.progressHeight);\n var css='.stx-navigating{cursor:wait}.stx-navigating a,.stx-navigating button{pointer-events:none}#stx-router-progress{position:fixed;top:0;left:0;right:0;height:'+ph+';background:'+pc+';box-shadow:0 0 8px '+pc+',0 0 4px '+pc+';transform:scaleX(0);transform-origin:left;transition:transform .18s ease-out,opacity .26s ease;opacity:0;pointer-events:none;z-index:999999}';\n if(o.viewTransitions&&'startViewTransition' in document){\n var dur=(o.viewTransitionDuration||220)+'ms';\n var ease=o.viewTransitionEasing||'cubic-bezier(0.16, 1, 0.3, 1)';\n css+='::view-transition-old(root),::view-transition-new(root){animation-duration:'+dur+';animation-timing-function:'+ease+'}';\n css+='::view-transition-old(root){animation-name:stx-r-fade-out}::view-transition-new(root){animation-name:stx-r-fade-in}';\n css+='@keyframes stx-r-fade-out{from{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}';\n css+='@keyframes stx-r-fade-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}';\n css+='@media (prefers-reduced-motion: reduce){::view-transition-old(root),::view-transition-new(root){animation-duration:0s;animation-name:none}}';\n }\n s.textContent=css;\n document.head.appendChild(s);\n }\n if(o.progress&&!document.getElementById('stx-router-progress')){\n var el=document.createElement('div');\n el.id='stx-router-progress';\n el.setAttribute('role','progressbar');\n el.setAttribute('aria-hidden','true');\n (document.body||document.documentElement).appendChild(el);\n progEl=el;\n } else if(o.progress){\n progEl=document.getElementById('stx-router-progress');\n }\n }\n\n function injectViewTransitionCSS(){\n if(document.getElementById('stx-view-transitions'))return;\n var s=document.createElement('style');s.id='stx-view-transitions';\n s.textContent='::view-transition-group(root){animation:none}::view-transition-old(root){animation:none}::view-transition-new(root){animation:none}#app-content,[data-stx-content]{view-transition-name:stx-content}::view-transition-old(stx-content){animation:stx-fade-out .15s ease-out both}::view-transition-new(stx-content){animation:stx-fade-in .15s ease-in .1s both}@keyframes stx-fade-out{from{opacity:1}to{opacity:0}}@keyframes stx-fade-in{from{opacity:0}to{opacity:1}}::view-transition{background:transparent}::view-transition-group(stx-content){background:inherit;overflow:hidden}';\n (document.head||document.documentElement).appendChild(s);\n }\n\n // ── Public API ──\n var router={\n navigate:navigate,\n navigateTo:navigate,\n prefetch:function(url){\n if(!cache[url]){\n fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){var isFrag=r.headers.get('X-STX-Fragment')==='true';return r.text().then(function(html){return isFrag?'<!--stx-fragment-->'+html:html})}).then(function(html){cache[url]=html}).catch(function(){});\n }\n },\n clearCache:function(){for(var k in cache)delete cache[k]},\n cache:cache,\n swap:swap,\n updateNav:updateNav\n };\n\n window.__stxRouter=router;\n window.stxRouter=router;\n if(window.stx)window.stx.router=router;\n\n // ── Initialize ──\n function init(){\n injectStyles();\n injectViewTransitionCSS();\n updateActiveLinks();\n updateNav(location.pathname);\n }\n\n if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();\n})();\n`\n}\n"
12
12
  ],
13
- "mappings": "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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
14
- "debugId": "3C52557F9211FAA564756E2164756E21",
13
+ "mappings": "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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
14
+ "debugId": "F05C3AD3376ECE0E64756E2164756E21",
15
15
  "names": []
16
16
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stx-router",
3
3
  "type": "module",
4
- "version": "0.2.10",
4
+ "version": "0.2.11",
5
5
  "description": "File-based router for STX — .stx template discovery, nested layouts, typed route params, middleware, and client-side SPA navigation.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",