bun-plugin-stx 0.2.138 → 0.2.140

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.
@@ -879,7 +879,7 @@ function getRouterScript() {
879
879
  // Re-localizing would map it back to the *current* locale and no-op.
880
880
  if(!force) url=withCurrentLocale(url);
881
881
  log('[router] navigate() called:',url,'isNavigating:',isNavigating);
882
- if(isNavigating)return;
882
+ if(isNavigating)return Promise.resolve(false);
883
883
  // Resolve against the current document URL, matching native <a> semantics.
884
884
  // With location.origin as the base, any relative href ('?status=resolved',
885
885
  // '#anchor', './sibling') resolved to the SITE ROOT \u2014 so filter tabs,
@@ -887,13 +887,13 @@ function getRouterScript() {
887
887
  // the SPA interceptor was active (#1777).
888
888
  var t=new URL(url,location.href);
889
889
 
890
- if(t.origin!==location.origin){location.href=url;return}
890
+ if(t.origin!==location.origin){location.href=url;return Promise.resolve(false)}
891
891
 
892
892
  if(t.pathname===location.pathname&&t.hash){
893
893
  if(pushState!==false)history.pushState({},'',t.href);
894
894
  var el=document.querySelector(t.hash);
895
895
  if(el)el.scrollIntoView({behavior:'smooth'});
896
- return;
896
+ return Promise.resolve(true);
897
897
  }
898
898
 
899
899
  // Skip if user clicks a link to the page they're already on. We
@@ -902,7 +902,7 @@ function getRouterScript() {
902
902
  // entry \u2014 without this allowance, hitting back would early-return
903
903
  // and the visible page content would be left frozen on the
904
904
  // forward-navigation page.
905
- if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return;
905
+ if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return Promise.resolve(false);
906
906
 
907
907
  isNavigating=true;
908
908
  document.body.classList.add(o.loadingClass);
@@ -921,22 +921,22 @@ function getRouterScript() {
921
921
  if(checkLayoutChange(layoutCache[targetPath],url,layoutGroupCache[targetPath])){
922
922
  // Layout changed \u2014 fetch full page and do full document swap
923
923
  log('[router] cache hit but layout changed \u2014 fetching full page');
924
- fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
924
+ return fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
925
925
  if(!r.ok)throw new Error(r.status);
926
926
  return r.text();
927
927
  }).then(function(html){
928
928
  log('[router] full page fetched from cache path, len:',html.length);
929
- swap(html,targetPath,pushState,targetHash);
929
+ return swap(html,targetPath,pushState,targetHash);
930
930
  }).catch(function(err){
931
931
  console.error('[router] full page fetch error:',err);
932
932
  location.href=url;
933
933
  }).finally(done);
934
- return;
935
934
  }
936
935
  pendingContainerAttrs=attrsCache[targetPath]||'';
937
- swap(cache[targetPath],targetPath,pushState,targetHash);
938
- applyTitle(titleCache[targetPath]);
939
- done();
936
+ return Promise.resolve(swap(cache[targetPath],targetPath,pushState,targetHash)).then(function(){
937
+ applyTitle(titleCache[targetPath]);
938
+ return true;
939
+ }).finally(done);
940
940
  }
941
941
  else {
942
942
  if(force&&cache[targetPath])evictCache(targetPath);
@@ -944,7 +944,7 @@ else {
944
944
  // the page content. Custom app-shell containers need full documents so
945
945
  // the router does not inject a <main> fragment into the wrong element.
946
946
  var wantsFragment=shouldUseFragmentResponse();
947
- fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
947
+ return fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
948
948
  if(!r.ok)throw new Error(r.status);
949
949
  var isFragment=wantsFragment&&r.headers.get('X-STX-Fragment')==='true';
950
950
  var newLayout=r.headers.get('X-STX-Layout')||'';
@@ -969,10 +969,12 @@ else {
969
969
  if(result.isFragment)result.html='<!--stx-fragment-->'+result.html;
970
970
  if(o.cache)setCache(targetPath,result.html,result.layout,result.layoutGroup,result.title,result.containerAttrs);
971
971
  pendingContainerAttrs=result.isFragment?(result.containerAttrs||''):'';
972
- swap(result.html,targetPath,pushState,targetHash);
973
- // Fragment swaps carry no <head>; apply the title from the header.
974
- // Full-document swaps already set document.title from the <title> tag.
975
- if(result.isFragment)applyTitle(result.title);
972
+ return Promise.resolve(swap(result.html,targetPath,pushState,targetHash)).then(function(){
973
+ // Fragment swaps carry no <head>; apply the title from the header.
974
+ // Full-document swaps already set document.title from the <title> tag.
975
+ if(result.isFragment)applyTitle(result.title);
976
+ return true;
977
+ });
976
978
  }).catch(function(err){
977
979
  console.error('[router] fetch error:',err);
978
980
  location.href=url;
@@ -994,10 +996,10 @@ else {
994
996
  function swap(html,url,pushState,hash){
995
997
  var isFragment=html.indexOf('<!--stx-fragment-->')===0;
996
998
  if(isFragment)html=html.slice('<!--stx-fragment-->'.length);
997
- if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return}
999
+ if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return Promise.resolve(false)}
998
1000
  var currentContent=getContainer();
999
1001
  log('[router] swap: isFragment='+isFragment+' container='+!!currentContent+' tag='+(currentContent&&currentContent.tagName)+' selector='+containerSel+' htmlLen='+html.length);
1000
- if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return}
1002
+ if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return Promise.resolve(false)}
1001
1003
 
1002
1004
  // Fragment mode: server returned just the page content (no document wrapper)
1003
1005
  if(isFragment){
@@ -1155,16 +1157,23 @@ else {
1155
1157
  // THEN fire stx:load \u2014 now _latestSetup is set and processElement has the right scope
1156
1158
  window.dispatchEvent(new Event('stx:load'));
1157
1159
  }
1158
- if(runViewTransition(doFragSwap)){}
1159
- 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)}
1160
- return;
1160
+ return new Promise(function(resolve,reject){
1161
+ function completeFragSwap(){
1162
+ try{
1163
+ doFragSwap();
1164
+ resolve(true);
1165
+ }catch(err){reject(err)}
1166
+ }
1167
+ if(runViewTransition(completeFragSwap)){}
1168
+ else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){completeFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}
1169
+ });
1161
1170
  }
1162
1171
 
1163
1172
  // Full document mode: parse with DOMParser and extract container content
1164
1173
  var parser=new DOMParser();
1165
1174
  var doc=parser.parseFromString(html,'text/html');
1166
1175
  var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');
1167
- if(!newContent){location.href=url;return}
1176
+ if(!newContent){location.href=url;return Promise.resolve(false)}
1168
1177
 
1169
1178
  // Clean up existing signals/effects
1170
1179
  if(window.stx&&window.stx._cleanupContainer){
@@ -1456,18 +1465,26 @@ else {
1456
1465
  }
1457
1466
  }
1458
1467
 
1459
- if(runViewTransition(doSwap)){
1460
- }
1468
+ return new Promise(function(resolve,reject){
1469
+ function completeSwap(){
1470
+ try{
1471
+ doSwap();
1472
+ resolve(true);
1473
+ }catch(err){reject(err)}
1474
+ }
1475
+ if(runViewTransition(completeSwap)){
1476
+ }
1461
1477
  else {
1462
- // Fallback fade for browsers without View Transitions API
1463
- currentContent.style.transition='opacity 0.12s ease-out';
1464
- currentContent.style.opacity='0';
1465
- setTimeout(function(){
1466
- doSwap();
1467
- currentContent.style.opacity='1';
1468
- setTimeout(function(){currentContent.style.transition=''},150);
1469
- },120);
1470
- }
1478
+ // Fallback fade for browsers without View Transitions API
1479
+ currentContent.style.transition='opacity 0.12s ease-out';
1480
+ currentContent.style.opacity='0';
1481
+ setTimeout(function(){
1482
+ completeSwap();
1483
+ currentContent.style.opacity='1';
1484
+ setTimeout(function(){currentContent.style.transition=''},150);
1485
+ },120);
1486
+ }
1487
+ });
1471
1488
  }
1472
1489
 
1473
1490
  // \u2500\u2500 Link interception \u2500\u2500
package/dist/serve.d.ts CHANGED
@@ -105,6 +105,7 @@ export declare interface ServeRequestContext {
105
105
  ip: string
106
106
  locale: string | null
107
107
  params: Record<string, string>
108
+ responseStatus?: number
108
109
  [key: string]: unknown
109
110
  }
110
111
  export declare interface ServeOptions {
package/dist/serve.js CHANGED
@@ -8700,7 +8700,7 @@ var defaultConfigDir4 = resolve12(process20.cwd(), "config");
8700
8700
  var defaultGeneratedDir4 = resolve12(process20.cwd(), "src/generated");
8701
8701
 
8702
8702
  // src/serve.ts
8703
- import { stateDir, stateDirName } from "@stacksjs/stx";
8703
+ import { extractPageResponseStatus, stateDir, stateDirName } from "@stacksjs/stx";
8704
8704
  var defaultStxModule = import("@stacksjs/stx");
8705
8705
  var REACTIVE_TEMPLATE_DIRECTIVE_RE = /@for|:for|@if|:if|@else|:else|x-for|x-if|x-else/;
8706
8706
  function extractServerScriptsFromTemplate(content) {
@@ -9325,7 +9325,7 @@ After installing: bun add bun-plugin-stx`);
9325
9325
  pageMiddlewarePatterns.length = 0;
9326
9326
  await Promise.all(files.map((f) => detectPageMiddleware(f)));
9327
9327
  try {
9328
- const { Router } = await import("./chunk-9e56perq.js");
9328
+ const { Router } = await import("./chunk-7xv85mm2.js");
9329
9329
  const pagesDirs = patterns.map((p) => p.replace(/\/$/, "")).filter(Boolean);
9330
9330
  const router = new Router(process19.cwd(), { pagesDirs, stateDir: stateDirName() });
9331
9331
  if (!options.quiet)
@@ -9392,7 +9392,7 @@ After installing: bun add bun-plugin-stx`);
9392
9392
  dir = nodePath.dirname(dir);
9393
9393
  }
9394
9394
  try {
9395
- const mod = await import("./chunk-11kz6apt.js");
9395
+ const mod = await import("./chunk-45dqy4z3.js");
9396
9396
  crosswindModule = { CSSGenerator: mod.CSSGenerator, config: mod.config };
9397
9397
  return crosswindModule;
9398
9398
  } catch {
@@ -9513,6 +9513,8 @@ After installing: bun add bun-plugin-stx`);
9513
9513
  }
9514
9514
  async function processTemplate(filePath, reqCtx) {
9515
9515
  const content = await Bun.file(filePath).text();
9516
+ if (reqCtx)
9517
+ reqCtx.responseStatus = extractPageResponseStatus(content) ?? 200;
9516
9518
  const skipCacheHint = /(?:^|[^\w$])__stx_skip_cache\s*=\s*true/.test(content);
9517
9519
  if (ENABLE_HTML_CACHE && !skipCacheHint) {
9518
9520
  const cacheKey = htmlCacheKey(filePath);
@@ -9682,6 +9684,8 @@ After installing: bun add bun-plugin-stx`);
9682
9684
  }
9683
9685
  async function processTemplateDynamic(filePath, paramNames, paramValues, routePath, reqCtx) {
9684
9686
  const content = await Bun.file(filePath).text();
9687
+ if (reqCtx)
9688
+ reqCtx.responseStatus = extractPageResponseStatus(content) ?? 200;
9685
9689
  const { serverScripts: dynServerScripts, templateContent } = extractServerScriptsFromTemplate(content);
9686
9690
  const context = {
9687
9691
  __filename: filePath,
@@ -10173,6 +10177,7 @@ ${html}`;
10173
10177
  }
10174
10178
  const content = await getRoute(path, reqCtx);
10175
10179
  if (content) {
10180
+ const responseStatus = reqCtx.responseStatus ?? 200;
10176
10181
  const isSpaNav = req.headers.get("X-STX-Router") === "true";
10177
10182
  if (isSpaNav) {
10178
10183
  const layoutMatch = content.match(/<!-- stx-layout: ([^ ]+) -->/);
@@ -10273,6 +10278,7 @@ ${trailingPageScripts.join(`
10273
10278
  const titleMatch = content.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
10274
10279
  const pageTitle = titleMatch ? titleMatch[1].trim() : "";
10275
10280
  return new Response(fragment, {
10281
+ status: responseStatus,
10276
10282
  headers: {
10277
10283
  "Content-Type": "text/html; charset=utf-8",
10278
10284
  "X-STX-Fragment": "true",
@@ -10292,6 +10298,7 @@ ${trailingPageScripts.join(`
10292
10298
  return runtimeCount === 1 ? match : "";
10293
10299
  });
10294
10300
  return new Response(injectHmrClient(cleaned), {
10301
+ status: responseStatus,
10295
10302
  headers: {
10296
10303
  "Content-Type": "text/html; charset=utf-8",
10297
10304
  "Cache-Control": "no-store",
@@ -10302,6 +10309,7 @@ ${trailingPageScripts.join(`
10302
10309
  const contentWithExt = await getRoute(`${path}.html`, reqCtx);
10303
10310
  if (contentWithExt) {
10304
10311
  return new Response(injectHmrClient(contentWithExt), {
10312
+ status: reqCtx.responseStatus ?? 200,
10305
10313
  headers: {
10306
10314
  "Content-Type": "text/html; charset=utf-8",
10307
10315
  "Cache-Control": "no-store",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-plugin-stx",
3
3
  "type": "module",
4
- "version": "0.2.138",
4
+ "version": "0.2.140",
5
5
  "description": "A Bun plugin that allows for using Laravel Blade-like syntax.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",