@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.
- package/dist/{chunk-0gz0rhvs.js → chunk-0gbptqh2.js} +1 -1
- package/dist/{chunk-g97atepq.js → chunk-0mnv8pf5.js} +1 -1
- package/dist/{chunk-4mrhxtn3.js → chunk-0va2vsqa.js} +2 -2
- package/dist/chunk-0wwgr4wv.js +2 -0
- package/dist/{chunk-nqq7y7m9.js → chunk-18p8dqya.js} +1 -1
- package/dist/chunk-1vwgywtn.js +2 -0
- package/dist/{chunk-awj7yy37.js → chunk-1ztjv7a4.js} +1 -1
- package/dist/{chunk-eans1ct0.js → chunk-20yc1zrp.js} +1 -1
- package/dist/{chunk-f1cgyd2h.js → chunk-24bgm3hh.js} +1 -1
- package/dist/{chunk-rvyfyc43.js → chunk-2559vc7d.js} +1 -1
- package/dist/{chunk-9nf3hgvq.js → chunk-286rffvb.js} +2 -2
- package/dist/{chunk-qev11kg8.js → chunk-2kv2gnzc.js} +1 -1
- package/dist/chunk-2pv79p7x.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-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-4z3yyryn.js +2 -0
- package/dist/{chunk-wx13qmaw.js → chunk-51gea48g.js} +1 -1
- package/dist/{chunk-bk95q0bw.js → chunk-58xpr98x.js} +1 -1
- package/dist/chunk-59fva5cz.js +2 -0
- package/dist/{chunk-gbwhbasw.js → chunk-5g39e9ra.js} +1 -1
- package/dist/{chunk-xsfwcj6x.js → chunk-604qr43v.js} +1 -1
- package/dist/chunk-64ttktzc.js +4 -0
- package/dist/chunk-6dmrpd71.js +2 -0
- package/dist/chunk-6vt9ddra.js +2 -0
- package/dist/{chunk-k23r03qj.js → chunk-6xqgkfb3.js} +1 -1
- package/dist/chunk-75vxhxn1.js +2 -0
- package/dist/{chunk-6zt2y7q3.js → chunk-769jvq54.js} +1 -1
- package/dist/{chunk-gssbag3e.js → chunk-7c1qq9zq.js} +1 -1
- package/dist/chunk-7n6fq2t7.js +2 -0
- package/dist/{chunk-ta398s3d.js → chunk-7xrvkrrx.js} +10 -10
- package/dist/{chunk-yyyxt326.js → chunk-7yzyn9k7.js} +1 -1
- package/dist/chunk-80rmf67y.js +2 -0
- package/dist/{chunk-ppyz9623.js → chunk-85p4dmft.js} +1 -1
- package/dist/{chunk-c1ae6afc.js → chunk-8g6jwkjy.js} +2 -2
- package/dist/{chunk-8ee62a9q.js → chunk-8q8gj45z.js} +1 -1
- package/dist/chunk-8tkn0yxq.js +2 -0
- package/dist/{chunk-gecmqs6p.js → chunk-8wqhts61.js} +1 -1
- package/dist/chunk-9aw5d4rr.js +2 -0
- package/dist/{chunk-fp7ms6e7.js → chunk-9ebfmdyb.js} +1 -1
- package/dist/{chunk-rzevgemj.js → chunk-a50hb40e.js} +1 -1
- package/dist/{chunk-jfzfrmzy.js → chunk-ajhrz96a.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-ba5t40dx.js +2 -0
- package/dist/{chunk-mbmqpaq1.js → chunk-bnq0p4r4.js} +1 -1
- package/dist/chunk-bzmxbz48.js +2 -0
- package/dist/{chunk-wnamjw6n.js → chunk-cpsepyzg.js} +1 -1
- package/dist/chunk-czje8k8c.js +2 -0
- package/dist/chunk-d4b67e6m.js +2 -0
- package/dist/chunk-e16hkjh9.js +2 -0
- package/dist/{chunk-gt8ja700.js → chunk-f044qmn3.js} +1 -1
- package/dist/chunk-f7e286pa.js +2 -0
- package/dist/{chunk-f325jzsk.js → chunk-f91yrkcz.js} +2 -2
- package/dist/chunk-fsee2x1q.js +2 -0
- package/dist/chunk-fwdn408g.js +2 -0
- package/dist/chunk-gy3sf0fw.js +2 -0
- package/dist/chunk-h78pksyp.js +2 -0
- package/dist/chunk-hg7ptfd4.js +2 -0
- package/dist/{chunk-s3dnk3gc.js → chunk-hsbrta4s.js} +1 -1
- 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-mv5fdcwc.js → chunk-k1qzydkj.js} +3 -3
- package/dist/chunk-k48jp969.js +2 -0
- package/dist/{chunk-hg2afckn.js → chunk-ka2xspj3.js} +1 -1
- package/dist/{chunk-mygq61f5.js → chunk-ka5wtqmw.js} +1 -1
- package/dist/{chunk-d5cqnwdd.js → chunk-kexk6z9s.js} +1 -1
- package/dist/{chunk-m8n0s4tk.js → chunk-kh9r3pfb.js} +1 -1
- package/dist/{chunk-qeyw5za9.js → chunk-ksqba0cq.js} +1 -1
- package/dist/chunk-kwjgt9jx.js +2 -0
- package/dist/{chunk-t8fqjb25.js → chunk-mk0j30e1.js} +1 -1
- package/dist/{chunk-m31n9pkr.js → chunk-msmhta0w.js} +1 -1
- package/dist/chunk-mvj75wef.js +2 -0
- package/dist/{chunk-1jbjrc0w.js → chunk-mvyadg84.js} +1 -1
- package/dist/{chunk-cbgh359m.js → chunk-n43zq50e.js} +1 -1
- package/dist/{chunk-g912mb7x.js → chunk-nnv8wytm.js} +1 -1
- package/dist/{chunk-w6d91maa.js → chunk-ns8fx1f9.js} +1 -1
- package/dist/{chunk-ydgdq45a.js → chunk-pwv15j35.js} +1 -1
- package/dist/{chunk-fczfdsab.js → chunk-r7qap4bh.js} +2 -2
- package/dist/{chunk-fg0nf7cv.js → chunk-r8z1rexd.js} +277 -272
- package/dist/chunk-raxr83fs.js +60 -0
- package/dist/{chunk-jxxv18a0.js → chunk-ry1key0g.js} +1 -1
- package/dist/{chunk-9c835qjn.js → chunk-s3pvp8qv.js} +1 -1
- package/dist/{chunk-sart9ehj.js → chunk-snmtft92.js} +1 -1
- package/dist/{chunk-zs5y7xnt.js → chunk-t5kwx6fa.js} +1 -1
- package/dist/{chunk-rrankpmj.js → chunk-ttny9g8k.js} +1 -1
- package/dist/chunk-v0ne90ft.js +2 -0
- package/dist/chunk-v33qvj8y.js +2 -0
- package/dist/{chunk-ze44hhxb.js → chunk-vbwq7he6.js} +2 -2
- package/dist/{chunk-d19tvdvv.js → chunk-vhan24as.js} +1 -1
- package/dist/chunk-vpbw6g2t.js +2 -0
- package/dist/{chunk-ek8cgwcg.js → chunk-vtd5bgt9.js} +1 -1
- package/dist/{chunk-00rtz7nw.js → chunk-vwq4kwwj.js} +1 -1
- package/dist/{chunk-bd9wrcq1.js → chunk-w8hkprzv.js} +1 -1
- package/dist/chunk-wbt9kz3j.js +2 -0
- 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-hrcxfvh1.js → chunk-y4dd2n2n.js} +1 -1
- package/dist/{chunk-7skk34dh.js → chunk-ybct46zd.js} +1 -1
- package/dist/chunk-yp0jymdz.js +2 -0
- package/dist/{chunk-7m4yhzhb.js → chunk-yyxhjfgd.js} +2 -2
- 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/head.d.ts +12 -0
- package/dist/head.js +21 -2
- 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 +56 -4
- package/dist/ssg.js +2 -2
- package/dist/types/config-types.d.ts +20 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/visual-testing.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-02hm88m5.js +0 -2
- package/dist/chunk-044mychj.js +0 -2
- package/dist/chunk-113y4ywy.js +0 -2
- package/dist/chunk-1c2j4eby.js +0 -4
- package/dist/chunk-2h94c5hm.js +0 -60
- package/dist/chunk-3eervtf9.js +0 -2
- package/dist/chunk-4jgr954p.js +0 -2
- package/dist/chunk-57ea6ye2.js +0 -2
- package/dist/chunk-8z0n5mtg.js +0 -2
- package/dist/chunk-92zzryxw.js +0 -2
- package/dist/chunk-a87jqtmd.js +0 -2
- package/dist/chunk-bezqaxqt.js +0 -2
- package/dist/chunk-dgpjxmhs.js +0 -2
- package/dist/chunk-er848s6f.js +0 -2
- package/dist/chunk-hftqr8ej.js +0 -2
- package/dist/chunk-hzav4hyd.js +0 -2
- package/dist/chunk-m537zgay.js +0 -2
- package/dist/chunk-n99ajrwv.js +0 -2
- package/dist/chunk-ncrfrp95.js +0 -2
- package/dist/chunk-nws8fbde.js +0 -2
- package/dist/chunk-phcvbqzn.js +0 -2
- package/dist/chunk-qpzxgkc5.js +0 -2
- package/dist/chunk-qt2dmyq5.js +0 -2
- package/dist/chunk-r2k2sewg.js +0 -2
- package/dist/chunk-r808fpme.js +0 -2
- package/dist/chunk-sen2cxqm.js +0 -2
- package/dist/chunk-tc6gqeha.js +0 -2
- package/dist/chunk-twbw18vs.js +0 -2
- package/dist/chunk-wjdfhfj6.js +0 -2
- package/dist/chunk-x10mrzgp.js +0 -2
- package/dist/chunk-xd5ahrtn.js +0 -2
- package/dist/chunk-xzgvcrnz.js +0 -2
- package/dist/chunk-yd7jyyr7.js +0 -2
- 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-
|
|
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-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">
|
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
|
@@ -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(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/�*39;|'/g, "'").replace(/&/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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
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-
|
|
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-
|
|
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 */
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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';
|
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.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.
|
|
121
|
-
"@stacksjs/sanitizer": "0.2.
|
|
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.
|
|
123
|
+
"bun-plugin-stx": "0.2.307",
|
|
124
124
|
"bunfig": "^0.15.17",
|
|
125
|
-
"stx-router": "0.2.
|
|
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"
|
package/dist/chunk-02hm88m5.js
DELETED
package/dist/chunk-044mychj.js
DELETED
|
@@ -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};
|
package/dist/chunk-113y4ywy.js
DELETED
|
@@ -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};
|
package/dist/chunk-1c2j4eby.js
DELETED
|
@@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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};
|