@stacksjs/actions 0.70.78 → 0.70.80
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/{chunk-v1dg1jp6.js → chunk-30cc35np.js} +1 -1
- package/dist/{chunk-49ry9mgz.js → chunk-9sx16wyz.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/dev/views.js +1 -1
- package/dist/queue/work.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};
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
import"./chunk-v0hqskdk.js";var q={type:"aws",useLoadBalancer:!0,app:{name:"app-server-1",domain:"stacksjs.com",region:"us-east-1",type:"app",size:"t3.micro",diskSize:20,serverOS:"ubuntu-20-lts-x86_64",bunVersion:"1.1.26",database:"sqlite",databaseName:"stacks"},app2:{name:"app-server-2",domain:"stacksjs.com",instanceType:"t3.micro",userData:`#!/bin/bash
|
|
3
3
|
echo "Hello World from App Server 2!" > /tmp/test.txt
|
|
4
4
|
chown ubuntu:ubuntu /tmp/test.txt
|
|
5
|
-
`},web:{name:"web-server",domain:"ow3.org",region:"us-east-1",type:"web",size:"t3.micro",diskSize:20,serverOS:"ubuntu-20-lts-x86_64",bunVersion:"1.1.26"},cache:{name:"cache-server",domain:"stacksjs.com",region:"us-east-1",type:"cache",size:"t3.micro",diskSize:20,serverOS:"ubuntu-20-lts-x86_64",bunVersion:"1.1.26"}};import{env as m}from"@stacksjs/env";var C={project:{name:"stacks",slug:"stacks",region:"us-east-1"},cloud:{provider:"hetzner"},mode:"server",environments:{production:{type:"production",deployBranch:"main",region:"us-east-1",variables:{NODE_ENV:"production",LOG_LEVEL:"info"}},staging:{type:"staging",deployBranch:"stage",domainPrefix:"staging",region:"us-east-1",variables:{NODE_ENV:"staging",LOG_LEVEL:"debug"}},development:{type:"development",deployBranch:"dev",domainPrefix:"dev",region:"us-east-1",variables:{NODE_ENV:"development",LOG_LEVEL:"debug"}}},infrastructure:{compute:{instances:1,size:"small",disk:{size:20,type:"ssd",encrypted:!0},webServer:"rpx",proxy:{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:"hello@stacksjs.com"}},servers:{app:q.app},containers:{api:{cpu:512,memory:1024,port:3000,healthCheck:"/health",desiredCount:2,autoScaling:{min:1,max:10,targetCpuUtilization:70,targetMemoryUtilization:80}}},loadBalancer:{enabled:!0,type:"application",healthCheck:{path:"/health",interval:30,healthyThreshold:2,unhealthyThreshold:5}},ssl:{enabled:!0,provider:"acm",domains:m.SSL_DOMAINS?.split(",")||["stacksjs.com","www.stacksjs.com"],redirectHttp:!0,letsEncrypt:{email:m.LETSENCRYPT_EMAIL||"admin@stacksjs.com",staging:!1,autoRenew:!0}},dns:{domain:m.APP_DOMAIN||"stacksjs.com",hostedZoneId:m.AWS_HOSTED_ZONE_ID||"Z01455702Q7952O6RCY37"},storage:{public:{public:!0,encryption:!0,versioning:!0,website:{indexDocument:"index.html",errorDocument:"index.html"}},private:{encryption:!0,versioning:!0},docs:{public:!0,encryption:!0,versioning:!0,path:"/docs",pathRewriteStyle:"flat",website:{indexDocument:"index.html",errorDocument:"404.html"}},blog:{public:!0,encryption:!0,versioning:!0,path:"/blog",website:{indexDocument:"index.html",errorDocument:"404.html"}},logs:{encryption:!0,versioning:!1},backups:{encryption:!0,versioning:!0},email:{public:!1,encryption:!0,versioning:!1}},functions:{},queues:{jobs:{visibilityTimeout:120,deadLetterQueue:!0,maxReceiveCount:3}},databases:{},cdn:{},monitoring:{}},sites:{main:{root:".",path:"/",domain:m.APP_DOMAIN||"stacksjs.com",start:"bun --conditions development storage/framework/core/buddy/src/cli.ts serve",port:3000,preStart:["bun install"]},api:{root:".",start:"bun --conditions development storage/framework/core/actions/src/serve/api.ts",port:3008,preStart:["bun install"],env:{HOST:"127.0.0.1",APP_ENV:"production"}},docs:{deploy:"server",root:"dist/docs/.bunpress",path:"/docs",domain:m.APP_DOMAIN||"stacksjs.com",build:"bunx @stacksjs/bunpress build --dir ./docs --outdir ./dist/docs",pathRewriteStyle:"directory"},blog:{deploy:"server",root:"dist/blog",path:"/blog",domain:m.APP_DOMAIN||"stacksjs.com",build:`bun -e "const {buildBlog}=await import('./storage/framework/core/actions/src/blog'); await buildBlog({outDir:'./dist/blog', baseUrl: (process.env.APP_URL?(/^https?:/.test(process.env.APP_URL)?process.env.APP_URL:'https://'+process.env.APP_URL):'https://stacksjs.com')})"`,pathRewriteStyle:"directory"},wwwStacksjs:{domain:"www.stacksjs.com",redirect:"https://stacksjs.com"}}},w={},E=w;export{C as tsCloud,E as default};
|
|
5
|
+
`},web:{name:"web-server",domain:"ow3.org",region:"us-east-1",type:"web",size:"t3.micro",diskSize:20,serverOS:"ubuntu-20-lts-x86_64",bunVersion:"1.1.26"},cache:{name:"cache-server",domain:"stacksjs.com",region:"us-east-1",type:"cache",size:"t3.micro",diskSize:20,serverOS:"ubuntu-20-lts-x86_64",bunVersion:"1.1.26"}};import{env as m}from"@stacksjs/env";var C={project:{name:"stacks",slug:"stacks",region:"us-east-1"},cloud:{provider:"hetzner"},mode:"server",environments:{production:{type:"production",deployBranch:"main",region:"us-east-1",variables:{NODE_ENV:"production",LOG_LEVEL:"info"}},staging:{type:"staging",deployBranch:"stage",domainPrefix:"staging",region:"us-east-1",variables:{NODE_ENV:"staging",LOG_LEVEL:"debug"}},development:{type:"development",deployBranch:"dev",domainPrefix:"dev",region:"us-east-1",variables:{NODE_ENV:"development",LOG_LEVEL:"debug"}}},infrastructure:{compute:{instances:1,size:"small",disk:{size:20,type:"ssd",encrypted:!0},webServer:"rpx",proxy:{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:"hello@stacksjs.com"}},servers:{app:q.app},containers:{api:{cpu:512,memory:1024,port:3000,healthCheck:"/health",desiredCount:2,autoScaling:{min:1,max:10,targetCpuUtilization:70,targetMemoryUtilization:80}}},loadBalancer:{enabled:!0,type:"application",healthCheck:{path:"/health",interval:30,healthyThreshold:2,unhealthyThreshold:5}},ssl:{enabled:!0,provider:"acm",domains:m.SSL_DOMAINS?.split(",")||["stacksjs.com","www.stacksjs.com"],redirectHttp:!0,letsEncrypt:{email:m.LETSENCRYPT_EMAIL||"admin@stacksjs.com",staging:!1,autoRenew:!0}},dns:{domain:m.APP_DOMAIN||"stacksjs.com",hostedZoneId:m.AWS_HOSTED_ZONE_ID||"Z01455702Q7952O6RCY37"},storage:{public:{public:!0,encryption:!0,versioning:!0,website:{indexDocument:"index.html",errorDocument:"index.html"}},private:{encryption:!0,versioning:!0},docs:{public:!0,encryption:!0,versioning:!0,path:"/docs",pathRewriteStyle:"flat",website:{indexDocument:"index.html",errorDocument:"404.html"}},blog:{public:!0,encryption:!0,versioning:!0,path:"/blog",website:{indexDocument:"index.html",errorDocument:"404.html"}},logs:{encryption:!0,versioning:!1},backups:{encryption:!0,versioning:!0},email:{public:!1,encryption:!0,versioning:!1}},functions:{},queues:{jobs:{visibilityTimeout:120,deadLetterQueue:!0,maxReceiveCount:3}},databases:{},cdn:{},monitoring:{}},sites:{main:{root:".",path:"/",domain:m.APP_DOMAIN||"stacksjs.com",start:"bun --conditions development storage/framework/core/buddy/src/cli.ts serve",port:3000,preStart:["bun install","bun --conditions development storage/framework/core/buddy/src/cli.ts migrate"]},api:{root:".",start:"bun --conditions development storage/framework/core/actions/src/serve/api.ts",port:3008,preStart:["bun install"],env:{HOST:"127.0.0.1",APP_ENV:"production"}},docs:{deploy:"server",root:"dist/docs/.bunpress",path:"/docs",domain:m.APP_DOMAIN||"stacksjs.com",build:"bunx @stacksjs/bunpress build --dir ./docs --outdir ./dist/docs",pathRewriteStyle:"directory"},blog:{deploy:"server",root:"dist/blog",path:"/blog",domain:m.APP_DOMAIN||"stacksjs.com",build:`bun -e "const {buildBlog}=await import('./storage/framework/core/actions/src/blog'); await buildBlog({outDir:'./dist/blog', baseUrl: (process.env.APP_URL?(/^https?:/.test(process.env.APP_URL)?process.env.APP_URL:'https://'+process.env.APP_URL):'https://stacksjs.com')})"`,pathRewriteStyle:"directory"},wwwStacksjs:{domain:"www.stacksjs.com",redirect:"https://stacksjs.com"}}},w={},E=w;export{C as tsCloud,E as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{qb as L}from"./chunk-v0hqskdk.js";import f from"process";import{log as N}from"@stacksjs/cli";import{getErrorMessage as E}from"@stacksjs/utils";async function C(){try{return(await import("./chunk-
|
|
2
|
+
import{qb as L}from"./chunk-v0hqskdk.js";import f from"process";import{log as N}from"@stacksjs/cli";import{getErrorMessage as E}from"@stacksjs/utils";async function C(){try{return(await import("./chunk-30cc35np.js")).tsCloud||null}catch{return null}}async function b(){let G=await C();return{name:G?.project?.name||"stacks",region:G?.project?.region||"us-east-1"}}async function v(G){try{let{AWSClient:Q}=await import("@stacksjs/ts-cloud"),J=new Q,_=new URLSearchParams({Action:"GetCallerIdentity",Version:"2011-06-15"}),K=await J.request({service:"sts",region:G,method:"POST",path:"/",body:_.toString()}),j=String(K).match(/<Account>(\d+)<\/Account>/);if(j&&j[1])return j[1];return f.env.AWS_ACCOUNT_ID||""}catch(Q){return f.env.AWS_ACCOUNT_ID||""}}async function p(G){let{environment:Q}=G,J=await C();if(!J)throw Error("Cloud configuration not found. Ensure config/cloud.ts exports tsCloud.");let{InfrastructureGenerator:_}=await import("@stacksjs/ts-cloud"),j=new _({config:J,environment:Q}).generate().getBuilder().build();return JSON.stringify(j)}function S(G){let Q={green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",cyan:"\x1B[36m",gray:"\x1B[90m",reset:"\x1B[0m"};if(G.includes("COMPLETE")&&!G.includes("ROLLBACK"))return`${Q.green}${G}${Q.reset}`;if(G.includes("IN_PROGRESS"))return`${Q.yellow}${G}${Q.reset}`;if(G.includes("FAILED")||G.includes("ROLLBACK"))return`${Q.red}${G}${Q.reset}`;if(G.includes("DELETE"))return`${Q.gray}${G}${Q.reset}`;return G}async function k(G){let{region:Q,domain:J,sslDomains:_,hostedZoneId:K,albDnsName:j,stackName:Y}=G;console.log(""),console.log("Setting up SSL certificate...");try{let{Route53Client:$,ACMClient:w,AWSClient:F}=await import("@stacksjs/ts-cloud"),P=new $(Q),V=new w(Q),W=new F;console.log(` Requesting SSL certificate for ${J}...`);let Z=await V.requestCertificate({DomainName:_[0]??J,SubjectAlternativeNames:_.length>1?_.slice(1):void 0,ValidationMethod:"DNS"});console.log(` Certificate ARN: ${Z.CertificateArn}`),await new Promise((R)=>setTimeout(R,5000));let U=await V.describeCertificate({CertificateArn:Z.CertificateArn});console.log(" Adding DNS validation records...");for(let R of U.DomainValidationOptions||[])if(R.ResourceRecord)await P.changeResourceRecordSets({HostedZoneId:K,ChangeBatch:{Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:R.ResourceRecord.Name,Type:"CNAME",TTL:300,ResourceRecords:[{Value:R.ResourceRecord.Value}]}}]}});console.log("\u2713 Validation records added"),console.log(" Waiting for certificate validation (this may take 1-5 minutes)...");for(let R=0;R<30;R++){let M=await V.describeCertificate({CertificateArn:Z.CertificateArn});if(M.Status==="ISSUED"){console.log("\u2713 Certificate issued!");let{AWSCloudFormationClient:A}=await import("@stacksjs/ts-cloud"),B=await new A(Q).listStackResources(Y),I=B.StackResourceSummaries.find((O)=>O.LogicalResourceId==="ApplicationLoadBalancer")?.PhysicalResourceId,X=B.StackResourceSummaries.find((O)=>O.LogicalResourceId==="ECSTargetGroup")?.PhysicalResourceId||B.StackResourceSummaries.find((O)=>O.LogicalResourceId==="WebTargetGroup")?.PhysicalResourceId;if(I&&X){console.log(" Creating HTTPS listener...");let O=new URLSearchParams({Action:"CreateListener",LoadBalancerArn:I,Protocol:"HTTPS",Port:"443","Certificates.member.1.CertificateArn":Z.CertificateArn,"DefaultActions.member.1.Type":"forward","DefaultActions.member.1.TargetGroupArn":X,Version:"2015-12-01"});await W.request({service:"elasticloadbalancing",region:Q,method:"POST",path:"/",body:O.toString()}),console.log("\u2713 HTTPS listener created!"),console.log(" Configuring HTTP to HTTPS redirect...");let h=new URLSearchParams({Action:"DescribeListeners",LoadBalancerArn:I,Version:"2015-12-01"}),H=await W.request({service:"elasticloadbalancing",region:Q,method:"POST",path:"/",body:h.toString()}),x=H?.DescribeListenersResponse?.DescribeListenersResult?.Listeners?.member||H?.DescribeListenersResult?.Listeners?.member,T=(Array.isArray(x)?x:x?[x]:[]).find((D)=>D.Port==="80"||D.Port===80);if(T){let D=new URLSearchParams({Action:"ModifyListener",ListenerArn:T.ListenerArn,"DefaultActions.member.1.Type":"redirect","DefaultActions.member.1.RedirectConfig.Protocol":"HTTPS","DefaultActions.member.1.RedirectConfig.Port":"443","DefaultActions.member.1.RedirectConfig.StatusCode":"HTTP_301",Version:"2015-12-01"});await W.request({service:"elasticloadbalancing",region:Q,method:"POST",path:"/",body:D.toString()}),console.log("\u2713 HTTP to HTTPS redirect configured!")}}let z=B.StackResourceSummaries.find((O)=>O.LogicalResourceId==="CloudFrontDistribution")?.PhysicalResourceId;if(z){console.log(" Updating CloudFront distribution with SSL certificate...");let O=await W.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${z}/config`}),h=O._headers?.etag||O._headers?.ETag,H=O.DistributionConfig;if(H&&h){H.Aliases={Quantity:_.length,Items:_},H.ViewerCertificate={ACMCertificateArn:Z.CertificateArn,SSLSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021",CloudFrontDefaultCertificate:!1};let x=`<?xml version="1.0" encoding="UTF-8"?>
|
|
3
3
|
<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
|
|
4
4
|
<CallerReference>${H.CallerReference}</CallerReference>
|
|
5
5
|
<Aliases>
|
package/dist/deploy/index.js
CHANGED
|
@@ -8,7 +8,7 @@ ${Q}${H}</${J}>
|
|
|
8
8
|
<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
|
|
9
9
|
${Object.entries(J).filter(([U])=>!U.startsWith("@_")).map(([U,H])=>AJ(U,H," ")).join("")}</DistributionConfig>
|
|
10
10
|
`}function _J(J){let U=[...new Set(J)].filter((Q)=>Number.isFinite(Q)&&Q>0).sort((Q,_)=>Q-_);if(U.length===0)return"true";return`if command -v firewall-cmd >/dev/null 2>&1; then firewall-cmd --permanent ${U.map((Q)=>`--add-port=${Q}/tcp`).join(" ")} && firewall-cmd --reload; fi`}async function CJ(J,U,H){if(!U)return;if(((await J.describeSecurityGroups({GroupIds:[U]}))?.SecurityGroups?.[0]?.IpPermissions||[]).some((G)=>{return G.IpProtocol==="tcp"&&Number(G.FromPort)<=H&&Number(G.ToPort)>=H&&wJ(G.IpRanges).some((y)=>y.CidrIp==="0.0.0.0/0")}))return;try{await J.authorizeSecurityGroupIngress({GroupId:U,IpPermissions:[{IpProtocol:"tcp",FromPort:H,ToPort:H,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Stacks API port ${H}`}]}]})}catch(G){if(!String(G?.message||"").includes("InvalidPermission.Duplicate"))throw G}}async function kJ(J,U,H){if(!U)return;let Q=await J.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${U}/config`,returnHeaders:!0}),_=Q.headers?.etag||Q.headers?.ETag||"",b=Q.body?.DistributionConfig||Q.DistributionConfig||Q.body;if(!_||!b?.Origins?.Items)return;let y=wJ(b.Origins.Items.Origin).find((c)=>String(c.Id||"").includes("-api"));if(!y?.CustomOriginConfig)return;if(Number(y.CustomOriginConfig.HTTPPort)===H)return;y.CustomOriginConfig.HTTPPort=H,await J.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${U}/config`,body:hJ(b),headers:{"Content-Type":"application/xml","If-Match":_}})}var xJ=S("Building framework...");xJ.start();await KJ("bun run build",{cwd:X.frameworkPath("core"),quiet:!1});xJ.succeed("Framework built");var LJ=X.projectPath("docs"),SJ=X.projectPath("dist/docs/.bunpress");if(RJ.hasFiles(LJ)){let J=S("Building documentation with BunPress...");J.start();try{let{rm:U}=await import("fs/promises"),H=`${T.env.HOME}/Code/Tools/bunpress/packages/bunpress/bin/cli.ts`,Q=X.projectPath("node_modules/@stacksjs/bunpress/dist/bin/cli.js"),_=await Bun.file(H).exists(),b=await Bun.file(Q).exists(),G=_?`bun ${H} build --dir ${LJ} --outdir ${X.projectPath("dist/docs")}`:b?`bun ${Q} build --dir ${LJ} --outdir ${X.projectPath("dist/docs")}`:"bunx @stacksjs/bunpress@0.1.5 build --dir ./docs --outdir ./dist/docs";await U(SJ,{recursive:!0,force:!0}),await KJ(G,{cwd:X.projectPath(),quiet:!V}),J.succeed(`Documentation built with BunPress${_?" (local checkout)":""}`)}catch(U){if(J.stop(),console.log(`\u26A0 Documentation build skipped: ${U.message}`),V)$.debug("To build docs manually: cd ~/Code/Tools/bunpress && bun packages/bunpress/bin/cli.ts build --dir /path/to/docs --outdir /path/to/dist/docs")}}else if(V)$.debug("No docs directory found, skipping documentation build");var vJ=RJ.hasFiles(X.projectPath("dist/blog")),yJ=["CampmateScript-Regular.woff2","SequoiaSans-Regular.woff2","Switchback-Regular.woff2"].every((J)=>JJ(X.projectPath(`dist/blog/assets/fonts/nps/${J}`))),gJ=["topography.svg","park-ridge.svg"].every((J)=>JJ(X.projectPath(`dist/blog/assets/images/${J}`))),ZJ=X.projectPath("dist/blog/index.html"),i=JJ(ZJ)?BJ(ZJ,"utf8"):"",cJ=i.length>0&&!i.includes("woff2-variations"),mJ=i.includes("--on-primary")&&i.includes("--newsletter-bg"),dJ=i.includes("topography.svg")&&i.includes("park-ridge.svg"),pJ=!i.includes("stamp-trail")&&!i.includes("blog-sign-tree.svg"),uJ=X.frameworkPath("core/cms/src/build.ts"),sJ=X.projectPath("config/blog.ts"),lJ=JJ(ZJ)&&[uJ,sJ].filter((J)=>JJ(J)).every((J)=>TJ(ZJ).mtimeMs>=TJ(J).mtimeMs);if(!vJ||!yJ||!gJ||!cJ||!mJ||!dJ||!pJ||!lJ){let J=S("Building blog...");J.start();try{let U=(await import(X.projectPath("config/blog"))).default,{buildBlogSite:H}=await import(X.frameworkPath("core/cms/src/build"));await H({config:U,outDir:X.projectPath("dist/blog")}),J.succeed("Blog built successfully")}catch(U){if(J.stop(),console.log(`\u26A0 Blog build skipped: ${U.message}`),V)$.debug(`Blog build error: ${U.stack}`)}}else if(V)$.debug("Pre-built blog found at dist/blog, skipping build");if(V)$.debug("Skipping views build (vite-config not configured)");var aJ=await import(X.projectPath("config/cloud")),iJ=aJ?.tsCloud?.mode||"server";if(iJ==="serverless"){let J=S("Building server...");J.start(),await KJ("bun build.ts",{cwd:X.frameworkPath("server"),quiet:!V}),J.succeed("Server built");let U=S("Packaging for deployment...");U.start(),await KJ("bun zip.ts",{cwd:X.corePath("cloud"),quiet:!V}),U.succeed("Package ready")}else if(V)$.debug("Skipping server build and packaging (server mode)");if(!T.env.AWS_ACCESS_KEY_ID||!T.env.AWS_SECRET_ACCESS_KEY){let{existsSync:J,readFileSync:U}=await import("fs"),H=T.env.APP_ENV||T.env.NODE_ENV||"production",Q=[X.projectPath(`.env.${H}`),X.projectPath(".env")];for(let _ of Q)if(J(_)){let b=U(_,"utf-8");for(let G of b.split(`
|
|
11
|
-
`)){let y=G.trim();if(y.startsWith("#")||!y.includes("="))continue;let c=y.indexOf("="),k=y.slice(0,c).trim(),N=y.slice(c+1).trim();if(N.startsWith('"')&&N.endsWith('"')||N.startsWith("'")&&N.endsWith("'"))N=N.slice(1,-1);if(k==="AWS_ACCESS_KEY_ID"&&N)T.env.AWS_ACCESS_KEY_ID=N;else if(k==="AWS_SECRET_ACCESS_KEY"&&N)T.env.AWS_SECRET_ACCESS_KEY=N;else if(k==="AWS_REGION"&&N&&!T.env.AWS_REGION)T.env.AWS_REGION=N;else if(k==="AWS_ACCOUNT_ID"&&N&&!T.env.AWS_ACCOUNT_ID)T.env.AWS_ACCOUNT_ID=N;else if(k.startsWith("MAIL_PASSWORD_")&&N&&!T.env[k])T.env[k]=N}if(V)$.debug(`Loaded AWS credentials from ${_}`);break}}try{let{deployStack:J,deployFrontend:U}=await import("../chunk-
|
|
11
|
+
`)){let y=G.trim();if(y.startsWith("#")||!y.includes("="))continue;let c=y.indexOf("="),k=y.slice(0,c).trim(),N=y.slice(c+1).trim();if(N.startsWith('"')&&N.endsWith('"')||N.startsWith("'")&&N.endsWith("'"))N=N.slice(1,-1);if(k==="AWS_ACCESS_KEY_ID"&&N)T.env.AWS_ACCESS_KEY_ID=N;else if(k==="AWS_SECRET_ACCESS_KEY"&&N)T.env.AWS_SECRET_ACCESS_KEY=N;else if(k==="AWS_REGION"&&N&&!T.env.AWS_REGION)T.env.AWS_REGION=N;else if(k==="AWS_ACCOUNT_ID"&&N&&!T.env.AWS_ACCOUNT_ID)T.env.AWS_ACCOUNT_ID=N;else if(k.startsWith("MAIL_PASSWORD_")&&N&&!T.env[k])T.env[k]=N}if(V)$.debug(`Loaded AWS credentials from ${_}`);break}}try{let{deployStack:J,deployFrontend:U}=await import("../chunk-9sx16wyz.js"),H=T.env.APP_ENV||T.env.NODE_ENV||"production",Q=T.env.AWS_REGION||"us-east-1",_=await import(X.projectPath("config/cloud")),b=_?.tsCloud?.mode||"server",G=_?.tsCloud?.project?.name||_?.tsCloud?.project?.slug||"stacks";if(b==="serverless"){console.log(""),console.log("Serverless deployment mode detected"),console.log("Building and pushing container image..."),console.log("");let z=T.env.AWS_ACCOUNT_ID||await y(Q);if(!z||z.length<10)throw Error(`Invalid AWS Account ID: "${z||"(empty)"}"
|
|
12
12
|
Set AWS_ACCOUNT_ID in your .env file or ensure valid AWS credentials are configured.`);let q=`${z}.dkr.ecr.${Q}.amazonaws.com/${G}-${H}-api`,A=`${q}:latest`;if(V)$.debug(`ECR repository: ${q}`);if(V)$.debug("ECR credentials will be validated before push...");let W=S("Building Docker image...");W.start();try{let{exec:Y}=await import("child_process"),{promisify:F}=await import("util"),x=F(Y),E=`docker build --platform linux/amd64 -t ${A} -f Dockerfile .`,{stdout:M,stderr:O}=await x(E,{cwd:X.projectPath(),env:T.env,maxBuffer:10485760,timeout:900000});if(V&&M)$.debug(M);if(V&&O)$.debug(O);W.succeed(`Docker image built: ${A}`)}catch(Y){if(W.fail("Docker build failed"),V)$.debug(`Docker build error: ${Y.message}`);throw Y}let K=S("Checking ECR repository...");K.start();try{let{ECRClient:Y}=await import("@stacksjs/ts-cloud"),F=new Y(Q),x=`${G}-${H}-api`;try{await F.describeRepositories({repositoryNames:[x]}),K.succeed(`ECR repository exists: ${x}`)}catch(E){if(E.code==="RepositoryNotFoundException"||E.message?.includes("RepositoryNotFoundException"))K.text=`Creating ECR repository: ${x}...`,await F.createRepository({repositoryName:x,imageScanningConfiguration:{scanOnPush:!0},imageTagMutability:"MUTABLE"}),K.succeed(`ECR repository created: ${x}`);else throw E}}catch(Y){if(K.fail("ECR repository check failed"),V)$.debug(`ECR repository error: ${Y.message}`);throw Y}let w=S("Authenticating to ECR...");w.start();try{let{ECRClient:Y}=await import("@stacksjs/ts-cloud"),E=(await new Y(Q).getAuthorizationToken()).authorizationData?.[0];if(!E?.authorizationToken)throw Error("No authorization token received from ECR");let M=Buffer.from(E.authorizationToken,"base64").toString("utf-8"),O=M.indexOf(":");if(O===-1)throw Error("ECR authorization token has unexpected format (missing colon separator)");let L=M.slice(O+1),j=Bun.spawnSync(["docker","login","--username","AWS","--password-stdin",`${z}.dkr.ecr.${Q}.amazonaws.com`],{stdin:new TextEncoder().encode(L),stdout:"pipe",stderr:"pipe"});if(j.exitCode!==0){let P=new TextDecoder().decode(j.stderr);throw Error(`Docker login failed: ${P}`)}w.succeed("Authenticated to ECR")}catch(Y){if(w.fail("ECR authentication failed"),V)$.debug(`ECR auth error: ${Y.message}`);throw Y}console.log("");let I=S("Pushing image to ECR...");I.start();try{let{exec:Y}=await import("child_process"),{promisify:F}=await import("util"),x=F(Y),E=`docker push ${A}`;await x(E,{env:T.env}),I.succeed(`Image pushed: ${A}`)}catch(Y){if(I.fail("Docker push failed"),V)$.debug(`Push error: ${Y.message}`);throw Y}console.log(""),console.log("Container image ready in ECR. CloudFormation will use this image."),console.log("")}else console.log(""),console.log("Server deployment mode detected"),console.log("Deploying EC2 infrastructure via CloudFormation..."),console.log("");async function y(z){try{let{STSClient:q}=await import("@stacksjs/ts-cloud"),K=(await new q(z).getCallerIdentity()).Account||T.env.AWS_ACCOUNT_ID||"";if(V)$.debug(`Retrieved AWS Account ID: ${K||"(empty)"}`);return K}catch(q){if(V)$.debug(`Failed to get AWS Account ID: ${q.message}`);return T.env.AWS_ACCOUNT_ID||""}}try{let z=await import(X.projectPath("cloud/deploy-script"));if(typeof z.beforeDeploy==="function")await z.beforeDeploy({environment:H,region:Q})}catch(z){if(z.code==="ERR_MODULE_NOT_FOUND"||z.code==="MODULE_NOT_FOUND"){if(V)$.debug("No beforeDeploy hook found (cloud/deploy-script not found)")}else if(console.warn(`\u26A0 beforeDeploy hook failed: ${z.message}`),V)$.debug(`beforeDeploy error stack: ${z.stack}`)}await J({environment:H,region:Q,waitForCompletion:!0,verbose:V});try{let z=await import(X.projectPath("cloud/deploy-script"));if(typeof z.afterDeploy==="function"){let{CloudFormationClient:q}=await import("@stacksjs/ts-cloud"),A=new q(Q),W=`${G}-cloud`,K={};try{K=await A.getStackOutputs(W)}catch(w){if(V)$.debug(`Failed to get stack outputs: ${w instanceof Error?w.message:String(w)}`)}await z.afterDeploy({environment:H,region:Q,outputs:K})}}catch(z){if(z.code==="ERR_MODULE_NOT_FOUND"||z.code==="MODULE_NOT_FOUND"){if(V)$.debug("No afterDeploy hook found (cloud/deploy-script not found)")}else if(console.warn(`\u26A0 afterDeploy hook failed: ${z.message}`),V)$.debug(`afterDeploy error stack: ${z.stack}`)}let c=S("Running database migrations...");c.start();try{let{generateMigrations:z,runDatabaseMigration:q}=await import("@stacksjs/database");await z(),await q(),c.succeed("Database migrations completed")}catch(z){if(c.stop(),console.log(`\u26A0 Database migrations skipped: ${z.message}`),V)$.debug(`Migration error: ${z.stack}`)}let k=S("Ensuring framework tables (auth, notifications, RBAC)...");k.start();try{let{migrateAuthTables:z,migrateNotificationTables:q,migrateRbacTables:A}=await import("@stacksjs/database"),W=[],K=[["auth",z],["notification",q],["RBAC",A]];for(let[w,I]of K){let Y=await I({verbose:V});if(!Y.success)W.push(`${w}: ${Y.error}`)}if(W.length>0)k.stop(),console.log(`\u26A0 Some framework tables could not be migrated: ${W.join("; ")}`);else k.succeed("Framework tables ensured (auth, notifications, RBAC)")}catch(z){if(k.stop(),console.log(`\u26A0 Framework table migrations skipped: ${z.message}`),V)$.debug(`Framework table migration error: ${z.stack}`)}if(b==="server"){let z=S("Retrieving server instance details...");z.start();try{let{CloudFormationClient:W}=await import("@stacksjs/ts-cloud"),K=new W(Q),w=`${G}-cloud`,I=await K.getStackOutputs(w);z.succeed("Server instances deployed"),console.log(""),console.log("Server instances:");for(let[Y,F]of Object.entries(I)){if(Y.endsWith("PublicIp"))console.log(` ${Y}: ${F}`);if(Y.endsWith("InstanceId"))console.log(` ${Y}: ${F}`)}console.log("")}catch(W){if(z.stop(),console.log(`\u26A0 Could not retrieve server details: ${W.message}`),V)$.debug(`Output retrieval error: ${W.stack}`)}let q=S("Deploying API server to EC2...");q.start();try{let{S3Client:W,CloudFormationClient:K,AWSClient:w}=await import("@stacksjs/ts-cloud"),{readFileSync:I,existsSync:Y}=await import("fs"),{resolve:F}=await import("path"),x=new W(Q),E=new K(Q),M=new w,O=`${G}-cloud`,L=await E.getStackOutputs(O),j=L.FrontendBucketName,P=Number(OJ.ports?.api||3008),C;for(let[g,v]of Object.entries(L))if(g.endsWith("InstanceId")&&typeof v==="string"){C=v;break}let f;if(C){let{EC2Client:g}=await import("@stacksjs/ts-cloud"),v=new g(Q);f=(await v.describeInstances({Filters:[{Name:"instance-id",Values:[C]}]}))?.Reservations?.[0]?.Instances?.[0]?.SecurityGroups?.[0]?.GroupId,await CJ(v,f,P)}if(!C||!j){if(q.stop(),!C)console.log("\u26A0 No EC2 instance found in stack outputs, skipping server deploy");if(!j)console.log("\u26A0 No S3 bucket found for staging server artifacts")}else{let g=L.publicCloudFrontDistributionId||L.CloudFrontDistributionId;await kJ(M,g,P);let v=F(X.projectPath("node_modules/@stacksjs/ts-cloud/dist/index.js"));if(Y(v)){let R=I(v);if(await a(()=>x.putObject({bucket:j,key:"_deploy/ts-cloud-dist.js",body:R,contentType:"application/javascript"}),"upload ts-cloud dist"),V)$.debug(" Uploaded ts-cloud dist to S3")}let m=`import { Database } from "bun:sqlite";
|
|
13
13
|
import { SESClient } from "./ts-cloud-dist.js";
|
|
14
14
|
|
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/dist/queue/work.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import
|
|
2
|
+
import m from"process";import{log as x}from"@stacksjs/logging";import{startProcessor as Y,stopProcessor as Z}from"@stacksjs/queue";m.on("unhandledRejection",(b)=>{x.error(`Unhandled Rejection in queue worker: ${b}`)});m.on("uncaughtException",(b)=>{x.error(`Uncaught Exception in queue worker: ${b.message}`)});var F=Number(m.env.STACKS_QUEUE_SHUTDOWN_GRACE_MS)||1e4,J=!1;async function Q(b){if(J)return;J=!0,x.info(`[queue] Worker received ${b}, draining in-flight jobs (max ${F/1000}s)\u2026`),setTimeout(()=>{x.warn("[queue] Drain window exceeded \u2014 forcing worker exit."),m.exit(1)},F+2000).unref();try{await Z({graceMs:F})}catch(z){x.error("[queue] Error while draining worker on shutdown:",z)}m.exit(0)}m.on("SIGTERM",()=>{Q("SIGTERM")});m.on("SIGINT",()=>{Q("SIGINT")});var V=K(),$=V.queue,X=Number(V.concurrency)||1;x.info(`Starting queue worker with ${X} concurrent worker(s)...`);var L=await Y($,{concurrency:X});if(L.isErr)x.error("Failed to start queue worker:",L.error),m.exit(1);x.success("Queue worker started successfully!");await new Promise(()=>{});function K(){let b={};return m.argv.forEach((z)=>{if(z.startsWith("--")){let[B,I]=z.slice(2).split("=");if(B&&I)b[B]=I;else if(B)b[B]="true"}}),b}
|
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.80",
|
|
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.80",
|
|
72
|
+
"@stacksjs/cli": "0.70.80",
|
|
73
|
+
"@stacksjs/config": "0.70.80",
|
|
74
|
+
"@stacksjs/database": "0.70.80",
|
|
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.80",
|
|
78
|
+
"@stacksjs/enums": "0.70.80",
|
|
79
|
+
"@stacksjs/env": "0.70.80",
|
|
80
|
+
"@stacksjs/error-handling": "0.70.80",
|
|
81
|
+
"@stacksjs/logging": "0.70.80",
|
|
82
|
+
"@stacksjs/path": "0.70.80",
|
|
83
|
+
"@stacksjs/security": "0.70.80",
|
|
84
|
+
"@stacksjs/storage": "0.70.80",
|
|
85
|
+
"@stacksjs/strings": "0.70.80",
|
|
86
|
+
"@stacksjs/utils": "0.70.80",
|
|
87
|
+
"@stacksjs/validation": "0.70.80"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"pickier": "^0.1.28"
|