@stacksjs/stx 0.2.336 → 0.2.338

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/dist/app-shell.js +9 -8
  2. package/dist/{chunk-9v0fsdsf.js → chunk-066yt1hy.js} +1 -1
  3. package/dist/{chunk-eth22r93.js → chunk-0xgc5t3y.js} +1 -1
  4. package/dist/{chunk-vd5xvsnv.js → chunk-18018jkn.js} +1 -1
  5. package/dist/{chunk-5tefa8qb.js → chunk-1vb2rj09.js} +2 -2
  6. package/dist/chunk-1wsewc5h.js +2 -0
  7. package/dist/{chunk-p1hy2bwn.js → chunk-1yj4xd6n.js} +3 -3
  8. package/dist/{chunk-fqq5k9ve.js → chunk-1z1efvtw.js} +1 -1
  9. package/dist/{chunk-cdqx2c2h.js → chunk-22hch2me.js} +1 -1
  10. package/dist/{chunk-kpeqn5tx.js → chunk-2gc4cevb.js} +1 -1
  11. package/dist/{chunk-mgmn1vxy.js → chunk-39xtzfzf.js} +1 -1
  12. package/dist/{chunk-zsnrcbw1.js → chunk-3cjvqa0s.js} +2 -2
  13. package/dist/chunk-3sgdth20.js +2 -0
  14. package/dist/chunk-41dfsdy9.js +2 -0
  15. package/dist/{chunk-ymrxpwr8.js → chunk-46tmg3k4.js} +2 -2
  16. package/dist/{chunk-e1sxe3q4.js → chunk-4904n5v0.js} +2 -2
  17. package/dist/chunk-4cw0s9f4.js +4 -0
  18. package/dist/chunk-4jj4kk18.js +2 -0
  19. package/dist/chunk-4np12rj1.js +2 -0
  20. package/dist/chunk-4pcjt99d.js +2 -0
  21. package/dist/{chunk-dvvx1wny.js → chunk-57atgbyq.js} +1 -1
  22. package/dist/chunk-58j32d7n.js +2 -0
  23. package/dist/{chunk-hyfjnn7g.js → chunk-5g6rprcy.js} +1 -1
  24. package/dist/{chunk-mm59b0gg.js → chunk-5qsg9q46.js} +1 -1
  25. package/dist/{chunk-m8kezfrt.js → chunk-5r7gfwpj.js} +5 -5
  26. package/dist/chunk-799s9mwc.js +47 -0
  27. package/dist/{chunk-yxppshfd.js → chunk-7a21q2q4.js} +1 -1
  28. package/dist/chunk-7d74am4w.js +2 -0
  29. package/dist/chunk-7ngnyy5k.js +2 -0
  30. package/dist/{chunk-r8rbf28v.js → chunk-7r79j1hs.js} +1 -1
  31. package/dist/{chunk-cr8v8k53.js → chunk-7r9vgzg4.js} +1 -1
  32. package/dist/{chunk-xwxdwqn9.js → chunk-7we3xfde.js} +1 -1
  33. package/dist/{chunk-fr66xp8q.js → chunk-823h67tv.js} +1 -1
  34. package/dist/{chunk-42en0cxm.js → chunk-86v2rps7.js} +1 -1
  35. package/dist/{chunk-xz3evxqp.js → chunk-8bxtvsgm.js} +1 -1
  36. package/dist/{chunk-09jdvqhg.js → chunk-8cg15rr7.js} +2 -2
  37. package/dist/chunk-95t7pked.js +2 -0
  38. package/dist/{chunk-xdmb578h.js → chunk-97ej3abh.js} +1 -1
  39. package/dist/{chunk-kw98dfza.js → chunk-9btdax2s.js} +1 -1
  40. package/dist/{chunk-pbexz0d4.js → chunk-9bvgzqw1.js} +2 -2
  41. package/dist/{chunk-te6qym2g.js → chunk-9jc2z17q.js} +2 -2
  42. package/dist/chunk-9m5sxaen.js +2 -0
  43. package/dist/{chunk-tjag2cmm.js → chunk-a26hcag1.js} +1 -1
  44. package/dist/chunk-a3m7mgjc.js +2 -0
  45. package/dist/{chunk-9368t9jm.js → chunk-a959m68j.js} +1 -1
  46. package/dist/{chunk-fkdnfjc2.js → chunk-aftqqqcg.js} +2 -2
  47. package/dist/chunk-aved735s.js +64 -0
  48. package/dist/{chunk-q0g5c39d.js → chunk-ay336sqb.js} +1 -1
  49. package/dist/{chunk-cvphepjb.js → chunk-b3pn6dh5.js} +1 -1
  50. package/dist/{chunk-5swem3qy.js → chunk-b4cabzk9.js} +1 -1
  51. package/dist/{chunk-ej8mv2k6.js → chunk-bgrkxzr7.js} +1 -1
  52. package/dist/{chunk-2cm03y4y.js → chunk-d3kjaae0.js} +1 -1
  53. package/dist/chunk-d7zxg9bp.js +16 -0
  54. package/dist/{chunk-1ebyt1ba.js → chunk-dekxwgc2.js} +1 -1
  55. package/dist/chunk-dvafkj8w.js +2 -0
  56. package/dist/chunk-e3rgky2r.js +3747 -0
  57. package/dist/{chunk-t41aaehf.js → chunk-e4g8wz6t.js} +1 -1
  58. package/dist/chunk-e9y48d60.js +2 -0
  59. package/dist/{chunk-pbzdjhp8.js → chunk-eq2j7w8p.js} +1 -1
  60. package/dist/chunk-f08ttkqr.js +2 -0
  61. package/dist/{chunk-4jdj52c5.js → chunk-f6sejeg3.js} +1 -1
  62. package/dist/chunk-fha0nyet.js +2 -0
  63. package/dist/{chunk-6k8h1fj1.js → chunk-fjrkyhm7.js} +1 -1
  64. package/dist/chunk-fw56y3cb.js +30 -0
  65. package/dist/chunk-fx5m9d3t.js +2 -0
  66. package/dist/{chunk-mwh3ymwc.js → chunk-g6czgcg4.js} +1 -1
  67. package/dist/chunk-gtfcw1gc.js +12 -0
  68. package/dist/chunk-gz539gk6.js +2 -0
  69. package/dist/chunk-h0y4mb2m.js +2 -0
  70. package/dist/chunk-hfzv07az.js +3 -0
  71. package/dist/{chunk-nat3actx.js → chunk-hrdd26r4.js} +1 -1
  72. package/dist/{chunk-cdsbxghb.js → chunk-jkyvk4x6.js} +1 -1
  73. package/dist/{chunk-4ty8j3xn.js → chunk-jx03a693.js} +1 -1
  74. package/dist/{chunk-vvd659y4.js → chunk-k3dtvay1.js} +1 -1
  75. package/dist/chunk-kawdj1j7.js +2 -0
  76. package/dist/{chunk-d4etph79.js → chunk-kdhrk7x5.js} +1 -1
  77. package/dist/chunk-kdwerx8e.js +2 -0
  78. package/dist/{chunk-n66k2v2q.js → chunk-kermxyfe.js} +2 -2
  79. package/dist/{chunk-x7yc7e9v.js → chunk-m11pb9cx.js} +1 -1
  80. package/dist/{chunk-k6ky5et7.js → chunk-m1p2n3nf.js} +1 -1
  81. package/dist/chunk-m46edxtt.js +3 -0
  82. package/dist/chunk-meqz313r.js +2 -0
  83. package/dist/{chunk-q05eh1n4.js → chunk-mnyehz4t.js} +2 -2
  84. package/dist/{chunk-0vv5s039.js → chunk-mys0rat0.js} +1 -1
  85. package/dist/chunk-n0a55zv2.js +2 -0
  86. package/dist/{chunk-7kw3grq5.js → chunk-nf7k53ap.js} +1 -1
  87. package/dist/{chunk-kffndzch.js → chunk-nhbc464j.js} +3 -3
  88. package/dist/{chunk-1hzgxk2m.js → chunk-nvp546bb.js} +1 -1
  89. package/dist/chunk-p1cddybx.js +2 -0
  90. package/dist/chunk-q0srntf6.js +2 -0
  91. package/dist/chunk-q3g4yf5r.js +2 -0
  92. package/dist/{chunk-c2ta859c.js → chunk-q9ckfwhh.js} +1 -1
  93. package/dist/chunk-qhdp0ycf.js +2 -0
  94. package/dist/{chunk-y4nzmkea.js → chunk-qsbjtp60.js} +1 -1
  95. package/dist/{chunk-1tva0f8f.js → chunk-qtc28zy1.js} +1 -1
  96. package/dist/{chunk-2vgkc0kg.js → chunk-r10fypcd.js} +1 -1
  97. package/dist/chunk-rkykwy3z.js +2 -0
  98. package/dist/{chunk-64djh88a.js → chunk-sqvqwd0p.js} +1 -1
  99. package/dist/{chunk-67bh5vrj.js → chunk-stbns4bg.js} +1 -1
  100. package/dist/chunk-szfk6pw6.js +2 -0
  101. package/dist/{chunk-amxtypkp.js → chunk-t00ga194.js} +1 -1
  102. package/dist/chunk-temapbqe.js +2 -0
  103. package/dist/{chunk-9kxfz708.js → chunk-tr1174hz.js} +1 -1
  104. package/dist/{chunk-q85qp5we.js → chunk-tr41gn5j.js} +1 -1
  105. package/dist/{chunk-crj19mqr.js → chunk-tr9ynxdw.js} +1 -1
  106. package/dist/{chunk-71y3bhcw.js → chunk-tsmdmf5h.js} +123 -37
  107. package/dist/{chunk-gptwwv3c.js → chunk-vaggjvsm.js} +1 -1
  108. package/dist/{chunk-ya5m5vbn.js → chunk-vgfd9582.js} +1 -1
  109. package/dist/chunk-vgfnre7b.js +2 -0
  110. package/dist/{chunk-n9c975db.js → chunk-vhzc08aa.js} +1 -1
  111. package/dist/{chunk-08w4gtyf.js → chunk-vm5jbgb1.js} +3 -3
  112. package/dist/{chunk-drqdc0mh.js → chunk-vxt5c5aq.js} +1 -1
  113. package/dist/{chunk-hzfd8cz0.js → chunk-w0hzaka3.js} +78 -67
  114. package/dist/{chunk-yk6446kr.js → chunk-w72v0ab1.js} +2 -2
  115. package/dist/{chunk-c65yrgck.js → chunk-wakb8z5q.js} +10 -10
  116. package/dist/{chunk-q569zmrr.js → chunk-wb90259a.js} +1 -1
  117. package/dist/chunk-x01sw9wy.js +2 -0
  118. package/dist/{chunk-dfejgnny.js → chunk-x48crnwa.js} +1 -1
  119. package/dist/{chunk-24b4711v.js → chunk-x4vhn880.js} +1 -1
  120. package/dist/{chunk-j2dj21ay.js → chunk-xe6zmdfq.js} +1 -1
  121. package/dist/chunk-y8vj3rtt.js +2 -0
  122. package/dist/chunk-yj1dxdfr.js +2 -0
  123. package/dist/{chunk-wx5zf66r.js → chunk-yne23w3c.js} +1 -1
  124. package/dist/{chunk-zz8qgqa1.js → chunk-ypzm47q3.js} +2 -2
  125. package/dist/chunk-z07knk3p.js +2 -0
  126. package/dist/{chunk-27xfkzks.js → chunk-zj039s33.js} +1 -1
  127. package/dist/{chunk-c79nfdyj.js → chunk-zk6ghjnj.js} +1 -1
  128. package/dist/chunk-zt4pf776.js +2 -0
  129. package/dist/{chunk-4k0ce745.js → chunk-zye9r15n.js} +2 -2
  130. package/dist/chunk-zzfpwxpp.js +2 -0
  131. package/dist/cli.js +14 -14
  132. package/dist/component-contract-checks.d.ts +18 -15
  133. package/dist/component-contract.d.ts +6 -14
  134. package/dist/craft-entry.js +1 -1
  135. package/dist/craft.js +1 -1
  136. package/dist/database.js +1 -1
  137. package/dist/expressions.d.ts +45 -0
  138. package/dist/expressions.js +60 -11
  139. package/dist/includes.js +4 -0
  140. package/dist/loops.js +10 -0
  141. package/dist/pwa.js +2 -2
  142. package/dist/server-components.js +2 -1
  143. package/dist/signals.js +121 -35
  144. package/dist/slots.js +86 -12
  145. package/dist/ssg.js +2 -2
  146. package/dist/stx-virtual-ts.d.ts +205 -95
  147. package/dist/template-syntax-escape.d.ts +36 -0
  148. package/dist/template-syntax-escape.js +8 -0
  149. package/dist/utils.js +9 -2
  150. package/dist/variable-extractor.d.ts +1 -0
  151. package/dist/variable-extractor.js +8 -0
  152. package/dist/visual-testing.js +1 -1
  153. package/package.json +8 -8
  154. package/dist/chunk-046dp691.js +0 -2
  155. package/dist/chunk-1brnvyhv.js +0 -2
  156. package/dist/chunk-3ntf8f5e.js +0 -2
  157. package/dist/chunk-4tnxnzja.js +0 -2
  158. package/dist/chunk-63yfp05p.js +0 -2
  159. package/dist/chunk-7y4eqkv4.js +0 -2
  160. package/dist/chunk-7ywnkv1f.js +0 -2
  161. package/dist/chunk-80zj5516.js +0 -2
  162. package/dist/chunk-8730k51r.js +0 -2
  163. package/dist/chunk-907qxn09.js +0 -2
  164. package/dist/chunk-9fcq5x2r.js +0 -2
  165. package/dist/chunk-a97tp43x.js +0 -2
  166. package/dist/chunk-atw841yx.js +0 -2
  167. package/dist/chunk-c1m1gng4.js +0 -2
  168. package/dist/chunk-caaenc3w.js +0 -60
  169. package/dist/chunk-dbfq77qe.js +0 -4
  170. package/dist/chunk-dnesmvvb.js +0 -2
  171. package/dist/chunk-eg8ksaft.js +0 -2
  172. package/dist/chunk-ewsx2qxm.js +0 -2
  173. package/dist/chunk-farwrdr2.js +0 -3
  174. package/dist/chunk-fcenm8n1.js +0 -2
  175. package/dist/chunk-gbz6pfs8.js +0 -2
  176. package/dist/chunk-gdbkqatx.js +0 -43
  177. package/dist/chunk-jnahcd4d.js +0 -2
  178. package/dist/chunk-ke88kpva.js +0 -30
  179. package/dist/chunk-krpkfndf.js +0 -3
  180. package/dist/chunk-kxtqbrfr.js +0 -3759
  181. package/dist/chunk-m1yrakpk.js +0 -2
  182. package/dist/chunk-q2hvne0v.js +0 -2
  183. package/dist/chunk-qpbk50xd.js +0 -2
  184. package/dist/chunk-rxdd3k6n.js +0 -2
  185. package/dist/chunk-ssd10kje.js +0 -2
  186. package/dist/chunk-szx6pxh3.js +0 -2
  187. package/dist/chunk-tpmgq2dx.js +0 -12
  188. package/dist/chunk-tte4m2s9.js +0 -2
  189. package/dist/chunk-v7gjsb3f.js +0 -2
  190. package/dist/chunk-vv289x82.js +0 -2
  191. package/dist/chunk-vx6mxybh.js +0 -2
  192. package/dist/chunk-x510wr8z.js +0 -2
  193. package/dist/chunk-x95sxapm.js +0 -2
  194. package/dist/chunk-xjrhzkx2.js +0 -2
  195. package/dist/chunk-y1x2ebhv.js +0 -2
  196. package/dist/chunk-yvec3f1c.js +0 -2
  197. package/dist/chunk-yzxm75jp.js +0 -2
package/dist/ssg.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{Gk as Uq,Hk as Iq,Lk as Fq}from"./chunk-e1sxe3q4.js";import{Mk as Eq,Nk as Tq,Ok as Dq}from"./chunk-4jdj52c5.js";import{hl as _q,kl as zq,ll as Aq}from"./chunk-zz8qgqa1.js";import"./chunk-p1hy2bwn.js";import{Dr as n,Xm as Oq,eq as P,tp as Bq,vo as l,yo as Hq}from"./chunk-kxtqbrfr.js";import"./chunk-caaenc3w.js";import"./chunk-amxtypkp.js";import"./chunk-nat3actx.js";import"./chunk-q0g5c39d.js";import{fu as Xq}from"./chunk-kffndzch.js";import"./chunk-c2ta859c.js";import"./chunk-r8rbf28v.js";import{Cu as d}from"./chunk-gptwwv3c.js";import"./chunk-n66k2v2q.js";import"./chunk-vvd659y4.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import{$v as jq,Zv as Yq,_v as Vq,aw as Gq,bw as Lq,cw as Nq}from"./chunk-hzfd8cz0.js";import"./chunk-q569zmrr.js";import{sw as y}from"./chunk-hyfjnn7g.js";import O from"fs";import j from"path";import{createHash as xq}from"crypto";function yq(q){try{return new Bun.Transpiler({loader:"js",minifyWhitespace:!0}).transformSync(q).replace(/\}(var |let |const |function )/g,"};$1").trim()}catch{return q}}var Pq=/<script\s+type="stx\/island"\s+data-stx-island="([^"]+)"([^>]*)>([\s\S]*?)<\/script>/g;function Cq(q){return Bun.hash(q).toString(16)}function Qq(q,Z={}){if(!q.includes('type="stx/island"'))return{html:q,chunks:[]};let $=new Map,Q=q.replace(Pq,(J,W,z,A)=>{let G=A.trim();if(!G)return J;if(/\bdata-stx-src=/.test(z))return J;if(Z.minify)G=yq(G);let X=Cq(G);if(!$.has(X))$.set(X,G);let B=Z.integrity?` data-stx-integrity="sha384-${xq("sha384").update(G).digest("base64")}"`:"";return`<script type="stx/island" data-stx-island="${W}" data-stx-src="/_stx/islands/${X}.js"${B}${z}></script>`}),K=Array.from($,([J,W])=>({hash:J,code:W}));return{html:Q,chunks:K}}var gq=new Set(["visible","idle"]);function Zq(q){if(!q.includes("data-stx-src="))return q;let Z=new Map,$=/data-stx-scope="([^"]+)"[^>]*?stx-hydrate="([^"]+)"/g,Q;while((Q=$.exec(q))!==null)Z.set(Q[1],Q[2]);let K=new Set,J=/data-stx-island="([^"]+)"[^>]*?data-stx-src="([^"]+)"/g,W;while((W=J.exec(q))!==null)if(gq.has(Z.get(W[1])||""))K.add(W[2]);let z=q.lastIndexOf("</head>");if(K.size===0||z===-1)return q;let A=Array.from(K).filter((G)=>!q.includes(`rel="prefetch" href="${G}"`)).map((G)=>`<link rel="prefetch" href="${G}" as="script">`).join("");if(!A)return q;return q.slice(0,z)+A+q.slice(z)}var fq=["STX_SITE_URL","SITE_URL","URL","VERCEL_URL","CF_PAGES_URL"];function h(q){let Z=q.trim();if(!Z)return null;let $=/^https?:\/\//i.test(Z)?Z:`https://${Z}`;try{return new URL($).origin+new URL($).pathname.replace(/\/$/,"")}catch{return null}}function mq(q){for(let Z of fq){let $=q[Z];if(!$)continue;let Q=h($);if(Q)return{url:Q,source:"env",via:Z}}return null}function $q(q){if(!q||typeof q!=="object")return null;let Z=q,$=Z.site?.url??Z.url??Z.app?.url;return typeof $==="string"?h($):null}async function dq(q){let{existsSync:Z}=await import("fs"),$=await import("path");for(let Q of["site.config.ts","site.config.js",".config/site.config.ts"]){let K=$.resolve(q,Q);if(!Z(K))continue;try{let J=await import(K),W=$q(J.default??J);if(W)return W}catch{}}return null}async function Kq(q={}){let Z=q.cwd??process.cwd(),$=q.env??process.env;if(q.explicit){let W=h(q.explicit);if(W)return{url:W,source:"option"}}let Q=$q(q.stxConfig);if(Q)return{url:Q,source:"stx.config",via:"site.url"};let K=await dq(Z);if(K)return{url:K,source:"site.config",via:"url"};let J=mq($);if(J)return J;return{url:"http://localhost",source:"fallback"}}function Wq(){return["No site URL configured \u2014 sitemap.xml and robots.txt will point at http://localhost."," Set one in stx.config.ts (site: { url: 'https://example.com' }), in site.config.ts,"," via --domain, or with SITE_URL in the build environment."].join(`
2
+ import{Ak as Fq,vk as Uq,wk as Iq}from"./chunk-4904n5v0.js";import{Bk as Eq,Ck as Tq,Dk as Dq}from"./chunk-f6sejeg3.js";import{$k as zq,Yk as _q,al as Aq}from"./chunk-ypzm47q3.js";import"./chunk-1yj4xd6n.js";import{Jp as P,Om as Oq,io as l,lo as Hq,rr as n}from"./chunk-e3rgky2r.js";import"./chunk-d7zxg9bp.js";import"./chunk-t00ga194.js";import"./chunk-hrdd26r4.js";import"./chunk-7r79j1hs.js";import"./chunk-ay336sqb.js";import{ht as Xq}from"./chunk-nhbc464j.js";import{mt as d}from"./chunk-vaggjvsm.js";import"./chunk-q9ckfwhh.js";import"./chunk-kermxyfe.js";import"./chunk-k3dtvay1.js";import{Tt as Bq}from"./chunk-aved735s.js";import"./chunk-799s9mwc.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import{$v as jq,Zv as Yq,_v as Vq,aw as Gq,bw as Lq,cw as Nq}from"./chunk-w0hzaka3.js";import"./chunk-wb90259a.js";import{tw as y}from"./chunk-5g6rprcy.js";import O from"fs";import j from"path";import{createHash as xq}from"crypto";function yq(q){try{return new Bun.Transpiler({loader:"js",minifyWhitespace:!0}).transformSync(q).replace(/\}(var |let |const |function )/g,"};$1").trim()}catch{return q}}var Pq=/<script\s+type="stx\/island"\s+data-stx-island="([^"]+)"([^>]*)>([\s\S]*?)<\/script>/g;function Cq(q){return Bun.hash(q).toString(16)}function Qq(q,Z={}){if(!q.includes('type="stx/island"'))return{html:q,chunks:[]};let $=new Map,Q=q.replace(Pq,(J,W,z,A)=>{let G=A.trim();if(!G)return J;if(/\bdata-stx-src=/.test(z))return J;if(Z.minify)G=yq(G);let X=Cq(G);if(!$.has(X))$.set(X,G);let B=Z.integrity?` data-stx-integrity="sha384-${xq("sha384").update(G).digest("base64")}"`:"";return`<script type="stx/island" data-stx-island="${W}" data-stx-src="/_stx/islands/${X}.js"${B}${z}></script>`}),K=Array.from($,([J,W])=>({hash:J,code:W}));return{html:Q,chunks:K}}var gq=new Set(["visible","idle"]);function Zq(q){if(!q.includes("data-stx-src="))return q;let Z=new Map,$=/data-stx-scope="([^"]+)"[^>]*?stx-hydrate="([^"]+)"/g,Q;while((Q=$.exec(q))!==null)Z.set(Q[1],Q[2]);let K=new Set,J=/data-stx-island="([^"]+)"[^>]*?data-stx-src="([^"]+)"/g,W;while((W=J.exec(q))!==null)if(gq.has(Z.get(W[1])||""))K.add(W[2]);let z=q.lastIndexOf("</head>");if(K.size===0||z===-1)return q;let A=Array.from(K).filter((G)=>!q.includes(`rel="prefetch" href="${G}"`)).map((G)=>`<link rel="prefetch" href="${G}" as="script">`).join("");if(!A)return q;return q.slice(0,z)+A+q.slice(z)}var fq=["STX_SITE_URL","SITE_URL","URL","VERCEL_URL","CF_PAGES_URL"];function h(q){let Z=q.trim();if(!Z)return null;let $=/^https?:\/\//i.test(Z)?Z:`https://${Z}`;try{return new URL($).origin+new URL($).pathname.replace(/\/$/,"")}catch{return null}}function mq(q){for(let Z of fq){let $=q[Z];if(!$)continue;let Q=h($);if(Q)return{url:Q,source:"env",via:Z}}return null}function $q(q){if(!q||typeof q!=="object")return null;let Z=q,$=Z.site?.url??Z.url??Z.app?.url;return typeof $==="string"?h($):null}async function dq(q){let{existsSync:Z}=await import("fs"),$=await import("path");for(let Q of["site.config.ts","site.config.js",".config/site.config.ts"]){let K=$.resolve(q,Q);if(!Z(K))continue;try{let J=await import(K),W=$q(J.default??J);if(W)return W}catch{}}return null}async function Kq(q={}){let Z=q.cwd??process.cwd(),$=q.env??process.env;if(q.explicit){let W=h(q.explicit);if(W)return{url:W,source:"option"}}let Q=$q(q.stxConfig);if(Q)return{url:Q,source:"stx.config",via:"site.url"};let K=await dq(Z);if(K)return{url:K,source:"site.config",via:"url"};let J=mq($);if(J)return J;return{url:"http://localhost",source:"fallback"}}function Wq(){return["No site URL configured \u2014 sitemap.xml and robots.txt will point at http://localhost."," Set one in stx.config.ts (site: { url: 'https://example.com' }), in site.config.ts,"," via --domain, or with SITE_URL in the build environment."].join(`
3
3
  `)}class wq{cacheDir;cache=new Map;loaded=!1;salt;constructor(q,Z=""){this.cacheDir=q,this.salt=Z}async load(){if(this.loaded)return;let q=j.join(this.cacheDir,"build-cache.json");if(await Bun.file(q).exists())try{let Z=JSON.parse(await Bun.file(q).text());for(let[$,Q]of Object.entries(Z))this.cache.set($,Q)}catch{}this.loaded=!0}async save(){await O.promises.mkdir(this.cacheDir,{recursive:!0});let q=j.join(this.cacheDir,"build-cache.json"),Z={};for(let[$,Q]of this.cache)Z[$]=Q;await Bun.write(q,JSON.stringify(Z))}getHash(q,Z){let $=O.statSync(q),Q=`${this.salt}|${q}:${$.mtimeMs}`;for(let J of Z)if(O.existsSync(J)){let W=O.statSync(J);Q+=`:${J}:${W.mtimeMs}`}let K=0;for(let J=0;J<Q.length;J++){let W=Q.charCodeAt(J);K=(K<<5)-K+W,K=K&K}return Math.abs(K).toString(36)}get(q,Z){let $=this.cache.get(q);if(!$)return null;let Q=this.getHash(Z,$.dependencies??[]);if($.hash!==Q)return this.cache.delete(q),null;return $.html}set(q,Z,$,Q){let K=this.getHash(Z,$);this.cache.set(q,{hash:K,html:Q,generatedAt:Date.now(),dependencies:$})}}class Rq{cacheDir;constructor(q){this.cacheDir=q}getFilePath(q){let Z=q.replace(/[^a-zA-Z0-9]/g,"_")+".json";return j.join(this.cacheDir,"isr",Z)}async get(q){let Z=this.getFilePath(q);if(!await Bun.file(Z).exists())return null;try{return JSON.parse(await Bun.file(Z).text())}catch{return null}}async set(q,Z){let $=this.getFilePath(q);await O.promises.mkdir(j.dirname($),{recursive:!0}),await Bun.write($,JSON.stringify(Z))}async invalidate(q){let Z=this.getFilePath(q);if(await Bun.file(Z).exists())await O.promises.unlink(Z)}async invalidatePattern(q){let Z=j.join(this.cacheDir,"isr");if(!O.existsSync(Z))return;let $=await O.promises.readdir(Z);for(let Q of $){let K=Q.replace(/_/g,"/").replace(".json","");if(q.test(K))await O.promises.unlink(j.join(Z,Q))}}async needsRevalidation(q){let Z=await this.get(q);if(!Z)return!0;return Date.now()>Z.revalidateAfter}}async function pq(q){try{let $=(await Bun.file(q).text()).match(/<script\s+server\b[^>]*>([\s\S]*?)<\/script>/i);if(!$)return null;let Q=$[1];if(!Q.includes("getStaticPaths"))return null;let K=Q.match(/(?:export\s+)?(?:async\s+)?function\s+getStaticPaths\s*\([^)]*\)\s*\{([\s\S]*?)\n[\t ]*\}/);if(!K)return null;return await Function(`
4
4
  return (async function getStaticPaths() {
5
5
  ${K[1]}
@@ -41,7 +41,7 @@ ${q.map((Q)=>{let K=new URL(Q.loc,Z).href,J=` <url>
41
41
  ${$.join(`
42
42
  `)}
43
43
  </channel>
44
- </rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-k6ky5et7.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-xdmb578h.js"),F=await _(J.publicDir,J.outputDir);if(F.count>0)console.log(`Optimized ${F.count} image(s) for responsive delivery`),L=[L,F.fingerprint].filter(Boolean).join(":");let C=new wq(J.cacheDir,L);if(J.cache)await C.load();try{let{generateCss:Y}=await import("./chunk-k6ky5et7.js");await Y('<div class="bg-black"></div>')}catch{}Yq();let kq=$?.routeMiddleware?.dir||"middleware";await jq(process.cwd(),kq);let p=Vq();if(p.length>0)console.log(`Loaded ${p.length} middleware: ${p.join(", ")}`);let bq=$?.routeMiddleware?.global||[];Fq($?.layoutsDir,d(process.cwd()));let i=l(".",{pagesDir:J.pagesDir,pagesDirs:$?._layerPageDirs});console.log(`Found ${i.length} routes`);let g=[];for(let Y of i){let N=await uq(Y);for(let H of N)g.push({route:Y,url:H.url,params:H.params,props:H.props,revalidate:H.revalidate??J.revalidate})}W.totalPages=g.length,console.log(`Generating ${W.totalPages} pages...`);let b=[],s=[];for(let Y=0;Y<g.length;Y+=J.concurrency)s.push(g.slice(Y,Y+J.concurrency));for(let Y of s)await Promise.all(Y.map(async(N)=>{let{route:H,url:V,params:S,props:Sq,revalidate:a}=N;try{await J.hooks.onPageStart?.(V);let w=await Bun.file(H.filePath).text(),R=JJ(w),vq=R?.middleware?Array.isArray(R.middleware)?R.middleware:[R.middleware]:[],t=[...bq,...vq];if(t.length>0){let D=Gq(V,S,R||{}),M=Lq(D,null,void 0,{isServer:!0}),E=await Nq(t,M);if(E.redirect){let U=typeof E.redirect==="string"?E.redirect:E.redirect.path||E.redirect,x=QJ(String(U),V),k=ZJ(V,J);await O.promises.mkdir(j.dirname(k),{recursive:!0}),await Bun.write(k,x),W.successCount++,W.pages.push({route:V,outputPath:k,size:Buffer.byteLength(x),cached:!1}),b.push({loc:V,lastmod:new Date().toISOString()}),console.log(` \u21B3 ${V} \u2192 redirect to ${U}`);return}if(E.abort){let U=typeof E.abort==="string"?E.abort:E.abort?.error?.message||"aborted";console.warn(` \u21B3 ${V} \u2014 middleware aborted: ${U}`);return}}let e=w.match(/definePageMeta\s*\(\s*\{[\s\S]*?validate\s*:\s*((?:\([^)]*\)|[^,}])*(?:\{[\s\S]*?\})?)/m);if(e)try{if(!await Function("route",`
44
+ </rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-m1p2n3nf.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-97ej3abh.js"),F=await _(J.publicDir,J.outputDir);if(F.count>0)console.log(`Optimized ${F.count} image(s) for responsive delivery`),L=[L,F.fingerprint].filter(Boolean).join(":");let C=new wq(J.cacheDir,L);if(J.cache)await C.load();try{let{generateCss:Y}=await import("./chunk-m1p2n3nf.js");await Y('<div class="bg-black"></div>')}catch{}Yq();let kq=$?.routeMiddleware?.dir||"middleware";await jq(process.cwd(),kq);let p=Vq();if(p.length>0)console.log(`Loaded ${p.length} middleware: ${p.join(", ")}`);let bq=$?.routeMiddleware?.global||[];Fq($?.layoutsDir,d(process.cwd()));let i=l(".",{pagesDir:J.pagesDir,pagesDirs:$?._layerPageDirs});console.log(`Found ${i.length} routes`);let g=[];for(let Y of i){let N=await uq(Y);for(let H of N)g.push({route:Y,url:H.url,params:H.params,props:H.props,revalidate:H.revalidate??J.revalidate})}W.totalPages=g.length,console.log(`Generating ${W.totalPages} pages...`);let b=[],s=[];for(let Y=0;Y<g.length;Y+=J.concurrency)s.push(g.slice(Y,Y+J.concurrency));for(let Y of s)await Promise.all(Y.map(async(N)=>{let{route:H,url:V,params:S,props:Sq,revalidate:a}=N;try{await J.hooks.onPageStart?.(V);let w=await Bun.file(H.filePath).text(),R=JJ(w),vq=R?.middleware?Array.isArray(R.middleware)?R.middleware:[R.middleware]:[],t=[...bq,...vq];if(t.length>0){let D=Gq(V,S,R||{}),M=Lq(D,null,void 0,{isServer:!0}),E=await Nq(t,M);if(E.redirect){let U=typeof E.redirect==="string"?E.redirect:E.redirect.path||E.redirect,x=QJ(String(U),V),k=ZJ(V,J);await O.promises.mkdir(j.dirname(k),{recursive:!0}),await Bun.write(k,x),W.successCount++,W.pages.push({route:V,outputPath:k,size:Buffer.byteLength(x),cached:!1}),b.push({loc:V,lastmod:new Date().toISOString()}),console.log(` \u21B3 ${V} \u2192 redirect to ${U}`);return}if(E.abort){let U=typeof E.abort==="string"?E.abort:E.abort?.error?.message||"aborted";console.warn(` \u21B3 ${V} \u2014 middleware aborted: ${U}`);return}}let e=w.match(/definePageMeta\s*\(\s*\{[\s\S]*?validate\s*:\s*((?:\([^)]*\)|[^,}])*(?:\{[\s\S]*?\})?)/m);if(e)try{if(!await Function("route",`
45
45
  const validate = ${e[1]};
46
46
  return validate(route);
47
47
  `)({params:S})){console.warn(`Validation failed for ${V}, skipping...`);return}}catch{}let I=null,qq=!1;if(J.cache){if(I=C.get(V,H.filePath),I)qq=!0,W.cachedCount++}if(!I){let D=await Mq(H,S,Sq,J,$);if(I=D.html,J.failOnIncludeError&&D.includeFailures.length>0)throw Error(`${D.includeFailures.length} include(s) failed to resolve, so this page would have shipped with an error banner where the markup should be:
@@ -1,3 +1,106 @@
1
+ /**
2
+ * Turn a `.stx` file into TypeScript that a real compiler can check
3
+ * (stacksjs/stx#1852, asks 4 and 5).
4
+ *
5
+ * `stx typecheck` and the VS Code tsserver plugin both need the same answer to
6
+ * "what TypeScript is in this file, and where did it come from". They used to
7
+ * answer it differently, and the editor's answer was wrong in three ways at
8
+ * once: it concatenated every script block into one buffer, which made two
9
+ * blocks that legitimately declare the same name collide; it dropped the HTML
10
+ * while doing so, so **every diagnostic landed on the wrong line**; and it then
11
+ * suppressed every "Cannot find name" mentioning a hardcoded list of runtime
12
+ * globals, which also suppressed genuine typos.
13
+ *
14
+ * This module is the single extractor, so the editor and CI cannot disagree
15
+ * about what a file contains or where a diagnostic belongs.
16
+ *
17
+ * ## Positions survive by construction
18
+ *
19
+ * The virtual source is built as an array of lines the same length as the
20
+ * source, with each block's body written at the index it already occupies. A
21
+ * diagnostic's line number therefore *is* the line number in the `.stx` file —
22
+ * no offset table, and nothing to get wrong when a file has several blocks.
23
+ *
24
+ * Only synthetic lines appended past the end of the file need a map, and
25
+ * {@link VirtualFile.lineMap} carries it.
26
+ *
27
+ * ## What is deliberately not attempted
28
+ *
29
+ * Template expressions are checked for syntax and for names that resolve, not
30
+ * for deep types. Two things stand in the way, and pretending otherwise would
31
+ * produce false positives in a CI gate:
32
+ *
33
+ * - The runtime globals are typed `any` (see `runtime-globals.ts`), so a
34
+ * signal's value type is unknown to begin with.
35
+ * - Templates auto-unwrap signals — `:if="flag"` reads the value while
36
+ * `@click="flag.set(true)"` reads the signal object — so the same name has
37
+ * two types depending on the attribute it appears in.
38
+ *
39
+ * Server-block bindings do have real types, and those are checked: see
40
+ * {@link buildTemplateScopeSource}, which inlines server bodies so
41
+ * `{{ row.total_vists }}` fails against a typed row.
42
+ *
43
+ * @module stx-virtual-ts
44
+ */
45
+ export type ScriptKind = 'server' | 'client' | 'plain';
46
+ export interface ScriptBlock {
47
+ kind: ScriptKind;
48
+ /** Block body, without the surrounding tags. */
49
+ code: string;
50
+ /** 1-based line in the source file where the body's first character sits. */
51
+ startLine: number;
52
+ /** The opening tag's attributes, trimmed. */
53
+ attrs: string;
54
+ }
55
+ /** A `{{ }}` interpolation or a directive attribute value. */
56
+ export interface TemplateExpression {
57
+ /** A generated contract check anchors at its source value, not its TS wrapper. */
58
+ anchor?: boolean;
59
+ /** The expression text, with any filter chain already removed. */
60
+ code: string;
61
+ /** 1-based line of the expression's first character. */
62
+ line: number;
63
+ /** 1-based column of the expression's first character. */
64
+ column: number;
65
+ kind: 'interpolation' | 'directive';
66
+ /** For directives, the attribute name (`:if`, `@click`, `x-text`). */
67
+ attribute?: string;
68
+ /**
69
+ * 0-based offset of the expression's first character, used to work out which
70
+ * `@if` / `@unless` blocks enclose it. Not part of a diagnostic; `line` and
71
+ * `column` carry that.
72
+ */
73
+ offset?: number;
74
+ }
75
+ /** A synthetic line's origin, for diagnostics that land outside the source. */
76
+ export interface MappedLine {
77
+ line: number;
78
+ column: number;
79
+ /** Present when the line came from a template expression. */
80
+ expression?: TemplateExpression;
81
+ /**
82
+ * Characters of wrapper before the expression starts on the synthetic line.
83
+ *
84
+ * Subtracting it turns a column in the virtual line into a column inside the
85
+ * expression, so a squiggle lands on the offending identifier rather than at
86
+ * the start of the attribute.
87
+ */
88
+ prefixLength?: number;
89
+ }
90
+ export interface VirtualFile {
91
+ text: string;
92
+ componentDependencies?: Map<string, string>;
93
+ /**
94
+ * Virtual 1-based line → where it came from.
95
+ *
96
+ * Only holds entries for lines the source does not already account for.
97
+ * Anything absent is at its own line number, because the body was written at
98
+ * the index it occupies in the file.
99
+ */
100
+ lineMap: Map<number, MappedLine>;
101
+ /** Lines after this are synthetic. */
102
+ sourceLineCount: number;
103
+ }
1
104
  /**
2
105
  * Pull the script blocks out of a `.stx` source, with the line each body starts on.
3
106
  *
@@ -23,6 +126,19 @@ export declare function maskNonTemplateRegions(source: string): string;
23
126
  * is TypeScript, and `||` is a real operator that must survive.
24
127
  */
25
128
  export declare function stripFilterChain(expression: string): string;
129
+ /**
130
+ * Placeholder for a server interpolation spliced into a client expression.
131
+ *
132
+ * `:show="photos()[{{ idx }}]"` is real stx — the server fills `{{ idx }}` in
133
+ * before the client ever parses the attribute. Left in place it is a syntax
134
+ * error, so it is replaced with a declared `any`; the interpolation itself is
135
+ * still extracted and checked on its own.
136
+ */
137
+ export declare const INTERPOLATION_PLACEHOLDER = "__stx_interpolated";
138
+ /** Name of the generated helper that reads an iterable's element type. */
139
+ export declare const ELEMENT_HELPER = "__StxElement";
140
+ /** Name of the generated helper that models a template's signal auto-unwrap. */
141
+ export declare const UNWRAP_HELPER = "__StxTemplateValue";
26
142
  export declare function substituteInterpolations(value: string): string;
27
143
  /**
28
144
  * The same substitution, but the result occupies the same space as the source.
@@ -76,6 +192,27 @@ export declare function blankScriptDirectives(code: string): string;
76
192
  * the braces literally.
77
193
  */
78
194
  export declare function extractTemplateExpressions(source: string): TemplateExpression[];
195
+ /**
196
+ * Names a template introduces that no script block declares.
197
+ *
198
+ * Loop bindings are collected for the whole file rather than tracked per
199
+ * subtree. That is deliberately over-permissive: using a loop variable outside
200
+ * its loop goes unreported, which is a missing error, whereas scoping it
201
+ * precisely without an HTML parser would invent errors that are not there.
202
+ */
203
+ export interface TemplateBinding {
204
+ name: string;
205
+ /**
206
+ * The iterable it was drawn from, when that is a plain identifier.
207
+ *
208
+ * `@foreach(rows as row)` can then type `row` as `rows`' element type, which
209
+ * is what turns a renamed column into a compile error rather than a silent
210
+ * `undefined`. Anything more complex than an identifier stays `any` — a call
211
+ * or a member chain would need the whole expression to resolve, and being
212
+ * wrong there invents errors.
213
+ */
214
+ iterable?: string;
215
+ }
79
216
  export declare function collectTemplateBindings(source: string): TemplateBinding[];
80
217
  /**
81
218
  * Top-level names a script block declares.
@@ -86,6 +223,13 @@ export declare function collectTemplateBindings(source: string): TemplateBinding
86
223
  export declare function collectBlockDeclarations(code: string): string[];
87
224
  /** Ambient declarations for the globals the stx runtime injects. */
88
225
  export declare function runtimeGlobalDeclarations(): string;
226
+ /**
227
+ * Context the server injects into a `<script server>` block.
228
+ *
229
+ * Mirrors what `serve.ts` puts in scope. Declaring these is what lets the
230
+ * checker report a genuine typo instead of suppressing every unresolved name.
231
+ */
232
+ export declare const STX_SERVER_CONTEXT: readonly ['params', 'query', 'cookies', 'host', 'ip', 'setResponseStatus', 'setResponseHeader', 'notFound', 'request', 'url', 'definePageMeta', 'defineClientPayload', 'defineStore', 'props', '$props'];
89
233
  export declare function serverContextDeclarations(): string;
90
234
  /**
91
235
  * The names a `defineClientPayload({ … })` call publishes, or `null` when the
@@ -101,7 +245,10 @@ export declare function serverContextDeclarations(): string;
101
245
  */
102
246
  export declare function extractClientPayloadNames(serverCode: string): string[] | null;
103
247
  /** Top-level `import` statements, and everything else, separated. */
104
- export declare function splitTopLevelImports(code: string): { imports: string, body: string };
248
+ export declare function splitTopLevelImports(code: string): {
249
+ imports: string;
250
+ body: string;
251
+ };
105
252
  /**
106
253
  * Declarations that give a client block the server values it is actually given.
107
254
  *
@@ -146,7 +293,10 @@ export declare function splitTopLevelImports(code: string): { imports: string, b
146
293
  * than a blanked copy, because the declaration's BODY is what has to be carried
147
294
  * across, not just its name.
148
295
  */
149
- export declare function extractTypeDeclarations(code: string): Array<{ name: string, text: string }>;
296
+ export declare function extractTypeDeclarations(code: string): Array<{
297
+ name: string;
298
+ text: string;
299
+ }>;
150
300
  export declare function clientPayloadDeclarations(serverCode: string, clientCode?: string): string;
151
301
  /**
152
302
  * Declarations at the TOP LEVEL of a block, ignoring anything nested.
@@ -180,6 +330,19 @@ export declare function collectTopLevelDeclarations(code: string): string[];
180
330
  * not actually mention any server name.
181
331
  */
182
332
  export declare function scrapedBridgeNames(serverCode: string, clientCode: string): string[];
333
+ /** Marker comment so a generated preamble is recognisable in a dumped buffer. */
334
+ export declare const PAYLOAD_COMMENT = "stx: types for the declared client payload (#1868)";
335
+ /** The same, for a page still relying on the name-scraping bridge. */
336
+ export declare const SCRAPED_COMMENT = "stx: untyped bridge names \u2014 declare a defineClientPayload to check these (#1868)";
337
+ /**
338
+ * Names the template engine puts in scope for every page.
339
+ *
340
+ * Declared rather than suppressed. The editor plugin used to drop every
341
+ * "Cannot find name" whose message mentioned one of a hardcoded list, which
342
+ * also dropped genuine typos; giving the names a declaration means an
343
+ * unrecognised one is still an error (#1852 ask 3).
344
+ */
345
+ export declare const STX_TEMPLATE_GLOBALS: readonly ['$env', '$user', '$slot', '$slots', '$attrs', '$props', '$page', '$route', '$loop', 'loop', '$errors', '$csrf', 'props', 'slot'];
183
346
  /**
184
347
  * Names declared by both a server block and a client/plain block.
185
348
  *
@@ -218,7 +381,10 @@ export declare function crossScopeCollisions(blocks: readonly ScriptBlock[]): st
218
381
  * rather than twice.
219
382
  */
220
383
  export declare function guardChainAt(source: string, offset: number): string[];
221
- export declare function expressionStatement(expression: TemplateExpression): { text: string, prefixLength: number } | null;
384
+ export declare function expressionStatement(expression: TemplateExpression): {
385
+ text: string;
386
+ prefixLength: number;
387
+ } | null;
222
388
  /**
223
389
  * Rewrite relative module specifiers to absolute paths against the real file.
224
390
  *
@@ -246,6 +412,31 @@ export declare function expressionStatement(expression: TemplateExpression): { t
246
412
  * change a line count, so every diagnostic still lands on the author's line.
247
413
  */
248
414
  export declare function absolutizeRelativeSpecifiers(code: string, originDir: string): string;
415
+ export interface BuildVirtualOptions {
416
+ /** Enables component call-site checks using the renderer's file lookup. */
417
+ filePath?: string;
418
+ componentsDir?: string;
419
+ projectRoot?: string;
420
+ readComponent?: (file: string) => string | undefined;
421
+ /** Append `{{ }}` and directive expressions. Default true. */
422
+ templateExpressions?: boolean;
423
+ /**
424
+ * Directory the `.stx` file really lives in.
425
+ *
426
+ * Relative imports in its script blocks are resolved against it, since the
427
+ * buffer this builds is written somewhere else entirely (#1928).
428
+ */
429
+ originDir?: string;
430
+ /** Append ambient declarations at all. Default true. */
431
+ globals?: boolean;
432
+ /**
433
+ * Declare the stx runtime globals as `any`. Default true.
434
+ *
435
+ * Pass `false` when the program already includes the package's `stx.d.ts`,
436
+ * which types them properly — these would shadow it.
437
+ */
438
+ runtimeGlobals?: boolean;
439
+ }
249
440
  /**
250
441
  * Build one line-aligned TypeScript buffer for a whole `.stx` file.
251
442
  *
@@ -260,9 +451,19 @@ export declare function buildVirtualTypeScript(source: string, options?: BuildVi
260
451
  /** Offsets at which each 1-based line starts. */
261
452
  export declare function lineStarts(text: string): number[];
262
453
  /** Offset → 1-based line and column. */
263
- export declare function offsetToPosition(starts: readonly number[], offset: number): { line: number, column: number };
454
+ export declare function offsetToPosition(starts: readonly number[], offset: number): {
455
+ line: number;
456
+ column: number;
457
+ };
264
458
  /** 1-based line and column → offset, clamped to the line. */
265
459
  export declare function positionToOffset(starts: readonly number[], line: number, column: number): number;
460
+ /** Where a diagnostic in a virtual buffer belongs in the `.stx` file. */
461
+ export interface ResolvedPosition {
462
+ line: number;
463
+ column: number;
464
+ /** Set when the diagnostic came from a template expression. */
465
+ expression?: TemplateExpression;
466
+ }
266
467
  /**
267
468
  * Translate a position in a virtual buffer back to the `.stx` file.
268
469
  *
@@ -271,94 +472,3 @@ export declare function positionToOffset(starts: readonly number[], line: number
271
472
  * must be dropped rather than pointed at an arbitrary line.
272
473
  */
273
474
  export declare function resolvePosition(virtual: VirtualFile, line: number, column: number): ResolvedPosition | null;
274
- /**
275
- * Placeholder for a server interpolation spliced into a client expression.
276
- *
277
- * `:show="photos()[{{ idx }}]"` is real stx — the server fills `{{ idx }}` in
278
- * before the client ever parses the attribute. Left in place it is a syntax
279
- * error, so it is replaced with a declared `any`; the interpolation itself is
280
- * still extracted and checked on its own.
281
- */
282
- export declare const INTERPOLATION_PLACEHOLDER: '__stx_interpolated';
283
- /** Name of the generated helper that reads an iterable's element type. */
284
- export declare const ELEMENT_HELPER: '__StxElement';
285
- /** Name of the generated helper that models a template's signal auto-unwrap. */
286
- export declare const UNWRAP_HELPER: '__StxTemplateValue';
287
- /**
288
- * Context the server injects into a `<script server>` block.
289
- *
290
- * Mirrors what `serve.ts` puts in scope. Declaring these is what lets the
291
- * checker report a genuine typo instead of suppressing every unresolved name.
292
- */
293
- export declare const STX_SERVER_CONTEXT: readonly ['params', 'query', 'cookies', 'host', 'ip', 'setResponseStatus', 'setResponseHeader', 'notFound', 'request', 'url', 'definePageMeta', unknown, unknown, 'defineStore', unknown, unknown, unknown, unknown, unknown, '$props'];
294
- /** Marker comment so a generated preamble is recognisable in a dumped buffer. */
295
- export declare const PAYLOAD_COMMENT: 'stx: types for the declared client payload (#1868)';
296
- /** The same, for a page still relying on the name-scraping bridge. */
297
- export declare const SCRAPED_COMMENT: 'stx: untyped bridge names — declare a defineClientPayload to check these (#1868)';
298
- /**
299
- * Names the template engine puts in scope for every page.
300
- *
301
- * Declared rather than suppressed. The editor plugin used to drop every
302
- * "Cannot find name" whose message mentioned one of a hardcoded list, which
303
- * also dropped genuine typos; giving the names a declaration means an
304
- * unrecognised one is still an error (#1852 ask 3).
305
- */
306
- export declare const STX_TEMPLATE_GLOBALS: readonly ['$env', '$user', '$slot', '$slots', '$attrs', '$props', '$page', '$route', '$loop', unknown, unknown, '$errors', '$csrf', 'props', 'slot'];
307
- export declare interface ScriptBlock {
308
- kind: ScriptKind
309
- code: string
310
- startLine: number
311
- attrs: string
312
- }
313
- /** A `{{ }}` interpolation or a directive attribute value. */
314
- export declare interface TemplateExpression {
315
- anchor?: boolean
316
- code: string
317
- line: number
318
- column: number
319
- kind: 'interpolation' | 'directive'
320
- attribute?: string
321
- offset?: number
322
- }
323
- /** A synthetic line's origin, for diagnostics that land outside the source. */
324
- export declare interface MappedLine {
325
- line: number
326
- column: number
327
- expression?: TemplateExpression
328
- prefixLength?: number
329
- }
330
- export declare interface VirtualFile {
331
- text: string
332
- componentDependencies?: Map<string, string>
333
- lineMap: Map<number, MappedLine>
334
- sourceLineCount: number
335
- }
336
- /**
337
- * Names a template introduces that no script block declares.
338
- *
339
- * Loop bindings are collected for the whole file rather than tracked per
340
- * subtree. That is deliberately over-permissive: using a loop variable outside
341
- * its loop goes unreported, which is a missing error, whereas scoping it
342
- * precisely without an HTML parser would invent errors that are not there.
343
- */
344
- export declare interface TemplateBinding {
345
- name: string
346
- iterable?: string
347
- }
348
- export declare interface BuildVirtualOptions {
349
- filePath?: string
350
- componentsDir?: string
351
- projectRoot?: string
352
- readComponent?: (file: string) => string | undefined
353
- templateExpressions?: boolean
354
- originDir?: string
355
- globals?: boolean
356
- runtimeGlobals?: boolean
357
- }
358
- /** Where a diagnostic in a virtual buffer belongs in the `.stx` file. */
359
- export declare interface ResolvedPosition {
360
- line: number
361
- column: number
362
- expression?: TemplateExpression
363
- }
364
- export type ScriptKind = 'server' | 'client' | 'plain';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Make a substituted VALUE unreadable as template syntax.
3
+ *
4
+ * A value reaches the output in the middle of a pipeline: expression passes run
5
+ * again over component expansion and over loop bodies, and the client runtime
6
+ * reads the document afterwards. So whatever a value contains gets a second
7
+ * look, and text that looks like template syntax is acted on -- the value is
8
+ * data, and data must not become markup.
9
+ *
10
+ * Every replacement here is a character reference, so nothing needs restoring
11
+ * afterwards and no placeholder can leak into a page. What a reader sees is
12
+ * unchanged: the browser decodes the references before anything reads them, an
13
+ * attribute parses back to the original character, and JSON.parse of a data
14
+ * attribute still works.
15
+ *
16
+ * Two modules escape values -- expressions.ts for template output and
17
+ * server-components.ts for its own substitution -- and they have to agree, so
18
+ * the rules live here rather than in either of them. This module deliberately
19
+ * imports nothing: server-components.ts keeps its own dependency-light escaping
20
+ * and can use this without pulling in the expression machinery.
21
+ *
22
+ * @module template-syntax-escape
23
+ */
24
+ /**
25
+ * A zero-width joiner. It breaks a syntax pattern while changing nothing a
26
+ * reader sees: no width, no line-breaking behaviour, and it copies as an
27
+ * invisible character.
28
+ */
29
+ export declare const WORD_JOINER = "&#8288;";
30
+ /**
31
+ * Neutralise template syntax in an ALREADY HTML-escaped value.
32
+ *
33
+ * Call it after HTML escaping: it relies on `<`, `>` and the quotes being gone,
34
+ * and on `{`, `}`, `@` and `(` still being themselves.
35
+ */
36
+ export declare function neutralizeTemplateSyntax(escaped: string): string;
@@ -0,0 +1,8 @@
1
+ export const WORD_JOINER = "&#8288;";
2
+ const DIRECTIVE_IN_VALUE = /@(?=[a-zA-Z_]\w*\s*\(|end[a-zA-Z]*\b|else(?:if)?\b|empty\b|case\b|default\b|break\b|continue\b|fallback\b)/g;
3
+ function joinBraces(length) {
4
+ return Array.from({ length }, () => "&#123;").join(WORD_JOINER);
5
+ }
6
+ export function neutralizeTemplateSyntax(escaped) {
7
+ return escaped.replace(/\{{2,}/g, (match) => joinBraces(match.length)).replace(/\{(?=!)/g, `&#123;${WORD_JOINER}`).replace(DIRECTIVE_IN_VALUE, "&#64;");
8
+ }
package/dist/utils.js CHANGED
@@ -21,6 +21,7 @@ import { findSfcTemplateBlock } from "./sfc-template.js";
21
21
  import { importOnce } from "./lazy-module.js";
22
22
  import { stashScriptElements } from "./html-masking.js";
23
23
  import { markProjectedRefs } from "./misc-directives.js";
24
+ import { collectBlockDeclarations } from "./stx-virtual-ts.js";
24
25
  export {
25
26
  extractDirectiveNames,
26
27
  getPositionInfo,
@@ -708,16 +709,20 @@ ${triedPaths.map((p) => ` - ${p}`).join(`
708
709
  preservedExpressionBaseline = new Set(Array.isArray(parentContext.__stx_preserved_client_expressions) ? parentContext.__stx_preserved_client_expressions : []);
709
710
  }
710
711
  }
712
+ const ownServerNames = new Set;
711
713
  for (const match of scriptMatches) {
712
714
  const attrs = match[1] || "";
713
715
  let content = match[2] || "";
714
716
  const isServerScript = attrs.includes("server");
715
717
  if (shouldTranspileTypeScript(attrs) && content.trim())
716
718
  content = transpileTypeScript(content);
717
- if (isServerScript && content)
719
+ if (isServerScript && content) {
720
+ for (const name of collectBlockDeclarations(content))
721
+ ownServerNames.add(name);
718
722
  try {
719
723
  await extractVariables(content, componentContext, componentFilePath);
720
724
  } catch (e) {}
725
+ }
721
726
  if (!isServerScript) {
722
727
  let cleanContent = content.replace(/^\s*const\s*\{[^}]+\}\s*=\s*window\.stx\s*;?\s*\n?/gm, "");
723
728
  const hasMustache = cleanContent.includes("{{") && cleanContent.includes("}}"), hasRawMarker = cleanContent.includes("{!!") && cleanContent.includes("!!}");
@@ -756,9 +761,11 @@ ${triedPaths.map((p) => ` - ${p}`).join(`
756
761
  content: projectRefs(slot.content)
757
762
  }]));
758
763
  templateContent = await applySlots(templateContent, projectRefs(defaultSlot), projectedSlots, componentContext);
759
- const clientSignalNames = componentClientSignalNames(clientScripts), inheritedClientSignalNames = Array.isArray(componentContext.__stx_client_signal_names) ? componentContext.__stx_client_signal_names : [];
764
+ const clientSignalNames = componentClientSignalNames(clientScripts), inheritedClientSignalNames = (Array.isArray(componentContext.__stx_client_signal_names) ? componentContext.__stx_client_signal_names : []).filter((name) => !ownServerNames.has(name));
760
765
  if (clientSignalNames.length > 0 || inheritedClientSignalNames.length > 0)
761
766
  componentContext.__stx_client_signal_names = [...new Set([...inheritedClientSignalNames, ...clientSignalNames])];
767
+ else
768
+ delete componentContext.__stx_client_signal_names;
762
769
  const componentOptions = {
763
770
  ...options,
764
771
  _rootComponentsDir: options._rootComponentsDir || options.componentsDir,
@@ -53,6 +53,7 @@ export declare function isModuleResolutionFailure(message: string): boolean;
53
53
  * as a correct answer rather than as a failure, which is exactly the shape that
54
54
  * is expensive to find.
55
55
  */
56
+ export declare function isSyntaxFailure(error: unknown): boolean;
56
57
  export declare function isMissingBindingFailure(message: string): boolean;
57
58
  /**
58
59
  * Extract variables from script content and add them to context
@@ -275,6 +275,12 @@ export function stripTypeScript(scriptContent) {
275
275
  export function isModuleResolutionFailure(message) {
276
276
  return /cannot find module|could not resolve|module not found|failed to resolve/i.test(message);
277
277
  }
278
+ export function isSyntaxFailure(error) {
279
+ if (error instanceof SyntaxError)
280
+ return !0;
281
+ const message = error instanceof Error ? error.message : String(error);
282
+ return /SyntaxError|Unexpected (token|identifier|string|number|keyword|end of)|Unterminated|Expected .+ but found/i.test(message);
283
+ }
278
284
  export function isMissingBindingFailure(message) {
279
285
  if (!/is not defined|can't find variable/i.test(message))
280
286
  return !1;
@@ -550,6 +556,8 @@ export async function extractVariables(scriptContent, context, filePath, options
550
556
  const msg = primaryError instanceof Error ? primaryError.message : String(primaryError);
551
557
  if (isModuleResolutionFailure(msg))
552
558
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} imports a module that does not resolve, so every variable in that script is undefined. Cause: ${msg}`);
559
+ else if (isSyntaxFailure(primaryError))
560
+ console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} does not parse, so every variable in that script is undefined. Cause: ${msg}`);
553
561
  else if (isMissingBindingFailure(msg))
554
562
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} names something that does not exist, so every variable in that script is undefined. Optional chaining does not help here: an undefined identifier throws before the chain is reached. Cause: ${msg}`);
555
563
  else if (process.env.STX_DEBUG)
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import"./chunk-hyfjnn7g.js";import B from"fs";import $ from"path";import k from"crypto";var V=[{name:"mobile",width:375,height:667,isMobile:!0,hasTouch:!0},{name:"tablet",width:768,height:1024,isMobile:!0,hasTouch:!0},{name:"desktop",width:1280,height:800,isMobile:!1,hasTouch:!1},{name:"wide",width:1920,height:1080,isMobile:!1,hasTouch:!1}];function J(N={}){let Y={snapshotDir:N.snapshotDir||"__snapshots__",screenshotDir:N.screenshotDir||"__screenshots__",updateSnapshots:N.updateSnapshots||process.env.UPDATE_SNAPSHOTS==="true",threshold:N.threshold??0.01,viewports:N.viewports||V,generateDiff:N.generateDiff??!0,diffDir:N.diffDir||"__diffs__",compare:N.compare||b,ci:N.ci??process.env.CI==="true",retries:N.retries??(N.ci?3:1)};return{async snapshot(M,X){let q=$.join(Y.snapshotDir,`${X}.html`),G=C(M),Q=K(G);if(await Bun.file(q).exists()){let W=await Bun.file(q).text(),Z=K(C(W));if(Q===Z)return{passed:!0,snapshotPath:q,message:"Snapshot matches"};if(Y.updateSnapshots)return await B.promises.mkdir($.dirname(q),{recursive:!0}),await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"Snapshot updated"};let F=$.join(Y.diffDir,`${X}.actual.html`),U=$.join(Y.diffDir,`${X}.diff.html`);return await B.promises.mkdir(Y.diffDir,{recursive:!0}),await Bun.write(F,G),await Bun.write(U,I(W,G)),{passed:!1,snapshotPath:q,actualPath:F,diffPath:U,message:"Snapshot does not match"}}return await B.promises.mkdir($.dirname(q),{recursive:!0}),await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"New snapshot created"}},async snapshotJson(M,X){let q=$.join(Y.snapshotDir,`${X}.json`),G=JSON.stringify(M,null,2);if(await Bun.file(q).exists()){let Q=await Bun.file(q).text();if(G===Q)return{passed:!0,snapshotPath:q};if(Y.updateSnapshots)return await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"Snapshot updated"};return{passed:!1,snapshotPath:q,message:`JSON snapshot mismatch:
2
+ import"./chunk-5g6rprcy.js";import B from"fs";import $ from"path";import k from"crypto";var V=[{name:"mobile",width:375,height:667,isMobile:!0,hasTouch:!0},{name:"tablet",width:768,height:1024,isMobile:!0,hasTouch:!0},{name:"desktop",width:1280,height:800,isMobile:!1,hasTouch:!1},{name:"wide",width:1920,height:1080,isMobile:!1,hasTouch:!1}];function J(N={}){let Y={snapshotDir:N.snapshotDir||"__snapshots__",screenshotDir:N.screenshotDir||"__screenshots__",updateSnapshots:N.updateSnapshots||process.env.UPDATE_SNAPSHOTS==="true",threshold:N.threshold??0.01,viewports:N.viewports||V,generateDiff:N.generateDiff??!0,diffDir:N.diffDir||"__diffs__",compare:N.compare||b,ci:N.ci??process.env.CI==="true",retries:N.retries??(N.ci?3:1)};return{async snapshot(M,X){let q=$.join(Y.snapshotDir,`${X}.html`),G=C(M),Q=K(G);if(await Bun.file(q).exists()){let W=await Bun.file(q).text(),Z=K(C(W));if(Q===Z)return{passed:!0,snapshotPath:q,message:"Snapshot matches"};if(Y.updateSnapshots)return await B.promises.mkdir($.dirname(q),{recursive:!0}),await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"Snapshot updated"};let F=$.join(Y.diffDir,`${X}.actual.html`),U=$.join(Y.diffDir,`${X}.diff.html`);return await B.promises.mkdir(Y.diffDir,{recursive:!0}),await Bun.write(F,G),await Bun.write(U,I(W,G)),{passed:!1,snapshotPath:q,actualPath:F,diffPath:U,message:"Snapshot does not match"}}return await B.promises.mkdir($.dirname(q),{recursive:!0}),await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"New snapshot created"}},async snapshotJson(M,X){let q=$.join(Y.snapshotDir,`${X}.json`),G=JSON.stringify(M,null,2);if(await Bun.file(q).exists()){let Q=await Bun.file(q).text();if(G===Q)return{passed:!0,snapshotPath:q};if(Y.updateSnapshots)return await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"Snapshot updated"};return{passed:!1,snapshotPath:q,message:`JSON snapshot mismatch:
3
3
  ${z(Q,G)}`}}return await B.promises.mkdir($.dirname(q),{recursive:!0}),await Bun.write(q,G),{passed:!0,snapshotPath:q,message:"New snapshot created"}},matchInlineSnapshot(M,X){let q=C(M);if(X===void 0)return{passed:!0,expected:q};let G=C(X);return{passed:q===G,expected:q}},getConfig(){return Y}}}function D(N={}){let Y=J(N),M=Y.getConfig();return{async compareScreenshots(X,q,G="desktop"){let Q=$.join(M.screenshotDir,G,`${X}.png`),W=$.join(M.diffDir,G,`${X}.actual.png`),Z=$.join(M.diffDir,G,`${X}.diff.png`);if(await Bun.file(Q).exists()){let F=await Bun.file(Q).arrayBuffer(),U=Buffer.from(F),_=await M.compare(q,U);if(_.match||_.diffPercentage<=M.threshold)return{viewport:G,passed:!0,baselinePath:Q};if(M.updateSnapshots)return await B.promises.mkdir($.dirname(Q),{recursive:!0}),await Bun.write(Q,q),{viewport:G,passed:!0,baselinePath:Q};if(await B.promises.mkdir($.dirname(W),{recursive:!0}),await Bun.write(W,q),_.diffImage&&M.generateDiff)await Bun.write(Z,_.diffImage);return{viewport:G,passed:!1,baselinePath:Q,actualPath:W,diffPath:M.generateDiff?Z:void 0,diffPercentage:_.diffPercentage}}return await B.promises.mkdir($.dirname(Q),{recursive:!0}),await Bun.write(Q,q),{viewport:G,passed:!0,baselinePath:Q}},async testViewports(X,q,G=M.viewports){let Q=[];for(let W of G){let Z=null;for(let F=0;F<M.retries;F++)try{let U=await q(W),_=await this.compareScreenshots(X,U,W.name);Q.push(_),Z=null;break}catch(U){if(Z=U,F<M.retries-1)await new Promise((_)=>setTimeout(_,100*(F+1)))}if(Z)Q.push({viewport:W.name,passed:!1,baselinePath:"",diffPercentage:100})}return Q},getSnapshotTester(){return Y}}}function L(N={}){let M=D(N).getSnapshotTester(),X=new Map;return{addStory(q){X.set(`${q.component}/${q.name}`,q)},addStories(q){for(let G of q)this.addStory(G)},getStories(){return Array.from(X.values())},getStoriesForComponent(q){return Array.from(X.values()).filter((G)=>G.component===q)},async testStory(q){let G=X.get(q);if(!G)return{name:q,passed:!1,duration:0,snapshots:[],screenshots:[],errors:[Error(`Story not found: ${q}`)]};let Q=Date.now(),W={name:q,passed:!0,duration:0,snapshots:[],screenshots:[],errors:[]};try{let Z=await G.render(),F=await M.snapshot(Z,q.replace(/\//g,"-"));if(W.snapshots.push(F),!F.passed)W.passed=!1}catch(Z){W.passed=!1,W.errors.push(Z)}return W.duration=Date.now()-Q,W},async testAllStories(){let q=[];for(let G of X.keys()){let Q=await this.testStory(G);q.push(Q)}return q},async generateStoryIndex(){let q={};for(let G of X.values()){if(!q[G.component])q[G.component]=[];q[G.component].push({name:G.name,args:G.args})}return JSON.stringify(q,null,2)}}}async function S(N,Y={}){let M={outputDir:Y.outputDir||"visual-test-report",format:Y.format||"html",title:Y.title||"Visual Test Report",includeScreenshots:Y.includeScreenshots??!0};await B.promises.mkdir(M.outputDir,{recursive:!0});let X=N.length,q=N.filter((F)=>F.passed).length,G=X-q,Q=N.reduce((F,U)=>F+U.duration,0);if(M.format==="json"){let F={title:M.title,summary:{total:X,passed:q,failed:G,duration:Q},results:N,generatedAt:new Date().toISOString()},U=$.join(M.outputDir,"report.json");return await Bun.write(U,JSON.stringify(F,null,2)),U}if(M.format==="markdown"){let F=`# ${M.title}
4
4
 
5
5
  `;F+=`## Summary
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/stx",
3
3
  "type": "module",
4
- "version": "0.2.336",
4
+ "version": "0.2.338",
5
5
  "description": "A performant UI Framework. Powered by Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -116,14 +116,14 @@
116
116
  },
117
117
  "dependencies": {
118
118
  "@stacksjs/ts-css": "^0.3.2",
119
- "@stacksjs/clapp": "^0.2.14",
120
- "@stacksjs/desktop": "0.2.336",
121
- "@stacksjs/sanitizer": "0.2.336",
119
+ "@stacksjs/clapp": "^0.2.16",
120
+ "@stacksjs/desktop": "0.2.338",
121
+ "@stacksjs/sanitizer": "0.2.338",
122
122
  "@stacksjs/ts-i18n": "^0.1.11",
123
- "bun-plugin-stx": "0.2.336",
124
- "bunfig": "^0.15.17",
125
- "stx-router": "0.2.336",
126
- "ts-broadcasting": "^0.0.9",
123
+ "bun-plugin-stx": "0.2.338",
124
+ "bunfig": "^0.15.19",
125
+ "stx-router": "0.2.338",
126
+ "ts-broadcasting": "^0.0.10",
127
127
  "ts-images": "^0.2.22",
128
128
  "ts-syntax-highlighter": "^0.2.1"
129
129
  }
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{hl as a,il as b,jl as c,kl as d,ll as e,ml as f,nl as g,ol as h,pl as i,ql as j,rl as k,sl as l,tl as m,ul as n,vl as o}from"./chunk-zz8qgqa1.js";import"./chunk-p1hy2bwn.js";import"./chunk-kxtqbrfr.js";import"./chunk-caaenc3w.js";import"./chunk-amxtypkp.js";import"./chunk-nat3actx.js";import"./chunk-q0g5c39d.js";import"./chunk-kffndzch.js";import"./chunk-c2ta859c.js";import"./chunk-r8rbf28v.js";import"./chunk-gptwwv3c.js";import"./chunk-n66k2v2q.js";import"./chunk-vvd659y4.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import"./chunk-hzfd8cz0.js";import"./chunk-q569zmrr.js";import"./chunk-hyfjnn7g.js";export{o as tempBuildName,b as shouldLogBundlerDiagnostics,f as setBundlerFallbackMode,l as rewriteRegistryImports,g as resolveBundlerFallback,j as registryIdForPath,c as recordBundleFailure,m as queueClientBundleBuild,k as normalizeRegistrySpecifiers,h as hasUserImports,d as getBundleFailures,a as clientBundleDependencies,e as clearBundleFailures,n as bundleClientScript,i as MODULE_SPECIFIER_PREFIX};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{To as a,Vo as b,Xo as c,Yo as d,fq as e,gq as f,hq as g,iq as h,jq as i,kq as j,lq as k,mq as l,nq as m,oq as n,pq as o,qq as p,rq as q,sq as r,tq as s,uq as t,vq as u,wq as v,xq as w,yq as x}from"./chunk-kxtqbrfr.js";import"./chunk-caaenc3w.js";import"./chunk-amxtypkp.js";import"./chunk-nat3actx.js";import"./chunk-q0g5c39d.js";import"./chunk-kffndzch.js";import"./chunk-c2ta859c.js";import"./chunk-r8rbf28v.js";import"./chunk-gptwwv3c.js";import"./chunk-n66k2v2q.js";import"./chunk-vvd659y4.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import"./chunk-hzfd8cz0.js";import"./chunk-q569zmrr.js";import"./chunk-hyfjnn7g.js";export{e as validateTemplate,g as validateDirective,n as userComponentFileExists,m as transpileTypeScript,p as slotContentHasExpressions,k as shouldTranspileTypeScript,t as resolveTemplatePath,r as renderComponentWithSlot,j as isJavaScriptScript,o as isHydrateTrigger,d as hasVariables,h as hasDirectives,u as getSourceLineInfo,l as getSharedTranspiler,f as getPositionInfo,x as getComponentCacheStats,s as fileExists,a as extractVariables,c as extractScriptFromTemplate,i as extractDirectiveNames,v as createDetailedErrorMessage,b as convertToCommonJS,q as componentClientSignalNames,w as clearComponentCache};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{ji as a,ki as b}from"./chunk-ya5m5vbn.js";import"./chunk-hyfjnn7g.js";export{a as processTeleportDirectives,b as ensureTeleportTargets};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{bl as a,cl as b,dl as c,el as d,fl as e}from"./chunk-zsnrcbw1.js";import"./chunk-hyfjnn7g.js";export{b as injectPwaTags,e as generateThemeColorMeta,c as generateSwRegistrationScript,a as generatePwaTags,d as generateManifestLink};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{bq as b,cq as c,dq as d,eq as e,yo as a}from"./chunk-kxtqbrfr.js";import"./chunk-caaenc3w.js";import"./chunk-amxtypkp.js";import"./chunk-nat3actx.js";import"./chunk-q0g5c39d.js";import"./chunk-kffndzch.js";import"./chunk-c2ta859c.js";import"./chunk-r8rbf28v.js";import"./chunk-gptwwv3c.js";import"./chunk-n66k2v2q.js";import"./chunk-vvd659y4.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import"./chunk-hzfd8cz0.js";import"./chunk-q569zmrr.js";import"./chunk-hyfjnn7g.js";export{d as validateClientScript,c as processOnceDirective,b as processJsonDirective,e as processDirectives,a as injectRouterScript};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{lt as a,mt as b}from"./chunk-amxtypkp.js";import"./chunk-hyfjnn7g.js";export{b as resolveStxTargets,a as looksLikeGlob};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{$i as e,Xi as a,Yi as b,Zi as c,_i as d,aj as f,bj as g,cj as h,dj as i,ej as j,fj as k,gj as l,hj as m,ij as n}from"./chunk-ymrxpwr8.js";import"./chunk-kxtqbrfr.js";import"./chunk-caaenc3w.js";import"./chunk-amxtypkp.js";import"./chunk-nat3actx.js";import"./chunk-q0g5c39d.js";import"./chunk-kffndzch.js";import"./chunk-c2ta859c.js";import"./chunk-r8rbf28v.js";import"./chunk-gptwwv3c.js";import"./chunk-n66k2v2q.js";import"./chunk-vvd659y4.js";import"./chunk-7r80apc5.js";import"./chunk-2tjk867y.js";import"./chunk-t8ctvjqe.js";import"./chunk-deqnt1w5.js";import"./chunk-hzfd8cz0.js";import"./chunk-q569zmrr.js";import"./chunk-hyfjnn7g.js";export{i as streamingSuspenseDirective,m as streamToResponse,g as streamTemplateSimple,a as streamTemplate,d as renderStreamingPage,k as registerStreamingDirectives,e as processStreamDirectives,l as processSectionDirectives,j as islandDirective,n as generateHydrationRuntime,f as extractStreamBoundaries,h as createStreamRenderer,b as buildSuspenseResolveScript,c as SUSPENSE_RESOLVER_RUNTIME};