@stacksjs/actions 0.70.45 → 0.70.53

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.
Files changed (127) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/action.d.ts +104 -17
  3. package/dist/blog.d.ts +12 -0
  4. package/dist/build/frontend-static.d.ts +16 -0
  5. package/dist/chunk-00qp27jy.js +93 -0
  6. package/dist/{chunk-jd1yzkq5.js → chunk-23thftnv.js} +1 -1
  7. package/dist/{chunk-jbvvb45k.js → chunk-4qzb8g3z.js} +1 -1
  8. package/dist/{chunk-s03z9zn3.js → chunk-5dfz9en9.js} +2 -2
  9. package/dist/{chunk-3beht8ja.js → chunk-5hwp0frq.js} +1 -1
  10. package/dist/{chunk-cqedfbaf.js → chunk-5pwpk005.js} +2 -2
  11. package/dist/chunk-604jy79b.js +5 -0
  12. package/dist/{chunk-yh15ydty.js → chunk-63swek9d.js} +2 -2
  13. package/dist/chunk-67am4dae.js +688 -0
  14. package/dist/{chunk-gt77jmb5.js → chunk-8gbewxns.js} +1 -1
  15. package/dist/chunk-8r76qydb.js +240 -0
  16. package/dist/{chunk-zbhjh5sz.js → chunk-9x17v4x2.js} +2 -2
  17. package/dist/chunk-aazd6qpv.js +3 -0
  18. package/dist/{chunk-n2fd1d0m.js → chunk-ag4fy7cx.js} +1 -1
  19. package/dist/{chunk-2qchdrf9.js → chunk-badehrwa.js} +1 -1
  20. package/dist/chunk-dbz9dp2h.js +3 -0
  21. package/dist/{chunk-v0wnrnaa.js → chunk-e8505qz8.js} +2 -2
  22. package/dist/chunk-jv7ry09n.js +3 -0
  23. package/dist/{chunk-w418anbq.js → chunk-jve1p4dz.js} +2 -2
  24. package/dist/chunk-mcwfmqzb.js +283 -0
  25. package/dist/chunk-n24m8prb.js +3 -0
  26. package/dist/{chunk-d5yxdz7e.js → chunk-nm9h5rye.js} +2 -2
  27. package/dist/{chunk-h0hfqr1p.js → chunk-ny1racy0.js} +2 -2
  28. package/dist/{chunk-2gh7kgpc.js → chunk-p601xr03.js} +1 -1
  29. package/dist/{chunk-yvva7qsg.js → chunk-pqnzp7x8.js} +2 -2
  30. package/dist/chunk-rj1cbghx.js +17 -0
  31. package/dist/chunk-rzhs51h1.js +3 -0
  32. package/dist/{chunk-tzx3h4r8.js → chunk-sp5cjdhd.js} +213 -76
  33. package/dist/chunk-tqax3gbq.js +16 -0
  34. package/dist/{chunk-c8qt2xst.js → chunk-vsj8ns4p.js} +1 -1
  35. package/dist/{chunk-zaw01rqz.js → chunk-x8nrbsk1.js} +2 -2
  36. package/dist/dev/dashboard-utils.d.ts +19 -1
  37. package/dist/dev/migrate-watcher.d.ts +1 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/make.d.ts +19 -0
  40. package/dist/queue/dlq-purge.d.ts +1 -0
  41. package/dist/queue/dlq-retry.d.ts +1 -0
  42. package/dist/queue/dlq.d.ts +1 -0
  43. package/dist/queue/list.d.ts +1 -0
  44. package/dist/queue/pause.d.ts +1 -0
  45. package/dist/queue/quarantine.d.ts +1 -0
  46. package/dist/queue/resume.d.ts +1 -0
  47. package/dist/queue/unquarantine.d.ts +1 -0
  48. package/dist/src/action.js +1 -1
  49. package/dist/src/actions.js +1 -1
  50. package/dist/src/add.js +1 -1
  51. package/dist/src/ai/request-model-access.js +1 -1
  52. package/dist/src/auth/setup.js +82 -24
  53. package/dist/src/blog.js +102 -0
  54. package/dist/src/build/core.js +1 -1
  55. package/dist/src/build/frontend-static.js +9 -0
  56. package/dist/src/build/views.js +1 -1
  57. package/dist/src/build.js +1 -1
  58. package/dist/src/commit.js +1 -1
  59. package/dist/src/database/seed.js +1 -1
  60. package/dist/src/deploy/index.js +38 -45
  61. package/dist/src/dev/api.js +4 -4
  62. package/dist/src/dev/dashboard-globals.js +1 -1
  63. package/dist/src/dev/dashboard-utils.js +1 -1
  64. package/dist/src/dev/dashboard.js +6 -6
  65. package/dist/src/dev/docs.js +1 -1
  66. package/dist/src/dev/index.js +1 -1
  67. package/dist/src/dev/migrate-watcher.js +2 -0
  68. package/dist/src/dev/views.js +1 -1
  69. package/dist/src/discover-packages.js +1 -1
  70. package/dist/src/examples.js +1 -1
  71. package/dist/src/generate/component-meta.js +1 -1
  72. package/dist/src/generate/env-files.js +1 -1
  73. package/dist/src/generate/ide-helpers.js +1 -1
  74. package/dist/src/generate/index.js +1 -1
  75. package/dist/src/generate/lib-entries.js +1 -1
  76. package/dist/src/generate/vscode-custom-data.js +1 -1
  77. package/dist/src/helpers/component-meta.js +1 -1
  78. package/dist/src/helpers/index.js +1 -1
  79. package/dist/src/helpers/lib-entries.js +1 -1
  80. package/dist/src/helpers/package-json.js +1 -1
  81. package/dist/src/helpers/utils.js +1 -1
  82. package/dist/src/helpers/vscode-custom-data.js +1 -1
  83. package/dist/src/index.js +1 -1
  84. package/dist/src/key-generate.js +1 -1
  85. package/dist/src/make-command.js +1 -1
  86. package/dist/src/make-job.js +1 -1
  87. package/dist/src/make-policy.js +1 -1
  88. package/dist/src/make-resource.js +1 -1
  89. package/dist/src/make.js +1 -1
  90. package/dist/src/migrate/fresh.js +1 -1
  91. package/dist/src/orm/base.js +1 -1
  92. package/dist/src/queue/dlq-purge.js +2 -0
  93. package/dist/src/queue/dlq-retry.js +2 -0
  94. package/dist/src/queue/dlq.js +5 -0
  95. package/dist/src/queue/failed.js +4 -4
  96. package/dist/src/queue/list.js +5 -0
  97. package/dist/src/queue/pause.js +2 -0
  98. package/dist/src/queue/quarantine.js +3 -0
  99. package/dist/src/queue/resume.js +2 -0
  100. package/dist/src/queue/unquarantine.js +2 -0
  101. package/dist/src/release.js +1 -1
  102. package/dist/src/run-action.js +1 -1
  103. package/dist/src/scaffold-crud.js +1 -1
  104. package/dist/src/serve/api.js +1 -1
  105. package/dist/src/setup/index.js +1 -1
  106. package/dist/src/setup/ssl.js +1 -1
  107. package/dist/src/stacks.js +1 -1
  108. package/dist/src/templates.js +1 -1
  109. package/dist/src/types.js +1 -1
  110. package/dist/src/upgrade/dependencies.js +1 -1
  111. package/dist/src/upgrade/framework-utils.js +1 -1
  112. package/dist/src/upgrade/framework.js +5 -5
  113. package/dist/src/upgrade/index.js +1 -1
  114. package/dist/src/upgrade.js +1 -1
  115. package/dist/upgrade/framework-utils.d.ts +48 -0
  116. package/package.json +18 -18
  117. package/dist/chunk-2kaj93p5.js +0 -3
  118. package/dist/chunk-3086k7zk.js +0 -184
  119. package/dist/chunk-4fz2qb8b.js +0 -17
  120. package/dist/chunk-4p0rjazd.js +0 -101
  121. package/dist/chunk-77pta9ww.js +0 -93
  122. package/dist/chunk-d4srk6ma.js +0 -3
  123. package/dist/chunk-h5rff0v9.js +0 -658
  124. package/dist/chunk-kr2k0h74.js +0 -16
  125. package/dist/chunk-kzhgexj4.js +0 -3
  126. package/dist/chunk-sxp97zys.js +0 -3
  127. package/dist/chunk-vek18p55.js +0 -5
@@ -1,17 +1,15 @@
1
1
  // @bun
2
- import{ib as W}from"../../chunk-jbvvb45k.js";import{existsSync as YJ,readFileSync as EJ,statSync as wJ}from"fs";import F from"process";import{runCommand as WJ,spinner as g}from"@stacksjs/cli";import{config as OJ}from"@stacksjs/config";import{path as V}from"@stacksjs/path";import{storage as FJ}from"@stacksjs/storage";import{ExitCode as NJ}from"@stacksjs/types";var z={debug:(...J)=>{if(F.argv.includes("--verbose")||F.argv.includes("-v"))console.log("\uD83D\uDD0D",...J)},success:(...J)=>console.log("\u2713",...J),error:(...J)=>console.error("\u2717",...J)},TJ="github.com/mail-os/mail",DJ=`${TJ}@0.1.0`,jJ="linux-x86_64",_J=["mail","mail-x86_64-linux","mail-x86_64-linux-gnu"],$=F.argv.includes("--verbose")||F.argv.includes("-v");async function xJ(J,U,K=8){let{existsSync:Q,readdirSync:T,statSync:C}=await import("fs"),{join:j,basename:d}=await import("path"),a=new Set(U),v=[];if(!Q(J))return v;function f(KJ,zJ){if(zJ>K)return;for(let UJ of T(KJ)){if(UJ===".git"||UJ==="node_modules")continue;let n=j(KJ,UJ),t=C(n);if(t.isDirectory())f(n,zJ+1);else if(t.isFile()&&a.has(d(n)))v.push(n)}}return f(J,0),v}async function AJ(J){let{readFileSync:U}=await import("fs"),K=U(J).slice(0,4);return K[0]===127&&K[1]===69&&K[2]===76&&K[3]===70}async function IJ(){let{existsSync:J}=await import("fs"),U=`${F.env.HOME}/Code/Tools/pantry/packages/ts-pantry/bin/cli.ts`;if(J(U))return{command:"bun",args:[U]};let K=V.projectPath("pantry/.bin/pantry");if(J(K))return{command:K,args:[]};let Q=`${F.env.HOME}/.local/share/pantry/global/bin/pantry`;if(J(Q))return{command:Q,args:[]};return{command:"pantry",args:[]}}async function fJ(){let{execFileSync:J}=await import("child_process"),U=V.projectPath("pantry"),K=await IJ();J(K.command,[...K.args,"install",DJ,"--install-dir",U,"--platform",jJ,"--quiet"],{cwd:V.projectPath(),stdio:$?"inherit":"pipe",env:F.env})}async function PJ(){let{existsSync:J}=await import("fs"),{join:U}=await import("path"),K=[V.projectPath("pantry"),`${F.env.HOME}/.local/share/pantry`],Q=[..._J.map((T)=>V.projectPath(`pantry/.bin/${T}`)),..._J.map((T)=>U(`${F.env.HOME}/.local/share/pantry/global/bin`,T))];for(let T of Q)if(J(T)&&await AJ(T))return T;for(let T of K){let C=await xJ(T,_J);for(let j of C)if(await AJ(j))return j}return null}var bJ={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".eot":"application/vnd.ms-fontobject",".otf":"font/otf",".webp":"image/webp",".mp4":"video/mp4",".webm":"video/webm",".mp3":"audio/mpeg",".wav":"audio/wav",".pdf":"application/pdf",".xml":"application/xml",".txt":"text/plain"};function VJ(J){let U=J.lastIndexOf("."),K=U>=0?J.slice(U).toLowerCase():"";return bJ[K]||"application/octet-stream"}async function XJ(J,U,K="",Q=[".DS_Store"]){let{readdirSync:T,statSync:C}=await import("fs"),{join:j}=await import("path"),d=T(J);for(let a of d){if(Q.includes(a))continue;let v=j(J,a),f=K?`${K}/${a}`:a;if(C(v).isDirectory())await XJ(v,U,f,Q);else await U(v,f)}}async function hJ(){try{let{generateSignalsRuntime:J}=await import("@stacksjs/stx/signals");return`<script>
3
- ${J()}
4
- </script>`}catch{return console.warn("Could not load STX signals runtime"),""}}async function e(J,U="s3 operation"){for(let Q=0;Q<=3;Q++)try{return await J()}catch(T){if(Q>=3)throw T;let C=Math.min(500*2**Q+Math.random()*200,5000);if($)z.debug(` Retrying ${U} (attempt ${Q+2}/4) in ${Math.round(C)}ms...`);await new Promise((j)=>setTimeout(j,C))}throw Error(`${U} failed after 4 attempts`)}function RJ(J){if(!J)return[];return Array.isArray(J)?J:[J]}function MJ(J,U,K=""){if(U===null||U===void 0)return"";if(typeof U==="boolean")return`${K}<${J}>${U}</${J}>
5
- `;if(typeof U==="number"||typeof U==="string")return`${K}<${J}>${U}</${J}>
6
- `;if(Array.isArray(U))return U.map((Q)=>MJ(J,Q,K)).join("");if(typeof U==="object"){if(J.startsWith("@_")||J==="?xml")return"";let Q="";for(let[T,C]of Object.entries(U))if(!T.startsWith("@_")&&T!=="#text")Q+=MJ(T,C,`${K} `);if(U["#text"]!==void 0)return`${K}<${J}>${U["#text"]}</${J}>
7
- `;return`${K}<${J}>
8
- ${Q}${K}</${J}>
9
- `}return""}function kJ(J){return`<?xml version="1.0" encoding="UTF-8"?>
2
+ import{pb as Z}from"../../chunk-4qzb8g3z.js";import{existsSync as JJ,readFileSync as BJ,statSync as TJ}from"fs";import T from"process";import{runCommand as KJ,spinner as S}from"@stacksjs/cli";import{config as OJ}from"@stacksjs/config";import{path as X}from"@stacksjs/path";import{storage as RJ}from"@stacksjs/storage";import{ExitCode as EJ}from"@stacksjs/types";var $={debug:(...J)=>{if(T.argv.includes("--verbose")||T.argv.includes("-v"))console.log("\uD83D\uDD0D",...J)},success:(...J)=>console.log("\u2713",...J),error:(...J)=>console.error("\u2717",...J)},GJ="github.com/mail-os/mail",NJ=`${GJ}@0.1.0`,jJ="linux-x86_64",XJ=["mail","mail-x86_64-linux","mail-x86_64-linux-gnu"],V=T.argv.includes("--verbose")||T.argv.includes("-v");async function DJ(J,U,H=8){let{existsSync:Q,readdirSync:_,statSync:b}=await import("fs"),{join:G,basename:y}=await import("path"),c=new Set(U),k=[];if(!Q(J))return k;function N(QJ,UJ){if(UJ>H)return;for(let o of _(QJ)){if(o===".git"||o==="node_modules")continue;let r=G(QJ,o),n=b(r);if(n.isDirectory())N(r,UJ+1);else if(n.isFile()&&c.has(y(r)))k.push(r)}}return N(J,0),k}async function MJ(J){let{readFileSync:U}=await import("fs"),H=U(J).slice(0,4);return H[0]===127&&H[1]===69&&H[2]===76&&H[3]===70}async function IJ(){let{existsSync:J}=await import("fs"),U=`${T.env.HOME}/Code/Tools/pantry/packages/ts-pantry/bin/cli.ts`;if(J(U))return{command:"bun",args:[U]};let H=X.projectPath("pantry/.bin/pantry");if(J(H))return{command:H,args:[]};let Q=`${T.env.HOME}/.local/share/pantry/global/bin/pantry`;if(J(Q))return{command:Q,args:[]};return{command:"pantry",args:[]}}async function PJ(){let{execFileSync:J}=await import("child_process"),U=X.projectPath("pantry"),H=await IJ();J(H.command,[...H.args,"install",NJ,"--install-dir",U,"--platform",jJ,"--quiet"],{cwd:X.projectPath(),stdio:V?"inherit":"pipe",env:T.env})}async function fJ(){let{existsSync:J}=await import("fs"),{join:U}=await import("path"),H=[X.projectPath("pantry"),`${T.env.HOME}/.local/share/pantry`],Q=[...XJ.map((_)=>X.projectPath(`pantry/.bin/${_}`)),...XJ.map((_)=>U(`${T.env.HOME}/.local/share/pantry/global/bin`,_))];for(let _ of Q)if(J(_)&&await MJ(_))return _;for(let _ of H){let b=await DJ(_,XJ);for(let G of b)if(await MJ(G))return G}return null}var bJ={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".eot":"application/vnd.ms-fontobject",".otf":"font/otf",".webp":"image/webp",".mp4":"video/mp4",".webm":"video/webm",".mp3":"audio/mpeg",".wav":"audio/wav",".pdf":"application/pdf",".xml":"application/xml",".txt":"text/plain"};function WJ(J){let U=J.lastIndexOf("."),H=U>=0?J.slice(U).toLowerCase():"";return bJ[H]||"application/octet-stream"}async function HJ(J,U,H="",Q=[".DS_Store"]){let{readdirSync:_,statSync:b}=await import("fs"),{join:G}=await import("path"),y=_(J);for(let c of y){if(Q.includes(c))continue;let k=G(J,c),N=H?`${H}/${c}`:c;if(b(k).isDirectory())await HJ(k,U,N,Q);else await U(k,N)}}async function a(J,U="s3 operation"){for(let Q=0;Q<=3;Q++)try{return await J()}catch(_){if(Q>=3)throw _;let b=Math.min(500*2**Q+Math.random()*200,5000);if(V)$.debug(` Retrying ${U} (attempt ${Q+2}/4) in ${Math.round(b)}ms...`);await new Promise((G)=>setTimeout(G,b))}throw Error(`${U} failed after 4 attempts`)}function wJ(J){if(!J)return[];return Array.isArray(J)?J:[J]}function AJ(J,U,H=""){if(U===null||U===void 0)return"";if(typeof U==="boolean")return`${H}<${J}>${U}</${J}>
3
+ `;if(typeof U==="number"||typeof U==="string")return`${H}<${J}>${U}</${J}>
4
+ `;if(Array.isArray(U))return U.map((Q)=>AJ(J,Q,H)).join("");if(typeof U==="object"){if(J.startsWith("@_")||J==="?xml")return"";let Q="";for(let[_,b]of Object.entries(U))if(!_.startsWith("@_")&&_!=="#text")Q+=AJ(_,b,`${H} `);if(U["#text"]!==void 0)return`${H}<${J}>${U["#text"]}</${J}>
5
+ `;return`${H}<${J}>
6
+ ${Q}${H}</${J}>
7
+ `}return""}function hJ(J){return`<?xml version="1.0" encoding="UTF-8"?>
10
8
  <DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
11
- ${Object.entries(J).filter(([U])=>!U.startsWith("@_")).map(([U,K])=>MJ(U,K," ")).join("")}</DistributionConfig>
12
- `}function LJ(J){let U=[...new Set(J)].filter((Q)=>Number.isFinite(Q)&&Q>0).sort((Q,T)=>Q-T);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,K){if(!U)return;if(((await J.describeSecurityGroups({GroupIds:[U]}))?.SecurityGroups?.[0]?.IpPermissions||[]).some((j)=>{return j.IpProtocol==="tcp"&&Number(j.FromPort)<=K&&Number(j.ToPort)>=K&&RJ(j.IpRanges).some((d)=>d.CidrIp==="0.0.0.0/0")}))return;try{await J.authorizeSecurityGroupIngress({GroupId:U,IpPermissions:[{IpProtocol:"tcp",FromPort:K,ToPort:K,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Stacks API port ${K}`}]}]})}catch(j){if(!String(j?.message||"").includes("InvalidPermission.Duplicate"))throw j}}async function SJ(J,U,K){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}),T=Q.headers?.etag||Q.headers?.ETag||"",C=Q.body?.DistributionConfig||Q.DistributionConfig||Q.body;if(!T||!C?.Origins?.Items)return;let d=RJ(C.Origins.Items.Origin).find((a)=>String(a.Id||"").includes("-api"));if(!d?.CustomOriginConfig)return;if(Number(d.CustomOriginConfig.HTTPPort)===K)return;d.CustomOriginConfig.HTTPPort=K,await J.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${U}/config`,body:kJ(C),headers:{"Content-Type":"application/xml","If-Match":T}})}var BJ=g("Building framework...");BJ.start();await WJ("bun run build",{cwd:V.frameworkPath("core"),quiet:!1});BJ.succeed("Framework built");var GJ=V.projectPath("docs"),vJ=V.projectPath("dist/docs/.bunpress");if(FJ.hasFiles(GJ)){let J=g("Building documentation with BunPress...");J.start();try{let{rm:U}=await import("fs/promises"),K=`${F.env.HOME}/Code/Tools/bunpress/packages/bunpress/bin/cli.ts`,Q=V.projectPath("node_modules/@stacksjs/bunpress/dist/bin/cli.js"),T=await Bun.file(K).exists(),C=await Bun.file(Q).exists(),j=T?`bun ${K} build --dir ${GJ} --outdir ${V.projectPath("dist/docs")}`:C?`bun ${Q} build --dir ${GJ} --outdir ${V.projectPath("dist/docs")}`:"bunx @stacksjs/bunpress@0.1.5 build --dir ./docs --outdir ./dist/docs";await U(vJ,{recursive:!0,force:!0}),await WJ(j,{cwd:V.projectPath(),quiet:!$}),J.succeed(`Documentation built with BunPress${T?" (local checkout)":""}`)}catch(U){if(J.stop(),console.log(`\u26A0 Documentation build skipped: ${U.message}`),$)z.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($)z.debug("No docs directory found, skipping documentation build");var yJ=FJ.hasFiles(V.projectPath("dist/blog")),gJ=["CampmateScript-Regular.woff2","SequoiaSans-Regular.woff2","Switchback-Regular.woff2"].every((J)=>YJ(V.projectPath(`dist/blog/assets/fonts/nps/${J}`))),cJ=["topography.svg","park-ridge.svg"].every((J)=>YJ(V.projectPath(`dist/blog/assets/images/${J}`))),HJ=V.projectPath("dist/blog/index.html"),JJ=YJ(HJ)?EJ(HJ,"utf8"):"",dJ=JJ.length>0&&!JJ.includes("woff2-variations"),mJ=JJ.includes("--on-primary")&&JJ.includes("--newsletter-bg"),pJ=JJ.includes("topography.svg")&&JJ.includes("park-ridge.svg"),uJ=!JJ.includes("stamp-trail")&&!JJ.includes("blog-sign-tree.svg"),sJ=V.frameworkPath("core/cms/src/build.ts"),lJ=V.projectPath("config/blog.ts"),aJ=YJ(HJ)&&[sJ,lJ].filter((J)=>YJ(J)).every((J)=>wJ(HJ).mtimeMs>=wJ(J).mtimeMs);if(!yJ||!gJ||!cJ||!dJ||!mJ||!pJ||!uJ||!aJ){let J=g("Building blog...");J.start();try{let U=(await import(V.projectPath("config/blog"))).default,{buildBlogSite:K}=await import(V.frameworkPath("core/cms/src/build"));await K({config:U,outDir:V.projectPath("dist/blog")}),J.succeed("Blog built successfully")}catch(U){if(J.stop(),console.log(`\u26A0 Blog build skipped: ${U.message}`),$)z.debug(`Blog build error: ${U.stack}`)}}else if($)z.debug("Pre-built blog found at dist/blog, skipping build");if($)z.debug("Skipping views build (vite-config not configured)");var iJ=await import(V.projectPath("config/cloud")),oJ=iJ?.tsCloud?.mode||"server";if(oJ==="serverless"){let J=g("Building server...");J.start(),await WJ("bun build.ts",{cwd:V.frameworkPath("server"),quiet:!$}),J.succeed("Server built");let U=g("Packaging for deployment...");U.start(),await WJ("bun zip.ts",{cwd:V.corePath("cloud"),quiet:!$}),U.succeed("Package ready")}else if($)z.debug("Skipping server build and packaging (server mode)");if(!F.env.AWS_ACCESS_KEY_ID||!F.env.AWS_SECRET_ACCESS_KEY){let{existsSync:J,readFileSync:U}=await import("fs"),K=F.env.APP_ENV||F.env.NODE_ENV||"production",Q=[V.projectPath(`.env.${K}`),V.projectPath(".env")];for(let T of Q)if(J(T)){let C=U(T,"utf-8");for(let j of C.split(`
13
- `)){let d=j.trim();if(d.startsWith("#")||!d.includes("="))continue;let a=d.indexOf("="),v=d.slice(0,a).trim(),f=d.slice(a+1).trim();if(f.startsWith('"')&&f.endsWith('"')||f.startsWith("'")&&f.endsWith("'"))f=f.slice(1,-1);if(v==="AWS_ACCESS_KEY_ID"&&f)F.env.AWS_ACCESS_KEY_ID=f;else if(v==="AWS_SECRET_ACCESS_KEY"&&f)F.env.AWS_SECRET_ACCESS_KEY=f;else if(v==="AWS_REGION"&&f&&!F.env.AWS_REGION)F.env.AWS_REGION=f;else if(v==="AWS_ACCOUNT_ID"&&f&&!F.env.AWS_ACCOUNT_ID)F.env.AWS_ACCOUNT_ID=f;else if(v.startsWith("MAIL_PASSWORD_")&&f&&!F.env[v])F.env[v]=f}if($)z.debug(`Loaded AWS credentials from ${T}`);break}}try{let{deployStack:J,deployFrontend:U}=await import("../../chunk-77pta9ww.js"),K=F.env.APP_ENV||F.env.NODE_ENV||"production",Q=F.env.AWS_REGION||"us-east-1",T=await import(V.projectPath("config/cloud")),C=T?.tsCloud?.mode||"server",j=T?.tsCloud?.project?.name||T?.tsCloud?.project?.slug||"stacks";if(C==="serverless"){console.log(""),console.log("Serverless deployment mode detected"),console.log("Building and pushing container image..."),console.log("");let Y=F.env.AWS_ACCOUNT_ID||await d(Q);if(!Y||Y.length<10)throw Error(`Invalid AWS Account ID: "${Y||"(empty)"}"
14
- Set AWS_ACCOUNT_ID in your .env file or ensure valid AWS credentials are configured.`);let H=`${Y}.dkr.ecr.${Q}.amazonaws.com/${j}-${K}-api`,M=`${H}:latest`;if($)z.debug(`ECR repository: ${H}`);if($)z.debug("ECR credentials will be validated before push...");let O=g("Building Docker image...");O.start();try{let{exec:q}=await import("child_process"),{promisify:D}=await import("util"),B=D(q),A=`docker build --platform linux/amd64 -t ${M} -f Dockerfile .`,{stdout:w,stderr:E}=await B(A,{cwd:V.projectPath(),env:F.env,maxBuffer:10485760,timeout:900000});if($&&w)z.debug(w);if($&&E)z.debug(E);O.succeed(`Docker image built: ${M}`)}catch(q){if(O.fail("Docker build failed"),$)z.debug(`Docker build error: ${q.message}`);throw q}let X=g("Checking ECR repository...");X.start();try{let{ECRClient:q}=await import("@stacksjs/ts-cloud"),D=new q(Q),B=`${j}-${K}-api`;try{await D.describeRepositories({repositoryNames:[B]}),X.succeed(`ECR repository exists: ${B}`)}catch(A){if(A.code==="RepositoryNotFoundException"||A.message?.includes("RepositoryNotFoundException"))X.text=`Creating ECR repository: ${B}...`,await D.createRepository({repositoryName:B,imageScanningConfiguration:{scanOnPush:!0},imageTagMutability:"MUTABLE"}),X.succeed(`ECR repository created: ${B}`);else throw A}}catch(q){if(X.fail("ECR repository check failed"),$)z.debug(`ECR repository error: ${q.message}`);throw q}let N=g("Authenticating to ECR...");N.start();try{let{ECRClient:q}=await import("@stacksjs/ts-cloud"),A=(await new q(Q).getAuthorizationToken()).authorizationData?.[0];if(!A?.authorizationToken)throw Error("No authorization token received from ECR");let w=Buffer.from(A.authorizationToken,"base64").toString("utf-8"),E=w.indexOf(":");if(E===-1)throw Error("ECR authorization token has unexpected format (missing colon separator)");let R=w.slice(E+1),G=Bun.spawnSync(["docker","login","--username","AWS","--password-stdin",`${Y}.dkr.ecr.${Q}.amazonaws.com`],{stdin:new TextEncoder().encode(R),stdout:"pipe",stderr:"pipe"});if(G.exitCode!==0){let P=new TextDecoder().decode(G.stderr);throw Error(`Docker login failed: ${P}`)}N.succeed("Authenticated to ECR")}catch(q){if(N.fail("ECR authentication failed"),$)z.debug(`ECR auth error: ${q.message}`);throw q}console.log("");let S=g("Pushing image to ECR...");S.start();try{let{exec:q}=await import("child_process"),{promisify:D}=await import("util"),B=D(q),A=`docker push ${M}`;await B(A,{env:F.env}),S.succeed(`Image pushed: ${M}`)}catch(q){if(S.fail("Docker push failed"),$)z.debug(`Push error: ${q.message}`);throw q}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 d(Y){try{let{STSClient:H}=await import("@stacksjs/ts-cloud"),X=(await new H(Y).getCallerIdentity()).Account||F.env.AWS_ACCOUNT_ID||"";if($)z.debug(`Retrieved AWS Account ID: ${X||"(empty)"}`);return X}catch(H){if($)z.debug(`Failed to get AWS Account ID: ${H.message}`);return F.env.AWS_ACCOUNT_ID||""}}try{let Y=await import(V.projectPath("cloud/deploy-script"));if(typeof Y.beforeDeploy==="function")await Y.beforeDeploy({environment:K,region:Q})}catch(Y){if(Y.code==="ERR_MODULE_NOT_FOUND"||Y.code==="MODULE_NOT_FOUND"){if($)z.debug("No beforeDeploy hook found (cloud/deploy-script not found)")}else if(console.warn(`\u26A0 beforeDeploy hook failed: ${Y.message}`),$)z.debug(`beforeDeploy error stack: ${Y.stack}`)}await J({environment:K,region:Q,waitForCompletion:!0,verbose:$});try{let Y=await import(V.projectPath("cloud/deploy-script"));if(typeof Y.afterDeploy==="function"){let{CloudFormationClient:H}=await import("@stacksjs/ts-cloud"),M=new H(Q),O=`${j}-cloud`,X={};try{X=await M.getStackOutputs(O)}catch(N){if($)z.debug(`Failed to get stack outputs: ${N instanceof Error?N.message:String(N)}`)}await Y.afterDeploy({environment:K,region:Q,outputs:X})}}catch(Y){if(Y.code==="ERR_MODULE_NOT_FOUND"||Y.code==="MODULE_NOT_FOUND"){if($)z.debug("No afterDeploy hook found (cloud/deploy-script not found)")}else if(console.warn(`\u26A0 afterDeploy hook failed: ${Y.message}`),$)z.debug(`afterDeploy error stack: ${Y.stack}`)}let a=g("Running database migrations...");a.start();try{let{generateMigrations:Y,runDatabaseMigration:H}=await import("@stacksjs/database");await Y(),await H(),a.succeed("Database migrations completed")}catch(Y){if(a.stop(),console.log(`\u26A0 Database migrations skipped: ${Y.message}`),$)z.debug(`Migration error: ${Y.stack}`)}if(C==="server"){let Y=g("Retrieving server instance details...");Y.start();try{let{CloudFormationClient:O}=await import("@stacksjs/ts-cloud"),X=new O(Q),N=`${j}-cloud`,S=await X.getStackOutputs(N);Y.succeed("Server instances deployed"),console.log(""),console.log("Server instances:");for(let[q,D]of Object.entries(S)){if(q.endsWith("PublicIp"))console.log(` ${q}: ${D}`);if(q.endsWith("InstanceId"))console.log(` ${q}: ${D}`)}console.log("")}catch(O){if(Y.stop(),console.log(`\u26A0 Could not retrieve server details: ${O.message}`),$)z.debug(`Output retrieval error: ${O.stack}`)}let H=g("Deploying API server to EC2...");H.start();try{let{S3Client:O,CloudFormationClient:X,AWSClient:N}=await import("@stacksjs/ts-cloud"),{readFileSync:S,existsSync:q}=await import("fs"),{resolve:D}=await import("path"),B=new O(Q),A=new X(Q),w=new N,E=`${j}-cloud`,R=await A.getStackOutputs(E),G=R.FrontendBucketName,P=Number(OJ.ports?.api||3008),b;for(let[c,m]of Object.entries(R))if(c.endsWith("InstanceId")&&typeof m==="string"){b=m;break}let h;if(b){let{EC2Client:c}=await import("@stacksjs/ts-cloud"),m=new c(Q);h=(await m.describeInstances({Filters:[{Name:"instance-id",Values:[b]}]}))?.Reservations?.[0]?.Instances?.[0]?.SecurityGroups?.[0]?.GroupId,await CJ(m,h,P)}if(!b||!G){if(H.stop(),!b)console.log("\u26A0 No EC2 instance found in stack outputs, skipping server deploy");if(!G)console.log("\u26A0 No S3 bucket found for staging server artifacts")}else{let c=R.publicCloudFrontDistributionId||R.CloudFrontDistributionId;await SJ(w,c,P);let m=D(V.projectPath("node_modules/@stacksjs/ts-cloud/dist/index.js"));if(q(m)){let _=S(m);if(await e(()=>B.putObject({bucket:G,key:"_deploy/ts-cloud-dist.js",body:_,contentType:"application/javascript"}),"upload ts-cloud dist"),$)z.debug(" Uploaded ts-cloud dist to S3")}let p=`import { Database } from "bun:sqlite";
9
+ ${Object.entries(J).filter(([U])=>!U.startsWith("@_")).map(([U,H])=>AJ(U,H," ")).join("")}</DistributionConfig>
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-00qp27jy.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
+ 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";
15
13
  import { SESClient } from "./ts-cloud-dist.js";
16
14
 
17
15
  const db = new Database("/var/www/api/stacks.db");
@@ -132,7 +130,7 @@ const server = Bun.serve({
132
130
  });
133
131
 
134
132
  console.log(\`Stacks API server running on port \${server.port}\`);
135
- `;if(await e(()=>B.putObject({bucket:G,key:"_deploy/server.ts",body:Buffer.from(p),contentType:"application/typescript"}),"upload server.ts"),$)z.debug(" Uploaded server.ts to S3");let i=["mkdir -p /var/www/api",`aws s3 cp s3://${G}/_deploy/ts-cloud-dist.js /var/www/api/ts-cloud-dist.js`,`aws s3 cp s3://${G}/_deploy/server.ts /var/www/api/server.ts`,LJ([P]),`cat > /etc/systemd/system/stacks-api.service << 'SERVICEFILE'
133
+ `;if(await a(()=>x.putObject({bucket:j,key:"_deploy/server.ts",body:Buffer.from(m),contentType:"application/typescript"}),"upload server.ts"),V)$.debug(" Uploaded server.ts to S3");let p=["mkdir -p /var/www/api",`aws s3 cp s3://${j}/_deploy/ts-cloud-dist.js /var/www/api/ts-cloud-dist.js`,`aws s3 cp s3://${j}/_deploy/server.ts /var/www/api/server.ts`,_J([P]),`cat > /etc/systemd/system/stacks-api.service << 'SERVICEFILE'
136
134
  [Unit]
137
135
  Description=Stacks Bun API Server
138
136
  After=network.target
@@ -149,15 +147,15 @@ Environment=NODE_ENV=production
149
147
  WantedBy=multi-user.target
150
148
  SERVICEFILE
151
149
  systemctl daemon-reload
152
- systemctl enable stacks-api`,"systemctl reset-failed stacks-api || true","systemctl restart stacks-api",`for i in $(seq 1 20); do curl -fsS http://127.0.0.1:${P}/api/health && break; sleep 1; done`,`curl -fsS http://127.0.0.1:${P}/api/health`,`echo "API server deployed and restarted on port ${P}"`].join(" && "),x=(await w.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[b],DocumentName:"AWS-RunShellScript",Parameters:{commands:[i]},TimeoutSeconds:120})}))?.Command?.CommandId;if(x){let _=0;while(_<30){await new Promise((L)=>setTimeout(L,3000));try{let L=await w.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:x,InstanceId:b})}),I=L?.Status;if(I==="Success"){H.succeed("API server deployed to EC2");break}else if(I==="Failed"||I==="Cancelled"||I==="TimedOut"){let k=L?.StandardErrorContent||"Unknown error";H.fail(`API server deploy failed: ${k}`);break}}catch{}_++}if(_>=30)H.fail("API server deploy timed out waiting for SSM command")}else H.fail("Failed to send SSM command");try{await B.deleteObject({bucket:G,key:"_deploy/ts-cloud-dist.js"}),await B.deleteObject({bucket:G,key:"_deploy/server.ts"})}catch{}}}catch(O){if(H.fail(`API server deployment failed: ${O.message}`),$)z.debug(`Server deploy error: ${O.stack}`)}let M=OJ.email;if(M?.server?.enabled){let O=M?.server?.mode||"server",X=g(`Deploying mail server (${O} mode) to EC2...`);X.start();try{let{S3Client:N,AWSClient:S,EC2Client:q}=await import("@stacksjs/ts-cloud"),{readFileSync:D,existsSync:B}=await import("fs"),{resolve:A,join:w}=await import("path"),{execSync:E}=await import("child_process"),R=new N(Q),G=new S,P=new q(Q),b=`${j}-cloud`,h,c,m,p;try{let{AWSCloudFormationClient:i}=await import("@stacksjs/ts-cloud"),x=await new i(Q).getStackOutputs(b);for(let[_,L]of Object.entries(x)){if(_.endsWith("InstanceId")&&typeof L==="string")h=L;if(_==="FrontendBucketName"&&typeof L==="string")c=L;if(_==="emailBucketName"&&typeof L==="string")m=L}}catch{}if(!m)m=`${j}-production-s3-email`;if(h&&c){let i=[25,80,110,143,465,587,993,995];try{let L=(await P.describeInstances({Filters:[{Name:"instance-id",Values:[h]}]}))?.Reservations?.[0]?.Instances?.[0]?.SecurityGroups;if(L?.[0]?.GroupId)p=L[0].GroupId}catch{if($)z.debug("Could not get security group for instance")}if(p)for(let _ of i)try{if(await P.authorizeSecurityGroupIngress({GroupId:p,IpPermissions:[{IpProtocol:"tcp",FromPort:_,ToPort:_,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Mail port ${_}`}]}]}),$)z.debug(` Opened port ${_} on security group ${p}`)}catch(L){if(!L.message?.includes("already exists")){if($)z.debug(` Port ${_}: ${L.message}`)}}let Z=M.domain||"stacksjs.com",x=M?.server?.subdomain||"mail";if(O==="server"){if($)z.debug("Deploying Zig mail server binary...");try{await fJ()}catch(L){if($)z.debug(` Pantry mail install failed: ${L.message}`)}let _=await PJ();if(_&&B(_)){if(!await AJ(_))throw X.fail(`Pantry installed ${TJ}, but the ${jJ} binary is not an ELF file.`),Error("Linux binary is not a valid ELF file");let L=D(_);if(await R.putObject({bucket:m,key:"mail-server/smtp-server",body:L,contentType:"application/octet-stream"}),$)z.debug(` Uploaded Zig binary (${(L.length/1024/1024).toFixed(1)}MB) to S3`);let I=["systemctl stop stacks-mail 2>/dev/null || true","systemctl disable stacks-mail 2>/dev/null || true","systemctl stop stacks-smtp 2>/dev/null || true","systemctl disable stacks-smtp 2>/dev/null || true","systemctl stop smtp-server 2>/dev/null || true","mkdir -p /opt/smtp-server /var/lib/smtp-server /var/log/smtp-server /var/spool/mail /etc/smtp-server /var/lib/smtp-server/backups",`aws s3 cp s3://${m}/mail-server/smtp-server /opt/smtp-server/smtp-server --region ${Q}`,"chmod +x /opt/smtp-server/smtp-server",'file /opt/smtp-server/smtp-server | grep -q ELF || { echo "Binary is not ELF"; exit 1; }',LJ(i),`cat > /etc/smtp-server/smtp-server.env << 'ENVEOF'
150
+ systemctl enable stacks-api`,"systemctl reset-failed stacks-api || true","systemctl restart stacks-api",`for i in $(seq 1 20); do curl -fsS http://127.0.0.1:${P}/api/health && break; sleep 1; done`,`curl -fsS http://127.0.0.1:${P}/api/health`,`echo "API server deployed and restarted on port ${P}"`].join(" && "),h=(await M.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[C],DocumentName:"AWS-RunShellScript",Parameters:{commands:[p]},TimeoutSeconds:120})}))?.Command?.CommandId;if(h){let R=0;while(R<30){await new Promise((B)=>setTimeout(B,3000));try{let B=await M.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:h,InstanceId:C})}),d=B?.Status;if(d==="Success"){q.succeed("API server deployed to EC2");break}else if(d==="Failed"||d==="Cancelled"||d==="TimedOut"){let t=B?.StandardErrorContent||"Unknown error";q.fail(`API server deploy failed: ${t}`);break}}catch{}R++}if(R>=30)q.fail("API server deploy timed out waiting for SSM command")}else q.fail("Failed to send SSM command");try{await x.deleteObject({bucket:j,key:"_deploy/ts-cloud-dist.js"}),await x.deleteObject({bucket:j,key:"_deploy/server.ts"})}catch{}}}catch(W){if(q.fail(`API server deployment failed: ${W.message}`),V)$.debug(`Server deploy error: ${W.stack}`)}let A=OJ.email;if(A?.server?.enabled){let W=A?.server?.mode||"server",K=S(`Deploying mail server (${W} mode) to EC2...`);K.start();try{let{S3Client:w,AWSClient:I,EC2Client:Y}=await import("@stacksjs/ts-cloud"),{readFileSync:F,existsSync:x}=await import("fs"),{resolve:E,join:M}=await import("path"),{execSync:O}=await import("child_process"),L=new w(Q),j=new I,P=new Y(Q),C=`${G}-cloud`,f,g,v,m;try{let{AWSCloudFormationClient:p}=await import("@stacksjs/ts-cloud"),h=await new p(Q).getStackOutputs(C);for(let[R,B]of Object.entries(h)){if(R.endsWith("InstanceId")&&typeof B==="string")f=B;if(R==="FrontendBucketName"&&typeof B==="string")g=B;if(R==="emailBucketName"&&typeof B==="string")v=B}}catch{}if(!v)v=`${G}-production-s3-email`;if(f&&g){let p=[25,80,110,143,465,587,993,995];try{let B=(await P.describeInstances({Filters:[{Name:"instance-id",Values:[f]}]}))?.Reservations?.[0]?.Instances?.[0]?.SecurityGroups;if(B?.[0]?.GroupId)m=B[0].GroupId}catch{if(V)$.debug("Could not get security group for instance")}if(m)for(let R of p)try{if(await P.authorizeSecurityGroupIngress({GroupId:m,IpPermissions:[{IpProtocol:"tcp",FromPort:R,ToPort:R,IpRanges:[{CidrIp:"0.0.0.0/0",Description:`Mail port ${R}`}]}]}),V)$.debug(` Opened port ${R} on security group ${m}`)}catch(B){if(!B.message?.includes("already exists")){if(V)$.debug(` Port ${R}: ${B.message}`)}}let D=A.domain||"stacksjs.com",h=A?.server?.subdomain||"mail";if(W==="server"){if(V)$.debug("Deploying Zig mail server binary...");try{await PJ()}catch(B){if(V)$.debug(` Pantry mail install failed: ${B.message}`)}let R=await fJ();if(R&&x(R)){if(!await MJ(R))throw K.fail(`Pantry installed ${GJ}, but the ${jJ} binary is not an ELF file.`),Error("Linux binary is not a valid ELF file");let B=F(R);if(await L.putObject({bucket:v,key:"mail-server/smtp-server",body:B,contentType:"application/octet-stream"}),V)$.debug(` Uploaded Zig binary (${(B.length/1024/1024).toFixed(1)}MB) to S3`);let d=["systemctl stop stacks-mail 2>/dev/null || true","systemctl disable stacks-mail 2>/dev/null || true","systemctl stop stacks-smtp 2>/dev/null || true","systemctl disable stacks-smtp 2>/dev/null || true","systemctl stop smtp-server 2>/dev/null || true","mkdir -p /opt/smtp-server /var/lib/smtp-server /var/log/smtp-server /var/spool/mail /etc/smtp-server /var/lib/smtp-server/backups",`aws s3 cp s3://${v}/mail-server/smtp-server /opt/smtp-server/smtp-server --region ${Q}`,"chmod +x /opt/smtp-server/smtp-server",'file /opt/smtp-server/smtp-server | grep -q ELF || { echo "Binary is not ELF"; exit 1; }',_J(p),`cat > /etc/smtp-server/smtp-server.env << 'ENVEOF'
153
151
  SMTP_PROFILE=production
154
152
  SMTP_HOST=0.0.0.0
155
153
  SMTP_PORT=25
156
- SMTP_HOSTNAME=${x}.${Z}
154
+ SMTP_HOSTNAME=${h}.${D}
157
155
  SMTP_ENABLE_TLS=false
158
156
  SMTP_ENABLE_AUTH=true
159
157
  SMTP_DB_PATH=/var/lib/smtp-server/smtp.db
160
- AWS_S3_BUCKET=${m}
158
+ AWS_S3_BUCKET=${v}
161
159
  AWS_REGION=${Q}
162
160
  SMTP_ENABLE_JSON_LOGGING=true
163
161
  SMTP_LOG_LEVEL=info
@@ -187,20 +185,20 @@ SyslogIdentifier=smtp-server
187
185
 
188
186
  [Install]
189
187
  WantedBy=multi-user.target
190
- SVCEOF`,"systemctl daemon-reload","systemctl enable smtp-server","systemctl restart smtp-server","sleep 3",'systemctl is-active smtp-server && echo "Mail server is running" || echo "Mail server failed to start"','ss -tlnp | grep -E "(25|143)" || echo "Warning: mail ports not listening yet"'].join(" && "),y=(await G.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[h],DocumentName:"AWS-RunShellScript",Parameters:{commands:[I]},TimeoutSeconds:300})}))?.Command?.CommandId;if(y){let s=0;while(s<100){await new Promise((l)=>setTimeout(l,3000));try{let l=await G.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:y,InstanceId:h})}),r=l?.Status;if(r==="Success"){if(X.succeed("Zig mail server deployed to EC2"),$&&l?.StandardOutputContent)console.log(l.StandardOutputContent);break}else if(r==="Failed"||r==="Cancelled"||r==="TimedOut"){let QJ=l?.StandardErrorContent||l?.StandardOutputContent||"Unknown error";X.fail(`Zig mail server deploy failed: ${QJ.slice(0,500)}`);break}}catch{}s++}if(s>=100)X.fail("Zig mail server deploy timed out")}else X.fail("Failed to send SSM command for mail server")}else X.fail(`No Pantry-provided ${jJ} mail binary found. Release ${TJ}, then run the Pantry binary sync for that package.`)}else{let _=A(V.projectPath("storage/framework/core/cloud/src/imap/smtp-server.ts")),L=w(V.projectPath(),".stacks/tmp/smtp-bundle");E(`bun build ${_} --target=bun --outdir=${L}`,{stdio:"pipe"});let I=w(L,"smtp-server.js");if(B(I)){let k=D(I),y=M.mailboxes||["chris","blake","glenn"],s=y.map((o)=>{let u=`MAIL_PASSWORD_${o.toUpperCase()}`;return` "${o}": { password: process.env["${u}"] || "", email: "${o}@${Z}" }`}).join(`,
191
- `),l=`import { SmtpServer } from "./smtp-server.js";
188
+ SVCEOF`,"systemctl daemon-reload","systemctl enable smtp-server","systemctl restart smtp-server","sleep 3",'systemctl is-active smtp-server && echo "Mail server is running" || echo "Mail server failed to start"','ss -tlnp | grep -E "(25|143)" || echo "Warning: mail ports not listening yet"'].join(" && "),$J=(await j.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[f],DocumentName:"AWS-RunShellScript",Parameters:{commands:[d]},TimeoutSeconds:300})}))?.Command?.CommandId;if($J){let zJ=0;while(zJ<100){await new Promise((u)=>setTimeout(u,3000));try{let u=await j.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:$J,InstanceId:f})}),e=u?.Status;if(e==="Success"){if(K.succeed("Zig mail server deployed to EC2"),V&&u?.StandardOutputContent)console.log(u.StandardOutputContent);break}else if(e==="Failed"||e==="Cancelled"||e==="TimedOut"){let qJ=u?.StandardErrorContent||u?.StandardOutputContent||"Unknown error";K.fail(`Zig mail server deploy failed: ${qJ.slice(0,500)}`);break}}catch{}zJ++}if(zJ>=100)K.fail("Zig mail server deploy timed out")}else K.fail("Failed to send SSM command for mail server")}else K.fail(`No Pantry-provided ${jJ} mail binary found. Release ${GJ}, then run the Pantry binary sync for that package.`)}else{let R=E(X.projectPath("storage/framework/core/cloud/src/imap/smtp-server.ts")),B=M(X.projectPath(),".stacks/tmp/smtp-bundle");O(`bun build ${R} --target=bun --outdir=${B}`,{stdio:"pipe"});let d=M(B,"smtp-server.js");if(x(d)){let t=F(d),$J=A.mailboxes||["chris","blake","glenn"],zJ=$J.map((s)=>{let l=`MAIL_PASSWORD_${s.toUpperCase()}`;return` "${s}": { password: process.env["${l}"] || "", email: "${s}@${D}" }`}).join(`,
189
+ `),u=`import { SmtpServer } from "./smtp-server.js";
192
190
  import * as fs from "fs";
193
- const domain = "${Z}";
194
- const users = { ${s} };
191
+ const domain = "${D}";
192
+ const users = { ${zJ} };
195
193
  const certDir = \`/etc/letsencrypt/live/mail.\${domain}\`;
196
194
  let tlsConfig = undefined;
197
195
  if (fs.existsSync(\`\${certDir}/privkey.pem\`)) {
198
196
  tlsConfig = { key: \`\${certDir}/privkey.pem\`, cert: \`\${certDir}/fullchain.pem\` };
199
197
  }
200
- const server = new SmtpServer({ port: 587, tlsPort: 465, host: "0.0.0.0", domain, users, tls: tlsConfig, sentBucket: "${j}-production-email", sentPrefix: "sent/" });
198
+ const server = new SmtpServer({ port: 587, tlsPort: 465, host: "0.0.0.0", domain, users, tls: tlsConfig, sentBucket: "${G}-production-email", sentPrefix: "sent/" });
201
199
  await server.start();
202
- `;await R.putObject({bucket:c,key:"_deploy/smtp-server.js",body:k,contentType:"application/javascript"}),await R.putObject({bucket:c,key:"_deploy/smtp-entry.ts",body:Buffer.from(l),contentType:"application/typescript"});let r=y.map((o)=>{let u=`MAIL_PASSWORD_${o.toUpperCase()}`;return`Environment=${u}=${F.env[u]||""}`}).join(`
203
- `),QJ=["mkdir -p /var/www/smtp",`aws s3 cp s3://${c}/_deploy/smtp-server.js /var/www/smtp/smtp-server.js`,`aws s3 cp s3://${c}/_deploy/smtp-entry.ts /var/www/smtp/smtp-entry.ts`,LJ(i),"if ! command -v certbot &> /dev/null; then dnf install -y certbot || yum install -y certbot || apt-get install -y certbot || true; fi",`if [ ! -d /etc/letsencrypt/live/mail.${Z} ]; then certbot certonly --standalone --non-interactive --agree-tos --email admin@${Z} -d mail.${Z} --http-01-port 80 || echo "Certbot failed"; fi`,`cat > /etc/systemd/system/stacks-smtp.service << 'SERVICEFILE'
200
+ `;await L.putObject({bucket:g,key:"_deploy/smtp-server.js",body:t,contentType:"application/javascript"}),await L.putObject({bucket:g,key:"_deploy/smtp-entry.ts",body:Buffer.from(u),contentType:"application/typescript"});let e=$J.map((s)=>{let l=`MAIL_PASSWORD_${s.toUpperCase()}`;return`Environment=${l}=${T.env[l]||""}`}).join(`
201
+ `),qJ=["mkdir -p /var/www/smtp",`aws s3 cp s3://${g}/_deploy/smtp-server.js /var/www/smtp/smtp-server.js`,`aws s3 cp s3://${g}/_deploy/smtp-entry.ts /var/www/smtp/smtp-entry.ts`,_J(p),"if ! command -v certbot &> /dev/null; then dnf install -y certbot || yum install -y certbot || apt-get install -y certbot || true; fi",`if [ ! -d /etc/letsencrypt/live/mail.${D} ]; then certbot certonly --standalone --non-interactive --agree-tos --email admin@${D} -d mail.${D} --http-01-port 80 || echo "Certbot failed"; fi`,`cat > /etc/systemd/system/stacks-smtp.service << 'SERVICEFILE'
204
202
  [Unit]
205
203
  Description=Stacks SMTP Proxy Server
206
204
  After=network.target
@@ -212,15 +210,10 @@ Restart=on-failure
212
210
  RestartSec=5
213
211
  Environment=NODE_ENV=production
214
212
  Environment=AWS_REGION=${Q}
215
- ${r}
213
+ ${e}
216
214
  [Install]
217
215
  WantedBy=multi-user.target
218
- SERVICEFILE`,"systemctl daemon-reload","systemctl enable stacks-smtp","systemctl restart stacks-smtp"].join(" && "),ZJ=(await G.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[h],DocumentName:"AWS-RunShellScript",Parameters:{commands:[QJ]},TimeoutSeconds:180})}))?.Command?.CommandId;if(ZJ){let o=0;while(o<60){await new Promise((u)=>setTimeout(u,3000));try{let u=await G.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:ZJ,InstanceId:h})}),qJ=u?.Status;if(qJ==="Success"){X.succeed("SMTP proxy deployed to EC2");break}else if(qJ==="Failed"||qJ==="Cancelled"||qJ==="TimedOut"){X.fail(`SMTP proxy deploy failed: ${u?.StandardErrorContent||"Unknown"}`);break}}catch{}o++}if(o>=60)X.fail("SMTP proxy deploy timed out")}else X.fail("Failed to send SSM command for SMTP proxy");try{await R.deleteObject({bucket:c,key:"_deploy/smtp-server.js"}),await R.deleteObject({bucket:c,key:"_deploy/smtp-entry.ts"})}catch{}}else if(X.stop(),$)z.debug("SMTP server bundle not found, skipping")}}else if(X.stop(),$)z.debug("No EC2 instance or bucket found, skipping mail server deploy")}catch(N){if(X.fail(`Mail server deployment failed: ${N.message}`),$)z.debug(`Mail server deploy error: ${N.stack}`)}}}let v=g("Deploying frontend to S3...");v.start();try{let{S3Client:Y,CloudFormationClient:H}=await import("@stacksjs/ts-cloud"),{existsSync:M,readdirSync:O,statSync:X,readFileSync:N,copyFileSync:S,mkdirSync:q,rmSync:D,writeFileSync:B}=await import("fs"),{join:A}=await import("path"),w=new Y(Q),E=new H(Q),R=`${j}-cloud`,G=await E.getStackOutputs(R),P=G.FrontendBucketName;if(!P)v.stop(),console.log("\u26A0 Frontend bucket not found in stack outputs (add storage.public to infrastructure config)");else{let b=V.storagePath("framework/frontend-dist");if(M(b))D(b,{recursive:!0});q(b,{recursive:!0}),q(A(b,"assets"),{recursive:!0});let h=V.resourcesPath("views/index.stx");if(M(h)){let Z=N(h,"utf-8"),x=Z.match(/<script server>([\s\S]*?)<\/script>/),_={};if(x){let I=x[1]??"";try{let k=[...I.matchAll(/(?:const|let|var)\s+(\w+)\s*=/g)].map((s)=>s[1]).filter((s)=>Boolean(s));_=Function(`${I}
219
- return { ${k.join(", ")} }`)()}catch(k){if($)z.debug(` Server block evaluation failed: ${k}, falling back to regex`);let y=I.matchAll(/const\s+(\w+)\s*=\s*(?:'([^']*)'|"([^"]*)"|([\d.]+))/g);for(let s of y){let l=s[1];if(l)_[l]=s[2]??s[3]??s[4]}}Z=Z.replace(/<script server>[\s\S]*?<\/script>\s*/,"")}Z=Z.replace(/\{\{\s*(\w+)\s*\}\}/g,(I,k)=>{let y=_[k];return y!==void 0&&y!==null?String(y):""});let L=/@foreach\s*\((\w+)\s+as\s+(\w+)\)([\s\S]*?)@endforeach/g;if(Z=Z.replace(L,(I,k,y,s)=>{let l=_[k];if(!Array.isArray(l)||l.length===0)return"";let r="";for(let QJ of l){let $J=s;$J=$J.replace(new RegExp(`\\{\\{\\s*${y}\\.(\\w+)\\s*\\}\\}`,"g"),(ZJ,o)=>{let u=QJ[o];return u!==void 0&&u!==null?String(u):""}),$J=$J.replace(new RegExp(`\\{!!\\s*${y}\\.(\\w+)\\s*!!\\}`,"g"),(ZJ,o)=>{let u=QJ[o];return u!==void 0&&u!==null?String(u):""}),r+=$J}return r}),Z=Z.replace(/^\s*@extends\([^)]+\)\s*$/gm,"").replace(/^\s*@include\([^)]+\)\s*$/gm,"").replace(/^\s*@section\('title',\s*['"][^'"]*['"]\)\s*$/gm,"").replace(/^\s*@section\('(?:content|footer)'\)\s*$/gm,"").replace(/^\s*@endsection\s*$/gm,""),/data-stx-scope|@model|@show|@text|@class|@style|@bind:|@if=|@for=/.test(Z)){let I=await hJ();if(I){let k=Z.match(/<body[^>]*>/);if(k){let y=(Z.indexOf(k[0])??0)+k[0].length;Z=Z.slice(0,y)+`
220
- `+I+Z.slice(y)}else Z=I+`
221
- `+Z;if($)z.debug(" Injected STX signals runtime for client-side reactivity")}}if(B(A(b,"index.html"),Z),$)z.debug(" Built index.html from STX template")}else B(A(b,"index.html"),`<!DOCTYPE html>
222
- <html><head><title>Stacks</title></head>
223
- <body><h1>Welcome to Stacks</h1></body></html>`);let c=V.resourcesPath("assets");if(M(c)){let Z=(x,_)=>{if(!M(_))q(_,{recursive:!0});for(let L of O(x)){let I=A(x,L),k=A(_,L);if(X(I).isDirectory())Z(I,k);else S(I,k)}};if(Z(c,A(b,"assets")),$)z.debug(" Copied assets directory")}await(async(Z,x="")=>{await XJ(Z,async(_,L)=>{let I=N(_),k=VJ(_),y=L==="index.html"||L.endsWith("/index.html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await e(()=>w.putObject({bucket:P,key:L,body:I,contentType:k,cacheControl:y}),`upload ${L}`),$)z.debug(` Uploaded: ${L}`)})})(b);let p=V.projectPath("bootstrap");if(M(p)){let Z=N(p);if(await e(()=>w.putObject({bucket:P,key:"install",body:Z,contentType:"text/plain",cacheControl:"no-cache, no-store, must-revalidate"}),"upload bootstrap install script"),$)z.debug(" Uploaded bootstrap install script")}let i=G.publicCloudFrontDistributionId||G.CloudFrontDistributionId;if(i){if($)z.debug(" Invalidating CloudFront cache...");let{AWSClient:Z}=await import("@stacksjs/ts-cloud");await new Z().request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${i}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
216
+ SERVICEFILE`,"systemctl daemon-reload","systemctl enable stacks-smtp","systemctl restart stacks-smtp"].join(" && "),FJ=(await j.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.SendCommand"},body:JSON.stringify({InstanceIds:[f],DocumentName:"AWS-RunShellScript",Parameters:{commands:[qJ]},TimeoutSeconds:180})}))?.Command?.CommandId;if(FJ){let s=0;while(s<60){await new Promise((l)=>setTimeout(l,3000));try{let l=await j.request({service:"ssm",region:Q,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":"AmazonSSM.GetCommandInvocation"},body:JSON.stringify({CommandId:FJ,InstanceId:f})}),YJ=l?.Status;if(YJ==="Success"){K.succeed("SMTP proxy deployed to EC2");break}else if(YJ==="Failed"||YJ==="Cancelled"||YJ==="TimedOut"){K.fail(`SMTP proxy deploy failed: ${l?.StandardErrorContent||"Unknown"}`);break}}catch{}s++}if(s>=60)K.fail("SMTP proxy deploy timed out")}else K.fail("Failed to send SSM command for SMTP proxy");try{await L.deleteObject({bucket:g,key:"_deploy/smtp-server.js"}),await L.deleteObject({bucket:g,key:"_deploy/smtp-entry.ts"})}catch{}}else if(K.stop(),V)$.debug("SMTP server bundle not found, skipping")}}else if(K.stop(),V)$.debug("No EC2 instance or bucket found, skipping mail server deploy")}catch(w){if(K.fail(`Mail server deployment failed: ${w.message}`),V)$.debug(`Mail server deploy error: ${w.stack}`)}}}let N=S("Deploying frontend to S3...");N.start();try{let{S3Client:z,CloudFormationClient:q}=await import("@stacksjs/ts-cloud"),{readFileSync:A}=await import("fs"),{buildFrontendStatic:W}=await import("../build/frontend-static.js"),K=new z(Q),w=new q(Q),I=`${G}-cloud`,Y=await w.getStackOutputs(I),F=Y.FrontendBucketName;if(!F)N.stop(),console.log("\u26A0 Frontend bucket not found in stack outputs (add storage.public to infrastructure config)");else{let x=await W();await(async(L,j="")=>{await HJ(L,async(P,C)=>{let f=A(P),g=WJ(P),v=C==="index.html"||C.endsWith("/index.html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await a(()=>K.putObject({bucket:F,key:C,body:f,contentType:g,cacheControl:v}),`upload ${C}`),V)$.debug(` Uploaded: ${C}`)})})(x);let M=X.projectPath("bootstrap");if(JJ(M)){let L=A(M);if(await a(()=>K.putObject({bucket:F,key:"install",body:L,contentType:"text/plain",cacheControl:"no-cache, no-store, must-revalidate"}),"upload bootstrap install script"),V)$.debug(" Uploaded bootstrap install script")}let O=Y.publicCloudFrontDistributionId||Y.CloudFrontDistributionId;if(O){if(V)$.debug(" Invalidating CloudFront cache...");let{AWSClient:L}=await import("@stacksjs/ts-cloud");await new L().request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${O}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
224
217
  <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
225
218
  <CallerReference>${Date.now()}</CallerReference>
226
219
  <Paths>
@@ -229,27 +222,27 @@ return { ${k.join(", ")} }`)()}catch(k){if($)z.debug(` Server block evaluation
229
222
  <Path>/*</Path>
230
223
  </Items>
231
224
  </Paths>
232
- </InvalidationBatch>`})}v.succeed(`Frontend deployed to S3 (${P})`)}}catch(Y){if(v.fail(`Frontend deployment failed: ${Y.message}`),$)z.debug(`Frontend error: ${Y.stack}`)}let f=V.projectPath("dist/docs/.bunpress"),{existsSync:KJ}=await import("fs");if(KJ(f)){let Y=g("Deploying documentation to S3...");Y.start();try{let{S3Client:H,CloudFormationClient:M}=await import("@stacksjs/ts-cloud"),{readFileSync:O}=await import("fs"),X=new H(Q),N=new M(Q),S=`${j}-cloud`,q=await N.getStackOutputs(S),D=q.DocsBucketName;if(!D)Y.stop(),console.log("\u26A0 Docs bucket not found in stack outputs (infrastructure may not be updated yet)");else{await(async(w,E="")=>{await XJ(w,async(R,G)=>{let P=O(R),b=VJ(R),h=G.endsWith(".html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await e(()=>X.putObject({bucket:D,key:G,body:P,contentType:b,cacheControl:h}),`upload docs ${G}`),$)z.debug(` Uploaded docs: ${G}`)},"",[".DS_Store",".bunpress"])})(f);let A=q.docsCloudFrontDistributionId||q.publicCloudFrontDistributionId||q.CloudFrontDistributionId;if(A){if($)z.debug(" Invalidating CloudFront cache for docs...");let{AWSClient:w}=await import("@stacksjs/ts-cloud"),E=new w,R=q.docsCloudFrontDistributionId?["/*"]:["/docs","/docs/*"];await E.request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${A}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
225
+ </InvalidationBatch>`})}N.succeed(`Frontend deployed to S3 (${F})`)}}catch(z){if(N.fail(`Frontend deployment failed: ${z.message}`),V)$.debug(`Frontend error: ${z.stack}`)}let QJ=X.projectPath("dist/docs/.bunpress"),{existsSync:UJ}=await import("fs");if(UJ(QJ)){let z=S("Deploying documentation to S3...");z.start();try{let{S3Client:q,CloudFormationClient:A}=await import("@stacksjs/ts-cloud"),{readFileSync:W}=await import("fs"),K=new q(Q),w=new A(Q),I=`${G}-cloud`,Y=await w.getStackOutputs(I),F=Y.DocsBucketName;if(!F)z.stop(),console.log("\u26A0 Docs bucket not found in stack outputs (infrastructure may not be updated yet)");else{await(async(M,O="")=>{await HJ(M,async(L,j)=>{let P=W(L),C=WJ(L),f=j.endsWith(".html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await a(()=>K.putObject({bucket:F,key:j,body:P,contentType:C,cacheControl:f}),`upload docs ${j}`),V)$.debug(` Uploaded docs: ${j}`)},"",[".DS_Store",".bunpress"])})(QJ);let E=Y.docsCloudFrontDistributionId||Y.publicCloudFrontDistributionId||Y.CloudFrontDistributionId;if(E){if(V)$.debug(" Invalidating CloudFront cache for docs...");let{AWSClient:M}=await import("@stacksjs/ts-cloud"),O=new M,L=Y.docsCloudFrontDistributionId?["/*"]:["/docs","/docs/*"];await O.request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${E}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
233
226
  <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
234
227
  <CallerReference>docs-${Date.now()}</CallerReference>
235
228
  <Paths>
236
- <Quantity>${R.length}</Quantity>
229
+ <Quantity>${L.length}</Quantity>
237
230
  <Items>
238
- ${R.map((G)=>`<Path>${G}</Path>`).join(`
231
+ ${L.map((j)=>`<Path>${j}</Path>`).join(`
239
232
  `)}
240
233
  </Items>
241
234
  </Paths>
242
- </InvalidationBatch>`})}Y.succeed(`Documentation deployed to S3 (${D})`)}}catch(H){if(Y.fail(`Documentation deployment failed: ${H.message}`),$)z.debug(`Docs deploy error: ${H.stack}`)}}else if($)z.debug("No docs build found at dist/docs, skipping docs deployment");let zJ=V.projectPath("dist/blog"),{existsSync:UJ}=await import("fs");if(UJ(zJ)){let Y=g("Deploying blog to S3...");Y.start();try{let{S3Client:H,CloudFormationClient:M}=await import("@stacksjs/ts-cloud"),{readFileSync:O}=await import("fs"),X=new H(Q),N=new M(Q),S=`${j}-cloud`,q=await N.getStackOutputs(S),D=q.BlogBucketName;if(!D)Y.stop(),console.log("\u26A0 Blog bucket not found in stack outputs");else{await XJ(zJ,async(A,w)=>{let E=O(A),R=VJ(A),G=w.endsWith(".html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await e(()=>X.putObject({bucket:D,key:w,body:E,contentType:R,cacheControl:G}),`upload blog ${w}`),$)z.debug(` Uploaded blog: ${w}`)},"",[".DS_Store"]);let B=q.blogCloudFrontDistributionId||q.publicCloudFrontDistributionId||q.CloudFrontDistributionId;if(B){if($)z.debug(" Invalidating CloudFront cache for blog...");let{AWSClient:A}=await import("@stacksjs/ts-cloud"),w=new A,E=q.blogCloudFrontDistributionId?["/*"]:["/blog","/blog/*"];await w.request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${B}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
235
+ </InvalidationBatch>`})}z.succeed(`Documentation deployed to S3 (${F})`)}}catch(q){if(z.fail(`Documentation deployment failed: ${q.message}`),V)$.debug(`Docs deploy error: ${q.stack}`)}}else if(V)$.debug("No docs build found at dist/docs, skipping docs deployment");let o=X.projectPath("dist/blog"),{existsSync:r}=await import("fs");if(r(o)){let z=S("Deploying blog to S3...");z.start();try{let{S3Client:q,CloudFormationClient:A}=await import("@stacksjs/ts-cloud"),{readFileSync:W}=await import("fs"),K=new q(Q),w=new A(Q),I=`${G}-cloud`,Y=await w.getStackOutputs(I),F=Y.BlogBucketName;if(!F)z.stop(),console.log("\u26A0 Blog bucket not found in stack outputs");else{await HJ(o,async(E,M)=>{let O=W(E),L=WJ(E),j=M.endsWith(".html")?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable";if(await a(()=>K.putObject({bucket:F,key:M,body:O,contentType:L,cacheControl:j}),`upload blog ${M}`),V)$.debug(` Uploaded blog: ${M}`)},"",[".DS_Store"]);let x=Y.blogCloudFrontDistributionId||Y.publicCloudFrontDistributionId||Y.CloudFrontDistributionId;if(x){if(V)$.debug(" Invalidating CloudFront cache for blog...");let{AWSClient:E}=await import("@stacksjs/ts-cloud"),M=new E,O=Y.blogCloudFrontDistributionId?["/*"]:["/blog","/blog/*"];await M.request({service:"cloudfront",region:"us-east-1",method:"POST",path:`/2020-05-31/distribution/${x}/invalidation`,headers:{"Content-Type":"application/xml"},body:`<?xml version="1.0" encoding="UTF-8"?>
243
236
  <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
244
237
  <CallerReference>blog-${Date.now()}</CallerReference>
245
238
  <Paths>
246
- <Quantity>${E.length}</Quantity>
239
+ <Quantity>${O.length}</Quantity>
247
240
  <Items>
248
- ${E.map((R)=>`<Path>${R}</Path>`).join(`
241
+ ${O.map((L)=>`<Path>${L}</Path>`).join(`
249
242
  `)}
250
243
  </Items>
251
244
  </Paths>
252
- </InvalidationBatch>`})}Y.succeed(`Blog deployed to S3 (${D})`)}}catch(H){if(Y.fail(`Blog deployment failed: ${H.message}`),$)z.debug(`Blog deploy error: ${H.stack}`)}}else if($)z.debug("No blog build found at dist/blog, skipping blog deployment");let n=g("Configuring 404 error page...");n.start();try{let{S3Client:Y,CloudFormationClient:H,AWSClient:M}=await import("@stacksjs/ts-cloud"),{existsSync:O,readFileSync:X}=await import("fs"),N=new Y(Q),S=new H(Q),q=new M,D=`${j}-cloud`,B=await S.getStackOutputs(D),A=B.FrontendBucketName,w=B.DocsBucketName,E=B.publicCloudFrontDistributionId||B.CloudFrontDistributionId,R=V.projectPath("dist/docs/.bunpress/404.html"),G;if(O(R)){if(G=X(R,"utf-8"),$)z.debug(" Using BunPress-generated 404.html")}else if(G=`<!DOCTYPE html>
245
+ </InvalidationBatch>`})}z.succeed(`Blog deployed to S3 (${F})`)}}catch(q){if(z.fail(`Blog deployment failed: ${q.message}`),V)$.debug(`Blog deploy error: ${q.stack}`)}}else if(V)$.debug("No blog build found at dist/blog, skipping blog deployment");let n=S("Configuring 404 error page...");n.start();try{let{S3Client:z,CloudFormationClient:q,AWSClient:A}=await import("@stacksjs/ts-cloud"),{existsSync:W,readFileSync:K}=await import("fs"),w=new z(Q),I=new q(Q),Y=new A,F=`${G}-cloud`,x=await I.getStackOutputs(F),E=x.FrontendBucketName,M=x.DocsBucketName,O=x.publicCloudFrontDistributionId||x.CloudFrontDistributionId,L=X.projectPath("dist/docs/.bunpress/404.html"),j;if(W(L)){if(j=K(L,"utf-8"),V)$.debug(" Using BunPress-generated 404.html")}else if(j=`<!DOCTYPE html>
253
246
  <html lang="en">
254
247
  <head>
255
248
  <meta charset="UTF-8">
@@ -296,12 +289,12 @@ return { ${k.join(", ")} }`)()}catch(k){if($)z.debug(` Server block evaluation
296
289
  <div class="action"><a class="link" href="/docs/">Take me home</a></div>
297
290
  </div>
298
291
  </body>
299
- </html>`,$)z.debug(" Using default 404.html template");if(A){if(await e(()=>N.putObject({bucket:A,key:"404.html",body:G,contentType:"text/html",cacheControl:"no-cache, no-store, must-revalidate"}),"upload 404.html to frontend bucket"),$)z.debug(` Uploaded 404.html to frontend bucket: ${A}`)}if(w){if(await e(()=>N.putObject({bucket:w,key:"404.html",body:G,contentType:"text/html",cacheControl:"no-cache, no-store, must-revalidate"}),"upload 404.html to docs bucket"),$)z.debug(` Uploaded 404.html to docs bucket: ${w}`)}if(E){if($)z.debug(" Configuring CloudFront custom error responses...");let P=await q.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${E}/config`,returnHeaders:!0}),b=P.headers?.etag||P.headers?.ETag||"",h=P.body?.DistributionConfig||P.DistributionConfig;if(h&&b){if(!((h.CustomErrorResponses?.Quantity||0)>0&&h.CustomErrorResponses?.Items?.CustomErrorResponse?.some?.((p)=>p.ErrorCode===404&&p.ResponsePagePath==="/404.html"))){h.CustomErrorResponses={Quantity:2,Items:{CustomErrorResponse:[{ErrorCode:403,ResponsePagePath:"/404.html",ResponseCode:404,ErrorCachingMinTTL:10},{ErrorCode:404,ResponsePagePath:"/404.html",ResponseCode:404,ErrorCachingMinTTL:10}]}};let p=(Z,x,_="")=>{if(x===null||x===void 0)return"";if(typeof x==="boolean")return`${_}<${Z}>${x}</${Z}>
300
- `;if(typeof x==="number"||typeof x==="string")return`${_}<${Z}>${x}</${Z}>
301
- `;if(Array.isArray(x))return x.map((L)=>p(Z,L,_)).join("");if(typeof x==="object"){if(Z.startsWith("@_")||Z==="?xml")return"";let L="";for(let[I,k]of Object.entries(x))if(!I.startsWith("@_")&&I!=="#text")L+=p(I,k,`${_} `);if(x["#text"]!==void 0)return`${_}<${Z}>${x["#text"]}</${Z}>
302
- `;return`${_}<${Z}>
303
- ${L}${_}</${Z}>
304
- `}return""},i=`<?xml version="1.0" encoding="UTF-8"?>
292
+ </html>`,V)$.debug(" Using default 404.html template");if(E){if(await a(()=>w.putObject({bucket:E,key:"404.html",body:j,contentType:"text/html",cacheControl:"no-cache, no-store, must-revalidate"}),"upload 404.html to frontend bucket"),V)$.debug(` Uploaded 404.html to frontend bucket: ${E}`)}if(M){if(await a(()=>w.putObject({bucket:M,key:"404.html",body:j,contentType:"text/html",cacheControl:"no-cache, no-store, must-revalidate"}),"upload 404.html to docs bucket"),V)$.debug(` Uploaded 404.html to docs bucket: ${M}`)}if(O){if(V)$.debug(" Configuring CloudFront custom error responses...");let P=await Y.request({service:"cloudfront",region:"us-east-1",method:"GET",path:`/2020-05-31/distribution/${O}/config`,returnHeaders:!0}),C=P.headers?.etag||P.headers?.ETag||"",f=P.body?.DistributionConfig||P.DistributionConfig;if(f&&C){if(!((f.CustomErrorResponses?.Quantity||0)>0&&f.CustomErrorResponses?.Items?.CustomErrorResponse?.some?.((m)=>m.ErrorCode===404&&m.ResponsePagePath==="/404.html"))){f.CustomErrorResponses={Quantity:2,Items:{CustomErrorResponse:[{ErrorCode:403,ResponsePagePath:"/404.html",ResponseCode:404,ErrorCachingMinTTL:10},{ErrorCode:404,ResponsePagePath:"/404.html",ResponseCode:404,ErrorCachingMinTTL:10}]}};let m=(D,h,R="")=>{if(h===null||h===void 0)return"";if(typeof h==="boolean")return`${R}<${D}>${h}</${D}>
293
+ `;if(typeof h==="number"||typeof h==="string")return`${R}<${D}>${h}</${D}>
294
+ `;if(Array.isArray(h))return h.map((B)=>m(D,B,R)).join("");if(typeof h==="object"){if(D.startsWith("@_")||D==="?xml")return"";let B="";for(let[d,t]of Object.entries(h))if(!d.startsWith("@_")&&d!=="#text")B+=m(d,t,`${R} `);if(h["#text"]!==void 0)return`${R}<${D}>${h["#text"]}</${D}>
295
+ `;return`${R}<${D}>
296
+ ${B}${R}</${D}>
297
+ `}return""},p=`<?xml version="1.0" encoding="UTF-8"?>
305
298
  <DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
306
- ${Object.entries(h).filter(([Z])=>!Z.startsWith("@_")).map(([Z,x])=>p(Z,x," ")).join("")}</DistributionConfig>
307
- `;if(await q.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${E}/config`,body:i,headers:{"Content-Type":"application/xml","If-Match":b}}),$)z.debug(" CloudFront custom error responses configured")}else if($)z.debug(" CloudFront custom error responses already configured")}}n.succeed("404 error page configured")}catch(Y){if(n.stop(),console.log(`\u26A0 404 page configuration skipped: ${Y.message}`),$)z.debug(`Error page config error: ${Y.stack}`)}try{let Y=await import(V.projectPath("config/cloud")),H=Y?.tsCloud?.infrastructure?.tunnel;if(H?.enabled){let M=H.domain||"";if(!M||M==="localtunnel.dev"||M==="api.localtunnel.dev")console.log("\u2139 Tunnel: Using shared localtunnel.dev (no custom tunnel deployment needed)");else{let O=g(`Deploying tunnel server to ${M}...`);O.start();try{let{deployTunnelServer:X}=await import("@stacksjs/tunnel");await X({domain:M,region:H.region||Y?.tsCloud?.project?.region||"us-east-1",instanceType:H.instanceType,prefix:H.prefix,enableSsl:H.ssl?.enabled,porkbunApiKey:H.ssl?.porkbunApiKey,porkbunSecretKey:H.ssl?.porkbunSecretKey,verbose:$}),O.succeed(`Tunnel server deployed to ${M}`)}catch(X){if(O.stop(),console.log(`\u26A0 Tunnel deployment skipped: ${X.message}`),$)z.debug(`Tunnel deploy error: ${X.stack}`)}}}}catch{}let t=g("Reconciling DNS records...");t.start();try{let{Route53Client:Y,CloudFormationClient:H}=await import("@stacksjs/ts-cloud"),M=new H(Q),O=`${j}-cloud`,X=await M.getStackOutputs(O),N=await import(V.projectPath("config/cloud")),S=N?.tsCloud?.infrastructure?.dns?.hostedZoneId,q=N?.tsCloud?.infrastructure?.dns?.domain||"stacksjs.com";if(S){let D=new Y(Q),B="Z2FDTNDATAQYW2",A=[{domain:q,cfDomain:X.publicCloudFrontDomain},{domain:`www.${q}`,cfDomain:X.publicCloudFrontDomain},{domain:`docs.${q}`,cfDomain:X.docsCloudFrontDomain},{domain:`blog.${q}`,cfDomain:X.blogCloudFrontDomain}],w=0;for(let{domain:E,cfDomain:R}of A){if(!R)continue;try{if(!((await D.listResourceRecordSets({HostedZoneId:S,StartRecordName:E,StartRecordType:"A",MaxItems:"1"}))?.ResourceRecordSets||[]).some((h)=>h.Name===`${E}.`&&h.Type==="A")){if(await D.changeResourceRecordSets({HostedZoneId:S,ChangeBatch:{Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:E,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:R,EvaluateTargetHealth:!1}}},{Action:"UPSERT",ResourceRecordSet:{Name:E,Type:"AAAA",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:R,EvaluateTargetHealth:!1}}}]}}),w++,$)z.debug(` Created DNS records: ${E} -> ${R}`)}else if($)z.debug(` DNS record exists: ${E}`)}catch(G){if($)z.debug(` DNS check/create failed for ${E}: ${G.message}`)}}if(w>0)t.succeed(`DNS records reconciled (${w} created)`);else t.succeed("DNS records verified")}else if(t.stop(),$)z.debug("No hosted zone ID configured, skipping DNS reconciliation")}catch(Y){if(t.stop(),console.log(`\u26A0 DNS reconciliation skipped: ${Y.message}`),$)z.debug(`DNS error: ${Y.stack}`)}console.log(""),z.success("Deployment completed successfully!")}catch(J){z.error("Deployment failed:",J),F.exit(NJ.FatalError)}
299
+ ${Object.entries(f).filter(([D])=>!D.startsWith("@_")).map(([D,h])=>m(D,h," ")).join("")}</DistributionConfig>
300
+ `;if(await Y.request({service:"cloudfront",region:"us-east-1",method:"PUT",path:`/2020-05-31/distribution/${O}/config`,body:p,headers:{"Content-Type":"application/xml","If-Match":C}}),V)$.debug(" CloudFront custom error responses configured")}else if(V)$.debug(" CloudFront custom error responses already configured")}}n.succeed("404 error page configured")}catch(z){if(n.stop(),console.log(`\u26A0 404 page configuration skipped: ${z.message}`),V)$.debug(`Error page config error: ${z.stack}`)}try{let z=await import(X.projectPath("config/cloud")),q=z?.tsCloud?.infrastructure?.tunnel;if(q?.enabled){let A=q.domain||"";if(!A||A==="localtunnel.dev"||A==="api.localtunnel.dev")console.log("\u2139 Tunnel: Using shared localtunnel.dev (no custom tunnel deployment needed)");else{let W=S(`Deploying tunnel server to ${A}...`);W.start();try{let{deployTunnelServer:K}=await import("@stacksjs/tunnel");await K({domain:A,region:q.region||z?.tsCloud?.project?.region||"us-east-1",instanceType:q.instanceType,prefix:q.prefix,enableSsl:q.ssl?.enabled,porkbunApiKey:q.ssl?.porkbunApiKey,porkbunSecretKey:q.ssl?.porkbunSecretKey,verbose:V}),W.succeed(`Tunnel server deployed to ${A}`)}catch(K){if(W.stop(),console.log(`\u26A0 Tunnel deployment skipped: ${K.message}`),V)$.debug(`Tunnel deploy error: ${K.stack}`)}}}}catch{}let VJ=S("Reconciling DNS records...");VJ.start();try{let{Route53Client:z,CloudFormationClient:q}=await import("@stacksjs/ts-cloud"),A=new q(Q),W=`${G}-cloud`,K=await A.getStackOutputs(W),w=await import(X.projectPath("config/cloud")),I=w?.tsCloud?.infrastructure?.dns?.hostedZoneId,Y=w?.tsCloud?.infrastructure?.dns?.domain||"stacksjs.com";if(I){let F=new z(Q),x="Z2FDTNDATAQYW2",E=[{domain:Y,cfDomain:K.publicCloudFrontDomain},{domain:`www.${Y}`,cfDomain:K.publicCloudFrontDomain},{domain:`docs.${Y}`,cfDomain:K.docsCloudFrontDomain},{domain:`blog.${Y}`,cfDomain:K.blogCloudFrontDomain}],M=0;for(let{domain:O,cfDomain:L}of E){if(!L)continue;try{if(!((await F.listResourceRecordSets({HostedZoneId:I,StartRecordName:O,StartRecordType:"A",MaxItems:"1"}))?.ResourceRecordSets||[]).some((f)=>f.Name===`${O}.`&&f.Type==="A")){if(await F.changeResourceRecordSets({HostedZoneId:I,ChangeBatch:{Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:O,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:L,EvaluateTargetHealth:!1}}},{Action:"UPSERT",ResourceRecordSet:{Name:O,Type:"AAAA",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:L,EvaluateTargetHealth:!1}}}]}}),M++,V)$.debug(` Created DNS records: ${O} -> ${L}`)}else if(V)$.debug(` DNS record exists: ${O}`)}catch(j){if(V)$.debug(` DNS check/create failed for ${O}: ${j.message}`)}}if(M>0)VJ.succeed(`DNS records reconciled (${M} created)`);else VJ.succeed("DNS records verified")}else if(VJ.stop(),V)$.debug("No hosted zone ID configured, skipping DNS reconciliation")}catch(z){if(VJ.stop(),console.log(`\u26A0 DNS reconciliation skipped: ${z.message}`),V)$.debug(`DNS error: ${z.stack}`)}console.log(""),$.success("Deployment completed successfully!")}catch(J){$.error("Deployment failed:",J),T.exit(EJ.FatalError)}
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- import{ib as w}from"../../chunk-jbvvb45k.js";import{existsSync as X}from"fs";import N from"process";import{parseOptions as D}from"@stacksjs/cli";import{config as G,overridesReady as O}from"@stacksjs/config";import{path as Y}from"@stacksjs/path";import{cors as W,route as J}from"@stacksjs/router";import{generateAutoImportFiles as Q,injectGlobalAutoImports as T}from"@stacksjs/server";var v=D();await O;var M=Number(N.env.PORT_API)||G.ports?.api||3008,U=Y.storagePath("framework/auto-imports/models.ts");if(!X(U))await Q();await T();try{let z=Y.appPath("Listener.ts");if(X(z)){let B=await import(z);if(typeof B.handleEvents==="function")await B.handleEvents()}}catch(z){let{log:B}=await import("@stacksjs/cli");B.warn(`[api:dev] failed to bootstrap event listeners \u2014 dispatched events will be ignored: ${z.message}`)}J.use(W().handle.bind(W()));var F=/^[a-zA-Z0-9._-]{8,128}$/;J.use(async(z,B)=>{let K=z?.headers?.get?.("x-request-id")||z?.headers?.get?.("X-Request-ID")||"",L=typeof K==="string"&&F.test(K)?K:crypto.randomUUID();z._requestId=L,z._startNs=N.hrtime.bigint();let C=await B();if(C&&C.status===404&&(C.headers.get("content-type")||"").includes("json"))try{let H=await C.clone().json();if(H&&(H.message==="Not Found"||H.error==="Not Found")){let Z=new URL(z.url),$={...H,path:Z.pathname,method:z.method,request_id:L},V=new Headers(C.headers);return V.set("X-Request-ID",L),new Response(JSON.stringify($),{status:404,headers:V})}}catch{}return C});await J.importRoutes();try{await J.serve({port:M,hostname:"127.0.0.1"}),console.log(`
3
- \u279C API server ready: http://localhost:${M}
2
+ import{pb as J}from"../../chunk-4qzb8g3z.js";import{existsSync as Y}from"fs";import Z from"process";import{parseOptions as Q}from"@stacksjs/cli";import{config as T,overridesReady as U}from"@stacksjs/config";import{path as K}from"@stacksjs/path";import{route as L}from"@stacksjs/router";import{generateAutoImportFiles as W,injectGlobalAutoImports as F}from"@stacksjs/server";var v=Q();await U;var X=Number(Z.env.PORT_API)||T.ports?.api||3008,P=K.storagePath("framework/auto-imports/models.ts");if(!Y(P))await W();await F();try{let z=K.appPath("Lib/typesense-dev.ts");if(Y(z)){let B=await import(z);if(typeof B.ensureTypesenseRunning==="function")await B.ensureTypesenseRunning()}}catch(z){let{log:B}=await import("@stacksjs/cli");B.warn(`[api:dev] search engine bootstrap skipped: ${z.message}`)}try{let z=K.appPath("Listener.ts");if(Y(z)){let B=await import(z);if(typeof B.handleEvents==="function")await B.handleEvents()}}catch(z){let{log:B}=await import("@stacksjs/cli");B.warn(`[api:dev] failed to bootstrap event listeners \u2014 dispatched events will be ignored: ${z.message}`)}try{let{startModelMigrationWatcher:z}=await import("./migrate-watcher.js");z()}catch(z){let{log:B}=await import("@stacksjs/cli");B.debug(`[api:dev] auto-migrate watcher not started: ${z.message}`)}var R=await import(K.frameworkPath("defaults/app/Middleware/Cors.ts")),_=R.default;L.use(_.toRouterHandler());var f=/^[a-zA-Z0-9._-]{8,128}$/;L.use(async(z,B)=>{let N=z?.headers?.get?.("x-request-id")||z?.headers?.get?.("X-Request-ID")||"",V=typeof N==="string"&&f.test(N)?N:crypto.randomUUID();z._requestId=V,z._startNs=Z.hrtime.bigint();let C=await B();if(C&&C.status===404&&(C.headers.get("content-type")||"").includes("json"))try{let H=await C.clone().json();if(H&&(H.message==="Not Found"||H.error==="Not Found")){let G=new URL(z.url),O={...H,path:G.pathname,method:z.method,request_id:V},$=new Headers(C.headers);return $.set("X-Request-ID",V),new Response(JSON.stringify(O),{status:404,headers:$})}}catch{}return C});await L.importRoutes();try{await L.serve({port:X,hostname:"127.0.0.1"}),console.log(`
3
+ \u279C API server ready: http://localhost:${X}
4
4
  `)}catch(z){if((z?.code||z?.errno)==="EADDRINUSE"||String(z?.message||"").includes("EADDRINUSE"))console.error(`
5
- [dev/api] Port ${M} is already in use. Kill the other process and re-run \`./buddy dev\`, or set PORT_API to another port.
6
- `),N.exit(1);throw z}
5
+ [dev/api] Port ${X} is already in use. Kill the other process and re-run \`./buddy dev\`, or set PORT_API to another port.
6
+ `),Z.exit(1);throw z}
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import"../../chunk-jbvvb45k.js";import{existsSync as $,readdirSync as U,statSync as k}from"fs";import{join as V}from"path";import w from"process";import{projectPath as W,storagePath as D}from"@stacksjs/path";var H=[D("framework/defaults/resources/functions/dashboard"),W("resources/functions"),W("app/Helpers")];async function F(q={}){let B=globalThis,C=[],G=0;for(let J of H){if(!$(J))continue;let K;try{K=U(J)}catch{continue}for(let A of K){let z=V(J,A),M;try{M=k(z)}catch{continue}if(M.isDirectory()){let O;try{O=U(z)}catch{continue}for(let Q of O){if(!X(Q))continue;let Z=V(z,Q),T=await Y(Z,B,q.verbose);G+=T.added,C.push(...T.collisions)}continue}if(!X(A))continue;let N=await Y(z,B,q.verbose);G+=N.added,C.push(...N.collisions)}}if(q.verbose)w.stdout.write(`[dashboard] hoisted ${G} helper globals`+(C.length>0?` (skipped ${C.length} collisions: ${C.slice(0,5).join(", ")}\u2026)`:"")+`
2
+ import"../../chunk-4qzb8g3z.js";import{existsSync as $,readdirSync as U,statSync as k}from"fs";import{join as V}from"path";import w from"process";import{projectPath as W,storagePath as D}from"@stacksjs/path";var H=[D("framework/defaults/resources/functions/dashboard"),W("resources/functions"),W("app/Helpers")];async function F(q={}){let B=globalThis,C=[],G=0;for(let J of H){if(!$(J))continue;let K;try{K=U(J)}catch{continue}for(let A of K){let z=V(J,A),M;try{M=k(z)}catch{continue}if(M.isDirectory()){let O;try{O=U(z)}catch{continue}for(let Q of O){if(!X(Q))continue;let Z=V(z,Q),T=await Y(Z,B,q.verbose);G+=T.added,C.push(...T.collisions)}continue}if(!X(A))continue;let N=await Y(z,B,q.verbose);G+=N.added,C.push(...N.collisions)}}if(q.verbose)w.stdout.write(`[dashboard] hoisted ${G} helper globals`+(C.length>0?` (skipped ${C.length} collisions: ${C.slice(0,5).join(", ")}\u2026)`:"")+`
3
3
  `)}function X(q){if(!/\.(?:ts|tsx|js|mjs)$/.test(q))return!1;if(q.startsWith("_"))return!1;if(q.endsWith(".test.ts")||q.endsWith(".spec.ts"))return!1;if(q.endsWith(".d.ts"))return!1;return!0}async function Y(q,B,C){let G;try{G=await import(q)}catch{return{added:0,collisions:[]}}let J=[],K=0;for(let[A,z]of Object.entries(G)){if(A==="default"||A.startsWith("_"))continue;if(typeof z==="function"||z&&typeof z==="object"){if(B[A]===void 0)B[A]=z,K++;else if(B[A]!==z)J.push(A)}}return{added:K,collisions:J}}export{F as hoistDashboardGlobals};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{Aa as i,Ba as j,Ca as k,Da as l,Ea as m,sa as a,ta as b,ua as c,va as d,wa as e,xa as f,ya as g,za as h}from"../../chunk-kzhgexj4.js";import"../../chunk-jbvvb45k.js";export{k as waitForServer,f as scanModelsDir,d as modelNameToId,i as isPortAvailable,a as iconMap,e as getModelIcon,j as findAvailablePort,b as excludeModels,g as discoverModels,c as dedicatedPages,l as buildSidebarConfig,h as buildManifest,m as buildDashboardUrl};
2
+ import{Aa as k,Ba as l,Ca as m,qa as a,ra as b,sa as c,ta as d,ua as e,va as f,wa as g,xa as h,ya as i,za as j}from"../../chunk-jv7ry09n.js";import"../../chunk-4qzb8g3z.js";export{k as waitForServer,f as scanModelsDir,d as modelNameToId,i as isPortAvailable,a as iconMap,e as getModelIcon,j as findAvailablePort,b as excludeModels,g as discoverModels,c as dedicatedPages,l as buildSidebarConfig,h as buildManifest,m as buildDashboardUrl};
@@ -1,8 +1,8 @@
1
1
  // @bun
2
- import{Ba as t,Ca as r,Da as a,ya as l,za as d}from"../../chunk-kzhgexj4.js";import{ib as L}from"../../chunk-jbvvb45k.js";import V from"process";import{existsSync as w,readFileSync as zE,writeFileSync as o}from"fs";import{bold as k,cyan as f,dim as _,green as h}from"@stacksjs/cli";import{projectPath as A,storagePath as J}from"@stacksjs/path";var b=V.argv.indexOf("--verbose"),I=b!==-1&&V.argv[b+1]!=="false",GE=Bun.nanoseconds(),s=console.log,NE=console.warn,v=[];console.log=(...X)=>{v.push(X.map(String).join(" "))};console.warn=(...X)=>{v.push(X.map(String).join(" "))};var p=J("framework/defaults/views/dashboard"),OE=A("resources/views/dashboard"),y=Number(V.env.PORT_ADMIN)||3002,T=await t(y),g=V.env.APP_URL||"",WE=g!==""&&g!=="localhost"&&!g.includes("localhost:"),n=WE?g.replace(/^https?:\/\//,""):null,C=n?`dashboard.${n}`:null,e=`${V.env.HOME}/.stacks/ssl`;function EE(){console.log=s,console.warn=(...X)=>{let O=X.map(String).join(" ");if(O.includes("[STX] DOM API violation")||O.includes("unsafe expression"))return;NE(...X)}}function F(X,O={}){let Y=new Headers(O.headers);return Y.set("content-type","application/json; charset=utf-8"),Y.set("cache-control","no-store"),new Response(JSON.stringify(X),{...O,headers:Y})}function KE(X){return X.trim().toLowerCase().replace(/['"]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}async function D(X){if(X.method==="GET"||X.method==="HEAD")return{};let O=X.headers.get("content-type")||"";if(O.includes("application/json"))return await X.json().catch(()=>({}));if(O.includes("form")){let Y=await X.formData();return Object.fromEntries(Y.entries())}return{}}var ZE={posts:["title","poster","content","excerpt","views","published_at","status","is_featured","author_id","created_at","updated_at"],pages:["title","template","views","published_at","conversions","author_id","created_at","updated_at"],authors:["name","email","user_id","created_at","updated_at"],categories:["name","description","slug","image_url","is_active","parent_category_id","display_order","created_at","updated_at"],tags:["name","slug","description","post_count","color","created_at","updated_at"],comments:["title","body","content","status","author_name","author_email","post_title","is_approved","approved_at","rejected_at","updated_at"]};function c(){let X=V.env.DB_DATABASE_PATH||"database/stacks.sqlite";return X.startsWith("/")?X:A(X)}function U(X){if(!/^[a-z_][a-z0-9_]*$/i.test(X))throw Error(`Invalid CMS database identifier: ${X}`);return`"${X.replace(/"/g,'""')}"`}function i(X,O){let Y=ZE[X];if(!Y)throw Error(`Unsupported CMS table: ${X}`);return Object.fromEntries(Object.entries(O).filter(([G,W])=>Y.includes(G)&&W!==void 0))}async function HE(){if((V.env.DB_CONNECTION||"sqlite")!=="sqlite"||!w(c()))return;let{Database:X}=await import("bun:sqlite"),O=new X(c());async function Y(G,W){return O.query(`select * from ${U(G)} where id = ? limit 1`).get(W)}return{async all(G,W="created_at"){return O.query(`select * from ${U(G)} order by ${U(W)} desc`).all()},async insert(G,W){let K=i(G,W),Z=Object.keys(K),H=Z.map(()=>"?").join(", "),$=`insert into ${U(G)} (${Z.map(U).join(", ")}) values (${H})`,E=O.query($).run(...Z.map((z)=>K[z]));return await Y(G,Number(E.lastInsertRowid))},async update(G,W,K){let Z=i(G,K),H=Object.keys(Z);if(H.length){let $=H.map((E)=>`${U(E)} = ?`).join(", ");O.query(`update ${U(G)} set ${$} where id = ?`).run(...H.map((E)=>Z[E]),W)}return await Y(G,W)},async delete(G,W){O.query(`delete from ${U(G)} where id = ?`).run(W)},find:Y,close(){O.close()}}}async function _E(){let X=await HE();if(X)return X;let{db:O}=await import("@stacksjs/database");return{async all(Y,G="created_at"){let W=O.selectFrom(Y).selectAll();if(G)W=W.orderBy(G,"desc");return await W.execute()},async insert(Y,G){let W=await O.insertInto(Y).values(G).returningAll().executeTakeFirst();if(!W||W.id==null){let K=G.email?["email",G.email]:G.name?["name",G.name]:["title",G.title];W=await O.selectFrom(Y).selectAll().where(K[0],"=",K[1]).orderBy("id","desc").executeTakeFirst()}return W},async update(Y,G,W){return await O.updateTable(Y).set(W).where("id","=",G).execute(),await O.selectFrom(Y).selectAll().where("id","=",G).executeTakeFirst()},async delete(Y,G){await O.deleteFrom(Y).where("id","=",G).execute()},async find(Y,G){return await O.selectFrom(Y).selectAll().where("id","=",G).executeTakeFirst()}}}async function x(X,O,Y="created_at"){try{return await X.all(O,Y)}catch{return[]}}async function FE(X){let O=new URL(X.url);if(!O.pathname.startsWith("/api/dashboard/cms"))return null;let Y;try{Y=await _E();let W=O.pathname.replace(/^\/api\/dashboard\/cms\/?/,"").split("/").filter(Boolean),K=W[0]||"",Z=W[1]?Number(W[1]):void 0,H=new Date().toISOString().slice(0,19).replace("T"," ");if(X.method==="GET"&&!K){let[$,E,z,N,Q,R]=await Promise.all([x(Y,"posts"),x(Y,"pages"),x(Y,"authors"),x(Y,"categories"),x(Y,"tags"),x(Y,"comments")]);return F({ok:!0,posts:$,pages:E,authors:z,categories:N,tags:Q,comments:R,stats:{posts:$.length,publishedPosts:$.filter((j)=>j.status==="published").length,draftPosts:$.filter((j)=>j.status==="draft").length,pages:E.length,categories:N.length,tags:Q.length,comments:R.length}})}if(K==="posts"){if(X.method==="POST"){let $=await D(X),E=String($.title||"").trim();if(!E)return F({ok:!1,error:"Title is required"},{status:422});let z=await Y.insert("posts",{title:E,poster:String($.poster||""),content:String($.content||$.body||""),excerpt:String($.excerpt||""),views:Number($.views||0),published_at:$.status==="published"?H:$.published_at||null,status:String($.status||"draft").toLowerCase(),is_featured:$.is_featured?1:0,author_id:$.author_id?Number($.author_id):null,created_at:H,updated_at:H});return F({ok:!0,post:z},{status:201})}if(X.method==="PATCH"&&Z){let $=await D(X),E={updated_at:H};for(let N of["title","poster","content","excerpt","status","published_at"])if($[N]!==void 0)E[N]=N==="status"?String($[N]).toLowerCase():$[N];if($.views!==void 0)E.views=Number($.views);if($.is_featured!==void 0)E.is_featured=$.is_featured?1:0;let z=await Y.update("posts",Z,E);if(!z)return F({ok:!1,error:"Post not found"},{status:404});return F({ok:!0,post:z})}if(X.method==="DELETE"&&Z)return await Y.delete("posts",Z),F({ok:!0})}if(K==="tags"||K==="categories"){let $=K;if(X.method==="POST"){let E=await D(X),z=String(E.name||"").trim();if(!z)return F({ok:!1,error:"Name is required"},{status:422});let N={name:z,slug:String(E.slug||KE(z)),description:String(E.description||""),created_at:H,updated_at:H};if(K==="categories")N.is_active=E.is_active===void 0?!0:Boolean(E.is_active);if(K==="tags")N.post_count=Number(E.post_count||0),N.color=String(E.color||"");let Q=await Y.insert($,N);return F({ok:!0,[K==="categories"?"category":"tag"]:Q},{status:201})}if(X.method==="PATCH"&&Z){let E=await D(X),z={updated_at:H};for(let Q of["name","slug","description","color","image_url","parent_category_id"])if(E[Q]!==void 0)z[Q]=E[Q];if(E.post_count!==void 0)z.post_count=Number(E.post_count);if(E.display_order!==void 0)z.display_order=Number(E.display_order);if(E.is_active!==void 0)z.is_active=E.is_active?1:0;let N=await Y.update($,Z,z);if(!N)return F({ok:!1,error:`${K==="categories"?"Category":"Tag"} not found`},{status:404});return F({ok:!0,[K==="categories"?"category":"tag"]:N})}if(X.method==="DELETE"&&Z)return await Y.delete($,Z),F({ok:!0})}if(K==="pages"){if(X.method==="POST"){let $=await D(X),E=String($.title||"").trim();if(!E)return F({ok:!1,error:"Title is required"},{status:422});let z=await Y.insert("pages",{title:E,template:String($.template||"default"),views:0,conversions:0,published_at:$.status==="published"?H:null,author_id:$.author_id?Number($.author_id):null,created_at:H,updated_at:H});return F({ok:!0,page:z},{status:201})}if(X.method==="PATCH"&&Z){let $=await D(X),E={updated_at:H};for(let N of["title","template","published_at"])if($[N]!==void 0)E[N]=$[N];if($.views!==void 0)E.views=Number($.views);if($.conversions!==void 0)E.conversions=Number($.conversions);if($.author_id!==void 0)E.author_id=$.author_id?Number($.author_id):null;let z=await Y.update("pages",Z,E);if(!z)return F({ok:!1,error:"Page not found"},{status:404});return F({ok:!0,page:z})}if(X.method==="DELETE"&&Z)return await Y.delete("pages",Z),F({ok:!0})}if(K==="authors"){if(X.method==="POST"){let $=await D(X),E=String($.name||"").trim(),z=String($.email||"").trim();if(!E||!z)return F({ok:!1,error:"Name and email are required"},{status:422});let N=await Y.insert("authors",{name:E,email:z,created_at:H,updated_at:H});return F({ok:!0,author:N},{status:201})}if(X.method==="PATCH"&&Z){let $=await D(X),E={updated_at:H};for(let N of["name","email"])if($[N]!==void 0)E[N]=$[N];if($.user_id!==void 0)E.user_id=$.user_id?Number($.user_id):null;let z=await Y.update("authors",Z,E);if(!z)return F({ok:!1,error:"Author not found"},{status:404});return F({ok:!0,author:z})}if(X.method==="DELETE"&&Z)return await Y.delete("authors",Z),F({ok:!0})}if(K==="comments"){if(X.method==="PATCH"&&Z){let $=await D(X),E={updated_at:H};if($.content!==void 0)E.content=$.content,E.body=$.content;if($.body!==void 0)E.content=$.body,E.body=$.body;for(let N of["status","author_name","author_email","post_title"])if($[N]!==void 0)E[N]=$[N];if(E.status==="approved")E.is_approved=1;if(E.status&&E.status!=="approved")E.is_approved=0;let z=await Y.update("comments",Z,E);if(!z)return F({ok:!1,error:"Comment not found"},{status:404});return F({ok:!0,comment:z})}if(X.method==="DELETE"&&Z)return await Y.delete("comments",Z),F({ok:!0})}return F({ok:!1,error:"CMS endpoint not found"},{status:404})}catch(G){return F({ok:!1,error:G?.message||String(G)},{status:500})}finally{Y?.close?.()}}async function VE(){try{await import("@stacksjs/orm")}catch(E){if(I)console.warn("[dashboard] orm preload failed:",E?.message||E)}try{let{hoistDashboardGlobals:E}=await import("./dashboard-globals.js");await E({verbose:I})}catch(E){if(I)console.warn("[dashboard] globals preload failed:",E?.message||E)}let X;try{X=(await import("../../chunk-4p0rjazd.js")).serve}catch{X=(await import(A("pantry/bun-plugin-stx/dist/serve.js"))).serve}let O;try{let E=A("pantry/@stacksjs/stx/dist/index.js");if(await Bun.file(E).exists())O=await import(E)}catch{}let{listConfigFiles:Y,readConfig:G,updateConfigKey:W}=await import(J("framework/defaults/resources/functions/dashboard/config-io.ts")),K={"/__deps/charts.js":J("framework/core/charts/dist/index.js")},Z={...Object.fromEntries(Object.entries(K).map(([E,z])=>[E,async()=>{let N=Bun.file(z);if(!await N.exists())return new Response(`// dependency dist missing: ${z}
3
- // rebuild with: cd ${z.replace(/\/dist\/[^/]+$/,"")} && bun build.ts`,{status:500,headers:{"content-type":"text/javascript; charset=utf-8"}});return new Response(N,{headers:{"content-type":"text/javascript; charset=utf-8","cache-control":"no-cache"}})}])),"/api/config/list":async()=>{try{return Response.json({ok:!0,files:Y()})}catch(E){return Response.json({ok:!1,error:E?.message},{status:500})}},"/api/config/read":async(E)=>{try{let N=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let Q=await G(N);if(!Q)return Response.json({ok:!1,error:"Not found"},{status:404});return Response.json({ok:!0,name:N,fields:Q.fields,values:Q.values})}catch(z){return Response.json({ok:!1,error:z?.message},{status:500})}},"/api/config/source":async(E)=>{try{let N=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let Q=await G(N);if(!Q)return Response.json({ok:!1,error:"Not found"},{status:404});return new Response(Q.source,{headers:{"content-type":"text/plain; charset=utf-8"}})}catch(z){return Response.json({ok:!1,error:z?.message},{status:500})}},"/api/config/update":async(E)=>{if(E.method!=="POST")return Response.json({ok:!1,error:"Method not allowed"},{status:405});try{let z=await E.json(),N=z.file?.replace(/\.ts$/,"");if(!N||!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid file"},{status:400});let Q=[];if(Array.isArray(z.updates))for(let M of z.updates){let S=M.key??M.path;if(typeof S==="string")Q.push({key:S,value:M.value})}else if(z.key)Q.push({key:z.key,value:z.value});if(Q.length===0)return Response.json({ok:!1,error:"No updates supplied"},{status:400});let R=[];for(let M of Q)try{let S=await W(N,M.key,H(M.value));R.push({key:M.key,ok:!0,newValue:S.newValue})}catch(S){R.push({key:M.key,ok:!1,error:S?.message})}let j=R.every((M)=>M.ok);return Response.json({ok:j,file:N,results:R})}catch(z){return Response.json({ok:!1,error:z?.message},{status:500})}}};function H(E){if(typeof E==="boolean"||typeof E==="number")return E;if(E==="true")return!0;if(E==="false")return!1;if(E===""||E==null)return"";if(typeof E==="string"&&/^-?\d+(?:\.\d+)?$/.test(E))return Number(E);return String(E)}X({patterns:[OE,p],port:T,componentsDir:J("framework/defaults/resources/components/Dashboard"),layoutsDir:p,partialsDir:p,quiet:!0,routes:Z,onRequest:FE,auth:!1,...O&&{stxModule:O}}).catch((E)=>{EE(),console.error(`
2
+ import{Aa as n,Ba as c,wa as m,xa as u,za as b}from"../../chunk-jv7ry09n.js";import{pb as F}from"../../chunk-4qzb8g3z.js";import z from"process";import{existsSync as j,readFileSync as e,writeFileSync as i}from"fs";import{bold as C,cyan as x,dim as Y,green as k}from"@stacksjs/cli";import{projectPath as D,storagePath as U}from"@stacksjs/path";var p=z.argv.indexOf("--verbose"),V=p!==-1&&z.argv[p+1]!=="false",EE=Bun.nanoseconds(),l=console.log,XE=console.warn,P=[];console.log=(...X)=>{P.push(X.map(String).join(" "))};console.warn=(...X)=>{P.push(X.map(String).join(" "))};var f=U("framework/defaults/views/dashboard"),YE=D("resources/views/dashboard"),h=Number(z.env.PORT_ADMIN)||3002,Q=await b(h),S=z.env.APP_URL||"",$E=S!==""&&S!=="localhost"&&!S.includes("localhost:"),y=$E?S.replace(/^https?:\/\//,""):null,w=y?`dashboard.${y}`:null,d=`${z.env.HOME}/.stacks/ssl`;function t(){console.log=l,console.warn=(...X)=>{let O=X.map(String).join(" ");if(O.includes("[STX] DOM API violation")||O.includes("unsafe expression"))return;XE(...X)}}async function zE(){try{await import("@stacksjs/orm")}catch(E){if(V)console.warn("[dashboard] orm preload failed:",E?.message||E)}try{let{hoistDashboardGlobals:E}=await import("./dashboard-globals.js");await E({verbose:V})}catch(E){if(V)console.warn("[dashboard] globals preload failed:",E?.message||E)}let X;try{X=(await import("../../chunk-8r76qydb.js")).serve}catch{X=(await import(D("pantry/bun-plugin-stx/dist/serve.js"))).serve}let O;try{let E=D("pantry/@stacksjs/stx/dist/index.js");if(await Bun.file(E).exists())O=await import(E)}catch{}let{listConfigFiles:G,readConfig:W,updateConfigKey:M}=await import(U("framework/defaults/resources/functions/dashboard/config-io.ts")),Z={"/__deps/charts.js":U("framework/core/charts/dist/index.js")},A={...Object.fromEntries(Object.entries(Z).map(([E,$])=>[E,async()=>{let N=Bun.file($);if(!await N.exists())return new Response(`// dependency dist missing: ${$}
3
+ // rebuild with: cd ${$.replace(/\/dist\/[^/]+$/,"")} && bun build.ts`,{status:500,headers:{"content-type":"text/javascript; charset=utf-8"}});return new Response(N,{headers:{"content-type":"text/javascript; charset=utf-8","cache-control":"no-cache"}})}])),"/api/config/list":async()=>{try{return Response.json({ok:!0,files:G()})}catch(E){return Response.json({ok:!1,error:E?.message},{status:500})}},"/api/config/read":async(E)=>{try{let N=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let K=await W(N);if(!K)return Response.json({ok:!1,error:"Not found"},{status:404});return Response.json({ok:!0,name:N,fields:K.fields,values:K.values})}catch($){return Response.json({ok:!1,error:$?.message},{status:500})}},"/api/config/source":async(E)=>{try{let N=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let K=await W(N);if(!K)return Response.json({ok:!1,error:"Not found"},{status:404});return new Response(K.source,{headers:{"content-type":"text/plain; charset=utf-8"}})}catch($){return Response.json({ok:!1,error:$?.message},{status:500})}},"/api/config/update":async(E)=>{if(E.method!=="POST")return Response.json({ok:!1,error:"Method not allowed"},{status:405});try{let $=await E.json(),N=$.file?.replace(/\.ts$/,"");if(!N||!/^[\w-]+$/.test(N))return Response.json({ok:!1,error:"Invalid file"},{status:400});let K=[];if(Array.isArray($.updates))for(let _ of $.updates){let R=_.key??_.path;if(typeof R==="string")K.push({key:R,value:_.value})}else if($.key)K.push({key:$.key,value:$.value});if(K.length===0)return Response.json({ok:!1,error:"No updates supplied"},{status:400});let I=[];for(let _ of K)try{let R=await M(N,_.key,H(_.value));I.push({key:_.key,ok:!0,newValue:R.newValue})}catch(R){I.push({key:_.key,ok:!1,error:R?.message})}let s=I.every((_)=>_.ok);return Response.json({ok:s,file:N,results:I})}catch($){return Response.json({ok:!1,error:$?.message},{status:500})}}};function H(E){if(typeof E==="boolean"||typeof E==="number")return E;if(E==="true")return!0;if(E==="false")return!1;if(E===""||E==null)return"";if(typeof E==="string"&&/^-?\d+(?:\.\d+)?$/.test(E))return Number(E);return String(E)}let L=null;try{let E=await import("@stacksjs/router"),$=(await import(D("app/Routes.ts"))).default;await E.loadRoutes($),L=E.route}catch(E){if(V)console.warn("[dashboard] Stacks router init failed:",E?.message||E)}X({patterns:[YE,f],port:Q,componentsDir:U("framework/defaults/resources/components/Dashboard"),layoutsDir:f,partialsDir:f,quiet:!0,routes:A,onRequest:L?async(E)=>{let N=new URL(E.url).pathname;if(N.startsWith("/api/config/")||N.startsWith("/__deps/"))return null;if(N.startsWith("/api/"))return L.handleRequest(E);if(E.method.toUpperCase()!=="GET")return L.handleRequest(E);return null}:void 0,auth:!1,...O&&{stxModule:O}}).catch((E)=>{t(),console.error(`
4
4
  Failed to start dashboard server: ${E?.message||E}
5
- `),V.exit(1)})}async function QE(){if(!C)return!1;if(V.env.STACKS_PROXY_MANAGED)return!1;try{let{startProxies:X}=await import("@stacksjs/rpx");return await X({proxies:[{from:`localhost:${T}`,to:C,cleanUrls:!1}],https:{basePath:e,validityDays:825},regenerateUntrustedCerts:!1,verbose:I}),!0}catch(X){if(I)s(` ${_(`Proxy: ${X}`)}`);return!1}}var ME=T+1;function P(X,O=200,Y={}){return new Response(JSON.stringify(X),{status:O,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type",...Y}})}function LE(){Bun.serve({port:ME,fetch:async(X)=>{if(X.method==="OPTIONS")return new Response(null,{headers:{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type"}});if(new URL(X.url).pathname==="/api/config/update"&&X.method==="POST")try{let{file:Y,updates:G}=await X.json();if(!Y||Y.includes("..")||!Y.match(/^[\w.-]+\.ts$/))return P({error:"Invalid file name"},400);let W=A(`config/${Y}`),K=zE(W,"utf-8");for(let{path:Z,value:H}of G){let E=Z.split(".").pop().replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),z=new RegExp(`(${E}\\s*:\\s*)(?:'[^']*'|"[^"]*"|\\d+(?:\\.\\d+)?|true|false)`);if(z.test(K)){let N=/^\d+(?:\.\d+)?$/.test(H),Q=H==="true"||H==="false",R=H.replace(/'/g,"\\'").replace(/\$/g,"$$$$"),j=N||Q?H:`'${R}'`;K=K.replace(z,`$1${j}`)}}return o(W,K,"utf-8"),P({success:!0})}catch(Y){return P({error:Y.message},500)}return P({error:"Not found"},404)}})}LE();var[,u]=await Promise.all([VE(),l(A("app/Models"),J("framework/defaults/app/Models"))]);async function RE(){let X={library:!0,content:!0,commerce:!0,marketing:!0,analytics:!0,management:!0,utilities:!0,data:{dashboard:!0,activity:!0,users:!0,teams:!0,subscribers:!0,allModels:!0}};try{let Y=(await import(A("config/dashboard.ts"))).default?.sections??{},G=Y.data??{};return{library:Y.library?.enabled??!0,content:Y.content?.enabled??!0,commerce:Y.commerce?.enabled??!0,marketing:Y.marketing?.enabled??!0,analytics:Y.analytics?.enabled??!0,management:Y.management?.enabled??!0,utilities:Y.utilities?.enabled??!0,data:{dashboard:G.dashboard?.enabled??!0,activity:G.activity?.enabled??!0,users:G.users?.enabled??!0,teams:G.teams?.enabled??!0,subscribers:G.subscribers?.enabled??!0,allModels:G.allModels?.enabled??!0}}}catch{return X}}var XE=await RE(),DE=J("framework/defaults/views/dashboard/.discovered-models.json"),TE={models:d(u),sections:XE};o(DE,JSON.stringify(TE,null,2));var UE=await r(T);EE();var IE=!1;QE().then((X)=>{IE=X}).catch((X)=>{if(I)console.warn("[Dashboard] Reverse proxy failed:",X)});var m=C?`https://${C}`:null,q=`http://localhost:${T}`,AE=q,YE=a(AE,u,XE),$E=`http://localhost:${T}/?native-sidebar=1`,jE=(Bun.nanoseconds()-GE)/1e6;console.log();console.log(` ${k(f("stacks dashboard"))}`);console.log();if(m)console.log(` ${h("\u279C")} ${k("Local")}: ${f(m)}`),console.log(` ${_("\u279C")} ${_("Origin")}: ${_(q)}`);else console.log(` ${h("\u279C")} ${k("Local")}: ${f(q)}`);console.log(` ${h("\u279C")} ${k("Window")}: ${_("Stacks Dashboard")} ${_("1400\xD7900")}`);console.log(` ${h("\u279C")} ${k("Models")}: ${_(`${u.length} discovered`)}`);if(T!==y)console.log(` ${_("\u279C")} ${_(`Port ${y} in use, using ${T}`)}`);if(!UE)console.log(` ${_("\u26A0")} ${_("Dev server may not be ready yet")}`);console.log();console.log(` ${_(`ready in ${jE.toFixed(0)} ms`)}`);if(I){if(console.log(),console.log(` ${_("\u279C")} ${_("Sidebar")}: ${_(`${YE.sections.length} sections, 240px`)}`),console.log(` ${_("\u279C")} ${_("URL")}: ${_($E)}`),C)console.log(` ${_("\u279C")} ${_("SSL")}: ${_(e)}`),console.log(` ${_("\u279C")} ${_("Proxy")}: ${_(`localhost:${T} \u2192 ${C}`)}`);if(v.length>0){console.log();for(let X of v)console.log(` ${_(X)}`)}}console.log();var B=null;try{let X=V.env.HOME?`${V.env.HOME}/Code/Tools/craft/packages/typescript/src/index.ts`:void 0;({createApp:B}=X&&w(X)?await import(X):await import("../../chunk-s03z9zn3.js"))}catch{try{({createApp:B}=await import("@craft-native/craft"))}catch{try{({createApp:B}=await import("@stacksjs/ts-craft"))}catch{}}}if(B){let X=A("resources/assets/images/app-icon.png"),O=J("framework/defaults/resources/assets/images/app-icon.png"),Y=await Bun.file(X).exists()?X:await Bun.file(O).exists()?O:void 0,G=(()=>{let K=V.env.CRAFT_BIN;if(K&&w(K))return K;let Z=`${V.env.HOME}/Code/Tools/craft/craft`;if(w(Z))return Z;let H=`${V.env.HOME}/Code/Tools/craft/bin/craft`;if(w(H))return H;let $=`${V.env.HOME}/Code/Tools/craft/packages/zig/zig-out/bin/craft`;if(w($))return $;let E=`${V.env.HOME}/Documents/Projects/craft/packages/zig/zig-out/bin/craft`;if(w(E))return E;return})();if(!G)B=null;if(!B)console.log(` ${_("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
6
- `),await new Promise(()=>{});let W=B({url:$E,quiet:!I,...G&&{craftPath:G},window:{title:"Stacks Dashboard",width:1400,height:900,titlebarHidden:!0,nativeSidebar:!0,sidebarWidth:240,sidebarConfig:YE,...Y&&{icon:Y}}});V.on("SIGINT",()=>{W.close(),V.exit(0)}),V.on("SIGTERM",()=>{W.close(),V.exit(0)});try{await W.show(),V.exit(0)}catch{let K=m||q;console.log(` ${_("Dashboard available at:")} ${f(K)}
7
- `),await new Promise(()=>{})}}else console.log(` ${_("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
8
- `),V.on("SIGINT",()=>V.exit(0)),V.on("SIGTERM",()=>V.exit(0)),await new Promise(()=>{});
5
+ `),z.exit(1)})}async function GE(){if(!w)return!1;if(z.env.STACKS_PROXY_MANAGED)return!1;try{let{startProxies:X}=await import("@stacksjs/rpx");return await X({proxies:[{from:`localhost:${Q}`,to:w,cleanUrls:!1}],https:{basePath:d,validityDays:825},regenerateUntrustedCerts:!1,verbose:V}),!0}catch(X){if(V)l(` ${Y(`Proxy: ${X}`)}`);return!1}}var NE=Q+1;function J(X,O=200,G={}){return new Response(JSON.stringify(X),{status:O,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type",...G}})}function OE(){Bun.serve({port:NE,fetch:async(X)=>{if(X.method==="OPTIONS")return new Response(null,{headers:{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type"}});if(new URL(X.url).pathname==="/api/config/update"&&X.method==="POST")try{let{file:G,updates:W}=await X.json();if(!G||G.includes("..")||!G.match(/^[\w.-]+\.ts$/))return J({error:"Invalid file name"},400);let M=D(`config/${G}`),Z=e(M,"utf-8");for(let{path:A,value:H}of W){let B=A.split(".").pop().replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),E=new RegExp(`(${B}\\s*:\\s*)(?:'[^']*'|"[^"]*"|\\d+(?:\\.\\d+)?|true|false)`);if(E.test(Z)){let $=/^\d+(?:\.\d+)?$/.test(H),N=H==="true"||H==="false",K=H.replace(/'/g,"\\'").replace(/\$/g,"$$$$"),I=$||N?H:`'${K}'`;Z=Z.replace(E,`$1${I}`)}}return i(M,Z,"utf-8"),J({success:!0})}catch(G){return J({error:G.message},500)}return J({error:"Not found"},404)}})}OE();var[,q]=await Promise.all([zE(),m(D("app/Models"),U("framework/defaults/app/Models"))]);async function WE(){let X={library:!0,content:!0,commerce:!0,marketing:!0,analytics:!0,management:!0,utilities:!0,ci:!1,data:{dashboard:!0,activity:!0,users:!0,teams:!0,subscribers:!0,allModels:!0}};try{let O=await import(D("config/dashboard.ts")),G=O.default?.sections??{},W=G.data??{};return{library:G.library?.enabled??!0,content:G.content?.enabled??!0,commerce:G.commerce?.enabled??!0,marketing:G.marketing?.enabled??!0,analytics:G.analytics?.enabled??!0,management:G.management?.enabled??!0,utilities:G.utilities?.enabled??!0,ci:O.default?.ci?.enabled??!1,data:{dashboard:W.dashboard?.enabled??!0,activity:W.activity?.enabled??!0,users:W.users?.enabled??!0,teams:W.teams?.enabled??!0,subscribers:W.subscribers?.enabled??!0,allModels:W.allModels?.enabled??!0}}}catch{return X}}var r=await WE(),KE=U("framework/defaults/views/dashboard/.discovered-models.json"),ZE={models:u(q),sections:r};i(KE,JSON.stringify(ZE,null,2));var HE=await n(Q);t();var _E=!1;GE().then((X)=>{_E=X}).catch((X)=>{if(V)console.warn("[Dashboard] Reverse proxy failed:",X)});var v=w?`https://${w}`:null,g=`http://localhost:${Q}`,FE=g,a=c(FE,q,r),o=`http://localhost:${Q}/?native-sidebar=1`,VE=(Bun.nanoseconds()-EE)/1e6;console.log();console.log(` ${C(x("stacks dashboard"))}`);console.log();if(v)console.log(` ${k("\u279C")} ${C("Local")}: ${x(v)}`),console.log(` ${Y("\u279C")} ${Y("Origin")}: ${Y(g)}`);else console.log(` ${k("\u279C")} ${C("Local")}: ${x(g)}`);console.log(` ${k("\u279C")} ${C("Window")}: ${Y("Stacks Dashboard")} ${Y("1400\xD7900")}`);console.log(` ${k("\u279C")} ${C("Models")}: ${Y(`${q.length} discovered`)}`);if(Q!==h)console.log(` ${Y("\u279C")} ${Y(`Port ${h} in use, using ${Q}`)}`);if(!HE)console.log(` ${Y("\u26A0")} ${Y("Dev server may not be ready yet")}`);console.log();console.log(` ${Y(`ready in ${VE.toFixed(0)} ms`)}`);if(V){if(console.log(),console.log(` ${Y("\u279C")} ${Y("Sidebar")}: ${Y(`${a.sections.length} sections, 240px`)}`),console.log(` ${Y("\u279C")} ${Y("URL")}: ${Y(o)}`),w)console.log(` ${Y("\u279C")} ${Y("SSL")}: ${Y(d)}`),console.log(` ${Y("\u279C")} ${Y("Proxy")}: ${Y(`localhost:${Q} \u2192 ${w}`)}`);if(P.length>0){console.log();for(let X of P)console.log(` ${Y(X)}`)}}console.log();var T=null;try{let X=z.env.HOME?`${z.env.HOME}/Code/Tools/craft/packages/typescript/src/index.ts`:void 0;({createApp:T}=X&&j(X)?await import(X):await import("../../chunk-5dfz9en9.js"))}catch{try{({createApp:T}=await import("@craft-native/craft"))}catch{try{({createApp:T}=await import("@stacksjs/ts-craft"))}catch{}}}if(T){let X=D("resources/assets/images/app-icon.png"),O=U("framework/defaults/resources/assets/images/app-icon.png"),G=await Bun.file(X).exists()?X:await Bun.file(O).exists()?O:void 0,W=(()=>{let Z=z.env.CRAFT_BIN;if(Z)return j(Z)?Z:void 0;let A=`${z.env.HOME}/Code/Tools/craft/craft`;if(j(A))return A;let H=`${z.env.HOME}/Code/Tools/craft/bin/craft`;if(j(H))return H;let L=`${z.env.HOME}/Code/Tools/craft/packages/zig/zig-out/bin/craft`;if(j(L))return L;let B=`${z.env.HOME}/Documents/Projects/craft/packages/zig/zig-out/bin/craft`;if(j(B))return B;return})();if(!W)T=null;if(!T)console.log(` ${Y("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
6
+ `),await new Promise(()=>{});let M=T({url:o,quiet:!V,...W&&{craftPath:W},window:{title:"Stacks Dashboard",width:1400,height:900,titlebarHidden:!0,nativeSidebar:!0,sidebarWidth:240,sidebarConfig:a,...G&&{icon:G}}});z.on("SIGINT",()=>{M.close(),z.exit(0)}),z.on("SIGTERM",()=>{M.close(),z.exit(0)});try{await M.show(),z.exit(0)}catch{let Z=v||g;console.log(` ${Y("Dashboard available at:")} ${x(Z)}
7
+ `),await new Promise(()=>{})}}else console.log(` ${Y("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
8
+ `),z.on("SIGINT",()=>z.exit(0)),z.on("SIGTERM",()=>z.exit(0)),await new Promise(()=>{});
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{projectPath as r}from"@stacksjs/path";import{startServer as t}from"@stacksjs/bunpress";var o=Number(process.env.PORT_DOCS)||3006;await t({port:o,root:r("docs"),watch:!0,quiet:!0});
2
+ import{overridesReady as n,config as r,docs as e}from"@stacksjs/config";import{projectPath as o}from"@stacksjs/path";import{startServer as c}from"@stacksjs/bunpress";await n;var a=Number(process.env.PORT_DOCS)||r.ports?.docs||3006,i=String(process.env.APP_URL||r.app?.url||""),s=i.replace(/^https?:\/\//,"").replace(/\/$/,""),p=s&&s!=="localhost"&&!s.includes(":"),t=p?`https://${s}/docs`:void 0,d={verbose:!1,docsDir:o("docs"),outDir:o("dist/docs"),...e,...t&&{sitemap:{...e.sitemap,baseUrl:t}}};await c({port:a,root:o("docs"),watch:!0,quiet:!0,config:d});
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{ia as a,ja as b,ka as c,la as d,ma as e,na as f,oa as g,pa as h,qa as i}from"../../chunk-h0hfqr1p.js";import"../../chunk-s735m9mg.js";import"../../chunk-sxp97zys.js";import"../../chunk-jbvvb45k.js";export{g as runSystemTrayDevServer,b as runFrontendDevServer,i as runDocsDevServer,a as runDevServer,h as runDesktopDevServer,f as runDashboardDevServer,e as runComponentsDevServer,c as runBackendDevServer,d as runApiDevServer};
2
+ import{Da as a,Ea as b,Fa as c,Ga as d,Ha as e,Ia as f,Ja as g,Ka as h,La as i}from"../../chunk-ny1racy0.js";import"../../chunk-s735m9mg.js";import"../../chunk-rzhs51h1.js";import"../../chunk-4qzb8g3z.js";export{g as runSystemTrayDevServer,b as runFrontendDevServer,i as runDocsDevServer,a as runDevServer,h as runDesktopDevServer,f as runDashboardDevServer,e as runComponentsDevServer,c as runBackendDevServer,d as runApiDevServer};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{pb as R}from"../../chunk-4qzb8g3z.js";import{existsSync as T,watch as U}from"fs";import V from"process";import{log as E}from"@stacksjs/logging";import{path as N}from"@stacksjs/path";var F,J=!1,K=!1;function _(){if(["0","false","off"].includes(String(V.env.STACKS_DEV_AUTO_MIGRATE).toLowerCase()))return;let A=[N.userModelsPath(""),N.storagePath("framework/models")].filter((z)=>{try{return T(z)}catch{return!1}});if(A.length===0)return;let I=(z)=>{if(z&&!z.endsWith(".ts"))return;if(F)clearTimeout(F);F=setTimeout(()=>void O(),400)},G=0;for(let z of A)try{U(z,{recursive:!0},(B,H)=>I(H)),G+=1}catch(B){E.debug(`[dev] model watch failed for ${z}: ${B instanceof Error?B.message:String(B)}`)}if(G>0)E.debug("[dev] auto-migrate watcher active \u2014 model edits will sync the database")}async function O(){if(J){K=!0;return}J=!0;try{let{previewPendingMigrations:A,generateMigrations:I,runDatabaseMigration:G}=await import("@stacksjs/database"),z=await A();if(z.length===0)return;let B=z.filter((Q)=>Q.destructive);if(B.length>0){E.warn(`[dev] ${B.length} destructive schema change${B.length===1?"":"s"} detected \u2014 not auto-applied. Run \`buddy migrate\` to review and apply.`);return}E.info(`[dev] Syncing database to models (${z.length} change${z.length===1?"":"s"})...`);let H=await I();if(H.isErr){E.error("[dev] auto-migrate: generation failed",H.error);return}let L=await G();if(L.isErr){E.error("[dev] auto-migrate: apply failed",L.error);return}E.success("[dev] Database is in sync with your models.")}catch(A){E.warn(`[dev] auto-migrate skipped: ${A instanceof Error?A.message:String(A)}`)}finally{if(J=!1,K){if(K=!1,F)clearTimeout(F);F=setTimeout(()=>void O(),400)}}}export{_ as startModelMigrationWatcher};