@stacksjs/stx 0.2.305 → 0.2.307

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/{chunk-0gz0rhvs.js → chunk-0gbptqh2.js} +1 -1
  2. package/dist/{chunk-g97atepq.js → chunk-0mnv8pf5.js} +1 -1
  3. package/dist/{chunk-4mrhxtn3.js → chunk-0va2vsqa.js} +2 -2
  4. package/dist/chunk-0wwgr4wv.js +2 -0
  5. package/dist/{chunk-nqq7y7m9.js → chunk-18p8dqya.js} +1 -1
  6. package/dist/chunk-1vwgywtn.js +2 -0
  7. package/dist/{chunk-awj7yy37.js → chunk-1ztjv7a4.js} +1 -1
  8. package/dist/{chunk-eans1ct0.js → chunk-20yc1zrp.js} +1 -1
  9. package/dist/{chunk-f1cgyd2h.js → chunk-24bgm3hh.js} +1 -1
  10. package/dist/{chunk-rvyfyc43.js → chunk-2559vc7d.js} +1 -1
  11. package/dist/{chunk-9nf3hgvq.js → chunk-286rffvb.js} +2 -2
  12. package/dist/{chunk-qev11kg8.js → chunk-2kv2gnzc.js} +1 -1
  13. package/dist/chunk-2pv79p7x.js +2 -0
  14. package/dist/{chunk-b4xwbh8a.js → chunk-322qz0cj.js} +1 -1
  15. package/dist/{chunk-t51mwjyq.js → chunk-397rqs12.js} +1 -1
  16. package/dist/{chunk-env6knrs.js → chunk-3by4c2g9.js} +1 -1
  17. package/dist/{chunk-tt4r8q4v.js → chunk-3pv0qj5f.js} +1 -1
  18. package/dist/chunk-455m2k1y.js +2 -0
  19. package/dist/{chunk-c131k3mt.js → chunk-4ee1aaet.js} +1 -1
  20. package/dist/{chunk-d3srvh3q.js → chunk-4hk5ewgp.js} +1 -1
  21. package/dist/chunk-4z3yyryn.js +2 -0
  22. package/dist/{chunk-wx13qmaw.js → chunk-51gea48g.js} +1 -1
  23. package/dist/{chunk-bk95q0bw.js → chunk-58xpr98x.js} +1 -1
  24. package/dist/chunk-59fva5cz.js +2 -0
  25. package/dist/{chunk-gbwhbasw.js → chunk-5g39e9ra.js} +1 -1
  26. package/dist/{chunk-xsfwcj6x.js → chunk-604qr43v.js} +1 -1
  27. package/dist/chunk-64ttktzc.js +4 -0
  28. package/dist/chunk-6dmrpd71.js +2 -0
  29. package/dist/chunk-6vt9ddra.js +2 -0
  30. package/dist/{chunk-k23r03qj.js → chunk-6xqgkfb3.js} +1 -1
  31. package/dist/chunk-75vxhxn1.js +2 -0
  32. package/dist/{chunk-6zt2y7q3.js → chunk-769jvq54.js} +1 -1
  33. package/dist/{chunk-gssbag3e.js → chunk-7c1qq9zq.js} +1 -1
  34. package/dist/chunk-7n6fq2t7.js +2 -0
  35. package/dist/{chunk-ta398s3d.js → chunk-7xrvkrrx.js} +10 -10
  36. package/dist/{chunk-yyyxt326.js → chunk-7yzyn9k7.js} +1 -1
  37. package/dist/chunk-80rmf67y.js +2 -0
  38. package/dist/{chunk-ppyz9623.js → chunk-85p4dmft.js} +1 -1
  39. package/dist/{chunk-c1ae6afc.js → chunk-8g6jwkjy.js} +2 -2
  40. package/dist/{chunk-8ee62a9q.js → chunk-8q8gj45z.js} +1 -1
  41. package/dist/chunk-8tkn0yxq.js +2 -0
  42. package/dist/{chunk-gecmqs6p.js → chunk-8wqhts61.js} +1 -1
  43. package/dist/chunk-9aw5d4rr.js +2 -0
  44. package/dist/{chunk-fp7ms6e7.js → chunk-9ebfmdyb.js} +1 -1
  45. package/dist/{chunk-rzevgemj.js → chunk-a50hb40e.js} +1 -1
  46. package/dist/{chunk-jfzfrmzy.js → chunk-ajhrz96a.js} +1 -1
  47. package/dist/{chunk-wfffa8zm.js → chunk-aqrp68m6.js} +1 -1
  48. package/dist/{chunk-8jam44my.js → chunk-at84gyvf.js} +1 -1
  49. package/dist/{chunk-ess2pgt5.js → chunk-b8cteeha.js} +1 -1
  50. package/dist/chunk-ba5t40dx.js +2 -0
  51. package/dist/{chunk-mbmqpaq1.js → chunk-bnq0p4r4.js} +1 -1
  52. package/dist/chunk-bzmxbz48.js +2 -0
  53. package/dist/{chunk-wnamjw6n.js → chunk-cpsepyzg.js} +1 -1
  54. package/dist/chunk-czje8k8c.js +2 -0
  55. package/dist/chunk-d4b67e6m.js +2 -0
  56. package/dist/chunk-e16hkjh9.js +2 -0
  57. package/dist/{chunk-gt8ja700.js → chunk-f044qmn3.js} +1 -1
  58. package/dist/chunk-f7e286pa.js +2 -0
  59. package/dist/{chunk-f325jzsk.js → chunk-f91yrkcz.js} +2 -2
  60. package/dist/chunk-fsee2x1q.js +2 -0
  61. package/dist/chunk-fwdn408g.js +2 -0
  62. package/dist/chunk-gy3sf0fw.js +2 -0
  63. package/dist/chunk-h78pksyp.js +2 -0
  64. package/dist/chunk-hg7ptfd4.js +2 -0
  65. package/dist/{chunk-s3dnk3gc.js → chunk-hsbrta4s.js} +1 -1
  66. package/dist/{chunk-695fkras.js → chunk-j3ajrx2n.js} +1 -1
  67. package/dist/{chunk-jsg1rthc.js → chunk-jd9nv63q.js} +1 -1
  68. package/dist/{chunk-jp2f8yzw.js → chunk-jryjwara.js} +1 -1
  69. package/dist/{chunk-4evbx7sz.js → chunk-jwnbwemq.js} +1 -1
  70. package/dist/{chunk-zhcs8m2a.js → chunk-k14nr7rz.js} +1 -1
  71. package/dist/{chunk-mv5fdcwc.js → chunk-k1qzydkj.js} +3 -3
  72. package/dist/chunk-k48jp969.js +2 -0
  73. package/dist/{chunk-hg2afckn.js → chunk-ka2xspj3.js} +1 -1
  74. package/dist/{chunk-mygq61f5.js → chunk-ka5wtqmw.js} +1 -1
  75. package/dist/{chunk-d5cqnwdd.js → chunk-kexk6z9s.js} +1 -1
  76. package/dist/{chunk-m8n0s4tk.js → chunk-kh9r3pfb.js} +1 -1
  77. package/dist/{chunk-qeyw5za9.js → chunk-ksqba0cq.js} +1 -1
  78. package/dist/chunk-kwjgt9jx.js +2 -0
  79. package/dist/{chunk-t8fqjb25.js → chunk-mk0j30e1.js} +1 -1
  80. package/dist/{chunk-m31n9pkr.js → chunk-msmhta0w.js} +1 -1
  81. package/dist/chunk-mvj75wef.js +2 -0
  82. package/dist/{chunk-1jbjrc0w.js → chunk-mvyadg84.js} +1 -1
  83. package/dist/{chunk-cbgh359m.js → chunk-n43zq50e.js} +1 -1
  84. package/dist/{chunk-g912mb7x.js → chunk-nnv8wytm.js} +1 -1
  85. package/dist/{chunk-w6d91maa.js → chunk-ns8fx1f9.js} +1 -1
  86. package/dist/{chunk-ydgdq45a.js → chunk-pwv15j35.js} +1 -1
  87. package/dist/{chunk-fczfdsab.js → chunk-r7qap4bh.js} +2 -2
  88. package/dist/{chunk-fg0nf7cv.js → chunk-r8z1rexd.js} +277 -272
  89. package/dist/chunk-raxr83fs.js +60 -0
  90. package/dist/{chunk-jxxv18a0.js → chunk-ry1key0g.js} +1 -1
  91. package/dist/{chunk-9c835qjn.js → chunk-s3pvp8qv.js} +1 -1
  92. package/dist/{chunk-sart9ehj.js → chunk-snmtft92.js} +1 -1
  93. package/dist/{chunk-zs5y7xnt.js → chunk-t5kwx6fa.js} +1 -1
  94. package/dist/{chunk-rrankpmj.js → chunk-ttny9g8k.js} +1 -1
  95. package/dist/chunk-v0ne90ft.js +2 -0
  96. package/dist/chunk-v33qvj8y.js +2 -0
  97. package/dist/{chunk-ze44hhxb.js → chunk-vbwq7he6.js} +2 -2
  98. package/dist/{chunk-d19tvdvv.js → chunk-vhan24as.js} +1 -1
  99. package/dist/chunk-vpbw6g2t.js +2 -0
  100. package/dist/{chunk-ek8cgwcg.js → chunk-vtd5bgt9.js} +1 -1
  101. package/dist/{chunk-00rtz7nw.js → chunk-vwq4kwwj.js} +1 -1
  102. package/dist/{chunk-bd9wrcq1.js → chunk-w8hkprzv.js} +1 -1
  103. package/dist/chunk-wbt9kz3j.js +2 -0
  104. package/dist/{chunk-ghw5p1yk.js → chunk-wm86mmgq.js} +1 -1
  105. package/dist/{chunk-d57gb0v2.js → chunk-wwghzbbg.js} +1 -1
  106. package/dist/{chunk-kxavsh3m.js → chunk-xcsf7my7.js} +1 -1
  107. package/dist/{chunk-hrcxfvh1.js → chunk-y4dd2n2n.js} +1 -1
  108. package/dist/{chunk-7skk34dh.js → chunk-ybct46zd.js} +1 -1
  109. package/dist/chunk-yp0jymdz.js +2 -0
  110. package/dist/{chunk-7m4yhzhb.js → chunk-yyxhjfgd.js} +2 -2
  111. package/dist/{chunk-t3qb9s6s.js → chunk-zdzd2jb4.js} +1 -1
  112. package/dist/{chunk-7gqbr8nr.js → chunk-zr1r73p3.js} +1 -1
  113. package/dist/cli.js +14 -14
  114. package/dist/craft-entry.js +1 -1
  115. package/dist/craft.js +1 -1
  116. package/dist/database.js +1 -1
  117. package/dist/expressions.d.ts +10 -1
  118. package/dist/expressions.js +42 -11
  119. package/dist/head.d.ts +12 -0
  120. package/dist/head.js +21 -2
  121. package/dist/pwa.js +2 -2
  122. package/dist/safe-evaluator.d.ts +18 -0
  123. package/dist/safe-evaluator.js +100 -17
  124. package/dist/seo.js +56 -4
  125. package/dist/ssg.js +2 -2
  126. package/dist/types/config-types.d.ts +20 -0
  127. package/dist/types/index.d.ts +1 -1
  128. package/dist/visual-testing.js +1 -1
  129. package/package.json +5 -5
  130. package/dist/chunk-02hm88m5.js +0 -2
  131. package/dist/chunk-044mychj.js +0 -2
  132. package/dist/chunk-113y4ywy.js +0 -2
  133. package/dist/chunk-1c2j4eby.js +0 -4
  134. package/dist/chunk-2h94c5hm.js +0 -60
  135. package/dist/chunk-3eervtf9.js +0 -2
  136. package/dist/chunk-4jgr954p.js +0 -2
  137. package/dist/chunk-57ea6ye2.js +0 -2
  138. package/dist/chunk-8z0n5mtg.js +0 -2
  139. package/dist/chunk-92zzryxw.js +0 -2
  140. package/dist/chunk-a87jqtmd.js +0 -2
  141. package/dist/chunk-bezqaxqt.js +0 -2
  142. package/dist/chunk-dgpjxmhs.js +0 -2
  143. package/dist/chunk-er848s6f.js +0 -2
  144. package/dist/chunk-hftqr8ej.js +0 -2
  145. package/dist/chunk-hzav4hyd.js +0 -2
  146. package/dist/chunk-m537zgay.js +0 -2
  147. package/dist/chunk-n99ajrwv.js +0 -2
  148. package/dist/chunk-ncrfrp95.js +0 -2
  149. package/dist/chunk-nws8fbde.js +0 -2
  150. package/dist/chunk-phcvbqzn.js +0 -2
  151. package/dist/chunk-qpzxgkc5.js +0 -2
  152. package/dist/chunk-qt2dmyq5.js +0 -2
  153. package/dist/chunk-r2k2sewg.js +0 -2
  154. package/dist/chunk-r808fpme.js +0 -2
  155. package/dist/chunk-sen2cxqm.js +0 -2
  156. package/dist/chunk-tc6gqeha.js +0 -2
  157. package/dist/chunk-twbw18vs.js +0 -2
  158. package/dist/chunk-wjdfhfj6.js +0 -2
  159. package/dist/chunk-x10mrzgp.js +0 -2
  160. package/dist/chunk-xd5ahrtn.js +0 -2
  161. package/dist/chunk-xzgvcrnz.js +0 -2
  162. package/dist/chunk-yd7jyyr7.js +0 -2
  163. package/dist/chunk-zs95z9tf.js +0 -2
package/dist/pwa.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- import{Ok as wq,Pk as dq,Qk as Cq,Rk as mq,Sk as gq}from"./chunk-m3a20mmb.js";import{$k as w,Tk as S,Uk as Tq,Vk as _q,Wk as z,Xk as D,Yk as P,Zk as kq,_k as vq,al as Iq,bl as d,cl as Hq,dl as Oq,el as Mq}from"./chunk-7skk34dh.js";import{Vv as Aq,Wv as bq,Xv as Sq,Yv as zq,Zv as Dq,_v as Pq}from"./chunk-fp7ms6e7.js";import{cw as N}from"./chunk-jp2f8yzw.js";import p from"fs";import E from"path";import C from"fs";import L from"path";var k=[72,96,128,144,152,192,384,512],v=[120,152,167,180],I=[16,32];async function H(G,B){let q={success:!0,generatedFiles:[],errors:[],warnings:[]},K=G.pwa?.icons;if(!K?.src)return q.errors.push("No source icon specified in pwa.icons.src"),q.success=!1,q;let Y=L.isAbsolute(K.src)?K.src:L.resolve(process.cwd(),K.src);if(!await Bun.file(Y).exists())return q.errors.push(`Source icon not found: ${Y}`),q.success=!1,q;let Q=L.resolve(B,K.outputDir||"pwa-icons");try{C.mkdirSync(Q,{recursive:!0})}catch{return q.errors.push(`Failed to create output directory: ${Q}`),q.success=!1,q}let X=K.sizes||k,j=K.generateWebP??!0,J=K.generateAppleIcons??!0;try{let y;try{y=await import("sharp")}catch{return q.errors.push(`sharp is not installed. Install it with: bun add sharp
3
- Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-er848s6f.js"),Y=await Bun.file(q).text();return await K(Y,{},q,G,new Set)}catch(K){console.warn(`[PWA] Failed to process custom offline page: ${K}`)}else console.warn(`[PWA] Custom offline page not found: ${q}`)}return f(G)}function f(G){let B=G.pwa?.offline,q=G.pwa?.manifest,K=B?.fallbackTitle||"You are offline",Y=B?.fallbackMessage||"Please check your internet connection and try again.",Q=q?.themeColor||"#4f46e5",X=q?.shortName||q?.name||"App";return`<!DOCTYPE html>
2
+ import{Ok as wq,Pk as dq,Qk as Cq,Rk as mq,Sk as gq}from"./chunk-m3a20mmb.js";import{$k as w,Tk as S,Uk as Tq,Vk as _q,Wk as z,Xk as D,Yk as P,Zk as kq,_k as vq,al as Iq,bl as d,cl as Hq,dl as Oq,el as Mq}from"./chunk-ybct46zd.js";import{$v as Dq,Xv as Aq,Yv as bq,Zv as Sq,_v as zq,aw as Pq}from"./chunk-9ebfmdyb.js";import{ew as N}from"./chunk-jryjwara.js";import p from"fs";import E from"path";import C from"fs";import L from"path";var k=[72,96,128,144,152,192,384,512],v=[120,152,167,180],I=[16,32];async function H(G,B){let q={success:!0,generatedFiles:[],errors:[],warnings:[]},K=G.pwa?.icons;if(!K?.src)return q.errors.push("No source icon specified in pwa.icons.src"),q.success=!1,q;let Y=L.isAbsolute(K.src)?K.src:L.resolve(process.cwd(),K.src);if(!await Bun.file(Y).exists())return q.errors.push(`Source icon not found: ${Y}`),q.success=!1,q;let Q=L.resolve(B,K.outputDir||"pwa-icons");try{C.mkdirSync(Q,{recursive:!0})}catch{return q.errors.push(`Failed to create output directory: ${Q}`),q.success=!1,q}let X=K.sizes||k,j=K.generateWebP??!0,J=K.generateAppleIcons??!0;try{let y;try{y=await import("sharp")}catch{return q.errors.push(`sharp is not installed. Install it with: bun add sharp
3
+ Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-1vwgywtn.js"),Y=await Bun.file(q).text();return await K(Y,{},q,G,new Set)}catch(K){console.warn(`[PWA] Failed to process custom offline page: ${K}`)}else console.warn(`[PWA] Custom offline page not found: ${q}`)}return f(G)}function f(G){let B=G.pwa?.offline,q=G.pwa?.manifest,K=B?.fallbackTitle||"You are offline",Y=B?.fallbackMessage||"Please check your internet connection and try again.",Q=q?.themeColor||"#4f46e5",X=q?.shortName||q?.name||"App";return`<!DOCTYPE html>
4
4
  <html lang="en">
5
5
  <head>
6
6
  <meta charset="UTF-8">
@@ -39,6 +39,24 @@ export declare function resetSafeEvaluatorConfig(): void;
39
39
  * Get current configuration
40
40
  */
41
41
  export declare function getSafeEvaluatorConfig(): SafeEvaluatorConfig;
42
+ /**
43
+ * Thrown when an expression breaks the evaluator's security policy.
44
+ *
45
+ * `rule` names what rejected it, on its own, so a caller reporting the failure
46
+ * can say why without re-parsing the message.
47
+ */
48
+ export declare class UnsafeExpressionError extends Error {
49
+ readonly rule: string;
50
+ readonly expression: string;
51
+ constructor(rule: string, expression: string, message?: string);
52
+ }
53
+ /**
54
+ * The rule an expression breaks, or `null` when it is safe to evaluate.
55
+ *
56
+ * Unlike {@link getExpressionSafetyReason}, this is the rule alone, without the
57
+ * expression repeated after it.
58
+ */
59
+ export declare function getExpressionSafetyRule(expression: string): string | null;
42
60
  /**
43
61
  * Sanitize an expression by checking for dangerous patterns
44
62
  */
@@ -26,7 +26,7 @@ const _ALLOWED_GLOBALS = new Set([
26
26
  "JSON",
27
27
  "Number",
28
28
  "Boolean"
29
- ]), DANGEROUS_PATTERNS = [
29
+ ]), NEW_OPERATOR_PATTERN = /\bnew\s+/, SAFE_CTOR_PARAM = "__stx_safe_ctors", DANGEROUS_PATTERNS = [
30
30
  /\b(eval|Function|setTimeout|setInterval|setImmediate)\b/,
31
31
  /\b(process|require|import|exports|module)\b/,
32
32
  /\b(window|document|global|globalThis)\b/,
@@ -37,7 +37,7 @@ const _ALLOWED_GLOBALS = new Set([
37
37
  /\b(Generator|AsyncGenerator)\b/,
38
38
  /__\w+__/,
39
39
  /\.(bind|call|apply)\s*\(/,
40
- /\bnew\s+/,
40
+ NEW_OPERATOR_PATTERN,
41
41
  /\bdelete\s+/,
42
42
  /\bthis\b/
43
43
  ], DANGEROUS_IDENTIFIERS = new Set([
@@ -67,14 +67,17 @@ const _ALLOWED_GLOBALS = new Set([
67
67
  "Generator",
68
68
  "AsyncGenerator",
69
69
  "delete",
70
- "this"
70
+ "this",
71
+ SAFE_CTOR_PARAM
71
72
  ]), DANGEROUS_BRACKET_KEYS = new Set([
72
73
  "__proto__",
73
74
  "constructor",
74
75
  "prototype"
75
76
  ]), BRACKET_NOTATION_PATTERN = /[\w)\]]\s*\[\s*['"]/;
76
- function stripStringLiterals(expr) {
77
- let result = "", inString = null, escaped = !1;
77
+ function stripStringLiteralsWithMap(expr) {
78
+ let result = "";
79
+ const map = [];
80
+ let inString = null, escaped = !1;
78
81
  for (let i = 0;i < expr.length; i++) {
79
82
  const ch = expr[i];
80
83
  if (escaped) {
@@ -96,6 +99,7 @@ function stripStringLiterals(expr) {
96
99
  tplDepth--;
97
100
  if (tplDepth > 0) {
98
101
  result += expr[i];
102
+ map.push(i);
99
103
  i++;
100
104
  }
101
105
  }
@@ -110,8 +114,72 @@ function stripStringLiterals(expr) {
110
114
  continue;
111
115
  }
112
116
  result += ch;
117
+ map.push(i);
118
+ }
119
+ return { text: result, map };
120
+ }
121
+ function stripStringLiterals(expr) {
122
+ return stripStringLiteralsWithMap(expr).text;
123
+ }
124
+ const INTL_CONSTRUCTORS = [
125
+ "Collator",
126
+ "DateTimeFormat",
127
+ "DisplayNames",
128
+ "ListFormat",
129
+ "Locale",
130
+ "NumberFormat",
131
+ "PluralRules",
132
+ "RelativeTimeFormat",
133
+ "Segmenter"
134
+ ], SAFE_CONSTRUCTORS = (() => {
135
+ const ctors = { Date, URL, URLSearchParams }, intl = Intl;
136
+ for (const name of INTL_CONSTRUCTORS)
137
+ if (typeof intl[name] === "function")
138
+ ctors[`Intl_${name}`] = intl[name];
139
+ return Object.freeze(Object.assign(Object.create(null), ctors));
140
+ })(), SAFE_NEW_RE = /^new(\s+)(Date|URLSearchParams|URL|Intl\s*\.\s*([A-Z_a-z]\w*))\s*\(/, NEW_TOKEN_RE = /(?<![\w$])new(?![\w$])/g, SAFE_NEW_RULE = `only new Date(), new URL(), new URLSearchParams() and new Intl.{${INTL_CONSTRUCTORS.join(",")}}() are allowed`;
141
+ function rewriteSafeConstructors(expression) {
142
+ const { text, map } = stripStringLiteralsWithMap(expression), replacements = [];
143
+ NEW_TOKEN_RE.lastIndex = 0;
144
+ let match;
145
+ while ((match = NEW_TOKEN_RE.exec(text)) !== null) {
146
+ const at = match.index;
147
+ if (/(?<!\.)\.\s*$/.test(text.slice(0, at)))
148
+ continue;
149
+ const tail = SAFE_NEW_RE.exec(text.slice(at)), intlName = tail?.[3], key = !tail ? null : intlName ? `Intl_${intlName}` : tail[2];
150
+ if (!tail || !key || !(key in SAFE_CONSTRUCTORS))
151
+ throw new UnsafeExpressionError(`matched /${NEW_OPERATOR_PATTERN.source}/; ${SAFE_NEW_RULE}`, expression);
152
+ const spanEnd = at + tail[0].length, originalStart = map[at], originalEnd = map[spanEnd - 1] + 1;
153
+ if (expression.slice(originalStart, originalEnd) !== text.slice(at, spanEnd))
154
+ throw new UnsafeExpressionError(`matched /${NEW_OPERATOR_PATTERN.source}/; ${SAFE_NEW_RULE}`, expression);
155
+ const nameStart = originalStart + 3 + tail[1].length;
156
+ replacements.push({ start: nameStart, end: nameStart + tail[2].length, key });
157
+ }
158
+ let source = expression;
159
+ for (let i = replacements.length - 1;i >= 0; i--) {
160
+ const r = replacements[i];
161
+ source = `${source.slice(0, r.start)}${SAFE_CTOR_PARAM}.${r.key}${source.slice(r.end)}`;
162
+ }
163
+ return { source, usesSafeConstructors: replacements.length > 0 };
164
+ }
165
+
166
+ export class UnsafeExpressionError extends Error {
167
+ rule;
168
+ expression;
169
+ constructor(rule, expression, message) {
170
+ super(message ?? `Potentially unsafe expression (${rule}): ${expression}`);
171
+ this.name = "UnsafeExpressionError";
172
+ this.rule = rule;
173
+ this.expression = expression;
174
+ }
175
+ }
176
+ export function getExpressionSafetyRule(expression) {
177
+ try {
178
+ prepareExpression(expression);
179
+ return null;
180
+ } catch (e) {
181
+ return e instanceof UnsafeExpressionError ? e.rule : e instanceof Error ? e.message : String(e);
113
182
  }
114
- return result;
115
183
  }
116
184
  function assertNoUnsafeIdentifierTokens(strippedExpression, originalExpression) {
117
185
  const identifierRe = /[$A-Z_a-z][$\w]*/g;
@@ -119,9 +187,9 @@ function assertNoUnsafeIdentifierTokens(strippedExpression, originalExpression)
119
187
  while ((match = identifierRe.exec(strippedExpression)) !== null) {
120
188
  const identifier = match[0], previous = strippedExpression[match.index - 1];
121
189
  if (DANGEROUS_IDENTIFIERS.has(identifier))
122
- throw Error(`Potentially unsafe expression (matched /\\b${identifier}\\b/; identifier ${identifier}): ${originalExpression}`);
190
+ throw new UnsafeExpressionError(`matched /\\b${identifier}\\b/; identifier ${identifier}`, originalExpression);
123
191
  if (previous === "." && DANGEROUS_BRACKET_KEYS.has(identifier))
124
- throw Error(`Potentially unsafe expression (matched /.${identifier}/; property ${identifier}): ${originalExpression}`);
192
+ throw new UnsafeExpressionError(`matched /.${identifier}/; property ${identifier}`, originalExpression);
125
193
  }
126
194
  }
127
195
  function assertSafeBracketLiteralKeys(expression) {
@@ -133,19 +201,26 @@ function assertSafeBracketLiteralKeys(expression) {
133
201
  continue;
134
202
  const previousNonSpace = expression.slice(0, match.index).match(/\S(?=\s*$)/)?.[0], nextNonSpace = expression.slice(match.index + match[0].length).match(/^\s*(\S)/)?.[1];
135
203
  if (!((previousNonSpace === "{" || previousNonSpace === ",") && nextNonSpace === ":"))
136
- throw Error(`Potentially unsafe expression (bracket key ${match[2]}): ${expression}`);
204
+ throw new UnsafeExpressionError(`bracket key ${match[2]}`, expression);
137
205
  }
138
206
  }
139
- export function sanitizeExpression(expression) {
207
+ function prepareExpression(expression) {
140
208
  const trimmed = expression.trim(), stripped = stripStringLiterals(trimmed);
141
209
  assertNoUnsafeIdentifierTokens(stripped, trimmed);
142
210
  assertSafeBracketLiteralKeys(trimmed);
143
- for (const pattern of DANGEROUS_PATTERNS)
211
+ for (const pattern of DANGEROUS_PATTERNS) {
212
+ if (pattern === NEW_OPERATOR_PATTERN)
213
+ continue;
144
214
  if (pattern.test(stripped))
145
- throw Error(`Potentially unsafe expression (matched /${pattern.source}/): ${trimmed}`);
215
+ throw new UnsafeExpressionError(`matched /${pattern.source}/`, trimmed);
216
+ }
146
217
  if (!currentConfig.allowBracketNotation && BRACKET_NOTATION_PATTERN.test(trimmed))
147
- throw Error(`Bracket notation with strings not allowed: ${trimmed}. Enable with configureSafeEvaluator({ allowBracketNotation: true })`);
148
- return trimmed;
218
+ throw new UnsafeExpressionError("bracket notation with a string key; enable with configureSafeEvaluator({ allowBracketNotation: true })", trimmed, `Bracket notation with strings not allowed: ${trimmed}. Enable with configureSafeEvaluator({ allowBracketNotation: true })`);
219
+ return rewriteSafeConstructors(trimmed);
220
+ }
221
+ export function sanitizeExpression(expression) {
222
+ prepareExpression(expression);
223
+ return expression.trim();
149
224
  }
150
225
  export function createSafeContext(context) {
151
226
  const safeContext = {};
@@ -317,14 +392,16 @@ export function isUsableParamName(name) {
317
392
  return VALID_PARAM_IDENT.test(name) && !RESERVED_PARAM_NAMES.has(name);
318
393
  }
319
394
  export function createSafeFunction(expression, contextKeys) {
320
- const sanitizedExpr = sanitizeExpression(expression), validEntries = [];
395
+ const { source: sanitizedExpr, usesSafeConstructors } = prepareExpression(expression), validEntries = [];
321
396
  for (let i = 0;i < contextKeys.length; i++) {
322
397
  if (!isUsableParamName(contextKeys[i]))
323
398
  continue;
399
+ if (contextKeys[i] === SAFE_CTOR_PARAM)
400
+ continue;
324
401
  validEntries.push({ key: contextKeys[i], index: i });
325
402
  }
326
403
  validEntries.sort((a, b) => a.key.localeCompare(b.key));
327
- const filteredKeys = validEntries.map((entry) => entry.key), validIndices = validEntries.map((entry) => entry.index), buildFunc = (extraParams) => compileFunctionBody([...filteredKeys, ...extraParams], `
404
+ const filteredKeys = validEntries.map((entry) => entry.key), validIndices = validEntries.map((entry) => entry.index), body = `
328
405
  'use strict';
329
406
  try {
330
407
  return ${sanitizedExpr};
@@ -335,7 +412,13 @@ catch (e) {
335
412
  }
336
413
  throw e;
337
414
  }
338
- `);
415
+ `;
416
+ return bindProjection(usesSafeConstructors ? (extraParams) => {
417
+ const compiled = compileFunctionBody([SAFE_CTOR_PARAM, ...filteredKeys, ...extraParams], body);
418
+ return (...args) => compiled(SAFE_CONSTRUCTORS, ...args);
419
+ } : (extraParams) => compileFunctionBody([...filteredKeys, ...extraParams], body), filteredKeys, contextKeys, validEntries, validIndices);
420
+ }
421
+ function bindProjection(buildFunc, filteredKeys, contextKeys, validEntries, validIndices) {
339
422
  let func = buildFunc([]);
340
423
  const alreadyCanonical = validEntries.every((entry, index) => entry.index === index);
341
424
  if (filteredKeys.length === contextKeys.length && alreadyCanonical)
package/dist/seo.js CHANGED
@@ -193,11 +193,29 @@ export function processSeoDirective(template, context, _filePath, _options) {
193
193
  `;
194
194
  if (og.imageHeight)
195
195
  metaTags += `<meta property="og:image:height" content="${escapeHtml(String(og.imageHeight))}">
196
+ `;
197
+ if (og.imageType)
198
+ metaTags += `<meta property="og:image:type" content="${escapeHtml(og.imageType)}">
196
199
  `;
197
200
  }
198
201
  if (og.siteName)
199
202
  metaTags += `<meta property="og:site_name" content="${escapeHtml(og.siteName)}">
200
203
  `;
204
+ if (og.locale)
205
+ metaTags += `<meta property="og:locale" content="${escapeHtml(og.locale)}">
206
+ `;
207
+ if (og.profile) {
208
+ const profile = [
209
+ ["first_name", og.profile.firstName],
210
+ ["last_name", og.profile.lastName],
211
+ ["username", og.profile.username],
212
+ ["gender", og.profile.gender]
213
+ ];
214
+ for (const [key, value] of profile)
215
+ if (value)
216
+ metaTags += `<meta property="profile:${key}" content="${escapeHtml(value)}">
217
+ `;
218
+ }
201
219
  }
202
220
  if (config.twitter) {
203
221
  const twitter = config.twitter;
@@ -216,6 +234,10 @@ export function processSeoDirective(template, context, _filePath, _options) {
216
234
  if (twitter.image || config.openGraph && config.openGraph.image) {
217
235
  const twitterImage = twitter.image || (config.openGraph ? config.openGraph.image : "") || "";
218
236
  metaTags += `<meta name="twitter:image" content="${escapeHtml(twitterImage)}">
237
+ `;
238
+ const twitterImageAlt = twitter.imageAlt || (!twitter.image && config.openGraph ? config.openGraph.imageAlt : void 0);
239
+ if (twitterImageAlt)
240
+ metaTags += `<meta name="twitter:image:alt" content="${escapeHtml(twitterImageAlt)}">
219
241
  `;
220
242
  }
221
243
  if (twitter.site)
@@ -253,12 +275,14 @@ export function injectSeoTags(html, context, options) {
253
275
  return html;
254
276
  if (!html.includes("<head>") && !html.includes("<head "))
255
277
  return html;
256
- const hasTitle = html.includes("<title>") || html.includes("</title>");
278
+ const hasTitle = html.includes("<title>") || html.includes("</title>"), pageHead = headSection(html), pageTitle = readPageTitle(pageHead), pageDescription = readPageDescription(pageHead);
257
279
  let title = "";
258
280
  if (context.title)
259
281
  title = context.title;
260
282
  else if (context.meta && context.meta.title)
261
283
  title = context.meta.title;
284
+ else if (pageTitle)
285
+ title = pageTitle;
262
286
  else if (options.seo?.defaultConfig?.title)
263
287
  title = options.seo.defaultConfig.title;
264
288
  else
@@ -268,6 +292,8 @@ export function injectSeoTags(html, context, options) {
268
292
  description = context.description;
269
293
  else if (context.meta && context.meta.description)
270
294
  description = context.meta.description;
295
+ else if (pageDescription)
296
+ description = pageDescription;
271
297
  else if (options.seo?.defaultConfig?.description)
272
298
  description = options.seo.defaultConfig.description;
273
299
  else
@@ -283,10 +309,11 @@ export function injectSeoTags(html, context, options) {
283
309
  image = options.seo.defaultImage;
284
310
  else if (options.defaultImage)
285
311
  image = options.defaultImage;
312
+ const titleTag = hasTitle ? "" : `
313
+ <meta name="title" content="${escapeHtml(title)}">`, descriptionTag = hasPageDescription(pageHead) ? "" : `
314
+ <meta name="description" content="${escapeHtml(description)}">`;
286
315
  let seoTagsMinimal = `
287
- <!-- stx SEO Tags -->
288
- <meta name="title" content="${escapeHtml(title)}">
289
- <meta name="description" content="${escapeHtml(description)}">
316
+ <!-- stx SEO Tags -->${titleTag}${descriptionTag}
290
317
  <meta property="og:title" content="${escapeHtml(title)}">
291
318
  <meta property="og:description" content="${escapeHtml(description)}">
292
319
  <meta property="og:type" content="website">
@@ -315,6 +342,31 @@ ${seoTagsMinimal}
315
342
  ${seoTagsMinimal}
316
343
  `);
317
344
  }
345
+ function headSection(html) {
346
+ const end = html.search(/<\/head\s*>/i);
347
+ return end === -1 ? html : html.slice(0, end);
348
+ }
349
+ function unescapeBasicEntities(str) {
350
+ return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0*39;|&apos;/g, "'").replace(/&amp;/g, "&");
351
+ }
352
+ function readPageTitle(head) {
353
+ const match = head.match(/<title(?:\s[^>]*)?>([\s\S]*?)<\/title\s*>/i);
354
+ return match ? unescapeBasicEntities(match[1].trim()) : "";
355
+ }
356
+ function descriptionMetaTags(head) {
357
+ return (head.match(/<meta\s[^>]*>/gi) || []).filter((tag) => /\sname\s*=\s*["']description["']/i.test(tag));
358
+ }
359
+ function hasPageDescription(head) {
360
+ return descriptionMetaTags(head).length > 0;
361
+ }
362
+ function readPageDescription(head) {
363
+ for (const tag of descriptionMetaTags(head)) {
364
+ const match = tag.match(/\scontent\s*=\s*(?:"([^"]*)"|'([^']*)')/i), content = (match?.[1] ?? match?.[2] ?? "").trim();
365
+ if (content)
366
+ return unescapeBasicEntities(content);
367
+ }
368
+ return "";
369
+ }
318
370
  function escapeHtml(str) {
319
371
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
320
372
  }
package/dist/ssg.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{Fk as Uq,Gk as Iq,Kk as Fq}from"./chunk-zhcs8m2a.js";import{Lk as Eq,Mk as Tq,Nk as Dq}from"./chunk-09zjty4k.js";import{gl as _q,jl as zq,kl as Aq}from"./chunk-gecmqs6p.js";import"./chunk-7m4yhzhb.js";import{Tm as Oq,_p as P,np as Bq,ro as l,uo as Hq,xr as n}from"./chunk-fg0nf7cv.js";import"./chunk-2h94c5hm.js";import"./chunk-8jam44my.js";import"./chunk-t51mwjyq.js";import"./chunk-wfffa8zm.js";import{_t as Xq}from"./chunk-mv5fdcwc.js";import"./chunk-4evbx7sz.js";import"./chunk-jxxv18a0.js";import{mu as d}from"./chunk-c131k3mt.js";import"./chunk-9nf3hgvq.js";import"./chunk-nqq7y7m9.js";import"./chunk-1c2j4eby.js";import"./chunk-kxavsh3m.js";import"./chunk-qev11kg8.js";import"./chunk-rrankpmj.js";import{Jv as Yq,Kv as Vq,Lv as jq,Mv as Gq,Nv as Lq,Ov as Nq}from"./chunk-fczfdsab.js";import"./chunk-fp7ms6e7.js";import{cw as y}from"./chunk-jp2f8yzw.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{Fk as Uq,Gk as Iq,Kk as Fq}from"./chunk-k14nr7rz.js";import{Lk as Eq,Mk as Tq,Nk as Dq}from"./chunk-09zjty4k.js";import{gl as _q,jl as zq,kl as Aq}from"./chunk-8wqhts61.js";import"./chunk-yyxhjfgd.js";import{$p as P,Um as Oq,op as Bq,so as l,vo as Hq,yr as n}from"./chunk-r8z1rexd.js";import"./chunk-raxr83fs.js";import"./chunk-at84gyvf.js";import"./chunk-397rqs12.js";import"./chunk-aqrp68m6.js";import{au as Xq}from"./chunk-k1qzydkj.js";import"./chunk-jwnbwemq.js";import"./chunk-ry1key0g.js";import{ou as d}from"./chunk-4ee1aaet.js";import"./chunk-286rffvb.js";import"./chunk-18p8dqya.js";import"./chunk-64ttktzc.js";import"./chunk-xcsf7my7.js";import"./chunk-2kv2gnzc.js";import"./chunk-ttny9g8k.js";import{Lv as Yq,Mv as Vq,Nv as jq,Ov as Gq,Pv as Lq,Qv as Nq}from"./chunk-r7qap4bh.js";import"./chunk-9ebfmdyb.js";import{ew as y}from"./chunk-jryjwara.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-k23r03qj.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-xd5ahrtn.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-k23r03qj.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-6xqgkfb3.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-6vt9ddra.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-6xqgkfb3.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:
@@ -118,8 +118,26 @@ export interface OpenGraphConfig {
118
118
  imageWidth?: number;
119
119
  /** Height of the OG image */
120
120
  imageHeight?: number;
121
+ /** MIME type of the OG image (`image/jpeg`), so a scraper need not sniff it */
122
+ imageType?: string;
121
123
  /** Site name for Open Graph */
122
124
  siteName?: string;
125
+ /** Locale of the page, `language_TERRITORY` (`en_US`) */
126
+ locale?: string;
127
+ /**
128
+ * The `profile:*` properties. Open Graph defines them for `type: 'profile'`,
129
+ * and a profile without them says whose profile it is nowhere.
130
+ */
131
+ profile?: OpenGraphProfile;
132
+ }
133
+ /**
134
+ * Open Graph `profile` object properties.
135
+ */
136
+ export interface OpenGraphProfile {
137
+ firstName?: string;
138
+ lastName?: string;
139
+ username?: string;
140
+ gender?: string;
123
141
  }
124
142
  /**
125
143
  * SEO Twitter card configuration
@@ -133,6 +151,8 @@ export interface TwitterConfig {
133
151
  description?: string;
134
152
  /** Image URL for Twitter card */
135
153
  image?: string;
154
+ /** Alt text for the card image. Defaults to the Open Graph `imageAlt`. */
155
+ imageAlt?: string;
136
156
  /** Twitter site handle */
137
157
  site?: string;
138
158
  /** Twitter creator handle */
@@ -15,6 +15,6 @@ export type { AuthContext, BaseTemplateContext, ContextValue, LoopContext, Permi
15
15
  export type { A11yDirective, AuthDirective, ComponentDirective, ConditionalDirective, CustomDirective, CustomDirectiveHandler, Directive, DirectiveOfKind, EnvDirective, ExpressionDirective, FormDirective, I18nDirective, IncludeDirective, LayoutDirective, LoopDirective, Middleware, MiddlewareHandler, ScriptDirective, SeoDirective, StackDirective, SwitchDirective, UserCustomDirective, } from './directive-types';
16
16
  export { isDirectiveKind } from './directive-types';
17
17
  export type { ComponentLibraryBuildResult, ComponentLibraryComponent, ComponentLibraryConfig, ComponentLibraryEvent, ComponentLibraryProperty, ComponentConfig, ComponentDefinition, ComponentDoc, ComponentPropDoc, ComponentPropsSchema, DirectiveDoc, DocFormat, DocGeneratorConfig, PropDefinition, PropType, TemplateDoc, WebComponent, WebComponentConfig, } from './component-types';
18
- export type { A11yConfig, AnalyticsConfig, AnalyticsDriver, AnimationConfig, FormConfig, HydrationConfig, I18nConfig, Island, LoopConfig, MarkdownConfig, OpenGraphConfig, SeoConfig, SeoFeatureConfig, StreamingConfig, StreamRenderer, StrictModeConfig, StxConfig, StxOptions, SyntaxHighlightingConfig, SyntaxHighlightTheme, TwitterConfig, } from './config-types';
18
+ export type { A11yConfig, AnalyticsConfig, AnalyticsDriver, AnimationConfig, FormConfig, HydrationConfig, I18nConfig, Island, LoopConfig, MarkdownConfig, OpenGraphConfig, OpenGraphProfile, SeoConfig, SeoFeatureConfig, StreamingConfig, StreamRenderer, StrictModeConfig, StxConfig, StxOptions, SyntaxHighlightingConfig, SyntaxHighlightTheme, TwitterConfig, } from './config-types';
19
19
  export type { PwaBackgroundSyncConfig, PwaCacheStorageConfig, PwaCacheStrategy, PwaConfig, PwaFileHandlerConfig, PwaIconConfig, PwaManifestConfig, PwaOfflineConfig, PwaPrecacheConfig, PwaProtocolHandlerConfig, PwaPushConfig, PwaRouteCache, PwaScreenshot, PwaServiceWorkerConfig, PwaShareTargetConfig, PwaShortcut, PwaUpdateConfig, } from './pwa-types';
20
20
  export type { CspConfig, CspDirectives, CspPreset, CspSourceValue, } from './csp-types';
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import"./chunk-jp2f8yzw.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-jryjwara.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.305",
4
+ "version": "0.2.307",
5
5
  "description": "A performant UI Framework. Powered by Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -117,12 +117,12 @@
117
117
  "dependencies": {
118
118
  "@stacksjs/ts-css": "^0.3.2",
119
119
  "@stacksjs/clapp": "^0.2.14",
120
- "@stacksjs/desktop": "0.2.305",
121
- "@stacksjs/sanitizer": "0.2.305",
120
+ "@stacksjs/desktop": "0.2.307",
121
+ "@stacksjs/sanitizer": "0.2.307",
122
122
  "@stacksjs/ts-i18n": "^0.1.11",
123
- "bun-plugin-stx": "0.2.305",
123
+ "bun-plugin-stx": "0.2.307",
124
124
  "bunfig": "^0.15.17",
125
- "stx-router": "0.2.305",
125
+ "stx-router": "0.2.307",
126
126
  "ts-broadcasting": "^0.0.9",
127
127
  "ts-images": "^0.2.18",
128
128
  "ts-syntax-highlighter": "^0.2.1"
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{al as a,bl as b,cl as c,dl as d,el as e}from"./chunk-7skk34dh.js";import"./chunk-jp2f8yzw.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{Vo as a,Wo as b}from"./chunk-fg0nf7cv.js";import"./chunk-2h94c5hm.js";import"./chunk-8jam44my.js";import"./chunk-t51mwjyq.js";import"./chunk-wfffa8zm.js";import"./chunk-mv5fdcwc.js";import"./chunk-4evbx7sz.js";import"./chunk-jxxv18a0.js";import"./chunk-c131k3mt.js";import"./chunk-9nf3hgvq.js";import"./chunk-nqq7y7m9.js";import"./chunk-1c2j4eby.js";import"./chunk-kxavsh3m.js";import"./chunk-qev11kg8.js";import"./chunk-rrankpmj.js";import"./chunk-fczfdsab.js";import"./chunk-fp7ms6e7.js";import"./chunk-jp2f8yzw.js";export{b as processLoops,a as parseLoopBinding};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{tk as a,uk as b,vk as c,wk as d}from"./chunk-s3dnk3gc.js";import"./chunk-4mrhxtn3.js";import"./chunk-fg0nf7cv.js";import"./chunk-2h94c5hm.js";import"./chunk-8jam44my.js";import"./chunk-t51mwjyq.js";import"./chunk-wfffa8zm.js";import"./chunk-mv5fdcwc.js";import"./chunk-4evbx7sz.js";import"./chunk-jxxv18a0.js";import"./chunk-c131k3mt.js";import"./chunk-9nf3hgvq.js";import"./chunk-nqq7y7m9.js";import"./chunk-1c2j4eby.js";import"./chunk-kxavsh3m.js";import"./chunk-qev11kg8.js";import"./chunk-rrankpmj.js";import"./chunk-fczfdsab.js";import"./chunk-fp7ms6e7.js";import"./chunk-jp2f8yzw.js";export{b as getAvailableTargets,c as getAvailableFormats,d as default,a as buildNative};
@@ -1,4 +0,0 @@
1
- // @bun
2
- var K={},Y=[],O={};function I(){return K}function h(){return O}function D(){K={},Y.length=0,O={}}function U(j){K=Q(K,j)}function Q(j,z){return{title:z.title??j.title,titleTemplate:z.titleTemplate??j.titleTemplate,base:z.base??j.base,meta:[...j.meta||[],...z.meta||[]],link:[...j.link||[],...z.link||[]],script:[...j.script||[],...z.script||[]],style:[...j.style||[],...z.style||[]],htmlAttrs:{...j.htmlAttrs,...z.htmlAttrs},bodyAttrs:{...j.bodyAttrs,...z.bodyAttrs}}}function Z(j){U(_(j))}function _(j){let z=[];if(j.description)z.push({name:"description",content:j.description});if(j.keywords){let L=Array.isArray(j.keywords)?j.keywords.join(", "):j.keywords;z.push({name:"keywords",content:L})}if(j.author)z.push({name:"author",content:j.author});if(j.robots)z.push({name:"robots",content:j.robots});let A=j.ogTitle??j.title,B=j.ogDescription??j.description;if(A)z.push({property:"og:title",content:A});if(B)z.push({property:"og:description",content:B});if(j.ogImage)z.push({property:"og:image",content:j.ogImage});if(j.ogUrl)z.push({property:"og:url",content:j.ogUrl});if(j.ogType)z.push({property:"og:type",content:j.ogType});if(j.ogSiteName)z.push({property:"og:site_name",content:j.ogSiteName});if(j.ogLocale)z.push({property:"og:locale",content:j.ogLocale});let E=j.twitterTitle??j.title,F=j.twitterDescription??j.description,J=j.twitterImage??j.ogImage;if(j.twitterCard)z.push({name:"twitter:card",content:j.twitterCard});if(E)z.push({name:"twitter:title",content:E});if(F)z.push({name:"twitter:description",content:F});if(J)z.push({name:"twitter:image",content:J});if(j.twitterSite)z.push({name:"twitter:site",content:j.twitterSite});if(j.twitterCreator)z.push({name:"twitter:creator",content:j.twitterCreator});if(j.articleAuthor)z.push({property:"article:author",content:j.articleAuthor});if(j.articlePublishedTime)z.push({property:"article:published_time",content:j.articlePublishedTime});if(j.articleModifiedTime)z.push({property:"article:modified_time",content:j.articleModifiedTime});if(j.articleSection)z.push({property:"article:section",content:j.articleSection});if(j.articleTags)for(let L of j.articleTags)z.push({property:"article:tag",content:L});let G=[];if(j.canonical)G.push({rel:"canonical",href:j.canonical});return{title:j.title,titleTemplate:j.titleTemplate,meta:z,link:G}}function S(j){if(O={...O,...j},j.title||j.description)Z({title:j.title,description:j.description})}function P(j){let z=typeof j==="function"?j():j;U({title:z})}function C(j=K){let z=[];if(j.title){let A=j.title;if(j.titleTemplate)A=typeof j.titleTemplate==="function"?j.titleTemplate(A):j.titleTemplate.replace("%s",A);z.push(`<title>${N(A)}</title>`)}if(j.base){let A=Object.entries(j.base).map(([B,E])=>`${B}="${N(E)}"`).join(" ");z.push(`<base ${A}>`)}for(let A of j.meta||[]){let B=Object.entries(A).filter(([E,F])=>F!==void 0).map(([E,F])=>{return`${E==="httpEquiv"?"http-equiv":E}="${N(String(F))}"`}).join(" ");z.push(`<meta ${B}>`)}for(let A of j.link||[]){let B=Object.entries(A).filter(([E,F])=>F!==void 0).map(([E,F])=>`${E}="${N(String(F))}"`).join(" ");z.push(`<link ${B}>`)}for(let A of j.script||[]){let{content:B,...E}=A,F=Object.entries(E).filter(([J,G])=>G!==void 0).map(([J,G])=>{if(typeof G==="boolean")return G?J:"";return`${J}="${N(String(G))}"`}).filter(Boolean).join(" ");if(B)z.push(`<script ${F}>${B}</script>`);else z.push(`<script ${F}></script>`)}for(let A of j.style||[]){let B=A.type?` type="${A.type}"`:"";z.push(`<style${B}>${A.content}</style>`)}return z.join(`
3
- `)}function M(j=K){if(!j.htmlAttrs)return"";return Object.entries(j.htmlAttrs).map(([z,A])=>`${z}="${N(A)}"`).join(" ")}function V(j=K){if(!j.bodyAttrs)return"";return Object.entries(j.bodyAttrs).map(([z,A])=>`${z}="${N(A)}"`).join(" ")}function N(j){return j.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function w(j=K){if(typeof document>"u")return;if(j.title){let z=j.title;if(j.titleTemplate)z=typeof j.titleTemplate==="function"?j.titleTemplate(z):j.titleTemplate.replace("%s",z);document.title=z}for(let z of j.meta||[]){let A=z.name?`meta[name="${z.name}"]`:z.property?`meta[property="${z.property}"]`:null;if(A){let B=document.querySelector(A);if(!B){if(B=document.createElement("meta"),z.name)B.setAttribute("name",z.name);if(z.property)B.setAttribute("property",z.property);document.head.appendChild(B)}B.setAttribute("content",z.content)}}for(let z of j.link||[]){let A=`link[rel="${z.rel}"]${z.href?`[href="${z.href}"]`:""}`,B=document.querySelector(A);if(!B)B=document.createElement("link"),document.head.appendChild(B);for(let[E,F]of Object.entries(z))if(F!==void 0)B.setAttribute(E,String(F))}if(j.htmlAttrs)for(let[z,A]of Object.entries(j.htmlAttrs))if(z==="class")for(let B of String(A).split(/\s+/).filter(Boolean))document.documentElement.classList.add(B);else document.documentElement.setAttribute(z,A);if(j.bodyAttrs)for(let[z,A]of Object.entries(j.bodyAttrs))document.body.setAttribute(z,A)}function y(j){let z="";return{content:j.replace(/@head\s*([\s\S]*?)@endhead/g,(B,E)=>{return z+=E.trim()+`
4
- `,""}),headContent:z.trim()}}function x(j,z){return j.replace(/@title\s*\(\s*(?:(['"`])(.+?)\1|([^)]+))\s*\)/g,(A,B,E,F)=>{let J=B?E:z[(F||"").trim()]??F,G=z.__stx_runtime_head??{};return z.__stx_runtime_head=Q(G,{title:J}),""})}function T(j,z){return j.replace(/@meta\s*\(\s*(['"`])(.+?)\1\s*,\s*(?:(['"`])(.+?)\3|([^)]+))\s*\)/g,(A,B,E,F,J,G)=>{let L=F?J:G,R=F?L:z[(L||"").trim()]??L,W=E.includes(":")?{property:E,content:R}:{name:E,content:R},X=z.__stx_runtime_head??{};return z.__stx_runtime_head=Q(X,{meta:[W]}),""})}export{I as xu,h as yu,D as zu,U as Au,Q as Bu,Z as Cu,_ as Du,S as Eu,P as Fu,C as Gu,M as Hu,V as Iu,w as Ju,y as Ku,x as Lu,T as Mu};