@stacksjs/actions 0.70.87 → 0.70.88

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 (284) hide show
  1. package/package.json +16 -16
  2. package/dist/action.d.ts +0 -149
  3. package/dist/action.js +0 -2
  4. package/dist/actions.d.ts +0 -2
  5. package/dist/actions.js +0 -2
  6. package/dist/add.d.ts +0 -6
  7. package/dist/add.js +0 -2
  8. package/dist/ai/request-model-access.d.ts +0 -1
  9. package/dist/ai/request-model-access.js +0 -2
  10. package/dist/auth/client.d.ts +0 -1
  11. package/dist/auth/client.js +0 -3
  12. package/dist/auth/prune.d.ts +0 -1
  13. package/dist/auth/prune.js +0 -2
  14. package/dist/auth/setup.d.ts +0 -1
  15. package/dist/auth/setup.js +0 -206
  16. package/dist/auth/token.d.ts +0 -1
  17. package/dist/auth/token.js +0 -2
  18. package/dist/blog.d.ts +0 -19
  19. package/dist/blog.js +0 -148
  20. package/dist/build/cli.d.ts +0 -1
  21. package/dist/build/cli.js +0 -2
  22. package/dist/build/component-libs.d.ts +0 -1
  23. package/dist/build/component-libs.js +0 -2
  24. package/dist/build/core.d.ts +0 -1
  25. package/dist/build/core.js +0 -2
  26. package/dist/build/desktop.d.ts +0 -1
  27. package/dist/build/desktop.js +0 -2
  28. package/dist/build/docs.d.ts +0 -1
  29. package/dist/build/docs.js +0 -2
  30. package/dist/build/frontend-static.d.ts +0 -16
  31. package/dist/build/frontend-static.js +0 -9
  32. package/dist/build/server.d.ts +0 -1
  33. package/dist/build/server.js +0 -2
  34. package/dist/build/stacks.d.ts +0 -1
  35. package/dist/build/stacks.js +0 -2
  36. package/dist/build/views.d.ts +0 -1
  37. package/dist/build/views.js +0 -2
  38. package/dist/build.d.ts +0 -9
  39. package/dist/build.js +0 -2
  40. package/dist/bump.d.ts +0 -1
  41. package/dist/bump.js +0 -8
  42. package/dist/cdn/invalidate-cache.d.ts +0 -1
  43. package/dist/cdn/invalidate-cache.js +0 -1
  44. package/dist/changelog.d.ts +0 -9
  45. package/dist/changelog.js +0 -3
  46. package/dist/check/ports.d.ts +0 -1
  47. package/dist/check/ports.js +0 -2
  48. package/dist/chunk-0c8sd1t6.js +0 -2
  49. package/dist/chunk-0g2nzhx9.js +0 -240
  50. package/dist/chunk-0gadhvn7.js +0 -3
  51. package/dist/chunk-0h27aa4r.js +0 -93
  52. package/dist/chunk-3peh8kqs.js +0 -851
  53. package/dist/chunk-62gdfav8.js +0 -3
  54. package/dist/chunk-6bk53y02.js +0 -3
  55. package/dist/chunk-78c5n3s2.js +0 -3
  56. package/dist/chunk-c74qv38e.js +0 -17
  57. package/dist/chunk-cdk2r2jd.js +0 -1
  58. package/dist/chunk-dbz9dp2h.js +0 -3
  59. package/dist/chunk-e142dheq.js +0 -3
  60. package/dist/chunk-ec4gky40.js +0 -3
  61. package/dist/chunk-h3d81wrg.js +0 -3
  62. package/dist/chunk-m3q0x4h0.js +0 -688
  63. package/dist/chunk-mqgbyhph.js +0 -5
  64. package/dist/chunk-n24m8prb.js +0 -3
  65. package/dist/chunk-n5eqwhck.js +0 -7
  66. package/dist/chunk-nsvnqv8y.js +0 -5
  67. package/dist/chunk-nty6mmx4.js +0 -283
  68. package/dist/chunk-s735m9mg.js +0 -1
  69. package/dist/chunk-tpb8jgsk.js +0 -7
  70. package/dist/chunk-tsbk5vne.js +0 -3
  71. package/dist/chunk-xg9xscqz.js +0 -1
  72. package/dist/chunk-y6e448he.js +0 -7
  73. package/dist/clean.d.ts +0 -1
  74. package/dist/clean.js +0 -2
  75. package/dist/commit.d.ts +0 -3
  76. package/dist/commit.js +0 -2
  77. package/dist/copy-types.d.ts +0 -1
  78. package/dist/copy-types.js +0 -3
  79. package/dist/database/seed.d.ts +0 -1
  80. package/dist/database/seed.js +0 -2
  81. package/dist/deploy/create-receipt-rule.d.ts +0 -1
  82. package/dist/deploy/create-receipt-rule.js +0 -2
  83. package/dist/deploy/index.d.ts +0 -1
  84. package/dist/deploy/index.js +0 -300
  85. package/dist/dev/api.d.ts +0 -1
  86. package/dist/dev/api.js +0 -6
  87. package/dist/dev/components.d.ts +0 -1
  88. package/dist/dev/components.js +0 -2
  89. package/dist/dev/dashboard-globals.d.ts +0 -4
  90. package/dist/dev/dashboard-globals.js +0 -3
  91. package/dist/dev/dashboard-utils.d.ts +0 -150
  92. package/dist/dev/dashboard-utils.js +0 -2
  93. package/dist/dev/dashboard.d.ts +0 -22
  94. package/dist/dev/dashboard.js +0 -8
  95. package/dist/dev/desktop.d.ts +0 -1
  96. package/dist/dev/desktop.js +0 -2
  97. package/dist/dev/docs.d.ts +0 -1
  98. package/dist/dev/docs.js +0 -2
  99. package/dist/dev/index.d.ts +0 -10
  100. package/dist/dev/index.js +0 -2
  101. package/dist/dev/migrate-watcher.d.ts +0 -1
  102. package/dist/dev/migrate-watcher.js +0 -2
  103. package/dist/dev/system-tray.d.ts +0 -1
  104. package/dist/dev/system-tray.js +0 -2
  105. package/dist/dev/views.d.ts +0 -1
  106. package/dist/dev/views.js +0 -2
  107. package/dist/discover-packages.d.ts +0 -18
  108. package/dist/discover-packages.js +0 -2
  109. package/dist/domains/add.d.ts +0 -1
  110. package/dist/domains/add.js +0 -2
  111. package/dist/domains/purchase.d.ts +0 -1
  112. package/dist/domains/purchase.js +0 -2
  113. package/dist/domains/remove.d.ts +0 -1
  114. package/dist/domains/remove.js +0 -2
  115. package/dist/examples.d.ts +0 -5
  116. package/dist/examples.js +0 -2
  117. package/dist/find-projects.d.ts +0 -1
  118. package/dist/find-projects.js +0 -2
  119. package/dist/fresh.d.ts +0 -1
  120. package/dist/fresh.js +0 -2
  121. package/dist/generate/action-types.d.ts +0 -1
  122. package/dist/generate/action-types.js +0 -8
  123. package/dist/generate/component-meta.d.ts +0 -1
  124. package/dist/generate/component-meta.js +0 -3
  125. package/dist/generate/custom-cli-file.d.ts +0 -1
  126. package/dist/generate/custom-cli-file.js +0 -4
  127. package/dist/generate/env-files.d.ts +0 -1
  128. package/dist/generate/env-files.js +0 -26
  129. package/dist/generate/ide-helpers.d.ts +0 -1
  130. package/dist/generate/ide-helpers.js +0 -3
  131. package/dist/generate/index.d.ts +0 -36
  132. package/dist/generate/index.js +0 -2
  133. package/dist/generate/lib-entries.d.ts +0 -1
  134. package/dist/generate/lib-entries.js +0 -3
  135. package/dist/generate/pantry-file.d.ts +0 -1
  136. package/dist/generate/pantry-file.js +0 -2
  137. package/dist/generate/symlink-core.d.ts +0 -1
  138. package/dist/generate/symlink-core.js +0 -2
  139. package/dist/generate/types.d.ts +0 -1
  140. package/dist/generate/types.js +0 -2
  141. package/dist/generate/vscode-custom-data.d.ts +0 -1
  142. package/dist/generate/vscode-custom-data.js +0 -3
  143. package/dist/generate/web-types.d.ts +0 -1
  144. package/dist/generate/web-types.js +0 -1
  145. package/dist/helpers/component-meta.d.ts +0 -26
  146. package/dist/helpers/component-meta.js +0 -2
  147. package/dist/helpers/index.d.ts +0 -4
  148. package/dist/helpers/index.js +0 -2
  149. package/dist/helpers/lib-entries.d.ts +0 -12
  150. package/dist/helpers/lib-entries.js +0 -2
  151. package/dist/helpers/package-json.d.ts +0 -2
  152. package/dist/helpers/package-json.js +0 -43
  153. package/dist/helpers/utils.d.ts +0 -23
  154. package/dist/helpers/utils.js +0 -2
  155. package/dist/helpers/vscode-custom-data.d.ts +0 -3
  156. package/dist/helpers/vscode-custom-data.js +0 -2
  157. package/dist/index.d.ts +0 -49
  158. package/dist/index.js +0 -2
  159. package/dist/key-generate.d.ts +0 -1
  160. package/dist/key-generate.js +0 -2
  161. package/dist/lint/fix.d.ts +0 -1
  162. package/dist/lint/fix.js +0 -3
  163. package/dist/lint/index.d.ts +0 -1
  164. package/dist/lint/index.js +0 -3
  165. package/dist/lint/lint.d.ts +0 -14
  166. package/dist/lint/lint.js +0 -2
  167. package/dist/make-command.d.ts +0 -10
  168. package/dist/make-command.js +0 -45
  169. package/dist/make-job.d.ts +0 -5
  170. package/dist/make-job.js +0 -129
  171. package/dist/make-policy.d.ts +0 -10
  172. package/dist/make-policy.js +0 -94
  173. package/dist/make-resource.d.ts +0 -10
  174. package/dist/make-resource.js +0 -113
  175. package/dist/make.d.ts +0 -52
  176. package/dist/make.js +0 -2
  177. package/dist/migrate/database.d.ts +0 -1
  178. package/dist/migrate/database.js +0 -2
  179. package/dist/migrate/fresh.d.ts +0 -1
  180. package/dist/migrate/fresh.js +0 -2
  181. package/dist/orm/base.d.ts +0 -1
  182. package/dist/orm/base.js +0 -2
  183. package/dist/orm/test.d.ts +0 -1
  184. package/dist/orm/test.js +0 -1
  185. package/dist/prepublish.d.ts +0 -1
  186. package/dist/prepublish.js +0 -2
  187. package/dist/queue/clear.d.ts +0 -1
  188. package/dist/queue/clear.js +0 -2
  189. package/dist/queue/dlq-purge.d.ts +0 -1
  190. package/dist/queue/dlq-purge.js +0 -2
  191. package/dist/queue/dlq-retry.d.ts +0 -1
  192. package/dist/queue/dlq-retry.js +0 -2
  193. package/dist/queue/dlq.d.ts +0 -1
  194. package/dist/queue/dlq.js +0 -5
  195. package/dist/queue/failed.d.ts +0 -1
  196. package/dist/queue/failed.js +0 -5
  197. package/dist/queue/flush.d.ts +0 -1
  198. package/dist/queue/flush.js +0 -3
  199. package/dist/queue/inspect.d.ts +0 -1
  200. package/dist/queue/inspect.js +0 -8
  201. package/dist/queue/list.d.ts +0 -1
  202. package/dist/queue/list.js +0 -5
  203. package/dist/queue/monitor.d.ts +0 -1
  204. package/dist/queue/monitor.js +0 -7
  205. package/dist/queue/pause.d.ts +0 -1
  206. package/dist/queue/pause.js +0 -2
  207. package/dist/queue/quarantine.d.ts +0 -1
  208. package/dist/queue/quarantine.js +0 -3
  209. package/dist/queue/resume.d.ts +0 -1
  210. package/dist/queue/resume.js +0 -2
  211. package/dist/queue/retry.d.ts +0 -1
  212. package/dist/queue/retry.js +0 -2
  213. package/dist/queue/schedule-list.d.ts +0 -1
  214. package/dist/queue/schedule-list.js +0 -5
  215. package/dist/queue/schedule.d.ts +0 -1
  216. package/dist/queue/schedule.js +0 -2
  217. package/dist/queue/status.d.ts +0 -1
  218. package/dist/queue/status.js +0 -5
  219. package/dist/queue/table.d.ts +0 -1
  220. package/dist/queue/table.js +0 -2
  221. package/dist/queue/unquarantine.d.ts +0 -1
  222. package/dist/queue/unquarantine.js +0 -2
  223. package/dist/queue/work.d.ts +0 -1
  224. package/dist/queue/work.js +0 -2
  225. package/dist/release.d.ts +0 -1
  226. package/dist/release.js +0 -3
  227. package/dist/route/list.d.ts +0 -1
  228. package/dist/route/list.js +0 -3
  229. package/dist/run-action.d.ts +0 -2
  230. package/dist/run-action.js +0 -2
  231. package/dist/saas/setup.d.ts +0 -1
  232. package/dist/saas/setup.js +0 -2
  233. package/dist/scaffold-crud.d.ts +0 -25
  234. package/dist/scaffold-crud.js +0 -87
  235. package/dist/schedule/run.d.ts +0 -1
  236. package/dist/schedule/run.js +0 -2
  237. package/dist/search/flush.d.ts +0 -1
  238. package/dist/search/flush.js +0 -2
  239. package/dist/search/import.d.ts +0 -1
  240. package/dist/search/import.js +0 -2
  241. package/dist/search/settings-list.d.ts +0 -1
  242. package/dist/search/settings-list.js +0 -2
  243. package/dist/search/settings.d.ts +0 -1
  244. package/dist/search/settings.js +0 -2
  245. package/dist/serve/api.d.ts +0 -1
  246. package/dist/serve/api.js +0 -2
  247. package/dist/setup/index.d.ts +0 -1
  248. package/dist/setup/index.js +0 -2
  249. package/dist/setup/ssl.d.ts +0 -38
  250. package/dist/setup/ssl.js +0 -2
  251. package/dist/stacks.d.ts +0 -4
  252. package/dist/stacks.js +0 -2
  253. package/dist/templates.d.ts +0 -28
  254. package/dist/templates.js +0 -2
  255. package/dist/test/feature.d.ts +0 -1
  256. package/dist/test/feature.js +0 -2
  257. package/dist/test/index.d.ts +0 -1
  258. package/dist/test/index.js +0 -2
  259. package/dist/test/ui.d.ts +0 -1
  260. package/dist/test/ui.js +0 -2
  261. package/dist/test/unit.d.ts +0 -1
  262. package/dist/test/unit.js +0 -2
  263. package/dist/typecheck.d.ts +0 -1
  264. package/dist/typecheck.js +0 -2
  265. package/dist/types.d.ts +0 -3
  266. package/dist/types.js +0 -2
  267. package/dist/upgrade/binary.d.ts +0 -1
  268. package/dist/upgrade/binary.js +0 -2
  269. package/dist/upgrade/bun.d.ts +0 -1
  270. package/dist/upgrade/bun.js +0 -1
  271. package/dist/upgrade/dependencies.d.ts +0 -1
  272. package/dist/upgrade/dependencies.js +0 -2
  273. package/dist/upgrade/framework-utils.d.ts +0 -150
  274. package/dist/upgrade/framework-utils.js +0 -2
  275. package/dist/upgrade/framework.d.ts +0 -1
  276. package/dist/upgrade/framework.js +0 -7
  277. package/dist/upgrade/index.d.ts +0 -1
  278. package/dist/upgrade/index.js +0 -2
  279. package/dist/upgrade/packages.d.ts +0 -14
  280. package/dist/upgrade/packages.js +0 -12
  281. package/dist/upgrade/shell.d.ts +0 -1
  282. package/dist/upgrade/shell.js +0 -5
  283. package/dist/upgrade.d.ts +0 -7
  284. package/dist/upgrade.js +0 -2
@@ -1,300 +0,0 @@
1
- // @bun
2
- import{Lb as Z}from"../chunk-h3d81wrg.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"?>
8
- <DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
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-0h27aa4r.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";
13
- import { SESClient } from "./ts-cloud-dist.js";
14
-
15
- const db = new Database("/var/www/api/stacks.db");
16
- db.run(\`CREATE TABLE IF NOT EXISTS subscribers (
17
- id INTEGER PRIMARY KEY AUTOINCREMENT,
18
- email TEXT NOT NULL UNIQUE,
19
- status TEXT DEFAULT 'subscribed',
20
- source TEXT DEFAULT 'homepage',
21
- created_at TEXT DEFAULT CURRENT_TIMESTAMP
22
- )\`);
23
-
24
- const CORS_HEADERS = {
25
- "Access-Control-Allow-Origin": "*",
26
- "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
27
- "Access-Control-Allow-Headers": "Content-Type",
28
- };
29
-
30
- const ses = new SESClient("${Q}");
31
-
32
- async function readBody(req) {
33
- const contentType = req.headers.get("content-type") || "";
34
-
35
- if (contentType.includes("application/json")) {
36
- return await req.json();
37
- }
38
-
39
- if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
40
- const form = await req.formData();
41
- return Object.fromEntries(form.entries());
42
- }
43
-
44
- const text = await req.text();
45
- return Object.fromEntries(new URLSearchParams(text));
46
- }
47
-
48
- async function sendWelcomeEmail(email) {
49
- try {
50
- await ses.sendSimpleEmail({
51
- from: "hello@stacksjs.com",
52
- to: email,
53
- subject: "Welcome to Stacks!",
54
- html: \`<!DOCTYPE html>
55
- <html>
56
- <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
57
- <body style="margin:0;padding:0;background-color:#0e0e0e;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;">
58
- <table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width:600px;margin:0 auto;padding:40px 20px;">
59
- <tr><td style="text-align:center;padding-bottom:32px;"><h1 style="color:#ececec;font-size:28px;font-weight:600;margin:0;">Stacks</h1></td></tr>
60
- <tr><td style="background-color:#1a1a1a;border-radius:12px;padding:32px;">
61
- <h2 style="color:#ececec;font-size:22px;font-weight:600;margin:0 0 16px;">Welcome aboard!</h2>
62
- <p style="color:#a0a0a0;font-size:16px;line-height:1.6;margin:0 0 16px;">Thanks for subscribing to Stacks. You will be the first to know about new releases, features, and updates.</p>
63
- <p style="color:#a0a0a0;font-size:16px;line-height:1.6;margin:0 0 24px;">Stacks is a rapid application development framework that helps you build type-safe web apps, APIs, and cloud infrastructure with ease.</p>
64
- <a href="https://stacksjs.com" style="display:inline-block;background-color:#6366f1;color:#ffffff;text-decoration:none;padding:12px 24px;border-radius:8px;font-size:14px;font-weight:500;">Visit Stacks</a>
65
- </td></tr>
66
- <tr><td style="text-align:center;padding-top:32px;"><p style="color:#666;font-size:13px;margin:0;">You received this email because you subscribed at stacksjs.com</p></td></tr>
67
- </table>
68
- </body>
69
- </html>\`,
70
- text: "Welcome to Stacks! Thanks for subscribing. You will be the first to know about new releases, features, and updates. Visit us at https://stacksjs.com",
71
- });
72
- console.log(\`Welcome email sent to \${email}\`);
73
- } catch (err) {
74
- console.error(\`Failed to send welcome email to \${email}:\`, err.message);
75
- }
76
- }
77
-
78
- const server = Bun.serve({
79
- port: ${P},
80
- hostname: "0.0.0.0",
81
- async fetch(req) {
82
- const url = new URL(req.url);
83
-
84
- if (req.method === "OPTIONS") {
85
- return new Response(null, { status: 204, headers: CORS_HEADERS });
86
- }
87
-
88
- if (url.pathname === "/health" || url.pathname === "/api/health") {
89
- return Response.json({ status: "ok" }, { headers: CORS_HEADERS });
90
- }
91
-
92
- if (url.pathname === "/api/email/subscribe" && req.method === "POST") {
93
- try {
94
- const body = await readBody(req);
95
- const email = (body.email || "").trim().toLowerCase();
96
- if (!email || !email.includes("@")) {
97
- return Response.json(
98
- { success: false, message: "A valid email is required" },
99
- { status: 400, headers: CORS_HEADERS },
100
- );
101
- }
102
-
103
- const existing = db.query("SELECT id FROM subscribers WHERE email = ?").get(email);
104
- if (existing) {
105
- return Response.json(
106
- { success: true, message: "Already subscribed" },
107
- { headers: CORS_HEADERS },
108
- );
109
- }
110
-
111
- db.run("INSERT INTO subscribers (email, source) VALUES (?, ?)", [email, body.source || "homepage"]);
112
-
113
- // Send welcome email asynchronously (do not block the response)
114
- sendWelcomeEmail(email);
115
-
116
- return Response.json(
117
- { success: true, message: "Thanks for subscribing!" },
118
- { headers: CORS_HEADERS },
119
- );
120
- } catch (e) {
121
- return Response.json(
122
- { success: false, message: "Server error" },
123
- { status: 500, headers: CORS_HEADERS },
124
- );
125
- }
126
- }
127
-
128
- return Response.json({ error: "Not found" }, { status: 404, headers: CORS_HEADERS });
129
- },
130
- });
131
-
132
- console.log(\`Stacks API server running on port \${server.port}\`);
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'
134
- [Unit]
135
- Description=Stacks Bun API Server
136
- After=network.target
137
-
138
- [Service]
139
- Type=simple
140
- WorkingDirectory=/var/www/api
141
- ExecStart=/root/.bun/bin/bun server.ts
142
- Restart=on-failure
143
- RestartSec=5
144
- Environment=NODE_ENV=production
145
-
146
- [Install]
147
- WantedBy=multi-user.target
148
- SERVICEFILE
149
- systemctl daemon-reload
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'
151
- SMTP_PROFILE=production
152
- SMTP_HOST=0.0.0.0
153
- SMTP_PORT=25
154
- SMTP_HOSTNAME=${h}.${D}
155
- SMTP_ENABLE_TLS=false
156
- SMTP_ENABLE_AUTH=true
157
- SMTP_DB_PATH=/var/lib/smtp-server/smtp.db
158
- AWS_S3_BUCKET=${v}
159
- AWS_REGION=${Q}
160
- SMTP_ENABLE_JSON_LOGGING=true
161
- SMTP_LOG_LEVEL=info
162
- SMTP_MAILBOX_PATH=/var/spool/mail
163
- SMTP_BACKUP_PATH=/var/lib/smtp-server/backups
164
- SMTP_MAX_CONNECTIONS=1000
165
- SMTP_MAX_MESSAGE_SIZE=52428800
166
- SMTP_MAX_RECIPIENTS=100
167
- SMTP_RATE_LIMIT_PER_IP=100
168
- SMTP_RATE_LIMIT_PER_USER=200
169
- SMTP_IO_MODE=epoll
170
- ENVEOF`,"chmod 600 /etc/smtp-server/smtp-server.env",`cat > /etc/systemd/system/smtp-server.service << 'SVCEOF'
171
- [Unit]
172
- Description=Stacks Mail Server (Zig)
173
- After=network.target
174
-
175
- [Service]
176
- Type=simple
177
- WorkingDirectory=/opt/smtp-server
178
- EnvironmentFile=/etc/smtp-server/smtp-server.env
179
- ExecStart=/opt/smtp-server/smtp-server
180
- Restart=always
181
- RestartSec=10
182
- StandardOutput=journal
183
- StandardError=journal
184
- SyslogIdentifier=smtp-server
185
-
186
- [Install]
187
- WantedBy=multi-user.target
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";
190
- import * as fs from "fs";
191
- const domain = "${D}";
192
- const users = { ${zJ} };
193
- const certDir = \`/etc/letsencrypt/live/mail.\${domain}\`;
194
- let tlsConfig = undefined;
195
- if (fs.existsSync(\`\${certDir}/privkey.pem\`)) {
196
- tlsConfig = { key: \`\${certDir}/privkey.pem\`, cert: \`\${certDir}/fullchain.pem\` };
197
- }
198
- const server = new SmtpServer({ port: 587, tlsPort: 465, host: "0.0.0.0", domain, users, tls: tlsConfig, sentBucket: "${G}-production-email", sentPrefix: "sent/" });
199
- await server.start();
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'
202
- [Unit]
203
- Description=Stacks SMTP Proxy Server
204
- After=network.target
205
- [Service]
206
- Type=simple
207
- WorkingDirectory=/var/www/smtp
208
- ExecStart=/root/.bun/bin/bun smtp-entry.ts
209
- Restart=on-failure
210
- RestartSec=5
211
- Environment=NODE_ENV=production
212
- Environment=AWS_REGION=${Q}
213
- ${e}
214
- [Install]
215
- WantedBy=multi-user.target
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"?>
217
- <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
218
- <CallerReference>${Date.now()}</CallerReference>
219
- <Paths>
220
- <Quantity>1</Quantity>
221
- <Items>
222
- <Path>/*</Path>
223
- </Items>
224
- </Paths>
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"?>
226
- <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
227
- <CallerReference>docs-${Date.now()}</CallerReference>
228
- <Paths>
229
- <Quantity>${L.length}</Quantity>
230
- <Items>
231
- ${L.map((j)=>`<Path>${j}</Path>`).join(`
232
- `)}
233
- </Items>
234
- </Paths>
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"?>
236
- <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
237
- <CallerReference>blog-${Date.now()}</CallerReference>
238
- <Paths>
239
- <Quantity>${O.length}</Quantity>
240
- <Items>
241
- ${O.map((L)=>`<Path>${L}</Path>`).join(`
242
- `)}
243
- </Items>
244
- </Paths>
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>
246
- <html lang="en">
247
- <head>
248
- <meta charset="UTF-8">
249
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
250
- <title>404 - Page Not Found</title>
251
- <meta name="robots" content="noindex">
252
- <style>
253
- :root {
254
- --vp-c-bg: #ffffff;
255
- --vp-c-divider: #e2e2e3;
256
- --vp-c-text-1: rgba(60, 60, 67);
257
- --vp-c-text-2: rgba(60, 60, 67, 0.78);
258
- --vp-c-brand-1: #3451b2;
259
- --vp-c-brand-2: #3a5ccc;
260
- }
261
- @media (prefers-color-scheme: dark) {
262
- :root {
263
- --vp-c-bg: #1b1b1f;
264
- --vp-c-divider: #2e2e32;
265
- --vp-c-text-1: rgba(255, 255, 245, 0.86);
266
- --vp-c-text-2: rgba(235, 235, 245, 0.6);
267
- --vp-c-brand-1: #a8b1ff;
268
- --vp-c-brand-2: #5c73e7;
269
- }
270
- }
271
- * { margin: 0; padding: 0; box-sizing: border-box; }
272
- body { min-height: 100vh; background: var(--vp-c-bg); color: var(--vp-c-text-1); font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
273
- .NotFound { padding: 96px 32px 168px; text-align: center; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; }
274
- .code { font-size: 64px; font-weight: 600; line-height: 64px; }
275
- .title { padding-top: 12px; letter-spacing: 2px; font-size: 20px; font-weight: 700; }
276
- .divider { margin: 24px auto 18px; width: 64px; height: 1px; background: var(--vp-c-divider); }
277
- .quote { max-width: 256px; font-size: 14px; font-weight: 500; color: var(--vp-c-text-2); }
278
- .action { padding-top: 20px; }
279
- .link { display: inline-block; border: 1px solid var(--vp-c-brand-1); border-radius: 16px; padding: 3px 16px; font-size: 14px; font-weight: 500; color: var(--vp-c-brand-1); text-decoration: none; transition: border-color 0.25s, color 0.25s; }
280
- .link:hover { border-color: var(--vp-c-brand-2); color: var(--vp-c-brand-2); }
281
- </style>
282
- </head>
283
- <body>
284
- <div class="NotFound">
285
- <p class="code">404</p>
286
- <h1 class="title">PAGE NOT FOUND</h1>
287
- <div class="divider"></div>
288
- <blockquote class="quote">But if you don't change your direction, and if you keep looking, you may end up where you are heading.</blockquote>
289
- <div class="action"><a class="link" href="/docs/">Take me home</a></div>
290
- </div>
291
- </body>
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"?>
298
- <DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
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)}
package/dist/dev/api.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/dev/api.js DELETED
@@ -1,6 +0,0 @@
1
- // @bun
2
- import{Lb as K}from"../chunk-h3d81wrg.js";import{existsSync as L}from"fs";import N from"process";import{parseOptions as Q}from"@stacksjs/cli";import{config as T,overridesReady as U}from"@stacksjs/config";import{path as V}from"@stacksjs/path";import{route as X}from"@stacksjs/router";import{generateAutoImportFiles as W,injectGlobalAutoImports as F}from"@stacksjs/server";var x=Q();await U;var $=Number(N.env.PORT_API)||T.ports?.api||3008,R=V.storagePath("framework/auto-imports/models.ts");if(!L(R))await W();await F();try{let z=V.appPath("Lib/typesense-dev.ts");if(L(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=V.appPath("Listener.ts");if(L(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}`)}function _(){let z=V.frameworkPath("defaults/app/Middleware/Cors.ts");if(L(z))return z;try{return`${Bun.resolveSync("@stacksjs/defaults/package.json",N.cwd()).replace(/package\.json$/,"")}app/Middleware/Cors.ts`}catch{return z}}var w=await import(_()),A=w.default;X.use(A.toRouterHandler());var E=/^[a-zA-Z0-9._-]{8,128}$/;X.use(async(z,B)=>{let Y=z?.headers?.get?.("x-request-id")||z?.headers?.get?.("X-Request-ID")||"",Z=typeof Y==="string"&&E.test(Y)?Y:crypto.randomUUID();z._requestId=Z,z._startNs=N.hrtime.bigint();let H=await B();if(H&&H.status===404&&(H.headers.get("content-type")||"").includes("json"))try{let J=await H.clone().json();if(J&&(J.message==="Not Found"||J.error==="Not Found")){let G=new URL(z.url),O={...J,path:G.pathname,method:z.method,request_id:Z},C=new Headers(H.headers);return C.set("X-Request-ID",Z),new Response(JSON.stringify(O),{status:404,headers:C})}}catch{}return H});await X.importRoutes();try{await X.serve({port:$,hostname:"127.0.0.1"}),console.log(`
3
- \u279C API server ready: http://localhost:${$}
4
- `)}catch(z){if((z?.code||z?.errno)==="EADDRINUSE"||String(z?.message||"").includes("EADDRINUSE"))console.error(`
5
- [dev/api] Port ${$} 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}
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{parseOptions as f,runCommand as q}from"@stacksjs/cli";import{libsPath as w}from"@stacksjs/path";var x=f();await q("bun run dev",{...x,cwd:w("components/vue")});
@@ -1,4 +0,0 @@
1
- export declare function hoistDashboardGlobals(opts?: HoistOptions): Promise<void>;
2
- declare interface HoistOptions {
3
- verbose?: boolean
4
- }
@@ -1,3 +0,0 @@
1
- // @bun
2
- import"../chunk-h3d81wrg.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
- `)}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,150 +0,0 @@
1
- import type { DashboardModelOptions } from '@stacksjs/types';
2
- /** Convert PascalCase model name to kebab-case ID */
3
- export declare function modelNameToId(name: string): string;
4
- /** Get the icon for a model name, falling back to the default */
5
- export declare function getModelIcon(name: string): string;
6
- /** Scan a directory for model files and add them to the models array */
7
- export declare function scanModelsDir(dir: string, seenNames: Set<string>, models: DiscoveredModel[], defaultCategory?: ModelCategory): Promise<void>;
8
- /** Discover models from both user and default directories */
9
- export declare function discoverModels(userModelsPath: string, defaultModelsPath: string): Promise<DiscoveredModel[]>;
10
- /** Build the manifest array for discovered models */
11
- export declare function buildManifest(models: DiscoveredModel[]): DiscoveredModelManifestRow[];
12
- /** Check if a port is available by attempting to listen on it */
13
- export declare function isPortAvailable(port: number): Promise<boolean>;
14
- /** Find an available port starting from the preferred port */
15
- export declare function findAvailablePort(preferred: number, maxAttempts?: number): Promise<number>;
16
- /** Wait for STX server to accept connections */
17
- export declare function waitForServer(port: number, maxWait?: number): Promise<boolean>;
18
- /** Build sidebar config for native sidebar navigation */
19
- export declare function buildSidebarConfig(baseRoute: string, discoveredModels: DiscoveredModel[], toggles?: DashboardSectionToggles): void;
20
- /**
21
- * Build the URL the Craft window opens to. The `native-sidebar=1` query
22
- * param signals the layout that Craft is rendering the sidebar natively,
23
- * so the layout can suppress its own HTML sidebar and let the macOS
24
- * NSOutlineView own that 240px column.
25
- */
26
- export declare function buildDashboardUrl(port: number): string;
27
- /**
28
- * Model name to icon mapping (SF Symbols)
29
- * @defaultValue
30
- * ```ts
31
- * {
32
- * user: 'person.fill',
33
- * team: 'person.2.fill',
34
- * subscriber: 'envelope.open.fill',
35
- * subscriberemail: 'envelope.fill',
36
- * post: 'doc.text.fill',
37
- * page: 'doc.fill',
38
- * product: 'cube.box.fill',
39
- * productvariant: 'cube.fill',
40
- * productunit: 'scalemass.fill',
41
- * order: 'list.clipboard.fill',
42
- * orderitem: 'list.bullet.clipboard.fill',
43
- * customer: 'person.crop.circle.fill',
44
- * payment: 'creditcard.fill',
45
- * paymentmethod: 'creditcard.and.123',
46
- * paymentproduct: 'creditcard.fill',
47
- * paymenttransaction: 'creditcard.fill',
48
- * category: 'tag.fill',
49
- * tag: 'tag',
50
- * comment: 'bubble.left.fill',
51
- * author: 'person.text.rectangle.fill',
52
- * notification: 'bell.fill',
53
- * job: 'briefcase.fill',
54
- * log: 'list.bullet.rectangle.portrait.fill',
55
- * campaign: 'megaphone.fill',
56
- * review: 'star.fill',
57
- * coupon: 'ticket.fill',
58
- * giftcard: 'giftcard.fill',
59
- * cart: 'cart.fill',
60
- * cartitem: 'cart.badge.plus',
61
- * taxrate: 'percent',
62
- * transaction: 'arrow.left.arrow.right.circle.fill',
63
- * subscription: 'repeat.circle.fill',
64
- * emaillist: 'envelope.badge.person.crop',
65
- * socialpost: 'bubble.left.and.bubble.right.fill',
66
- * manufacturer: 'building.2.fill',
67
- * shippingmethod: 'shippingbox.fill',
68
- * shippingzone: 'map.fill',
69
- * shippingrate: 'dollarsign.circle.fill',
70
- * deliveryroute: 'map.fill',
71
- * driver: 'car.fill',
72
- * digitaldelivery: 'arrow.down.doc.fill',
73
- * licensekey: 'key.fill',
74
- * loyaltypoint: 'star.circle.fill',
75
- * loyaltyreward: 'gift.fill',
76
- * printdevice: 'printer.fill',
77
- * receipt: 'doc.text.fill',
78
- * waitlistproduct: 'clock.fill',
79
- * waitlistrestaurant: 'clock.badge.checkmark.fill',
80
- * websocket: 'antenna.radiowaves.left.and.right',
81
- * default: 'tablecells.fill'
82
- * }
83
- * ```
84
- */
85
- export declare const iconMap: Record<string, string>;
86
- // Models excluded from sidebar (already have dedicated pages)
87
- export declare const excludeModels: Set<any>;
88
- // Models that have dedicated dashboard pages
89
- export declare const dedicatedPages: Set<any>;
90
- export declare interface DiscoveredModel {
91
- name: string
92
- icon: string
93
- id: string
94
- category?: ModelCategory
95
- dashboard?: DashboardModelOptions
96
- }
97
- /**
98
- * Manifest row written to `defaults/views/dashboard/.discovered-models.json`
99
- * for the web-side sidebar to consume. Includes the per-model `dashboard`
100
- * config (stacksjs/stacks#1843) so both sidebar builders (the native one
101
- * here and the HTML one in `defaults/resources/functions/dashboard/sidebar.ts`)
102
- * see the same data.
103
- */
104
- export declare interface DiscoveredModelManifestRow {
105
- id: string
106
- name: string
107
- icon: string
108
- hasDedicatedPage: boolean
109
- category: ModelCategory
110
- dashboard?: DashboardModelOptions
111
- }
112
- /**
113
- * Per-section toggles. Read from the project's `config/dashboard.ts` (when
114
- * present) and passed through buildSidebarConfig / buildSidebarNavHtml so the
115
- * commerce / content / marketing sections collapse out of the sidebar entirely
116
- * for projects that don't ship those features. Anything not specified is on.
117
- *
118
- * `data` is a per-row toggle map (instead of a single boolean) because the
119
- * Data section is always relevant — projects just want to hide individual
120
- * basic rows like Subscribers when they're not running a newsletter, while
121
- * still seeing their userland models.
122
- */
123
- export declare interface DashboardSectionToggles {
124
- commerce?: boolean
125
- content?: boolean
126
- marketing?: boolean
127
- analytics?: boolean
128
- management?: boolean
129
- utilities?: boolean
130
- library?: boolean
131
- ci?: boolean
132
- data?: {
133
- dashboard?: boolean
134
- activity?: boolean
135
- users?: boolean
136
- teams?: boolean
137
- subscribers?: boolean
138
- allModels?: boolean
139
- }
140
- }
141
- /**
142
- * Sidebar category each discovered model gets surfaced under.
143
- * - `userland`: model in the project's `app/Models/` (always shown in Data)
144
- * - `data`: framework root-level model that belongs in Data
145
- * - `commerce`: model in framework `commerce/` subdir or commerce-coded root model
146
- * - `content`: model in framework `Content/` subdir or content-coded root model
147
- * - `marketing`: outreach / subscriber-list models grouped under Marketing
148
- * - `system`: framework-internal models (jobs, deployments, requests…) → App
149
- */
150
- export type ModelCategory = 'userland' | 'data' | 'commerce' | 'content' | 'marketing' | 'system';
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{$a as e,Xa as a,Ya as b,Za as c,_a as d,ab as f,bb as g,cb as h,db as i,eb as j,fb as k,gb as l,hb as m}from"../chunk-ec4gky40.js";import"../chunk-h3d81wrg.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,22 +0,0 @@
1
- /* eslint-enable no-console */
2
- // Import Craft dynamically. Its static import triggers bun-router
3
- // config loading which prints warnings before our console.log override is
4
- // active. We also let it be missing — the native window is a nicety, not a
5
- // requirement; the dashboard runs fine as a plain web server in that case.
6
- declare interface CraftApplication {
7
- show: () => Promise<void>
8
- close: () => void
9
- }
10
- // Load dashboard section toggles from `config/dashboard.ts` if present.
11
- // Falls back to "everything enabled" when the file is missing or fails to
12
- // parse, so a fresh project (no dashboard config) still gets the full
13
- // sidebar. Shape mirrors `DashboardSectionToggles` in dashboard-utils.ts.
14
- declare type DataRowToggles = {
15
- dashboard: boolean
16
- activity: boolean
17
- users: boolean
18
- teams: boolean
19
- subscribers: boolean
20
- allModels: boolean
21
- }
22
- declare type CraftCreateApp = (options: Record<string, unknown>) => CraftApplication;
@@ -1,8 +0,0 @@
1
- // @bun
2
- import{bb as m,cb as u,eb as b,fb as n}from"../chunk-ec4gky40.js";import{Lb as A}from"../chunk-h3d81wrg.js";import $ from"process";import{existsSync as j,readFileSync as o,writeFileSync as c}from"fs";import{bold as B,cyan as x,dim as Y,green as k}from"@stacksjs/cli";import{projectPath as T,storagePath as D}from"@stacksjs/path";var p=$.argv.indexOf("--verbose"),F=p!==-1&&$.argv[p+1]!=="false",s=Bun.nanoseconds(),i=console.log,e=console.warn,P=[];console.log=(...X)=>{P.push(X.map(String).join(" "))};console.warn=(...X)=>{P.push(X.map(String).join(" "))};var g=D("framework/defaults/views/dashboard"),EE=T("resources/views/dashboard"),h=Number($.env.PORT_ADMIN)||3002,V=await b(h),S=$.env.APP_URL||"",XE=S!==""&&S!=="localhost"&&!S.includes("localhost:"),y=XE?S.replace(/^https?:\/\//,""):null,C=y?`dashboard.${y}`:null,l=`${$.env.HOME}/.stacks/ssl`;function d(){console.log=i,console.warn=(...X)=>{let O=X.map(String).join(" ");if(O.includes("[STX] DOM API violation")||O.includes("unsafe expression"))return;e(...X)}}async function YE(){try{await import("@stacksjs/orm")}catch(E){if(F)console.warn("[dashboard] orm preload failed:",E?.message||E)}try{let{hoistDashboardGlobals:E}=await import("./dashboard-globals.js");await E({verbose:F})}catch(E){if(F)console.warn("[dashboard] globals preload failed:",E?.message||E)}let X;try{X=(await import("../chunk-0g2nzhx9.js")).serve}catch{X=(await import(T("pantry/bun-plugin-stx/dist/serve.js"))).serve}let O;try{let E=$.env.STX_SRC||`${$.env.HOME}/Code/Tools/stx/packages/stx/src/index.ts`;if(await Bun.file(E).exists())O=await import(E)}catch{}if(O&&F)console.log("[Dashboard] Using local stx checkout");if(!O)try{let E=T("pantry/@stacksjs/stx/dist/index.js");if(await Bun.file(E).exists())O=await import(E)}catch{}let{listConfigFiles:G,readConfig:K,updateConfigKey:Q}=await import(D("framework/defaults/resources/functions/dashboard/config-io.ts")),N={"/__deps/charts.js":D("framework/core/charts/dist/index.js")},U={...Object.fromEntries(Object.entries(N).map(([E,z])=>[E,async()=>{let W=Bun.file(z);if(!await W.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(W,{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 W=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(W))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let Z=await K(W);if(!Z)return Response.json({ok:!1,error:"Not found"},{status:404});return Response.json({ok:!0,name:W,fields:Z.fields,values:Z.values})}catch(z){return Response.json({ok:!1,error:z?.message},{status:500})}},"/api/config/source":async(E)=>{try{let W=new URL(E.url).searchParams.get("name")||"";if(!/^[\w-]+$/.test(W))return Response.json({ok:!1,error:"Invalid config name"},{status:400});let Z=await K(W);if(!Z)return Response.json({ok:!1,error:"Not found"},{status:404});return new Response(Z.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(),W=z.file?.replace(/\.ts$/,"");if(!W||!/^[\w-]+$/.test(W))return Response.json({ok:!1,error:"Invalid file"},{status:400});let Z=[];if(Array.isArray(z.updates))for(let _ of z.updates){let I=_.key??_.path;if(typeof I==="string")Z.push({key:I,value:_.value})}else if(z.key)Z.push({key:z.key,value:z.value});if(Z.length===0)return Response.json({ok:!1,error:"No updates supplied"},{status:400});let R=[];for(let _ of Z)try{let I=await Q(W,_.key,H(_.value));R.push({key:_.key,ok:!0,newValue:I.newValue})}catch(I){R.push({key:_.key,ok:!1,error:I?.message})}let a=R.every((_)=>_.ok);return Response.json({ok:a,file:W,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)}let L=null;try{let E=await import("@stacksjs/router"),z=(await import(T("app/Routes.ts"))).default;await E.loadRoutes(z),L=E.route}catch(E){if(F)console.warn("[dashboard] Stacks router init failed:",E?.message||E)}X({patterns:[EE,g],port:V,componentsDir:D("framework/defaults/resources/components/Dashboard"),layoutsDir:g,partialsDir:g,quiet:!0,routes:U,onRequest:L?async(E)=>{let W=new URL(E.url).pathname;if(W.startsWith("/api/config/")||W.startsWith("/__deps/"))return null;if(W.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)=>{d(),console.error(`
4
- Failed to start dashboard server: ${E?.message||E}
5
- `),$.exit(1)})}async function $E(){if(!C)return!1;if($.env.STACKS_PROXY_MANAGED)return!1;try{let{startProxies:X}=await import("@stacksjs/rpx");return await X({proxies:[{from:`localhost:${V}`,to:C,cleanUrls:!1}],https:{basePath:l,validityDays:825},regenerateUntrustedCerts:!1,verbose:F}),!0}catch(X){if(F)i(` ${Y(`Proxy: ${X}`)}`);return!1}}var zE=V+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 GE(){Bun.serve({port:zE,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:K}=await X.json();if(!G||G.includes("..")||!G.match(/^[\w.-]+\.ts$/))return J({error:"Invalid file name"},400);let Q=T(`config/${G}`),N=o(Q,"utf-8");for(let{path:U,value:H}of K){let w=U.split(".").pop().replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),E=new RegExp(`(${w}\\s*:\\s*)(?:'[^']*'|"[^"]*"|\\d+(?:\\.\\d+)?|true|false)`);if(E.test(N)){let z=/^\d+(?:\.\d+)?$/.test(H),W=H==="true"||H==="false",Z=H.replace(/'/g,"\\'").replace(/\$/g,"$$$$"),R=z||W?H:`'${Z}'`;N=N.replace(E,`$1${R}`)}}return c(Q,N,"utf-8"),J({success:!0})}catch(G){return J({error:G.message},500)}return J({error:"Not found"},404)}})}GE();var[,t]=await Promise.all([YE(),m(T("app/Models"),D("framework/defaults/app/Models"))]);async function OE(){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(T("config/dashboard.ts")),G=O.default?.sections??{},K=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:K.dashboard?.enabled??!0,activity:K.activity?.enabled??!0,users:K.users?.enabled??!0,teams:K.teams?.enabled??!0,subscribers:K.subscribers?.enabled??!0,allModels:K.allModels?.enabled??!0}}}catch{return X}}var WE=await OE(),KE=D("framework/defaults/views/dashboard/.discovered-models.json"),ZE={models:u(t),sections:WE};c(KE,JSON.stringify(ZE,null,2));var NE=await n(V);d();var HE=!1;$E().then((X)=>{HE=X}).catch((X)=>{if(F)console.warn("[Dashboard] Reverse proxy failed:",X)});var v=C?`https://${C}`:null,q=`http://localhost:${V}`,r=`http://localhost:${V}/`,_E=(Bun.nanoseconds()-s)/1e6;console.log();console.log(` ${B(x("stacks dashboard"))}`);console.log();if(v)console.log(` ${k("\u279C")} ${B("Local")}: ${x(v)}`),console.log(` ${Y("\u279C")} ${Y("Origin")}: ${Y(q)}`);else console.log(` ${k("\u279C")} ${B("Local")}: ${x(q)}`);console.log(` ${k("\u279C")} ${B("Window")}: ${Y("Stacks Dashboard")} ${Y("1400\xD7900")}`);console.log(` ${k("\u279C")} ${B("Models")}: ${Y(`${t.length} discovered`)}`);if(V!==h)console.log(` ${Y("\u279C")} ${Y(`Port ${h} in use, using ${V}`)}`);if(!NE)console.log(` ${Y("\u26A0")} ${Y("Dev server may not be ready yet")}`);console.log();console.log(` ${Y(`ready in ${_E.toFixed(0)} ms`)}`);if(F){if(console.log(),console.log(` ${Y("\u279C")} ${Y("Sidebar")}: ${Y(`${sidebarConfig.sections.length} sections, 240px`)}`),console.log(` ${Y("\u279C")} ${Y("URL")}: ${Y(r)}`),C)console.log(` ${Y("\u279C")} ${Y("SSL")}: ${Y(l)}`),console.log(` ${Y("\u279C")} ${Y("Proxy")}: ${Y(`localhost:${V} \u2192 ${C}`)}`);if(P.length>0){console.log();for(let X of P)console.log(` ${Y(X)}`)}}console.log();var M,f=$.env.HOME?`${$.env.HOME}/Code/Tools/craft/packages/typescript/src/index.ts`:void 0;if(f&&j(f))try{({createApp:M}=await import(f))}catch{}if(!M){let X=["craft-native","@craft-native/craft","@stacksjs/ts-craft"];for(let O of X)try{if({createApp:M}=await import(O),M)break}catch{}}if(M){let X=T("resources/assets/images/app-icon.png"),O=D("framework/defaults/resources/assets/images/app-icon.png"),G=await Bun.file(X).exists()?X:await Bun.file(O).exists()?O:void 0,K=(()=>{let N=$.env.CRAFT_BIN;if(N)return j(N)?N:void 0;let U=`${$.env.HOME}/Code/Tools/craft/craft`;if(j(U))return U;let H=`${$.env.HOME}/Code/Tools/craft/bin/craft`;if(j(H))return H;let L=`${$.env.HOME}/Code/Tools/craft/packages/zig/zig-out/bin/craft`;if(j(L))return L;let w=`${$.env.HOME}/Documents/Projects/craft/packages/zig/zig-out/bin/craft`;if(j(w))return w;return})();if(!K)M=void 0;if(!M)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 Q=M({url:r,quiet:!F,...K&&{craftPath:K},window:{title:"Stacks Dashboard",width:1400,height:900,titlebarHidden:!0,webSidebarMaterial:!0,webSidebarWidth:250,...G&&{icon:G}}});$.on("SIGINT",()=>{Q.close(),$.exit(0)}),$.on("SIGTERM",()=>{Q.close(),$.exit(0)});try{await Q.show(),$.exit(0)}catch{let N=v||q;console.log(` ${Y("Dashboard available at:")} ${x(N)}
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
- `),$.on("SIGINT",()=>$.exit(0)),$.on("SIGTERM",()=>$.exit(0)),await new Promise(()=>{});
@@ -1 +0,0 @@
1
- export {};