@stacksjs/stx 0.2.304 → 0.2.306
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-0gz0rhvs.js → chunk-0gbptqh2.js} +1 -1
- package/dist/{chunk-g97atepq.js → chunk-0mnv8pf5.js} +1 -1
- package/dist/{chunk-nqq7y7m9.js → chunk-18p8dqya.js} +1 -1
- package/dist/{chunk-gfc3qye3.js → chunk-1bmtk8s5.js} +1 -1
- package/dist/{chunk-fvtv1s5j.js → chunk-1zcm299e.js} +1 -1
- package/dist/{chunk-awj7yy37.js → chunk-1ztjv7a4.js} +1 -1
- package/dist/{chunk-qev11kg8.js → chunk-2kv2gnzc.js} +1 -1
- package/dist/chunk-2mx57479.js +2 -0
- package/dist/{chunk-b4xwbh8a.js → chunk-322qz0cj.js} +1 -1
- package/dist/{chunk-t51mwjyq.js → chunk-397rqs12.js} +1 -1
- package/dist/{chunk-env6knrs.js → chunk-3by4c2g9.js} +1 -1
- package/dist/{chunk-tt4r8q4v.js → chunk-3pv0qj5f.js} +1 -1
- package/dist/{chunk-9499k64n.js → chunk-3qc0h6bj.js} +2 -2
- package/dist/{chunk-9xzszvn5.js → chunk-3qfz82gw.js} +1 -1
- package/dist/chunk-455m2k1y.js +2 -0
- package/dist/{chunk-c131k3mt.js → chunk-4ee1aaet.js} +1 -1
- package/dist/{chunk-d3srvh3q.js → chunk-4hk5ewgp.js} +1 -1
- package/dist/{chunk-xganfzgn.js → chunk-4k0h6sca.js} +1 -1
- package/dist/chunk-4mtc9vyb.js +2 -0
- package/dist/chunk-4yky0frv.js +2 -0
- package/dist/{chunk-wx13qmaw.js → chunk-51gea48g.js} +1 -1
- package/dist/chunk-5598ankf.js +2 -0
- package/dist/{chunk-gbwhbasw.js → chunk-5g39e9ra.js} +1 -1
- package/dist/{chunk-8215nhej.js → chunk-5yhb5fad.js} +1 -1
- package/dist/{chunk-xsfwcj6x.js → chunk-604qr43v.js} +1 -1
- package/dist/chunk-6vt9ddra.js +2 -0
- package/dist/{chunk-9vqnrcrw.js → chunk-74sgwgyt.js} +1 -1
- package/dist/{chunk-zggm7kjd.js → chunk-79nj87t6.js} +1 -1
- package/dist/chunk-7amgwmrw.js +2 -0
- package/dist/{chunk-gssbag3e.js → chunk-7c1qq9zq.js} +1 -1
- package/dist/chunk-7q81jygp.js +2 -0
- package/dist/{chunk-sb7ana2z.js → chunk-7sn5rbrd.js} +1 -1
- package/dist/{chunk-yyyxt326.js → chunk-7yzyn9k7.js} +1 -1
- package/dist/{chunk-ppyz9623.js → chunk-85p4dmft.js} +1 -1
- package/dist/chunk-8n2cafmh.js +2 -0
- package/dist/{chunk-8ee62a9q.js → chunk-8q8gj45z.js} +1 -1
- package/dist/chunk-9aw5d4rr.js +2 -0
- package/dist/{chunk-5k1hznvq.js → chunk-9b9znn2f.js} +2 -2
- package/dist/{chunk-y7wsk78j.js → chunk-9eat8v8r.js} +1 -1
- package/dist/{chunk-fp7ms6e7.js → chunk-9ebfmdyb.js} +1 -1
- package/dist/chunk-9j1jfhrf.js +2 -0
- package/dist/chunk-9ypp0a8t.js +2 -0
- package/dist/{chunk-rzevgemj.js → chunk-a50hb40e.js} +1 -1
- package/dist/{chunk-z9ezmjwd.js → chunk-aftse9mb.js} +1 -1
- package/dist/{chunk-wfffa8zm.js → chunk-aqrp68m6.js} +1 -1
- package/dist/{chunk-8jam44my.js → chunk-at84gyvf.js} +1 -1
- package/dist/{chunk-ess2pgt5.js → chunk-b8cteeha.js} +1 -1
- package/dist/{chunk-mbmqpaq1.js → chunk-bnq0p4r4.js} +1 -1
- package/dist/{chunk-ez28vck6.js → chunk-bs18cyh6.js} +1 -1
- package/dist/{chunk-yz16bgs3.js → chunk-bxqzqwv5.js} +1 -1
- package/dist/chunk-bzmxbz48.js +2 -0
- package/dist/{chunk-5x2fc4vk.js → chunk-e5yebhrk.js} +2 -2
- package/dist/{chunk-45y8bjrv.js → chunk-ejjzrtym.js} +10 -10
- package/dist/{chunk-54f8bpp6.js → chunk-ewcxfn7m.js} +3 -3
- package/dist/{chunk-gt8ja700.js → chunk-f044qmn3.js} +1 -1
- package/dist/chunk-f3k3kk5x.js +2 -0
- package/dist/{chunk-y2kmm6bt.js → chunk-ffexgxm3.js} +1 -1
- package/dist/chunk-fh97a60e.js +2 -0
- package/dist/chunk-fzwqh8sy.js +2 -0
- package/dist/chunk-g812bscg.js +2 -0
- package/dist/chunk-gt40xkj3.js +2 -0
- package/dist/chunk-h78pksyp.js +2 -0
- package/dist/chunk-hq3w5crk.js +2 -0
- package/dist/chunk-hy1ma54e.js +2 -0
- package/dist/{chunk-695fkras.js → chunk-j3ajrx2n.js} +1 -1
- package/dist/{chunk-jsg1rthc.js → chunk-jd9nv63q.js} +1 -1
- package/dist/{chunk-jp2f8yzw.js → chunk-jryjwara.js} +1 -1
- package/dist/{chunk-4evbx7sz.js → chunk-jwnbwemq.js} +1 -1
- package/dist/{chunk-zhcs8m2a.js → chunk-k14nr7rz.js} +1 -1
- package/dist/{chunk-hg2afckn.js → chunk-ka2xspj3.js} +1 -1
- package/dist/{chunk-mygq61f5.js → chunk-ka5wtqmw.js} +1 -1
- package/dist/{chunk-6vswphz4.js → chunk-kdkv0j67.js} +1 -1
- package/dist/{chunk-d5cqnwdd.js → chunk-kexk6z9s.js} +1 -1
- package/dist/{chunk-9wrrr7g3.js → chunk-kgtbm5rp.js} +1 -1
- package/dist/{chunk-qeyw5za9.js → chunk-ksqba0cq.js} +1 -1
- package/dist/chunk-kz149fx5.js +2 -0
- package/dist/chunk-mhety3pf.js +2 -0
- package/dist/{chunk-m31n9pkr.js → chunk-msmhta0w.js} +1 -1
- package/dist/chunk-mvj75wef.js +2 -0
- package/dist/{chunk-cbgh359m.js → chunk-n43zq50e.js} +1 -1
- package/dist/{chunk-g912mb7x.js → chunk-nnv8wytm.js} +1 -1
- package/dist/chunk-nvb9nsqv.js +2 -0
- package/dist/chunk-ps7nfwq5.js +2 -0
- package/dist/{chunk-hay1rzb0.js → chunk-qhnyrwz2.js} +268 -267
- package/dist/{chunk-fczfdsab.js → chunk-r7qap4bh.js} +2 -2
- package/dist/chunk-raxr83fs.js +60 -0
- package/dist/{chunk-jfzfrmzy.js → chunk-rtaa4ys9.js} +1 -1
- package/dist/{chunk-jxxv18a0.js → chunk-ry1key0g.js} +1 -1
- package/dist/{chunk-ankp4reb.js → chunk-s3951qwp.js} +1 -1
- package/dist/{chunk-9c835qjn.js → chunk-s3pvp8qv.js} +1 -1
- package/dist/chunk-smtve243.js +2 -0
- package/dist/{chunk-sart9ehj.js → chunk-snmtft92.js} +1 -1
- package/dist/chunk-szdwkfzq.js +2 -0
- package/dist/{chunk-zs5y7xnt.js → chunk-t5kwx6fa.js} +1 -1
- package/dist/{chunk-39qzhpn6.js → chunk-ttkt7xhd.js} +2 -2
- package/dist/{chunk-rrankpmj.js → chunk-ttny9g8k.js} +1 -1
- package/dist/chunk-v33qvj8y.js +2 -0
- package/dist/{chunk-30nbe9hr.js → chunk-v7b5ny0x.js} +2 -2
- package/dist/{chunk-d19tvdvv.js → chunk-vhan24as.js} +1 -1
- package/dist/chunk-vpbw6g2t.js +2 -0
- package/dist/{chunk-1c2j4eby.js → chunk-w1dxgs78.js} +1 -1
- package/dist/{chunk-hgjjnjas.js → chunk-w764f6g4.js} +2 -2
- package/dist/{chunk-bd9wrcq1.js → chunk-w8hkprzv.js} +1 -1
- package/dist/{chunk-ghw5p1yk.js → chunk-wm86mmgq.js} +1 -1
- package/dist/{chunk-d57gb0v2.js → chunk-wwghzbbg.js} +1 -1
- package/dist/{chunk-kxavsh3m.js → chunk-xcsf7my7.js} +1 -1
- package/dist/chunk-xfdckfqr.js +2 -0
- package/dist/{chunk-hrcxfvh1.js → chunk-y4dd2n2n.js} +1 -1
- package/dist/{chunk-7skk34dh.js → chunk-ybct46zd.js} +1 -1
- package/dist/chunk-z8yh03mr.js +2 -0
- package/dist/{chunk-t3qb9s6s.js → chunk-zdzd2jb4.js} +1 -1
- package/dist/{chunk-7gqbr8nr.js → chunk-zr1r73p3.js} +1 -1
- package/dist/cli.js +14 -14
- package/dist/craft-entry.js +1 -1
- package/dist/craft.js +1 -1
- package/dist/database.js +1 -1
- package/dist/expressions.d.ts +10 -1
- package/dist/expressions.js +42 -11
- package/dist/includes.js +19 -1
- package/dist/pwa.js +2 -2
- package/dist/safe-evaluator.d.ts +18 -0
- package/dist/safe-evaluator.js +100 -17
- package/dist/seo.js +34 -4
- package/dist/ssg.js +2 -2
- package/dist/visual-testing.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-02hm88m5.js +0 -2
- package/dist/chunk-2h94c5hm.js +0 -60
- package/dist/chunk-3z6bqqr7.js +0 -2
- package/dist/chunk-43p1qq7g.js +0 -2
- package/dist/chunk-4jgr954p.js +0 -2
- package/dist/chunk-51j2aqvb.js +0 -2
- package/dist/chunk-5qfpcgcs.js +0 -2
- package/dist/chunk-6hcc4973.js +0 -2
- package/dist/chunk-8z0n5mtg.js +0 -2
- package/dist/chunk-976g5qe5.js +0 -2
- package/dist/chunk-9px4y692.js +0 -2
- package/dist/chunk-a07chbgj.js +0 -2
- package/dist/chunk-b1hd8kvy.js +0 -2
- package/dist/chunk-c3tmzx7q.js +0 -2
- package/dist/chunk-ckzhp09g.js +0 -2
- package/dist/chunk-dgpjxmhs.js +0 -2
- package/dist/chunk-hzav4hyd.js +0 -2
- package/dist/chunk-jjq9q9jr.js +0 -2
- package/dist/chunk-kbw2qzqx.js +0 -2
- package/dist/chunk-kdxvraec.js +0 -2
- package/dist/chunk-krfjb7b8.js +0 -2
- package/dist/chunk-nws8fbde.js +0 -2
- package/dist/chunk-pr14wjkn.js +0 -2
- package/dist/chunk-rpfcnq8n.js +0 -2
- package/dist/chunk-rst1rw09.js +0 -2
- package/dist/chunk-snt2773t.js +0 -2
- package/dist/chunk-vd3h9z7e.js +0 -2
- package/dist/chunk-wbecqx03.js +0 -2
- package/dist/chunk-xd5ahrtn.js +0 -2
- package/dist/chunk-xq1swv2e.js +0 -2
- package/dist/chunk-xzgvcrnz.js +0 -2
- package/dist/chunk-yyebm8q4.js +0 -2
- package/dist/chunk-zbtfhxhn.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-
|
|
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-
|
|
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-smtve243.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">
|
package/dist/safe-evaluator.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/safe-evaluator.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
77
|
-
let result = ""
|
|
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
|
|
190
|
+
throw new UnsafeExpressionError(`matched /\\b${identifier}\\b/; identifier ${identifier}`, originalExpression);
|
|
123
191
|
if (previous === "." && DANGEROUS_BRACKET_KEYS.has(identifier))
|
|
124
|
-
throw
|
|
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
|
|
204
|
+
throw new UnsafeExpressionError(`bracket key ${match[2]}`, expression);
|
|
137
205
|
}
|
|
138
206
|
}
|
|
139
|
-
|
|
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
|
|
215
|
+
throw new UnsafeExpressionError(`matched /${pattern.source}/`, trimmed);
|
|
216
|
+
}
|
|
146
217
|
if (!currentConfig.allowBracketNotation && BRACKET_NOTATION_PATTERN.test(trimmed))
|
|
147
|
-
throw
|
|
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 =
|
|
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),
|
|
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
|
@@ -253,12 +253,14 @@ export function injectSeoTags(html, context, options) {
|
|
|
253
253
|
return html;
|
|
254
254
|
if (!html.includes("<head>") && !html.includes("<head "))
|
|
255
255
|
return html;
|
|
256
|
-
const hasTitle = html.includes("<title>") || html.includes("</title>");
|
|
256
|
+
const hasTitle = html.includes("<title>") || html.includes("</title>"), pageHead = headSection(html), pageTitle = readPageTitle(pageHead), pageDescription = readPageDescription(pageHead);
|
|
257
257
|
let title = "";
|
|
258
258
|
if (context.title)
|
|
259
259
|
title = context.title;
|
|
260
260
|
else if (context.meta && context.meta.title)
|
|
261
261
|
title = context.meta.title;
|
|
262
|
+
else if (pageTitle)
|
|
263
|
+
title = pageTitle;
|
|
262
264
|
else if (options.seo?.defaultConfig?.title)
|
|
263
265
|
title = options.seo.defaultConfig.title;
|
|
264
266
|
else
|
|
@@ -268,6 +270,8 @@ export function injectSeoTags(html, context, options) {
|
|
|
268
270
|
description = context.description;
|
|
269
271
|
else if (context.meta && context.meta.description)
|
|
270
272
|
description = context.meta.description;
|
|
273
|
+
else if (pageDescription)
|
|
274
|
+
description = pageDescription;
|
|
271
275
|
else if (options.seo?.defaultConfig?.description)
|
|
272
276
|
description = options.seo.defaultConfig.description;
|
|
273
277
|
else
|
|
@@ -283,10 +287,11 @@ export function injectSeoTags(html, context, options) {
|
|
|
283
287
|
image = options.seo.defaultImage;
|
|
284
288
|
else if (options.defaultImage)
|
|
285
289
|
image = options.defaultImage;
|
|
290
|
+
const titleTag = hasTitle ? "" : `
|
|
291
|
+
<meta name="title" content="${escapeHtml(title)}">`, descriptionTag = hasPageDescription(pageHead) ? "" : `
|
|
292
|
+
<meta name="description" content="${escapeHtml(description)}">`;
|
|
286
293
|
let seoTagsMinimal = `
|
|
287
|
-
<!-- stx SEO Tags
|
|
288
|
-
<meta name="title" content="${escapeHtml(title)}">
|
|
289
|
-
<meta name="description" content="${escapeHtml(description)}">
|
|
294
|
+
<!-- stx SEO Tags -->${titleTag}${descriptionTag}
|
|
290
295
|
<meta property="og:title" content="${escapeHtml(title)}">
|
|
291
296
|
<meta property="og:description" content="${escapeHtml(description)}">
|
|
292
297
|
<meta property="og:type" content="website">
|
|
@@ -315,6 +320,31 @@ ${seoTagsMinimal}
|
|
|
315
320
|
${seoTagsMinimal}
|
|
316
321
|
`);
|
|
317
322
|
}
|
|
323
|
+
function headSection(html) {
|
|
324
|
+
const end = html.search(/<\/head\s*>/i);
|
|
325
|
+
return end === -1 ? html : html.slice(0, end);
|
|
326
|
+
}
|
|
327
|
+
function unescapeBasicEntities(str) {
|
|
328
|
+
return str.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/�*39;|'/g, "'").replace(/&/g, "&");
|
|
329
|
+
}
|
|
330
|
+
function readPageTitle(head) {
|
|
331
|
+
const match = head.match(/<title(?:\s[^>]*)?>([\s\S]*?)<\/title\s*>/i);
|
|
332
|
+
return match ? unescapeBasicEntities(match[1].trim()) : "";
|
|
333
|
+
}
|
|
334
|
+
function descriptionMetaTags(head) {
|
|
335
|
+
return (head.match(/<meta\s[^>]*>/gi) || []).filter((tag) => /\sname\s*=\s*["']description["']/i.test(tag));
|
|
336
|
+
}
|
|
337
|
+
function hasPageDescription(head) {
|
|
338
|
+
return descriptionMetaTags(head).length > 0;
|
|
339
|
+
}
|
|
340
|
+
function readPageDescription(head) {
|
|
341
|
+
for (const tag of descriptionMetaTags(head)) {
|
|
342
|
+
const match = tag.match(/\scontent\s*=\s*(?:"([^"]*)"|'([^']*)')/i), content = (match?.[1] ?? match?.[2] ?? "").trim();
|
|
343
|
+
if (content)
|
|
344
|
+
return unescapeBasicEntities(content);
|
|
345
|
+
}
|
|
346
|
+
return "";
|
|
347
|
+
}
|
|
318
348
|
function escapeHtml(str) {
|
|
319
349
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
320
350
|
}
|
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-
|
|
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-79nj87t6.js";import"./chunk-3qc0h6bj.js";import{$p as P,Um as Oq,op as Bq,so as l,vo as Hq,yr as n}from"./chunk-qhnyrwz2.js";import"./chunk-raxr83fs.js";import"./chunk-at84gyvf.js";import"./chunk-397rqs12.js";import"./chunk-aqrp68m6.js";import{au as Xq}from"./chunk-ewcxfn7m.js";import"./chunk-jwnbwemq.js";import"./chunk-ry1key0g.js";import{ou as d}from"./chunk-4ee1aaet.js";import"./chunk-w764f6g4.js";import"./chunk-18p8dqya.js";import"./chunk-w1dxgs78.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-
|
|
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-3qfz82gw.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-3qfz82gw.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:
|
package/dist/visual-testing.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-
|
|
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.
|
|
4
|
+
"version": "0.2.306",
|
|
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.
|
|
121
|
-
"@stacksjs/sanitizer": "0.2.
|
|
120
|
+
"@stacksjs/desktop": "0.2.306",
|
|
121
|
+
"@stacksjs/sanitizer": "0.2.306",
|
|
122
122
|
"@stacksjs/ts-i18n": "^0.1.11",
|
|
123
|
-
"bun-plugin-stx": "0.2.
|
|
123
|
+
"bun-plugin-stx": "0.2.306",
|
|
124
124
|
"bunfig": "^0.15.17",
|
|
125
|
-
"stx-router": "0.2.
|
|
125
|
+
"stx-router": "0.2.306",
|
|
126
126
|
"ts-broadcasting": "^0.0.9",
|
|
127
127
|
"ts-images": "^0.2.18",
|
|
128
128
|
"ts-syntax-highlighter": "^0.2.1"
|
package/dist/chunk-02hm88m5.js
DELETED