@stacksjs/actions 0.70.78 → 0.70.79
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 +6 -0
- package/dist/blog.js +19 -19
- package/dist/dev/views.js +1 -1
- package/package.json +16 -16
package/dist/blog.d.ts
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
* non-blog paths. Handles the listing, posts, the RSS feed, and the sitemap.
|
|
4
4
|
*/
|
|
5
5
|
export declare function renderBlog(req: Request): Promise<Response | null>;
|
|
6
|
+
/*.md` frontmatter with NO BunPress dependency, so they work in
|
|
7
|
+
* dev and production alike. Returns null for any non-feed path (the stx page
|
|
8
|
+
* layer then handles /blog and /blog/<slug>). Absolute URLs use the configured
|
|
9
|
+
* site url (blog config), never the loopback request origin.
|
|
10
|
+
*/
|
|
11
|
+
export declare function renderBlogFeed(req: Request): Promise<Response | null>;
|
|
6
12
|
/**
|
|
7
13
|
* Build the blog to a static directory the same way /docs is built (see
|
|
8
14
|
* config/cloud.ts). Emits clean-URL pages (`<slug>/index.html`), the listing,
|
package/dist/blog.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-v0hqskdk.js";import{existsSync as
|
|
2
|
+
import"./chunk-v0hqskdk.js";import{existsSync as R,mkdirSync as C,readdirSync as b,readFileSync as X,writeFileSync as o}from"fs";import{homedir as i}from"os";import{join as B}from"path";var M=B(process.cwd(),"content/blog"),E=B(M,".theme.css"),y={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 & 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."},q=null;function w(){if(!q)q=(async()=>{try{let z=(await import(B(process.cwd(),"config/blog.ts"))).default??{},J={...y,...z};if(!z.siteTitle&&z.title)J.siteTitle=z.title;return J}catch{return y}})();return q}var O=null;async function U(){if(!O)O=(async()=>{let G=[B(i(),"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("@")||R(z))return await import(z)}catch{}return null})();return O}function $(G){return String(G).replace(/[&<>"]/g,(z)=>({"&":"&","<":"<",">":">",'"':"""})[z])}function L(G){return String(G).replace(/[&<>"']/g,(z)=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[z])}function S(G,z){return`${G.replace(/\/$/,"")}/blog/${z}`}function r(G){if(!G)return"";let z=new Date(G);return Number.isNaN(z.getTime())?G:z.toUTCString()}async function H(G){let z=await w(),J=G||z.url,W=x().slice(0,50).map((Z)=>{let V=S(J,Z.slug);return` <item>
|
|
3
3
|
<title>${L(Z.fm.title||Z.slug)}</title>
|
|
4
4
|
<link>${L(V)}</link>
|
|
5
5
|
<guid>${L(V)}</guid>
|
|
6
|
-
<pubDate>${L(
|
|
6
|
+
<pubDate>${L(r(Z.fm.date))}</pubDate>
|
|
7
7
|
<description>${L(Z.fm.description||"")}</description>
|
|
8
8
|
</item>`}).join(`
|
|
9
9
|
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -14,12 +14,12 @@ import"./chunk-v0hqskdk.js";import{existsSync as x,mkdirSync as C,readdirSync as
|
|
|
14
14
|
<description>${L(z.description)}</description>
|
|
15
15
|
${W}
|
|
16
16
|
</channel>
|
|
17
|
-
</rss>`}async function
|
|
17
|
+
</rss>`}async function h(G){let z=await w(),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
|
-
${[`${J}/blog`,...
|
|
19
|
+
${[`${J}/blog`,...x().map((W)=>S(J,W.slug))].map((W)=>` <url><loc>${L(W)}</loc></url>`).join(`
|
|
20
20
|
`)}
|
|
21
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
|
|
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 T(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 D(){let G=await w(),z=G.themes.length?G.themes:y.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
23
|
`),W=z.length>1?`<div class="blog-theme-toggle" role="group" aria-label="Theme">
|
|
24
24
|
${Y}
|
|
25
25
|
</div>`:"";return`<script>
|
|
@@ -52,45 +52,45 @@ ${[`${J}/blog`,...A().map((W)=>U(J,W.slug))].map((W)=>` <url><loc>${L(W)}</loc>
|
|
|
52
52
|
}
|
|
53
53
|
})()
|
|
54
54
|
</script>
|
|
55
|
-
${W}`}async function
|
|
55
|
+
${W}`}async function F(){return`<div class="blog-landscape" aria-hidden="true">
|
|
56
56
|
<span class="ridge"></span>
|
|
57
57
|
<span class="river"></span>
|
|
58
|
-
<p class="colophon">${(await
|
|
59
|
-
</div>`}async function
|
|
60
|
-
${Y}`},themeConfig:{siteTitle:J.siteTitle,nav:J.nav}}}function
|
|
58
|
+
<p class="colophon">${(await w()).colophon}</p>
|
|
59
|
+
</div>`}async function v(G,z){let J=await w(),Y=R(E)?X(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 x(){if(!R(M))return[];return b(M).filter((G)=>G.endsWith(".md")).map((G)=>{let{data:z}=m(X(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 D()+`
|
|
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
64
|
<h1>Nothing here</h1>
|
|
65
65
|
<p>This post doesn't exist (or it moved). Head back to <a href="/blog">all posts</a>.</p>
|
|
66
|
-
</div>`+await
|
|
66
|
+
</div>`+await F(),await v(G,{title:"Not found"}),"/blog","page")}async function u(G,z,J){let Y=await w(),W=B(M,`${z}.md`);if(!R(W))return null;let Z=X(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,k=$(K.charAt(0).toUpperCase()),j=`
|
|
67
67
|
<a class="blog-back" href="/blog">\u2190 All posts</a>
|
|
68
68
|
<div class="blog-post-head">
|
|
69
69
|
<h1>${$(Q.title||z)}</h1>
|
|
70
70
|
<p class="blog-post-meta">
|
|
71
71
|
<span class="author">${$(K)}</span>
|
|
72
72
|
<span class="dot">\xB7</span>
|
|
73
|
-
<time>${$(
|
|
73
|
+
<time>${$(T(Q.date))}</time>
|
|
74
74
|
</p>
|
|
75
75
|
${Q.poster?`<figure class="blog-post-poster"><img src="${$(Q.poster)}" alt="${$(Q.title||"")}"></figure>`:""}
|
|
76
|
-
</div>`,
|
|
77
|
-
<div class="avatar">${
|
|
76
|
+
</div>`,I=Q.authorBio?`<aside class="blog-author-card">
|
|
77
|
+
<div class="avatar">${k}</div>
|
|
78
78
|
<div><span class="name">${$(K)}</span><p class="bio">${$(Q.authorBio)}</p></div>
|
|
79
|
-
</aside>`:"",_=`${J}/blog/${z}`,
|
|
79
|
+
</aside>`:"",_=`${J}/blog/${z}`,n=`
|
|
80
80
|
<div class="blog-share">
|
|
81
81
|
<span class="blog-share-label">Share</span>
|
|
82
82
|
<a href="https://twitter.com/intent/tweet?url=${encodeURIComponent(_)}&text=${encodeURIComponent(Q.title||"")}" target="_blank" rel="noreferrer">X / Twitter</a>
|
|
83
83
|
<a href="https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(_)}" target="_blank" rel="noreferrer">LinkedIn</a>
|
|
84
|
-
</div>`,N=
|
|
84
|
+
</div>`,N=x().filter((A)=>A.slug!==z).slice(0,3),c=N.length?`<nav class="blog-more">
|
|
85
85
|
<h2>More from the blog</h2>
|
|
86
|
-
<ul>${N.map((
|
|
87
|
-
</nav>`:"";return G.wrapInLayout(await
|
|
86
|
+
<ul>${N.map((A)=>`<li><a href="/blog/${$(A.slug)}">${$(A.fm.title||A.slug)}</a></li>`).join("")}</ul>
|
|
87
|
+
</nav>`:"";return G.wrapInLayout(await D()+j+V+I+n+c+await F(),await v(G,Q),`/blog/${z}`,"page")}async function d(G){let z=await w(),Y=x().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
88
|
${K}
|
|
89
89
|
<div>
|
|
90
90
|
${Q?'<span class="blog-card-flag">Featured</span>':""}
|
|
91
91
|
<h2 class="blog-card-title">${$(V.fm.title||V.slug)}</h2>
|
|
92
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 ${$(
|
|
93
|
+
<div class="blog-card-meta">${$(V.fm.author||z.author)} \xB7 ${$(T(V.fm.date))}</div>
|
|
94
94
|
</div>
|
|
95
95
|
</a>`}).join(`
|
|
96
96
|
`),W=`
|
|
@@ -145,4 +145,4 @@ ${Y}`},themeConfig:{siteTitle:J.siteTitle,nav:J.nav}}}function A(){if(!x(M))retu
|
|
|
145
145
|
<h1>${$(z.title)}</h1>
|
|
146
146
|
<p>${$(z.description)}</p>
|
|
147
147
|
</div>
|
|
148
|
-
<div class="blog-cards">${Y||W}</div>`;return G.wrapInLayout(await
|
|
148
|
+
<div class="blog-cards">${Y||W}</div>`;return G.wrapInLayout(await D()+Z+await F(),await v(G,{title:z.title,description:z.description}),"/blog","page")}async function g(G,z){let J=await w(),Y={...await v(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}):H(z)}async function f(G,z){let J={...await v(G,{title:"Blog"}),sitemap:{enabled:!0,baseUrl:`${z}/blog`}};return typeof G.buildSitemap==="function"?G.buildSitemap(M,J):h(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 U();if(!V)return null;let Q=(j,I=200)=>new Response(j,{status:I,headers:{"Content-Type":"text/html; charset=utf-8"}});if(Y)return new Response(await g(V,z.origin),{headers:{"Content-Type":"application/rss+xml; charset=utf-8"}});if(W)return new Response(await f(V,z.origin),{headers:{"Content-Type":"application/xml; charset=utf-8"}});if(J==="/blog"||J==="/blog/")return Q(await d(V));let K=J.replace(/^\/blog\//,"").replace(/\/$/,""),k=await u(V,K,z.origin);return k?Q(k):Q(await l(V),404)}async function e(G){if(G.method!=="GET"&&G.method!=="HEAD")return null;let{pathname:z}=new URL(G.url);if(z==="/blog/feed.xml")return new Response(await H(""),{headers:{"Content-Type":"application/rss+xml; charset=utf-8"}});if(z==="/blog/sitemap.xml")return new Response(await h(""),{headers:{"Content-Type":"application/xml; charset=utf-8"}});return null}async function zz(G={outDir:"dist/blog"}){let z=G.outDir||"dist/blog",J=(G.baseUrl||(await w()).url).replace(/\/$/,""),Y=await U();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}),o(K,Q,"utf-8")};W("index.html",await d(Y));let Z=x();for(let V of Z){let Q=await u(Y,V.slug,J);if(Q)W(B(V.slug,"index.html"),Q)}W("feed.xml",await g(Y,J)),W("sitemap.xml",await f(Y,J)),console.log(`[blog] built ${Z.length} post(s) + listing, feed.xml, sitemap.xml \u2192 ${z}`)}export{e as renderBlogFeed,s as renderBlog,zz as buildBlog};
|
package/dist/dev/views.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{qb as O}from"../chunk-v0hqskdk.js";import{AsyncLocalStorage as k}from"async_hooks";import{existsSync as
|
|
2
|
+
import{qb as O}from"../chunk-v0hqskdk.js";import{AsyncLocalStorage as k}from"async_hooks";import{existsSync as D}from"fs";import{config as T,overridesReady as P}from"@stacksjs/config";import{projectPath as Z}from"@stacksjs/path";var L=new k;function _(){return L.getStore()??globalThis.__stxServeContext}globalThis.requestContext={cookie(z){return _()?.cookies?.[z]??null},url(){return _()?.url??""},locale(){return _()?.locale??"de"}};var A=Z("serve.ts");try{if(await Bun.file(A).exists())await import(A);else await V()}catch{await V()}function g(z){let H={},J=z.headers.get("cookie")||"";if(!J)return H;for(let M of J.split(";")){let X=M.trim(),U=X.indexOf("=");if(U===-1)continue;let N=X.slice(0,U).trim(),$=X.slice(U+1).trim();if(!N)continue;try{H[N]=decodeURIComponent($)}catch{H[N]=$}}return H}async function V(){await P;let{injectGlobalAutoImports:z,isApiBoundRequest:H,proxyToBackend:J}=await import("@stacksjs/server"),{applyRequestLocale:M}=await import("@stacksjs/i18n");await z();let{serve:X}=await import("../chunk-hv8tkjw2.js"),{site:U,i18n:N}=await f(),$="resources/views",E="storage/framework/defaults/resources/views",w=await I(["resources/views/layouts","resources/layouts"])??"resources/views/layouts",B="storage/framework/defaults/resources/layouts",b=await I(["resources/views/components","resources/components"])??"resources/views/components",R=Number(process.env.PORT)||3000,y=Number(process.env.PORT_API)||3008,m=Number(process.env.PORT_DOCS)||T.ports?.docs||3006,C=`http://127.0.0.1:${y}`,v=`http://127.0.0.1:${m}`,j=T?.auth?.defaultTokenName??"auth-token";await X({patterns:[$,E],port:R,componentsDir:"storage/framework/defaults/resources/components",layoutsDir:w,partialsDir:b,fallbackLayoutsDir:B,fallbackPartialsDir:E,quiet:!0,...N&&{i18n:N},...U?.url&&{site:U},auth:{cookieName:j,redirectTo:"/login"},onRequest:async(K)=>{let Y=new URL(K.url),{maintenanceGate:x}=await import("@stacksjs/server"),F=await x(K);if(F)return F;if(D(Z("resources/views/blog.stx"))){let{renderBlogFeed:W}=await import("../blog.js"),Q=await W(K);if(Q)return Q}else{let{renderBlog:W}=await import("../blog.js"),Q=await W(K);if(Q)return Q}if(Y.pathname==="/docs"||Y.pathname.startsWith("/docs/"))return J(K,v,"/docs");if(H(K,Y.pathname))return J(K,C);if(N&&K.method==="GET"){let W=Y.pathname.match(/^\/locale\/([a-z]{2}(?:-[a-z]{2})?)\/?$/i);if(W){let{createLocaleSwitchResponse:Q}=await import("@stacksjs/i18n");return Q(K,W[1],N)}}let S=await M(K),G={cookies:g(K),url:K.url,locale:S};return globalThis.__stxServeSearch=Y.search,globalThis.__stxServeContext=G,L.enterWith(G),null}})}async function I(z){for(let H of z)if(D(Z(H)))return H;return null}function h(z){let H=z.i18n.locales,J=z.i18n.defaultLocale??H[0];return{locales:H,defaultLocale:J,labels:z.i18n.labels??Object.fromEntries(H.map((M)=>[M,M.toUpperCase()])),translations:{},pickerSelector:z.i18n.pickerSelector??"#lang-picker"}}async function p(z){try{let{resolveI18n:H}=await import("@stacksjs/stx");if(typeof H==="function"){let J=H(z,Z());if(J)return J}}catch{}return h(z)}async function f(){let z=Z("site.config.ts");if(!D(z))return{};try{let J=(await import(z)).default;if(!J)return{};if(!J.i18n)return{site:J};let M=await p(J);return{site:J,i18n:M}}catch{}return{}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/actions",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.79",
|
|
5
5
|
"description": "The Stacks actions.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -68,23 +68,23 @@
|
|
|
68
68
|
"@stacksjs/ts-md": "^0.1.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@stacksjs/api": "0.70.
|
|
72
|
-
"@stacksjs/cli": "0.70.
|
|
73
|
-
"@stacksjs/config": "0.70.
|
|
74
|
-
"@stacksjs/database": "0.70.
|
|
71
|
+
"@stacksjs/api": "0.70.79",
|
|
72
|
+
"@stacksjs/cli": "0.70.79",
|
|
73
|
+
"@stacksjs/config": "0.70.79",
|
|
74
|
+
"@stacksjs/database": "0.70.79",
|
|
75
75
|
"@stacksjs/tlsx": "^0.13.2",
|
|
76
76
|
"better-dx": "^0.2.16",
|
|
77
|
-
"@stacksjs/dns": "0.70.
|
|
78
|
-
"@stacksjs/enums": "0.70.
|
|
79
|
-
"@stacksjs/env": "0.70.
|
|
80
|
-
"@stacksjs/error-handling": "0.70.
|
|
81
|
-
"@stacksjs/logging": "0.70.
|
|
82
|
-
"@stacksjs/path": "0.70.
|
|
83
|
-
"@stacksjs/security": "0.70.
|
|
84
|
-
"@stacksjs/storage": "0.70.
|
|
85
|
-
"@stacksjs/strings": "0.70.
|
|
86
|
-
"@stacksjs/utils": "0.70.
|
|
87
|
-
"@stacksjs/validation": "0.70.
|
|
77
|
+
"@stacksjs/dns": "0.70.79",
|
|
78
|
+
"@stacksjs/enums": "0.70.79",
|
|
79
|
+
"@stacksjs/env": "0.70.79",
|
|
80
|
+
"@stacksjs/error-handling": "0.70.79",
|
|
81
|
+
"@stacksjs/logging": "0.70.79",
|
|
82
|
+
"@stacksjs/path": "0.70.79",
|
|
83
|
+
"@stacksjs/security": "0.70.79",
|
|
84
|
+
"@stacksjs/storage": "0.70.79",
|
|
85
|
+
"@stacksjs/strings": "0.70.79",
|
|
86
|
+
"@stacksjs/utils": "0.70.79",
|
|
87
|
+
"@stacksjs/validation": "0.70.79"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"pickier": "^0.1.28"
|