@stacksjs/actions 0.70.75 → 0.70.76

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/blog.d.ts CHANGED
@@ -10,3 +10,4 @@ export declare function renderBlog(req: Request): Promise<Response | null>;
10
10
  * (e.g. https://stacksjs.com) — used for absolute feed/sitemap/share URLs.
11
11
  */
12
12
  export declare function buildBlog(options?: { outDir: string, baseUrl?: string }): Promise<void>;
13
+ declare type BlogThemeMode = 'colored' | 'light' | 'dark';
package/dist/blog.js CHANGED
@@ -1,28 +1,32 @@
1
1
  // @bun
2
- import"./chunk-v0hqskdk.js";import{existsSync as x,mkdirSync as X,readdirSync as H,readFileSync as R,writeFileSync as h}from"fs";import{homedir as u}from"os";import{join as Z}from"path";var $=Z(process.cwd(),"content/blog"),F=Z($,".theme.css"),O=null;async function S(){if(!O)O=(async()=>{let z=[Z(u(),"Code/Tools/bunpress/packages/bunpress/dist/src/index.js"),Z(process.cwd(),"pantry/@stacksjs/bunpress/dist/src/index.js"),"@stacksjs/bunpress"];for(let A of z)try{if(A.startsWith("@")||x(A))return await import(A)}catch{}return null})();return O}function Y(z){return String(z).replace(/[&<>"]/g,(A)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[A])}function B(z){return String(z).replace(/[&<>"']/g,(A)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"})[A])}function D(z,A){return`${z.replace(/\/$/,"")}/blog/${A}`}function g(z){if(!z)return"";let A=new Date(z);return Number.isNaN(A.getTime())?z:A.toUTCString()}function c(z){let A=z||"https://stacksjs.com",Q=q().slice(0,50).map((K)=>{let W=D(A,K.slug);return` <item>
3
- <title>${B(K.fm.title||K.slug)}</title>
4
- <link>${B(W)}</link>
5
- <guid>${B(W)}</guid>
6
- <pubDate>${B(g(K.fm.date))}</pubDate>
7
- <description>${B(K.fm.description||"")}</description>
2
+ import"./chunk-v0hqskdk.js";import{existsSync as x,mkdirSync as C,readdirSync as n,readFileSync as y,writeFileSync as c}from"fs";import{homedir as b}from"os";import{join as B}from"path";var M=B(process.cwd(),"content/blog"),E=B(M,".theme.css"),X={title:"The Stacks Blog",description:"Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.",siteTitle:"Stacks Blog",author:"The Stacks Team",url:"https://stacksjs.com",nav:[{text:"Blog",link:"/blog"},{text:"Docs",link:"/docs"},{text:"GitHub",link:"https://github.com/stacksjs/stacks"}],themes:["colored","light","dark"],defaultTheme:"colored",colophon:'Built with Stacks \xB7 TypeScript &amp; Bun \xB7 <a href="/blog/feed.xml">RSS</a>',emptyTitle:"No posts yet",emptyText:"The first one is in the works. Leave your email and it will land in your inbox the moment it ships."},I=null;function k(){if(!I)I=(async()=>{try{let z=(await import(B(process.cwd(),"config/blog.ts"))).default??{},J={...X,...z};if(!z.siteTitle&&z.title)J.siteTitle=z.title;return J}catch{return X}})();return I}var O=null;async function S(){if(!O)O=(async()=>{let G=[B(b(),"Code/Tools/bunpress/packages/bunpress/dist/src/index.js"),B(process.cwd(),"pantry/@stacksjs/bunpress/dist/src/index.js"),"@stacksjs/bunpress"];for(let z of G)try{if(z.startsWith("@")||x(z))return await import(z)}catch{}return null})();return O}function $(G){return String(G).replace(/[&<>"]/g,(z)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[z])}function L(G){return String(G).replace(/[&<>"']/g,(z)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"})[z])}function U(G,z){return`${G.replace(/\/$/,"")}/blog/${z}`}function o(G){if(!G)return"";let z=new Date(G);return Number.isNaN(z.getTime())?G:z.toUTCString()}async function i(G){let z=await k(),J=G||z.url,W=A().slice(0,50).map((Z)=>{let V=U(J,Z.slug);return` <item>
3
+ <title>${L(Z.fm.title||Z.slug)}</title>
4
+ <link>${L(V)}</link>
5
+ <guid>${L(V)}</guid>
6
+ <pubDate>${L(o(Z.fm.date))}</pubDate>
7
+ <description>${L(Z.fm.description||"")}</description>
8
8
  </item>`}).join(`
9
9
  `);return`<?xml version="1.0" encoding="UTF-8"?>
10
10
  <rss version="2.0">
11
11
  <channel>
12
- <title>The Stacks Blog</title>
13
- <link>${B(`${A}/blog`)}</link>
14
- <description>Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.</description>
15
- ${Q}
12
+ <title>${L(z.title)}</title>
13
+ <link>${L(`${J}/blog`)}</link>
14
+ <description>${L(z.description)}</description>
15
+ ${W}
16
16
  </channel>
17
- </rss>`}function f(z){let A=z||"https://stacksjs.com";return`<?xml version="1.0" encoding="UTF-8"?>
17
+ </rss>`}async function r(G){let z=await k(),J=G||z.url;return`<?xml version="1.0" encoding="UTF-8"?>
18
18
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
19
- ${[`${A}/blog`,...q().map((Q)=>D(A,Q.slug))].map((Q)=>` <url><loc>${B(Q)}</loc></url>`).join(`
19
+ ${[`${J}/blog`,...A().map((W)=>U(J,W.slug))].map((W)=>` <url><loc>${L(W)}</loc></url>`).join(`
20
20
  `)}
21
- </urlset>`}function d(z){let A=z.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!A)return{data:{},body:z};let G={},Q=A[1]??"";for(let K of Q.split(`
22
- `)){let W=K.indexOf(":");if(W===-1)continue;let J=K.slice(0,W).trim(),V=K.slice(W+1).trim();if(V.startsWith('"')&&V.endsWith('"')||V.startsWith("'")&&V.endsWith("'"))V=V.slice(1,-1);G[J]=V}return{data:G,body:A[2]??""}}function E(z){if(!z)return"";let A=new Date(z);if(Number.isNaN(A.getTime()))return z;return`${["January","February","March","April","May","June","July","August","September","October","November","December"][A.getUTCMonth()]} ${A.getUTCDate()}, ${A.getUTCFullYear()}`}function I(){return`<script>
21
+ </urlset>`}function m(G){let z=G.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!z)return{data:{},body:G};let J={},Y=z[1]??"";for(let W of Y.split(`
22
+ `)){let Z=W.indexOf(":");if(Z===-1)continue;let V=W.slice(0,Z).trim(),Q=W.slice(Z+1).trim();if(Q.startsWith('"')&&Q.endsWith('"')||Q.startsWith("'")&&Q.endsWith("'"))Q=Q.slice(1,-1);J[V]=Q}return{data:J,body:z[2]??""}}function h(G){if(!G)return"";let z=new Date(G);if(Number.isNaN(z.getTime()))return G;return`${["January","February","March","April","May","June","July","August","September","October","November","December"][z.getUTCMonth()]} ${z.getUTCDate()}, ${z.getUTCFullYear()}`}var P={colored:{label:"Park theme",glyph:"\uD83C\uDF32"},light:{label:"Light theme",glyph:"\u2600"},dark:{label:"Dark theme",glyph:"\uD83C\uDF19"}};async function F(){let G=await k(),z=G.themes.length?G.themes:X.themes,J=z.includes(G.defaultTheme)?G.defaultTheme:z[0],Y=z.map((Z)=>`<button type="button" data-t="${Z}" title="${P[Z].label}" aria-label="${P[Z].label}" onclick="stxBlogTheme('${Z}')">${P[Z].glyph}</button>`).join(`
23
+ `),W=z.length>1?`<div class="blog-theme-toggle" role="group" aria-label="Theme">
24
+ ${Y}
25
+ </div>`:"";return`<script>
23
26
  (function () {
27
+ var modes = ${JSON.stringify(z)}
24
28
  function ok(theme) {
25
- return theme === 'light' || theme === 'colored' || theme === 'dark'
29
+ return modes.indexOf(theme) !== -1
26
30
  }
27
31
 
28
32
  var queryTheme = ''
@@ -37,7 +41,7 @@ ${[`${A}/blog`,...q().map((Q)=>D(A,Q.slug))].map((Q)=>` <url><loc>${B(Q)}</loc>
37
41
  }
38
42
  catch {}
39
43
 
40
- var theme = ok(queryTheme) ? queryTheme : (ok(savedTheme) ? savedTheme : 'colored')
44
+ var theme = ok(queryTheme) ? queryTheme : (ok(savedTheme) ? savedTheme : ${JSON.stringify(J)})
41
45
  document.documentElement.setAttribute('data-theme', theme)
42
46
  window.stxBlogTheme = function (nextTheme) {
43
47
  try {
@@ -48,55 +52,97 @@ ${[`${A}/blog`,...q().map((Q)=>D(A,Q.slug))].map((Q)=>` <url><loc>${B(Q)}</loc>
48
52
  }
49
53
  })()
50
54
  </script>
51
- <div class="blog-theme-toggle" role="group" aria-label="Theme">
52
- <button type="button" data-t="colored" title="Park (default)" aria-label="Park theme" onclick="stxBlogTheme('colored')">\uD83C\uDF32</button>
53
- <button type="button" data-t="light" title="Light" aria-label="Light theme" onclick="stxBlogTheme('light')">\u2600</button>
54
- <button type="button" data-t="dark" title="Dark" aria-label="Dark theme" onclick="stxBlogTheme('dark')">\uD83C\uDF19</button>
55
- </div>`}function P(){return`<div class="blog-landscape" aria-hidden="true">
55
+ ${W}`}async function D(){return`<div class="blog-landscape" aria-hidden="true">
56
56
  <span class="ridge"></span>
57
57
  <span class="river"></span>
58
- <p class="colophon">Built with Stacks \xB7 TypeScript &amp; Bun \xB7 <a href="/blog/feed.xml">RSS</a></p>
59
- </div>`}function k(z,A){let G=x(F)?R(F,"utf-8"):"",Q=z.defaultConfig.markdown?.css||"";return{...z.defaultConfig,title:A.title||"Stacks Blog",description:A.description||"The official Stacks blog.",docsDir:$,theme:"vitepress",markdown:{...z.defaultConfig.markdown,css:`${Q}
60
- ${G}`},themeConfig:{siteTitle:"Stacks Blog",nav:[{text:"Blog",link:"/blog"},{text:"Docs",link:"/docs"},{text:"GitHub",link:"https://github.com/stacksjs/stacks"}]}}}function q(){if(!x($))return[];return H($).filter((z)=>z.endsWith(".md")).map((z)=>{let{data:A}=d(R(Z($,z),"utf-8"));return{slug:z.replace(/\.md$/,""),fm:A}}).filter((z)=>!!z.fm.title&&!!z.fm.date).sort((z,A)=>{let G=z.fm.featured==="true"?1:0,Q=A.fm.featured==="true"?1:0;if(G!==Q)return Q-G;return(A.fm.date||"").localeCompare(z.fm.date||"")})}async function n(z){return z.wrapInLayout(I()+`
58
+ <p class="colophon">${(await k()).colophon}</p>
59
+ </div>`}async function w(G,z){let J=await k(),Y=x(E)?y(E,"utf-8"):"",W=G.defaultConfig.markdown?.css||"";return{...G.defaultConfig,title:z.title||J.title,description:z.description||J.description,docsDir:M,theme:"vitepress",markdown:{...G.defaultConfig.markdown,css:`${W}
60
+ ${Y}`},themeConfig:{siteTitle:J.siteTitle,nav:J.nav}}}function A(){if(!x(M))return[];return n(M).filter((G)=>G.endsWith(".md")).map((G)=>{let{data:z}=m(y(B(M,G),"utf-8"));return{slug:G.replace(/\.md$/,""),fm:z}}).filter((G)=>!!G.fm.title&&!!G.fm.date).sort((G,z)=>{let J=G.fm.featured==="true"?1:0,Y=z.fm.featured==="true"?1:0;if(J!==Y)return Y-J;return(z.fm.date||"").localeCompare(G.fm.date||"")})}async function l(G){return G.wrapInLayout(await F()+`
61
61
  <a class="blog-back" href="/blog">\u2190 All posts</a>
62
62
  <div class="blog-404">
63
63
  <span class="blog-404-art" aria-hidden="true"></span>
64
- <h1>You've wandered off the trail</h1>
65
- <p>This post isn't on the map (or it moved camp). Head back to <a href="/blog">the trailhead</a>.</p>
66
- </div>`+P(),k(z,{title:"Not found"}),"/blog","page")}async function y(z,A,G){let Q=Z($,`${A}.md`);if(!x(Q))return null;let K=R(Q,"utf-8"),{html:W,frontmatter:J}=await z.markdownToHtml(K,$);if(!J.title||!J.date)return null;let V=Y((J.author||"S").charAt(0).toUpperCase()),L=`
64
+ <h1>Nothing here</h1>
65
+ <p>This post doesn't exist (or it moved). Head back to <a href="/blog">all posts</a>.</p>
66
+ </div>`+await D(),await w(G,{title:"Not found"}),"/blog","page")}async function H(G,z,J){let Y=await k(),W=B(M,`${z}.md`);if(!x(W))return null;let Z=y(W,"utf-8"),{html:V,frontmatter:Q}=await G.markdownToHtml(Z,M);if(!Q.title||!Q.date)return null;let K=Q.author||Y.author,v=$(K.charAt(0).toUpperCase()),R=`
67
67
  <a class="blog-back" href="/blog">\u2190 All posts</a>
68
68
  <div class="blog-post-head">
69
- <h1>${Y(J.title||A)}</h1>
69
+ <h1>${$(Q.title||z)}</h1>
70
70
  <p class="blog-post-meta">
71
- <span class="author">${Y(J.author||"The Stacks Team")}</span>
71
+ <span class="author">${$(K)}</span>
72
72
  <span class="dot">\xB7</span>
73
- <time>${Y(E(J.date))}</time>
73
+ <time>${$(h(Q.date))}</time>
74
74
  </p>
75
- ${J.poster?`<figure class="blog-post-poster"><img src="${Y(J.poster)}" alt="${Y(J.title||"")}"></figure>`:""}
76
- </div>`,w=J.authorBio?`<aside class="blog-author-card">
77
- <div class="avatar">${V}</div>
78
- <div><span class="name">${Y(J.author||"The Stacks Team")}</span><p class="bio">${Y(J.authorBio)}</p></div>
79
- </aside>`:"",v=`${G}/blog/${A}`,j=`
75
+ ${Q.poster?`<figure class="blog-post-poster"><img src="${$(Q.poster)}" alt="${$(Q.title||"")}"></figure>`:""}
76
+ </div>`,j=Q.authorBio?`<aside class="blog-author-card">
77
+ <div class="avatar">${v}</div>
78
+ <div><span class="name">${$(K)}</span><p class="bio">${$(Q.authorBio)}</p></div>
79
+ </aside>`:"",_=`${J}/blog/${z}`,g=`
80
80
  <div class="blog-share">
81
81
  <span class="blog-share-label">Share</span>
82
- <a href="https://twitter.com/intent/tweet?url=${encodeURIComponent(v)}&text=${encodeURIComponent(J.title||"")}" target="_blank" rel="noreferrer">X / Twitter</a>
83
- <a href="https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(v)}" target="_blank" rel="noreferrer">LinkedIn</a>
84
- </div>`,_=q().filter((M)=>M.slug!==A).slice(0,3),U=_.length?`<nav class="blog-more">
82
+ <a href="https://twitter.com/intent/tweet?url=${encodeURIComponent(_)}&text=${encodeURIComponent(Q.title||"")}" target="_blank" rel="noreferrer">X / Twitter</a>
83
+ <a href="https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(_)}" target="_blank" rel="noreferrer">LinkedIn</a>
84
+ </div>`,N=A().filter((q)=>q.slug!==z).slice(0,3),f=N.length?`<nav class="blog-more">
85
85
  <h2>More from the blog</h2>
86
- <ul>${_.map((M)=>`<li><a href="/blog/${Y(M.slug)}">${Y(M.fm.title||M.slug)}</a></li>`).join("")}</ul>
87
- </nav>`:"";return z.wrapInLayout(I()+L+W+w+j+U+P(),k(z,J),`/blog/${A}`,"page")}async function N(z){let Q=`
88
- <div class="blog-listing-head">
89
- <span class="sign" aria-hidden="true"></span>
90
- <h1>The Stacks Blog</h1>
91
- <p>Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.</p>
92
- </div>
93
- <div class="blog-cards">${q().map((K)=>{let W=K.fm.featured==="true",J=K.fm.poster?`<div class="blog-card-media"><img src="${Y(K.fm.poster)}" alt="" loading="lazy"></div>`:"";return`<a class="blog-card${W?" is-featured":""}" href="/blog/${Y(K.slug)}">
94
- ${J}
86
+ <ul>${N.map((q)=>`<li><a href="/blog/${$(q.slug)}">${$(q.fm.title||q.slug)}</a></li>`).join("")}</ul>
87
+ </nav>`:"";return G.wrapInLayout(await F()+R+V+j+g+f+await D(),await w(G,Q),`/blog/${z}`,"page")}async function T(G){let z=await k(),Y=A().map((V)=>{let Q=V.fm.featured==="true",K=V.fm.poster?`<div class="blog-card-media"><img src="${$(V.fm.poster)}" alt="" loading="lazy"></div>`:"";return`<a class="blog-card${Q?" is-featured":""}" href="/blog/${$(V.slug)}">
88
+ ${K}
95
89
  <div>
96
- ${W?'<span class="blog-card-flag">Featured</span>':""}
97
- <h2 class="blog-card-title">${Y(K.fm.title||K.slug)}</h2>
98
- <p class="blog-card-excerpt">${Y((K.fm.description||"").slice(0,180))}</p>
99
- <div class="blog-card-meta">${Y(K.fm.author||"The Stacks Team")} \xB7 ${Y(E(K.fm.date))}</div>
90
+ ${Q?'<span class="blog-card-flag">Featured</span>':""}
91
+ <h2 class="blog-card-title">${$(V.fm.title||V.slug)}</h2>
92
+ <p class="blog-card-excerpt">${$((V.fm.description||"").slice(0,180))}</p>
93
+ <div class="blog-card-meta">${$(V.fm.author||z.author)} \xB7 ${$(h(V.fm.date))}</div>
100
94
  </div>
101
95
  </a>`}).join(`
102
- `)||"<p>No posts yet.</p>"}</div>`;return z.wrapInLayout(I()+Q+P(),k(z,{title:"Blog",description:"The official Stacks blog."}),"/blog","page")}function C(z,A){let G={...k(z,{title:"The Stacks Blog"}),sitemap:{enabled:!0,baseUrl:`${A}/blog`}};return typeof z.buildRssFeed==="function"?z.buildRssFeed($,G,{enabled:!0,title:"The Stacks Blog",description:"Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.",maxItems:50}):Promise.resolve(c(A))}function T(z,A){let G={...k(z,{title:"Blog"}),sitemap:{enabled:!0,baseUrl:`${A}/blog`}};return typeof z.buildSitemap==="function"?z.buildSitemap($,G):Promise.resolve(f(A))}async function m(z){if(z.method!=="GET"&&z.method!=="HEAD")return null;let A=new URL(z.url),{pathname:G}=A,Q=G==="/blog/feed.xml",K=G==="/blog/sitemap.xml",W=G==="/blog"||G==="/blog/"||/^\/blog\/[^/.]+$/.test(G);if(!Q&&!K&&!W)return null;let J=await S();if(!J)return null;let V=(v,j=200)=>new Response(v,{status:j,headers:{"Content-Type":"text/html; charset=utf-8"}});if(Q)return new Response(await C(J,A.origin),{headers:{"Content-Type":"application/rss+xml; charset=utf-8"}});if(K)return new Response(await T(J,A.origin),{headers:{"Content-Type":"application/xml; charset=utf-8"}});if(G==="/blog"||G==="/blog/")return V(await N(J));let L=G.replace(/^\/blog\//,"").replace(/\/$/,""),w=await y(J,L,A.origin);return w?V(w):V(await n(J),404)}async function r(z={outDir:"dist/blog"}){let A=z.outDir||"dist/blog",G=(z.baseUrl||"").replace(/\/$/,""),Q=await S();if(!Q)throw Error("[blog] BunPress not found \u2014 cannot build the blog.");X(A,{recursive:!0});let K=(J,V)=>{let L=Z(A,J);X(Z(L,".."),{recursive:!0}),h(L,V,"utf-8")};K("index.html",await N(Q));let W=q();for(let J of W){let V=await y(Q,J.slug,G);if(V)K(Z(J.slug,"index.html"),V)}K("feed.xml",await C(Q,G)),K("sitemap.xml",await T(Q,G)),console.log(`[blog] built ${W.length} post(s) + listing, feed.xml, sitemap.xml \u2192 ${A}`)}export{m as renderBlog,r as buildBlog};
96
+ `),W=`
97
+ <div class="blog-empty">
98
+ <h2>${$(z.emptyTitle)}</h2>
99
+ <p>${$(z.emptyText)}</p>
100
+ <form class="blog-subscribe" method="POST" action="/api/email/subscribe">
101
+ <input type="email" name="email" placeholder="you@example.com" autocomplete="email" aria-label="Email address" required>
102
+ <input type="hidden" name="source" value="blog-empty">
103
+ <button type="submit">Subscribe</button>
104
+ <p class="blog-form-note" role="status" aria-live="polite"></p>
105
+ </form>
106
+ </div>
107
+ <script>
108
+ (function () {
109
+ var form = document.querySelector('.blog-subscribe')
110
+ if (!form) return
111
+ var note = form.querySelector('.blog-form-note')
112
+ var button = form.querySelector('button[type="submit"]')
113
+ var say = function (text) { if (note) note.textContent = text }
114
+ form.addEventListener('submit', function (event) {
115
+ event.preventDefault()
116
+ var input = form.querySelector('input[name="email"]')
117
+ if (!input || !input.value) { say('Enter an email address first.'); return }
118
+ if (button) button.disabled = true
119
+ say('Subscribing...')
120
+ var body = new URLSearchParams()
121
+ body.set('email', input.value)
122
+ body.set('source', 'blog-empty')
123
+ fetch('/api/email/subscribe', {
124
+ method: 'POST',
125
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
126
+ body: body.toString(),
127
+ })
128
+ .then(function (res) { return res.json().catch(function () { return {} }) })
129
+ .then(function (data) {
130
+ if (data && data.success) {
131
+ say(data.message === 'Already subscribed' ? 'You are already on the list.' : 'Subscribed. Check your inbox to confirm.')
132
+ form.reset()
133
+ }
134
+ else {
135
+ say((data && data.message) || 'Something went wrong. Try again.')
136
+ }
137
+ })
138
+ .catch(function () { say('Network error. Try again in a moment.') })
139
+ .finally(function () { if (button) button.disabled = false })
140
+ })
141
+ })()
142
+ </script>`,Z=`
143
+ <div class="blog-listing-head">
144
+ <span class="sign" aria-hidden="true"></span>
145
+ <h1>${$(z.title)}</h1>
146
+ <p>${$(z.description)}</p>
147
+ </div>
148
+ <div class="blog-cards">${Y||W}</div>`;return G.wrapInLayout(await F()+Z+await D(),await w(G,{title:z.title,description:z.description}),"/blog","page")}async function u(G,z){let J=await k(),Y={...await w(G,{title:J.title}),sitemap:{enabled:!0,baseUrl:`${z}/blog`}};return typeof G.buildRssFeed==="function"?G.buildRssFeed(M,Y,{enabled:!0,title:J.title,description:J.description,maxItems:50}):i(z)}async function d(G,z){let J={...await w(G,{title:"Blog"}),sitemap:{enabled:!0,baseUrl:`${z}/blog`}};return typeof G.buildSitemap==="function"?G.buildSitemap(M,J):r(z)}async function s(G){if(G.method!=="GET"&&G.method!=="HEAD")return null;let z=new URL(G.url),{pathname:J}=z,Y=J==="/blog/feed.xml",W=J==="/blog/sitemap.xml",Z=J==="/blog"||J==="/blog/"||/^\/blog\/[^/.]+$/.test(J);if(!Y&&!W&&!Z)return null;let V=await S();if(!V)return null;let Q=(R,j=200)=>new Response(R,{status:j,headers:{"Content-Type":"text/html; charset=utf-8"}});if(Y)return new Response(await u(V,z.origin),{headers:{"Content-Type":"application/rss+xml; charset=utf-8"}});if(W)return new Response(await d(V,z.origin),{headers:{"Content-Type":"application/xml; charset=utf-8"}});if(J==="/blog"||J==="/blog/")return Q(await T(V));let K=J.replace(/^\/blog\//,"").replace(/\/$/,""),v=await H(V,K,z.origin);return v?Q(v):Q(await l(V),404)}async function e(G={outDir:"dist/blog"}){let z=G.outDir||"dist/blog",J=(G.baseUrl||(await k()).url).replace(/\/$/,""),Y=await S();if(!Y)throw Error("[blog] BunPress not found \u2014 cannot build the blog.");C(z,{recursive:!0});let W=(V,Q)=>{let K=B(z,V);C(B(K,".."),{recursive:!0}),c(K,Q,"utf-8")};W("index.html",await T(Y));let Z=A();for(let V of Z){let Q=await H(Y,V.slug,J);if(Q)W(B(V.slug,"index.html"),Q)}W("feed.xml",await u(Y,J)),W("sitemap.xml",await d(Y,J)),console.log(`[blog] built ${Z.length} post(s) + listing, feed.xml, sitemap.xml \u2192 ${z}`)}export{s as renderBlog,e as buildBlog};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
- "version": "0.70.75",
4
+ "version": "0.70.76",
5
5
  "description": "The Stacks actions.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -64,27 +64,27 @@
64
64
  "@stacksjs/bumpx": "^0.2.6",
65
65
  "@stacksjs/bunpress": "^0.1.12",
66
66
  "@stacksjs/logsmith": "^0.2.3",
67
- "@stacksjs/ts-cloud": "^0.7.14",
67
+ "@stacksjs/ts-cloud": "^0.7.15",
68
68
  "@stacksjs/ts-md": "^0.1.1"
69
69
  },
70
70
  "devDependencies": {
71
- "@stacksjs/api": "0.70.75",
72
- "@stacksjs/cli": "0.70.75",
73
- "@stacksjs/config": "0.70.75",
74
- "@stacksjs/database": "0.70.75",
71
+ "@stacksjs/api": "0.70.76",
72
+ "@stacksjs/cli": "0.70.76",
73
+ "@stacksjs/config": "0.70.76",
74
+ "@stacksjs/database": "0.70.76",
75
75
  "@stacksjs/tlsx": "^0.13.2",
76
76
  "better-dx": "^0.2.16",
77
- "@stacksjs/dns": "0.70.75",
78
- "@stacksjs/enums": "0.70.75",
79
- "@stacksjs/env": "0.70.75",
80
- "@stacksjs/error-handling": "0.70.75",
81
- "@stacksjs/logging": "0.70.75",
82
- "@stacksjs/path": "0.70.75",
83
- "@stacksjs/security": "0.70.75",
84
- "@stacksjs/storage": "0.70.75",
85
- "@stacksjs/strings": "0.70.75",
86
- "@stacksjs/utils": "0.70.75",
87
- "@stacksjs/validation": "0.70.75"
77
+ "@stacksjs/dns": "0.70.76",
78
+ "@stacksjs/enums": "0.70.76",
79
+ "@stacksjs/env": "0.70.76",
80
+ "@stacksjs/error-handling": "0.70.76",
81
+ "@stacksjs/logging": "0.70.76",
82
+ "@stacksjs/path": "0.70.76",
83
+ "@stacksjs/security": "0.70.76",
84
+ "@stacksjs/storage": "0.70.76",
85
+ "@stacksjs/strings": "0.70.76",
86
+ "@stacksjs/utils": "0.70.76",
87
+ "@stacksjs/validation": "0.70.76"
88
88
  },
89
89
  "peerDependencies": {
90
90
  "pickier": "^0.1.28"