@stacksjs/ts-cloud 0.16.56 → 0.16.58

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 (96) hide show
  1. package/dist/bin/{chunk-8nfrknq3.js → chunk-0vfw6xy0.js} +1 -1
  2. package/dist/bin/{chunk-1q6wqzh1.js → chunk-1gznb7bh.js} +3 -3
  3. package/dist/bin/chunk-32nkkq9k.js +1 -0
  4. package/dist/bin/chunk-37aphhk9.js +3 -0
  5. package/dist/bin/{chunk-6sfn8fjv.js → chunk-4fkmd2ce.js} +1 -1
  6. package/dist/bin/{chunk-tbp1gf1p.js → chunk-5mnfp9ae.js} +1 -1
  7. package/dist/bin/chunk-5wz1e4ne.js +1 -0
  8. package/dist/bin/chunk-71vhvzhv.js +1 -0
  9. package/dist/bin/{chunk-jxm62h8r.js → chunk-8t01yv89.js} +1 -1
  10. package/dist/bin/{chunk-6a1tny5g.js → chunk-9292d4yb.js} +85 -85
  11. package/dist/bin/{chunk-sbate1ky.js → chunk-agakphd1.js} +1 -1
  12. package/dist/bin/{chunk-k1kk78qg.js → chunk-ebhfg18g.js} +4 -4
  13. package/dist/bin/{chunk-1cccv502.js → chunk-enmw6v4x.js} +1 -1
  14. package/dist/bin/{chunk-8fh0gv4q.js → chunk-gvv4hn0h.js} +1 -1
  15. package/dist/bin/{chunk-s98wngxx.js → chunk-nnrta1g9.js} +1 -1
  16. package/dist/bin/{chunk-trtxnca4.js → chunk-p1eqv66t.js} +73 -73
  17. package/dist/bin/{chunk-dg8ceycc.js → chunk-qvrfaeqq.js} +7 -7
  18. package/dist/bin/chunk-sgkyg842.js +1 -0
  19. package/dist/bin/{chunk-rqvrjp8g.js → chunk-t8qzx4ka.js} +21 -21
  20. package/dist/bin/{chunk-v9js2b1d.js → chunk-tdftrmyx.js} +1 -1
  21. package/dist/bin/{chunk-hkx5j0bn.js → chunk-vmrkqtch.js} +1 -1
  22. package/dist/bin/{chunk-bn2sn094.js → chunk-wg9zm31f.js} +1 -1
  23. package/dist/bin/{chunk-jyvr7eh5.js → chunk-wzpsq446.js} +1 -1
  24. package/dist/bin/{chunk-e3zsrpbj.js → chunk-yn3499yh.js} +1 -1
  25. package/dist/bin/{chunk-28124w0n.js → chunk-zp1cxtbh.js} +1 -1
  26. package/dist/bin/{chunk-ek27709c.js → chunk-zpjy26jk.js} +3 -3
  27. package/dist/bin/cli.js +211 -211
  28. package/dist/bin/dashboard-server.js +1 -1
  29. package/dist/{chunk-86d69jp3.js → chunk-4f0b21fp.js} +3 -3
  30. package/dist/{chunk-acxmtx6c.js → chunk-y2dej583.js} +72 -72
  31. package/dist/deploy/index.js +1 -1
  32. package/dist/drivers/index.js +1 -1
  33. package/dist/drivers/shared/compute-ops.d.ts +6 -3
  34. package/dist/drivers/shared/remote-exec.d.ts +2 -0
  35. package/dist/index.js +1 -1
  36. package/dist/mail/index.js +2 -2
  37. package/dist/ui/404.html +1 -1
  38. package/dist/ui/accept-invitation.html +1 -1
  39. package/dist/ui/access-denied.html +1 -1
  40. package/dist/ui/account/automation.html +6 -6
  41. package/dist/ui/account/security.html +2 -2
  42. package/dist/ui/applications/compose.html +6 -6
  43. package/dist/ui/applications/new.html +2 -2
  44. package/dist/ui/data/backups.html +6 -6
  45. package/dist/ui/data/services.html +6 -6
  46. package/dist/ui/data/volumes.html +6 -6
  47. package/dist/ui/index.html +6 -6
  48. package/dist/ui/infrastructure/topology.html +5 -5
  49. package/dist/ui/integrations.html +2 -2
  50. package/dist/ui/operations/alerts.html +6 -6
  51. package/dist/ui/operations/configuration.html +6 -6
  52. package/dist/ui/operations/jobs.html +6 -6
  53. package/dist/ui/operations/maintenance.html +6 -6
  54. package/dist/ui/operations/observability.html +6 -6
  55. package/dist/ui/operations/previews.html +6 -6
  56. package/dist/ui/operations/queue.html +6 -6
  57. package/dist/ui/operations/regions.html +5 -5
  58. package/dist/ui/operations/releases.html +6 -6
  59. package/dist/ui/operations/spend.html +6 -6
  60. package/dist/ui/operations/workloads.html +6 -6
  61. package/dist/ui/security.html +2 -2
  62. package/dist/ui/server/actions.html +6 -6
  63. package/dist/ui/server/activity.html +2 -2
  64. package/dist/ui/server/capacity.html +6 -6
  65. package/dist/ui/server/database.html +6 -6
  66. package/dist/ui/server/deployments.html +6 -6
  67. package/dist/ui/server/diagnostics.html +2 -2
  68. package/dist/ui/server/firewall.html +6 -6
  69. package/dist/ui/server/fleet.html +6 -6
  70. package/dist/ui/server/logs.html +6 -6
  71. package/dist/ui/server/metrics.html +6 -6
  72. package/dist/ui/server/security.html +2 -2
  73. package/dist/ui/server/services.html +2 -2
  74. package/dist/ui/server/sites.html +5 -5
  75. package/dist/ui/server/ssh-keys.html +5 -5
  76. package/dist/ui/server/team.html +6 -6
  77. package/dist/ui/server/terminal.html +2 -2
  78. package/dist/ui/serverless/alarms.html +5 -5
  79. package/dist/ui/serverless/assets.html +2 -2
  80. package/dist/ui/serverless/cost.html +2 -2
  81. package/dist/ui/serverless/data.html +6 -6
  82. package/dist/ui/serverless/deployments.html +2 -2
  83. package/dist/ui/serverless/firewall.html +1 -1
  84. package/dist/ui/serverless/functions.html +6 -6
  85. package/dist/ui/serverless/logs.html +6 -6
  86. package/dist/ui/serverless/metrics.html +2 -2
  87. package/dist/ui/serverless/queues.html +6 -6
  88. package/dist/ui/serverless/secrets.html +6 -6
  89. package/dist/ui/serverless/traces.html +6 -6
  90. package/dist/ui/serverless.html +5 -5
  91. package/package.json +3 -3
  92. package/dist/bin/chunk-4sv46rnt.js +0 -1
  93. package/dist/bin/chunk-6tdt3ea9.js +0 -1
  94. package/dist/bin/chunk-cdseg15k.js +0 -3
  95. package/dist/bin/chunk-et6hzqpx.js +0 -1
  96. package/dist/bin/chunk-pexjxc5g.js +0 -1
@@ -1 +1 @@
1
- import{xr,Qc,Yc,wt,_r,Or,$r,Lr,bn}from"./chunk-hkx5j0bn.js";import"./chunk-dg8ceycc.js";import"./chunk-rqvrjp8g.js";import"./chunk-z6xnegpe.js";export{_r as AwsSecretsManagerConfigurationBackend,Or as AwsSsmConfigurationBackend,Lr as ConfigurationService,xr as ConfigurationStore,$r as ExternalConfigurationBackend,wt as LocalEncryptedConfigurationBackend,Qc as parseDotenv,Yc as serializeDotenv,bn as synchronizeConfiguredConfiguration};
1
+ import{xr,Qc,Yc,wt,_r,Or,$r,Lr,bn}from"./chunk-vmrkqtch.js";import"./chunk-qvrfaeqq.js";import"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";export{_r as AwsSecretsManagerConfigurationBackend,Or as AwsSsmConfigurationBackend,Lr as ConfigurationService,xr as ConfigurationStore,$r as ExternalConfigurationBackend,wt as LocalEncryptedConfigurationBackend,Qc as parseDotenv,Yc as serializeDotenv,bn as synchronizeConfiguredConfiguration};
@@ -1,6 +1,6 @@
1
- import{je,A,Jt,Br,ji}from"./chunk-rqvrjp8g.js";import{execSync as D}from"node:child_process";import{randomBytes as R}from"node:crypto";import{chmodSync as j,copyFileSync as x,existsSync as u,mkdirSync as w,readFileSync as U,statSync as N,writeFileSync as m}from"node:fs";import{tmpdir as E}from"node:os";import{basename as P,dirname as v,isAbsolute as O,join as a,resolve as B}from"node:path";import{fileURLToPath as C}from"node:url";function h(e){if(!e||typeof e!=="object")return e;return Object.fromEntries(Object.keys(e).map((r)=>[r,""]))}function M(e){let r=JSON.parse(JSON.stringify(e??{}));if(r.hetzner)delete r.hetzner.apiToken;delete r.aws,delete r.stateDir;for(let t of Object.values(r.sites??{})){if(t?.env)t.env=h(t.env);if(t?.environment)t.environment=h(t.environment)}for(let t of Object.values(r.environments??{}))if(t?.variables)t.variables=h(t.variables);for(let t of Object.values(r.infrastructure?.databases??{}))if(t?.password)t.password="";if(r.infrastructure?.appDatabase?.password)r.infrastructure.appDatabase.password="";if(r.infrastructure?.compute?.database?.password)r.infrastructure.compute.database.password="";if(r.infrastructure?.compute?.managedServices?.vitess?.password)r.infrastructure.compute.managedServices.vitess.password="";return r}function y(e){let r=M(e);return["// Generated by ts-cloud for the management dashboard — do not edit.","//","// This is the project's resolved cloud config, inlined so it needs no","// imports on the box. Credentials are deliberately absent.",`export default ${JSON.stringify(r,null,2)}`,""].join(`
2
- `)}var Kd="dashboard";function zc(){return je("dashboard-credentials.json")}function F(){return R(24).toString("base64url")}function Jd(e,r,t){let s=process.env.TS_CLOUD_UI_PASSWORD?.trim();if(s)return{password:s,source:"env"};if(b(process.env.TS_CLOUD_UI_PUBLIC))return{password:void 0,source:"public"};let n=zc(),i=A(e,"dashboard-credentials.json");try{if(u(i)){let o=JSON.parse(U(i,"utf8"));if(o?.password)return{password:o.password,source:"generated"}}}catch{}let d=F();try{w(v(i),{recursive:!0}),m(i,`${JSON.stringify({username:r,password:d,generatedAt:new Date().toISOString()},null,2)}
1
+ import{je,R,Jt,Br,ji}from"./chunk-t8qzx4ka.js";import{execSync as D}from"node:child_process";import{randomBytes as M}from"node:crypto";import{chmodSync as j,copyFileSync as x,existsSync as u,mkdirSync as w,readFileSync as U,statSync as N,writeFileSync as m}from"node:fs";import{tmpdir as E}from"node:os";import{basename as P,dirname as v,isAbsolute as O,join as a,resolve as B}from"node:path";import{fileURLToPath as C}from"node:url";function h(e){if(!e||typeof e!=="object")return e;return Object.fromEntries(Object.keys(e).map((r)=>[r,""]))}function A(e){let r=JSON.parse(JSON.stringify(e??{}));if(r.hetzner)delete r.hetzner.apiToken;delete r.aws,delete r.stateDir;for(let t of Object.values(r.sites??{})){if(t?.env)t.env=h(t.env);if(t?.environment)t.environment=h(t.environment)}for(let t of Object.values(r.environments??{}))if(t?.variables)t.variables=h(t.variables);for(let t of Object.values(r.infrastructure?.databases??{}))if(t?.password)t.password="";if(r.infrastructure?.appDatabase?.password)r.infrastructure.appDatabase.password="";if(r.infrastructure?.compute?.database?.password)r.infrastructure.compute.database.password="";if(r.infrastructure?.compute?.managedServices?.vitess?.password)r.infrastructure.compute.managedServices.vitess.password="";return r}function y(e){let r=A(e);return["// Generated by ts-cloud for the management dashboard — do not edit.","//","// This is the project's resolved cloud config, inlined so it needs no","// imports on the box. Credentials are deliberately absent.",`export default ${JSON.stringify(r,null,2)}`,""].join(`
2
+ `)}var Kd="dashboard";function zc(){return je("dashboard-credentials.json")}function F(){return M(24).toString("base64url")}function Jd(e,r,t){let s=process.env.TS_CLOUD_UI_PASSWORD?.trim();if(s)return{password:s,source:"env"};if(b(process.env.TS_CLOUD_UI_PUBLIC))return{password:void 0,source:"public"};let n=zc(),i=R(e,"dashboard-credentials.json");try{if(u(i)){let o=JSON.parse(U(i,"utf8"));if(o?.password)return{password:o.password,source:"generated"}}}catch{}let d=F();try{w(v(i),{recursive:!0}),m(i,`${JSON.stringify({username:r,password:d,generatedAt:new Date().toISOString()},null,2)}
3
3
  `),j(i,384),t.info(`Management dashboard: generated a password for '${r}' and saved it to ${n} (read it there — it is not printed). Set TS_CLOUD_UI_PASSWORD to pin your own, or TS_CLOUD_UI_PUBLIC=1 to serve without auth.`)}catch(o){t.warn(`Management dashboard: could not persist the generated password (${o?.message??o}). Using it for this deploy only — pass: ${d}
4
- This password is now in your deploy log. Set TS_CLOUD_UI_PASSWORD to a value of your own and redeploy once ${n} is writable.`)}return{password:d,source:"generated"}}var I={info:()=>{},warn:()=>{}};function b(e){return e!=null&&e!==""&&e!=="0"&&e.toLowerCase()!=="false"}function J(){return je("dashboard-release")}function L(){let e=v(C(import.meta.url));for(let r of[a(e,"..","..","package.json"),a(e,"..","package.json")])try{let t=JSON.parse(U(r,"utf8"));if(t.name==="@stacksjs/ts-cloud"&&t.version)return`^${t.version}`}catch{}return"latest"}function z(){return process.env.TS_CLOUD_UI_VERSION?.trim()||L()}function V(e,r,t){if(!e?.project?.slug)return t.warn("Management dashboard: the cloud config has no project slug — skipping the live dashboard."),null;let s=A(r,"dashboard-release");try{w(s,{recursive:!0}),m(a(s,"cloud.config.ts"),y(e));let n=z();if(n.startsWith("file:")){let d=n.slice(5),o=O(d)?d:B(r,d);if(!u(o)||!N(o).isFile())n=L(),t.warn(`Management dashboard: TS_CLOUD_UI_VERSION points to a missing package file (${o}); using the deploying ts-cloud version ${n} instead.`);else{let c=P(o),l=a(s,c);if(o!==l)x(o,l);n=`file:./${c}`}}let i={name:"ts-cloud-dashboard",private:!0,type:"module",dependencies:{"@stacksjs/ts-cloud":n}};return m(a(s,"package.json"),`${JSON.stringify(i,null,2)}
4
+ This password is now in your deploy log. Set TS_CLOUD_UI_PASSWORD to a value of your own and redeploy once ${n} is writable.`)}return{password:d,source:"generated"}}var I={info:()=>{},warn:()=>{}};function b(e){return e!=null&&e!==""&&e!=="0"&&e.toLowerCase()!=="false"}function J(){return je("dashboard-release")}function L(){let e=v(C(import.meta.url));for(let r of[a(e,"..","..","package.json"),a(e,"..","package.json")])try{let t=JSON.parse(U(r,"utf8"));if(t.name==="@stacksjs/ts-cloud"&&t.version)return`^${t.version}`}catch{}return"latest"}function z(){return process.env.TS_CLOUD_UI_VERSION?.trim()||L()}function V(e,r,t){if(!e?.project?.slug)return t.warn("Management dashboard: the cloud config has no project slug — skipping the live dashboard."),null;let s=R(r,"dashboard-release");try{w(s,{recursive:!0}),m(a(s,"cloud.config.ts"),y(e));let n=z();if(n.startsWith("file:")){let d=n.slice(5),o=O(d)?d:B(r,d);if(!u(o)||!N(o).isFile())n=L(),t.warn(`Management dashboard: TS_CLOUD_UI_VERSION points to a missing package file (${o}); using the deploying ts-cloud version ${n} instead.`);else{let c=P(o),l=a(s,c);if(o!==l)x(o,l);n=`file:./${c}`}}let i={name:"ts-cloud-dashboard",private:!0,type:"module",dependencies:{"@stacksjs/ts-cloud":n}};return m(a(s,"package.json"),`${JSON.stringify(i,null,2)}
5
5
  `),J()}catch(n){return t.warn(`Management dashboard: could not stage the live release (${n?.message??n}) — skipping.`),null}}function Do(e){if(u(a(e,"packages","ui","pages"))||u(a(e,"packages","ui","package.json")))return{uiRoot:"packages/ui/dist",build:"cd packages/ui && bun install && bun run build"};let r=v(C(import.meta.url)),t=[a(r,"ui"),a(r,"..","ui"),a(r,"..","..","ui"),a(r,"..","dist","ui")];for(let s of t)if(u(a(s,"index.html"))||u(a(s,"serverless.html")))return{uiRoot:s,build:!1};return null}function ko(e,r={}){let t=r.logger??I,s=r.cwd??process.cwd();if(b(process.env.TS_CLOUD_UI_DISABLE))return t.info("Management dashboard: skipped (TS_CLOUD_UI_DISABLE set)."),e;if(e.cloud?.attachTo)return t.info(`Management dashboard: ${e.project.slug} is attached to ${e.cloud.attachTo}; the server owner's dashboard monitors every attached project.`),e;if(Jt(e))return e;let n=e.environments&&Object.keys(e.environments)[0],i=process.env.TS_CLOUD_UI_DOMAIN?.trim()||void 0,d=Number(process.env.TS_CLOUD_UI_PORT)||void 0,o={...e.sites??{}};if(!b(process.env.TS_CLOUD_UI_STATIC)){let g=V(e,s,t);if(!g)return e;let p=ji(e,n??"production",{uiRoot:g,build:!1,domain:i,port:d,live:!0});if(p.length===0)return t.info("Management dashboard: no domain resolved (set TS_CLOUD_UI_DOMAIN or configure a site domain) — skipping."),e;for(let{name:k,site:_}of p)o[k]=_,t.info(`Management dashboard → https://${_.domain} (sign in with your ts-cloud account; the first deploy prints an admin password once)`);return e.sites=o,e}let c=Do(s);if(!c)return t.info("Management dashboard: UI not found (no local ui/ or packaged dist/ui) — skipping auto-deploy."),e;let l=process.env.TS_CLOUD_UI_USERNAME?.trim()||"admin",f=Jd(s,l,t),S=ji(e,n??"production",{uiRoot:c.uiRoot,build:c.build,domain:i,username:l,password:f.password,realm:process.env.TS_CLOUD_UI_REALM?.trim()||void 0,live:!1,port:d});if(S.length===0)return t.info("Management dashboard: no domain resolved (set TS_CLOUD_UI_DOMAIN or configure a site domain) — skipping."),e;let T=f.source==="public"?"NO AUTH — TS_CLOUD_UI_PUBLIC is set (dashboard is publicly reachable)":f.source==="env"?"htpasswd-protected (TS_CLOUD_UI_PASSWORD)":`htpasswd-protected (auto-generated — see ${zc()})`;t.warn("Management dashboard: static mode — one shared password, and no per-site collaborators. Unset TS_CLOUD_UI_STATIC for the live dashboard.");for(let{name:g,site:p}of S)o[g]=p,t.info(`Management dashboard → https://${p.domain} (${T})`);return e.sites=o,e}function No(e){return Object.keys(e.sites??{}).filter(Br)}function $s(e,r){if(!e?.root)return null;let t=r.cwd??process.cwd(),s=r.logger??I;try{if(typeof e.build==="string"&&e.build.trim())s.info(`Management dashboard: building UI (${e.build})`),D(e.build,{cwd:t,stdio:"inherit"});let n=O(e.root)?e.root:a(t,e.root);if(!u(n))return s.warn(`Management dashboard: build output not found at ${n} — skipping dashboard artifact.`),null;let i=a(E(),`${r.slug}-${r.siteName??Kd}-${r.sha}.tar.gz`);return D(`tar czf "${i}" -C "${n}" .`,{stdio:"inherit"}),i}catch(n){return s.warn(`Management dashboard: failed to build artifact — ${n?.message??n}. Skipping dashboard deploy.`),null}}
6
6
  export{Kd,zc,Jd,Do,ko,No,$s};
@@ -0,0 +1 @@
1
+ import{di}from"./chunk-zp1cxtbh.js";import"./chunk-p23wfy3r.js";import"./chunk-wzpsq446.js";import"./chunk-sy4zws71.js";import"./chunk-zpjy26jk.js";import"./chunk-rbyrd9we.js";import"./chunk-7cactd6c.js";import"./chunk-0xfy78nc.js";import"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";export{di as resolveDashboardData};
@@ -0,0 +1,3 @@
1
+ import{J,w,U,xi,Js,Ht,Kc,Jc}from"./chunk-ebhfg18g.js";function g(e){return`'${e.split("'").join("'\\''")}'`}function p(e){let r=e.user||"root",t=e.script.join(`
2
+ `),s=r==="root"?'bash -l "$TS_CLOUD_RECIPE"':`runuser -l ${g(r)} -c "bash $TS_CLOUD_RECIPE"`;return["set -uo pipefail",`echo "__TS_CLOUD_RECIPE_BEGIN__ ${e.name} (user=${r})"`,"TS_CLOUD_RECIPE=$(mktemp)",`cat > "$TS_CLOUD_RECIPE" <<'TS_CLOUD_RECIPE_EOF'`,t,"TS_CLOUD_RECIPE_EOF",'chmod +r "$TS_CLOUD_RECIPE"',s,"TS_CLOUD_RC=$?",'rm -f "$TS_CLOUD_RECIPE"',`echo "__TS_CLOUD_RECIPE_END__ ${e.name} exit=$TS_CLOUD_RC"`,"exit $TS_CLOUD_RC"]}var c={info:()=>{},warn:()=>{},error:()=>{},step:()=>{},success:()=>{}};async function u(e){return await e.driver.findComputeTargets({slug:e.slug,environment:e.environment,role:e.role||"app"})}async function Hs(e,r){let t=e.logger||c,s=await u(e);if(s.length===0)return{success:!1,error:`No '${e.role||"app"}' servers found for ${e.slug}/${e.environment}.`};let n=J(e.slug,r.siteName),o=Ht(n,r.to||"unused"),a=r.onlyIfLive?f(o.current,r.siteName,r.onlyIfLive):[];if(r.dryRun){let l=await e.driver.runRemoteDeploy({targets:s,commands:["set -uo pipefail",...a,...Kc(o,r.to?{to:r.to}:{})],comment:`ts-cloud rollback plan ${e.slug}/${r.siteName}`,tags:{Project:e.slug,Environment:e.environment,Role:e.role||"app"}});return{success:l.success,error:l.error,perInstance:l.perInstance}}let m=["set -euo pipefail",...a,...Jc(o,{...r.to?{to:r.to}:{},unitBase:`${e.slug}-${r.siteName}`})];if(r.site&&w(r.site)==="server-php")m.push(`(cd ${U} && pantry restart php-fpm)`,`if [ -f ${o.current}/artisan ]; then (cd ${o.current} && TS_CLOUD_RB_ENV=$(cd ${U} && pantry env) && eval "$TS_CLOUD_RB_ENV" && php artisan queue:restart); fi`);t.step(`Rolling back ${r.siteName}${r.to?` to ${r.to}`:" to the previous release"} on ${s.length} server(s)...`);let i=await e.driver.runRemoteDeploy({targets:s,commands:m,comment:`ts-cloud rollback ${e.slug}/${r.siteName}`,tags:{Project:e.slug,Environment:e.environment,Role:e.role||"app"}});if(!i.success)t.error(`Rollback failed: ${i.error||"unknown error"}`);else t.success(`Rolled back ${r.siteName}.`);return{success:i.success,error:i.error,perInstance:i.perInstance}}function f(e,r,t){let s=t.replace(/[^0-9A-Za-z._-]/g,"");return[`TS_CLOUD_LIVE_ID=$(basename "$(readlink -f ${e} 2>/dev/null)" 2>/dev/null || true)`,`if [ -z "$TS_CLOUD_LIVE_ID" ] || [ "$TS_CLOUD_LIVE_ID" = "." ]; then echo "${r}: no live release here; left alone"; exit 0; fi`,`case "${s}" in "$TS_CLOUD_LIVE_ID"*) ;; *) echo "${r} serves $TS_CLOUD_LIVE_ID, not ${s}; left alone"; exit 0 ;; esac`]}async function mm(e,r){let t=await u(e);if(t.length===0)return{success:!1,error:`No '${e.role||"app"}' servers found for ${e.slug}/${e.environment}.`};let s=Js(J(e.slug,r.siteName)),n=Math.max(1,r.limit??20),o=[`[ -f ${s} ] && tail -n ${n} ${s} || echo "no deploy history for ${r.siteName}"`],a=await e.driver.runRemoteDeploy({targets:t,commands:o,comment:`ts-cloud deploy:history ${e.slug}/${r.siteName}`,tags:{Project:e.slug,Environment:e.environment,Role:e.role||"app"}});return{success:a.success,error:a.error,perInstance:a.perInstance}}async function gm(e,r){let t=e.logger||c,s=await u(e);if(s.length===0)return{success:!1,error:`No '${e.role||"app"}' servers found for ${e.slug}/${e.environment}.`};t.step(`Running recipe '${r.name}' as ${r.user||"root"} on ${s.length} server(s)...`);let n=await e.driver.runRemoteDeploy({targets:s,commands:p({name:r.name,script:r.script,user:r.user}),comment:`ts-cloud recipe ${r.name}`,tags:{Project:e.slug,Environment:e.environment,Role:e.role||"app"}});if(!n.success)t.error(`Recipe '${r.name}' failed: ${n.error||"unknown error"}`);else t.success(`Recipe '${r.name}' completed.`);return{success:n.success,error:n.error,perInstance:n.perInstance}}async function qs(e,r){let t=e.logger||c;if(!r.database?.name)return{success:!1,error:"No appDatabase configured to restore."};let s=await u(e);if(s.length===0)return{success:!1,error:`No '${e.role||"app"}' servers found for ${e.slug}/${e.environment}.`};t.step(`Restoring database '${r.database.name}'${r.from?` from ${r.from}`:" from the latest backup"} on ${s.length} server(s)...`);let n=await e.driver.runRemoteDeploy({targets:s,commands:xi(r.database,{from:r.from}),comment:`ts-cloud db:restore ${e.slug}/${r.database.name}`,tags:{Project:e.slug,Environment:e.environment,Role:e.role||"app"}});if(!n.success)t.error(`Restore failed: ${n.error||"unknown error"}`);else t.success(`Restored ${r.database.name}.`);return{success:n.success,error:n.error,perInstance:n.perInstance}}
3
+ export{Hs,mm,gm,qs};
@@ -1 +1 @@
1
- import{Wp,un,po,ae,Kp,wc,Pd,Ss,Jp,Xp,Qp,Ac,mo,vs,Rc,pn,Cr,Yp,Ei,Zp,Ic,Dd,kd,Cs,Pc,Dc,Tr,go,Er,kc,Ts,wi,Nd,fo,Nc,xc,ho,xd,_c,Oc,$c,Lc,Es,_d,Od,em,$d,Mc,yo,Ld,Md,ws,Ut,As,Rs,Is,Uc,Ud,Fc,Ps,tm,bt,rm,Bc,Ft,jc,nm,Vc,Fd,im,ee,Bd,Ds,om,bo,Ai,Ri,ks,jd,Vd,sm,Ns,xs}from"./chunk-jxm62h8r.js";import"./chunk-dg8ceycc.js";import"./chunk-rqvrjp8g.js";import"./chunk-z6xnegpe.js";export{ws as AnomalyConfigStore,jd as AwsSpendTransport,Vd as ComputeSpendTransport,Cs as CounterTracker,Ic as DEFAULT_METER_MAPPINGS,Ac as DEFAULT_PRICE_BOOK,go as DEFAULT_THRESHOLDS,Ut as DETECTABLE_SIGNALS,po as ENFORCEMENT_ACTIONS,ho as ENFORCEMENT_DESCRIPTIONS,ae as ENFORCEMENT_SEVERITY,Ud as FOCUS_VERSION,un as METERS,Wp as METER_KEYS,Kp as MICRO_CENTS,Nd as MIN_PROJECTION_CONFIDENCE,Fd as RecordingSpendTransport,Ld as SENSITIVITY_THRESHOLDS,Ri as SPEND_CYCLE_SECONDS,Bc as SPEND_GATE_SETTING,om as SPEND_LEASE_SETTING,Rs as SignalSource,jc as SpendCapError,Ft as SpendGate,bo as SpendLoopLease,Ds as SpendNotificationRouter,Ai as SpendRunner,bt as SpendService,Er as SpendStore,im as URGENT_SPEND_EVENTS,xd as USER_VISIBLE_ACTIONS,Dc as aggregateDeltas,yo as anomalyOptionsForSignal,nm as assertSpendAllows,Cr as budgetWindow,sm as compositeSpendTransport,Vc as createEnforcementHandlers,$d as detectAnomalies,Mc as detectLatestAnomaly,Nc as evaluateBudget,em as ewma,Dd as findMapping,Pd as findPriceEntry,ee as formatCents,wi as formatTimeToExhaustion,fo as governingLimitCents,Ns as handleSpendRequest,Ei as hourBucket,Zp as hourBucketsBetween,Lc as isOperationAllowed,mo as isValidTimeZone,Uc as lookbackHoursForSignal,Es as median,_d as medianAbsoluteDeviation,xc as mergeDecisions,Qp as mergePriceBooks,Pc as meterTelemetry,Is as optionsForSignal,Ts as percentOfLimit,_c as planEnforcement,Yp as previousBudgetWindow,Ss as priceUsage,Jp as priceUsageLines,kc as projectSpend,Od as robustZScore,Xp as roundCents,Md as routeMatches,Oc as runEnforcement,Tr as scopeKey,As as signalDefinition,Bd as spendNotificationText,xs as spendOpenApiPaths,ks as startSpendLoop,tm as streamFocusJsonl,$c as strongestActiveAction,wc as tieredMicroCents,Ps as toFocusJsonl,Fc as toFocusRecords,kd as usageDeltaKey,pn as utcInstantOfLocal,rm as zeroFill,Rc as zoneOffsetMs,vs as zonedParts};
1
+ import{Wp,un,po,ae,Kp,wc,Pd,Ss,Jp,Xp,Qp,Ac,mo,vs,Rc,pn,Cr,Yp,Ei,Zp,Ic,Dd,kd,Cs,Pc,Dc,Tr,go,Er,kc,Ts,wi,Nd,fo,Nc,xc,ho,xd,_c,Oc,$c,Lc,Es,_d,Od,em,$d,Mc,yo,Ld,Md,ws,Ut,As,Rs,Is,Uc,Ud,Fc,Ps,tm,bt,rm,Bc,Ft,jc,nm,Vc,Fd,im,ee,Bd,Ds,om,bo,Ai,Ri,ks,jd,Vd,sm,Ns,xs}from"./chunk-8t01yv89.js";import"./chunk-qvrfaeqq.js";import"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";export{ws as AnomalyConfigStore,jd as AwsSpendTransport,Vd as ComputeSpendTransport,Cs as CounterTracker,Ic as DEFAULT_METER_MAPPINGS,Ac as DEFAULT_PRICE_BOOK,go as DEFAULT_THRESHOLDS,Ut as DETECTABLE_SIGNALS,po as ENFORCEMENT_ACTIONS,ho as ENFORCEMENT_DESCRIPTIONS,ae as ENFORCEMENT_SEVERITY,Ud as FOCUS_VERSION,un as METERS,Wp as METER_KEYS,Kp as MICRO_CENTS,Nd as MIN_PROJECTION_CONFIDENCE,Fd as RecordingSpendTransport,Ld as SENSITIVITY_THRESHOLDS,Ri as SPEND_CYCLE_SECONDS,Bc as SPEND_GATE_SETTING,om as SPEND_LEASE_SETTING,Rs as SignalSource,jc as SpendCapError,Ft as SpendGate,bo as SpendLoopLease,Ds as SpendNotificationRouter,Ai as SpendRunner,bt as SpendService,Er as SpendStore,im as URGENT_SPEND_EVENTS,xd as USER_VISIBLE_ACTIONS,Dc as aggregateDeltas,yo as anomalyOptionsForSignal,nm as assertSpendAllows,Cr as budgetWindow,sm as compositeSpendTransport,Vc as createEnforcementHandlers,$d as detectAnomalies,Mc as detectLatestAnomaly,Nc as evaluateBudget,em as ewma,Dd as findMapping,Pd as findPriceEntry,ee as formatCents,wi as formatTimeToExhaustion,fo as governingLimitCents,Ns as handleSpendRequest,Ei as hourBucket,Zp as hourBucketsBetween,Lc as isOperationAllowed,mo as isValidTimeZone,Uc as lookbackHoursForSignal,Es as median,_d as medianAbsoluteDeviation,xc as mergeDecisions,Qp as mergePriceBooks,Pc as meterTelemetry,Is as optionsForSignal,Ts as percentOfLimit,_c as planEnforcement,Yp as previousBudgetWindow,Ss as priceUsage,Jp as priceUsageLines,kc as projectSpend,Od as robustZScore,Xp as roundCents,Md as routeMatches,Oc as runEnforcement,Tr as scopeKey,As as signalDefinition,Bd as spendNotificationText,xs as spendOpenApiPaths,ks as startSpendLoop,tm as streamFocusJsonl,$c as strongestActiveAction,wc as tieredMicroCents,Ps as toFocusJsonl,Fc as toFocusRecords,kd as usageDeltaKey,pn as utcInstantOfLocal,rm as zeroFill,Rc as zoneOffsetMs,vs as zonedParts};
@@ -1,4 +1,4 @@
1
- import{B}from"./chunk-rqvrjp8g.js";import"./chunk-z6xnegpe.js";function g(t){let e=t.sites||{};for(let r of Object.values(e))if(r?.repository?.url)return{provider:r.repository.provider,branch:r.repository.branch};return}function m(t){let e=t.trim().toLowerCase();if(e.includes("github.com"))return"github";if(e.includes("gitlab.com"))return"gitlab";if(e.includes("bitbucket.org"))return"bitbucket";return}function a(t){return`'${t.replace(/'/g,"'\\''")}'`}function E(t){return t.replace(/'/g,"''")}function _(t,e){let r=["bunx --bun @stacksjs/ts-cloud deploy","--env",a(t)];if(e.site)r.push("--site",a(e.site));if(e.skipDnsVerification)r.push("--skip-dns-verification");return r.push("--yes"),r.join(" ")}function v(t,e="production",r={}){let l=g(t),n=r.provider||l?.provider;if(n!=="github"&&n!=="gitlab"&&n!=="bitbucket")return null;let i=t.environments?.[e],s=i?.deployBranch||l?.branch||"main",u=_(e,r),c=JSON.stringify(s),d=JSON.stringify(e),p=i?.domain?i.domain.startsWith("http")?i.domain:`https://${i.domain}`:void 0,f=p?`
1
+ import{B}from"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";function g(t){let e=t.sites||{};for(let r of Object.values(e))if(r?.repository?.url)return{provider:r.repository.provider,branch:r.repository.branch};return}function m(t){let e=t.trim().toLowerCase();if(e.includes("github.com"))return"github";if(e.includes("gitlab.com"))return"gitlab";if(e.includes("bitbucket.org"))return"bitbucket";return}function a(t){return`'${t.replace(/'/g,"'\\''")}'`}function E(t){return t.replace(/'/g,"''")}function _(t,e){let r=["bunx --bun @stacksjs/ts-cloud deploy","--env",a(t)];if(e.site)r.push("--site",a(e.site));if(e.skipDnsVerification)r.push("--skip-dns-verification");return r.push("--yes"),r.join(" ")}function v(t,e="production",r={}){let l=g(t),n=r.provider||l?.provider;if(n!=="github"&&n!=="gitlab"&&n!=="bitbucket")return null;let i=t.environments?.[e],s=i?.deployBranch||l?.branch||"main",u=_(e,r),c=JSON.stringify(s),d=JSON.stringify(e),p=i?.domain?i.domain.startsWith("http")?i.domain:`https://${i.domain}`:void 0,f=p?`
2
2
  url: ${JSON.stringify(p)}`:"",h=r.setup==="pantry"?` - name: Setup Pantry
3
3
  uses: home-lang/pantry/packages/action@main`:` - uses: oven-sh/setup-bun@v2
4
4
  - run: bun install --frozen-lockfile`,y=B(t)==="hetzner"&&!!t.infrastructure?.compute,o=r.sshPrivateKeySecret||"SSH_PRIVATE_KEY";if(!/^[A-Z_][A-Z0-9_]*$/i.test(o))throw Error(`Invalid SSH private key secret name '${o}'`);let b=y?`
@@ -0,0 +1 @@
1
+ import{Fp}from"./chunk-tdftrmyx.js";import"./chunk-3mhzd931.js";import"./chunk-zpjy26jk.js";import"./chunk-0xfy78nc.js";import"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";export{Fp as buildAndPushServerlessImage};
@@ -0,0 +1 @@
1
+ import{Hs,mm,gm,qs}from"./chunk-37aphhk9.js";import"./chunk-ebhfg18g.js";import"./chunk-t8qzx4ka.js";import"./chunk-z6xnegpe.js";export{mm as getComputeDeployHistory,qs as restoreDatabaseBackup,Hs as rollbackComputeSite,gm as runComputeRecipe};
@@ -1,4 +1,4 @@
1
- import{re,h}from"./chunk-dg8ceycc.js";import{Co}from"./chunk-bzzwbkrx.js";class K extends Error{constructor(){super("Operation cancellation was requested")}}class le extends Error{timeoutSeconds;constructor(e){super(`Operation exceeded its ${e}s timeout`);this.timeoutSeconds=e}}class Ue extends Error{errorClass;constructor(e,t){super(e);this.errorClass=t}}var ue={project:2,environment:1,provider:2,builds:1},tr=30,Xe=16384,rr=["succeeded","failed","cancelled","timed_out"],Ae=new Map,rt=new WeakMap;function nt(e){if(e.path===":memory:"){let n=rt.get(e);if(n)return n;let o=new Set;return rt.set(e,o),o}let t=Ae.get(e.path);if(t)return t;let r=new Set;return Ae.set(e.path,r),r}function V(e){return typeof e==="string"&&e?e:void 0}function nr(e){try{let t=JSON.parse(String(e));return Array.isArray(t)?t.map(String):[]}catch{return[]}}function or(e){return{operationId:String(e.operation_id),lockKey:V(e.lock_key),providerKey:V(e.provider_key),buildSlot:Number(e.build_slot)===1,maxAttempts:Number(e.max_attempts),availableAt:String(e.available_at),timeoutSeconds:Number(e.timeout_seconds),heartbeatAt:V(e.heartbeat_at),currentStep:V(e.current_step),blockedReason:V(e.blocked_reason),retryClasses:nr(e.retry_classes),resumePolicy:String(e.resume_policy),cancellationMode:String(e.cancellation_mode),retentionUntil:String(e.retention_until),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function ot(e){return{sequence:Number(e.sequence),id:String(e.id),operationId:String(e.operation_id),stream:String(e.stream),step:V(e.step),message:String(e.message),redacted:Number(e.redacted)===1,truncated:Number(e.truncated)===1,createdAt:String(e.created_at)}}function x(e,t,r){return Number.isFinite(e)?Math.min(r,Math.max(1,Math.floor(e))):t}class S{controlPlane;nowFn;idFn;workerId;leaseMs;limits;constructor(e,t={}){this.controlPlane=e;this.workerId=t.workerId??`worker:${process.pid}:${crypto.randomUUID()}`,this.leaseMs=x(t.leaseMs,60000,3600000),this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID());let r=e.getSetting("queue.concurrency");this.limits={project:x(t.limits?.project??r?.project,ue.project,100),environment:x(t.limits?.environment??r?.environment,ue.environment,100),provider:x(t.limits?.provider??r?.provider,ue.provider,100),builds:x(t.limits?.builds??r?.builds,ue.builds,100)}}now(){return this.nowFn().toISOString()}leaseExpiry(){return new Date(this.nowFn().getTime()+this.leaseMs).toISOString()}enqueue(e){let t=this.controlPlane.createOperation(e);if(this.getJob(t.id))return this.view(t.id);let n=this.now(),o=x(e.maxAttempts,1,20),i=x(e.timeoutSeconds,1800,86400),s=x(e.retentionDays,tr,3650),a=e.availableAt?new Date(e.availableAt).toISOString():n,d=new Date(this.nowFn().getTime()+s*24*60*60*1000).toISOString();this.controlPlane.database.run(`INSERT OR IGNORE INTO operation_jobs (operation_id, lock_key, provider_key, build_slot, max_attempts, available_at, timeout_seconds, retry_classes, resume_policy, cancellation_mode, retention_until, created_at, updated_at)
1
+ import{re,h}from"./chunk-qvrfaeqq.js";import{Co}from"./chunk-bzzwbkrx.js";class K extends Error{constructor(){super("Operation cancellation was requested")}}class le extends Error{timeoutSeconds;constructor(e){super(`Operation exceeded its ${e}s timeout`);this.timeoutSeconds=e}}class Ue extends Error{errorClass;constructor(e,t){super(e);this.errorClass=t}}var ue={project:2,environment:1,provider:2,builds:1},tr=30,Xe=16384,rr=["succeeded","failed","cancelled","timed_out"],Ae=new Map,rt=new WeakMap;function nt(e){if(e.path===":memory:"){let n=rt.get(e);if(n)return n;let o=new Set;return rt.set(e,o),o}let t=Ae.get(e.path);if(t)return t;let r=new Set;return Ae.set(e.path,r),r}function V(e){return typeof e==="string"&&e?e:void 0}function nr(e){try{let t=JSON.parse(String(e));return Array.isArray(t)?t.map(String):[]}catch{return[]}}function or(e){return{operationId:String(e.operation_id),lockKey:V(e.lock_key),providerKey:V(e.provider_key),buildSlot:Number(e.build_slot)===1,maxAttempts:Number(e.max_attempts),availableAt:String(e.available_at),timeoutSeconds:Number(e.timeout_seconds),heartbeatAt:V(e.heartbeat_at),currentStep:V(e.current_step),blockedReason:V(e.blocked_reason),retryClasses:nr(e.retry_classes),resumePolicy:String(e.resume_policy),cancellationMode:String(e.cancellation_mode),retentionUntil:String(e.retention_until),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function ot(e){return{sequence:Number(e.sequence),id:String(e.id),operationId:String(e.operation_id),stream:String(e.stream),step:V(e.step),message:String(e.message),redacted:Number(e.redacted)===1,truncated:Number(e.truncated)===1,createdAt:String(e.created_at)}}function x(e,t,r){return Number.isFinite(e)?Math.min(r,Math.max(1,Math.floor(e))):t}class S{controlPlane;nowFn;idFn;workerId;leaseMs;limits;constructor(e,t={}){this.controlPlane=e;this.workerId=t.workerId??`worker:${process.pid}:${crypto.randomUUID()}`,this.leaseMs=x(t.leaseMs,60000,3600000),this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID());let r=e.getSetting("queue.concurrency");this.limits={project:x(t.limits?.project??r?.project,ue.project,100),environment:x(t.limits?.environment??r?.environment,ue.environment,100),provider:x(t.limits?.provider??r?.provider,ue.provider,100),builds:x(t.limits?.builds??r?.builds,ue.builds,100)}}now(){return this.nowFn().toISOString()}leaseExpiry(){return new Date(this.nowFn().getTime()+this.leaseMs).toISOString()}enqueue(e){let t=this.controlPlane.createOperation(e);if(this.getJob(t.id))return this.view(t.id);let n=this.now(),o=x(e.maxAttempts,1,20),i=x(e.timeoutSeconds,1800,86400),s=x(e.retentionDays,tr,3650),a=e.availableAt?new Date(e.availableAt).toISOString():n,d=new Date(this.nowFn().getTime()+s*24*60*60*1000).toISOString();this.controlPlane.database.run(`INSERT OR IGNORE INTO operation_jobs (operation_id, lock_key, provider_key, build_slot, max_attempts, available_at, timeout_seconds, retry_classes, resume_policy, cancellation_mode, retention_until, created_at, updated_at)
2
2
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[t.id,e.lockKey??e.resourceId??null,e.providerKey??null,e.buildSlot?1:0,o,a,i,JSON.stringify([...new Set(e.retryClasses??[])]),e.resumePolicy??"fail",e.cancellationMode??"cooperative",d,n,n]),this.appendLog(t.id,"Queued for durable execution.",{stream:"system"});let c=this.view(t.id);return this.notifyAvailable(),c}onAvailable(e){let t=nt(this.controlPlane);return t.add(e),()=>{if(t.delete(e),t.size===0&&this.controlPlane.path!==":memory:")Ae.delete(this.controlPlane.path)}}notifyAvailable(){for(let e of nt(this.controlPlane))e()}getJob(e){let t=this.controlPlane.database.query("SELECT * FROM operation_jobs WHERE operation_id=?").get(e);return t?or(t):void 0}view(e){let t=this.controlPlane.getOperation(e),r=this.getJob(e);if(!t||!r)return;let n;if(t.state==="queued")n={ahead:Number(this.controlPlane.database.query("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? AND (o.priority>? OR (o.priority=? AND o.created_at<?))").get(this.now(),t.priority,t.priority,t.createdAt)?.count??0),precision:"bounded"};return{operation:t,job:r,approximatePosition:n}}list(e={}){return this.controlPlane.listOperations({projectId:e.projectId,state:e.state,limit:e.limit??200}).map((t)=>this.view(t.id)).filter((t)=>!!t)}configureConcurrency(e,t={}){let r={project:x(e.project,this.limits.project,100),environment:x(e.environment,this.limits.environment,100),provider:x(e.provider,this.limits.provider,100),builds:x(e.builds,this.limits.builds,100)};return Object.assign(this.limits,r),this.controlPlane.setSetting("queue.concurrency",r),this.controlPlane.appendEvent({organizationId:t.organizationId,actorId:t.actorId,type:"queue.concurrency.updated",level:"warning",payload:r}),r}runningCount(e,t){return Number(this.controlPlane.database.query(e).get(...t)?.count??0)}blockReason(e,t){if(t.lockKey){if(this.controlPlane.database.query("SELECT * FROM operation_locks WHERE lock_key=? AND operation_id!=? AND lease_expires_at>?").get(t.lockKey,e.id,this.now()))return`resource_lock:${t.lockKey}`}if(e.projectId&&this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND project_id=?",[e.projectId])>=this.limits.project)return"project_concurrency";if(e.environmentId&&this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND environment_id=?",[e.environmentId])>=this.limits.environment)return"environment_concurrency";if(t.providerKey&&this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.provider_key=?",[t.providerKey])>=this.limits.provider)return"provider_concurrency";if(t.buildSlot&&this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.build_slot=1",[])>=this.limits.builds)return"build_concurrency";return}claim(e){return this.controlPlane.transaction(()=>{let t=this.now();this.controlPlane.database.run("DELETE FROM operation_locks WHERE lease_expires_at<=?",[t]);let r=this.controlPlane.getOperation(e),n=r?this.getJob(r.id):void 0;if(!r||!n||r.state!=="queued"||n.availableAt>t)return;if(r.cancelRequestedAt){this.controlPlane.transitionOperation(r.id,{to:"cancelled",expectedVersion:r.version,output:{cancelledBeforeStart:!0}}),this.appendLog(r.id,"Cancelled before execution began.",{stream:"system"});return}let o=this.blockReason(r,n);if(o){this.controlPlane.database.run("UPDATE operation_jobs SET blocked_reason=?, updated_at=? WHERE operation_id=?",[o,t,r.id]);return}let i=this.controlPlane.claimOperation(r.id,this.workerId,this.leaseMs);if(!i)return;let s=i.leaseExpiresAt??this.leaseExpiry();if(n.lockKey)this.controlPlane.database.run("INSERT INTO operation_locks (lock_key, operation_id, lease_owner, lease_expires_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)",[n.lockKey,r.id,this.workerId,s,t,t]);return this.controlPlane.database.run("UPDATE operation_jobs SET heartbeat_at=?, blocked_reason=NULL, updated_at=? WHERE operation_id=?",[t,t,r.id]),this.appendLog(r.id,`Claimed by ${this.workerId}; attempt ${i.attempt}.`,{stream:"system"}),this.view(r.id)})}claimNext(e){let t=this.now(),r=e?.length?`AND o.kind IN (${e.map(()=>"?").join(",")})`:"",n=this.controlPlane.database.query(`SELECT o.id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? ${r} ORDER BY o.priority DESC, o.created_at ASC, o.rowid ASC LIMIT 100`).all(t,...e??[]);for(let o of n){let i=this.claim(String(o.id));if(i)return i}return}heartbeat(e,t){let r=this.controlPlane.getOperation(e);if(!r||r.state!=="running"||r.leaseOwner!==this.workerId)throw Error("Operation lease is not owned by this worker");let n=this.now(),o=this.leaseExpiry(),i=this.getJob(e);if(this.controlPlane.database.run("UPDATE operations SET lease_expires_at=?, updated_at=?, version=version+1 WHERE id=? AND state='running' AND lease_owner=? AND version=?",[o,n,e,this.workerId,r.version]).changes!==1)throw Error("Operation lease changed before heartbeat");if(this.controlPlane.database.run("UPDATE operation_jobs SET heartbeat_at=?, current_step=COALESCE(?, current_step), updated_at=? WHERE operation_id=?",[n,t??null,n,e]),i?.lockKey)this.controlPlane.database.run("UPDATE operation_locks SET lease_expires_at=?, updated_at=? WHERE lock_key=? AND operation_id=? AND lease_owner=?",[o,n,i.lockKey,e,this.workerId]);if(t&&t!==i?.currentStep)this.controlPlane.appendEvent({projectId:r.projectId,operationId:e,resourceId:r.resourceId,actorId:r.actorId,correlationId:r.correlationId,type:"operation.step",payload:{step:t}})}appendLog(e,t,r={}){if(!this.getJob(e))throw Error(`Queue job ${e} was not found`);let n=t,o=!1;for(let u of r.secrets??[])if(u&&n.includes(u))n=n.split(u).join("[REDACTED]"),o=!0;let i=h({message:n});if(i.message!==n)o=!0;n=i.message??"[output unavailable]";let s=Buffer.from(n),a=s.byteLength>Xe;if(a)n=`${s.subarray(0,Xe-32).toString("utf8")}
3
3
  [output truncated]`;let d=this.idFn(),c=this.now();return this.controlPlane.database.run("INSERT INTO operation_logs (id, operation_id, stream, step, message, redacted, truncated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",[d,e,r.stream??"stdout",r.step??null,n,o?1:0,a?1:0,c]),ot(this.controlPlane.database.query("SELECT * FROM operation_logs WHERE id=?").get(d))}logs(e,t={}){let r=Math.min(1000,Math.max(1,t.limit??200));return this.controlPlane.database.query("SELECT * FROM operation_logs WHERE operation_id=? AND sequence>? ORDER BY sequence ASC LIMIT ?").all(e,t.after??0,r).map(ot)}requestCancellation(e,t){let r=this.controlPlane.getOperation(e);if(!r||rr.includes(r.state))throw Error("Only queued or running operations can be cancelled");let n=this.controlPlane.requestCancellation(e);if(this.controlPlane.appendEvent({projectId:r.projectId,operationId:e,resourceId:r.resourceId,actorId:t,correlationId:r.correlationId,type:"operation.cancellation_requested",level:"warning",payload:{state:r.state}}),this.appendLog(e,r.state==="queued"?"Cancellation accepted before execution.":"Cancellation requested; waiting for the current provider step.",{stream:"system"}),n.state==="queued")return this.finish(e,"cancelled",{cancelledBeforeStart:!0});return n}retry(e,t,r={}){let n=this.controlPlane.getOperation(e),o=this.getJob(e);if(!n||!o||!["failed","cancelled","timed_out"].includes(n.state))throw Error("Only failed, cancelled, or timed-out queue jobs can be retried");if(n.attempt>=o.maxAttempts)throw Error(`Operation reached its ${o.maxAttempts}-attempt limit`);if(!o.retryClasses.includes(t))throw Error(`Retry class ${t} is not allowed for this operation`);let i=this.controlPlane.transitionOperation(e,{to:"queued",expectedVersion:n.version,error:`Retry requested after ${t}`}),s=new Date(this.nowFn().getTime()+Math.max(0,r.delayMs??0)).toISOString();this.controlPlane.database.run("UPDATE operations SET cancel_requested_at=NULL, finished_at=NULL WHERE id=?",[e]),this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason=NULL, updated_at=? WHERE operation_id=?",[s,this.now(),e]),this.controlPlane.appendEvent({projectId:n.projectId,operationId:e,resourceId:n.resourceId,actorId:r.actorId,correlationId:n.correlationId,type:"operation.retry_requested",payload:{errorClass:t,availableAt:s,nextAttempt:n.attempt+1}}),this.appendLog(e,`Retry queued for error class ${t}.`,{stream:"system"});let a=this.controlPlane.getOperation(i.id);return this.notifyAvailable(),a}release(e){this.controlPlane.database.run("DELETE FROM operation_locks WHERE operation_id=?",[e])}finish(e,t,r={},n){let o=this.controlPlane.getOperation(e);if(!o)throw Error(`Operation ${e} was not found`);let i=this.controlPlane.transitionOperation(e,{to:t,expectedVersion:o.version,output:r,error:n});return this.release(e),i}complete(e,t={}){let r=this.controlPlane.getOperation(e);if(!r||r.state!=="running"||r.leaseOwner!==this.workerId)throw Error("Only the lease owner can complete a running operation");return this.appendLog(e,"Operation completed successfully.",{stream:"system"}),this.finish(e,"succeeded",t)}fail(e,t,r={}){let n=this.controlPlane.getOperation(e);if(!n||n.state!=="running"||n.leaseOwner!==this.workerId)throw Error("Only the lease owner can fail a running operation");return this.appendLog(e,t,{stream:"stderr"}),this.finish(e,"failed",r,t)}async runOne(e){let t=this.claimNext(Object.keys(e));if(!t)return{handled:!1};let{operation:r,job:n}=t,o=e[r.kind];if(!o)return{handled:!1};let i=new AbortController,s=!1,a=setTimeout(()=>{s=!0,i.abort(new le(n.timeoutSeconds))},n.timeoutSeconds*1000),d=setInterval(()=>{try{this.heartbeat(r.id)}catch{}},Math.max(250,Math.floor(this.leaseMs/3))),c=setInterval(()=>{if(this.controlPlane.getOperation(r.id)?.cancelRequestedAt)i.abort(new K)},100),u={operation:r,signal:i.signal,log:(p,l)=>this.appendLog(r.id,p,l),checkpoint:(p,l)=>{this.heartbeat(r.id,p),this.appendLog(r.id,l??p,{stream:"step",step:p})},heartbeat:()=>this.heartbeat(r.id),cancellationRequested:()=>!!this.controlPlane.getOperation(r.id)?.cancelRequestedAt,throwIfCancellationRequested:()=>{if(this.controlPlane.getOperation(r.id)?.cancelRequestedAt)throw new K}};try{let p=await Promise.race([o(u),new Promise((g,y)=>i.signal.addEventListener("abort",()=>y(i.signal.reason),{once:!0}))]);if(this.controlPlane.getOperation(r.id).cancelRequestedAt){let g=n.cancellationMode==="provider_non_cancellable";return this.appendLog(r.id,g?"Provider step completed after cancellation was requested; reconciliation is required.":"Operation cancelled cooperatively.",{stream:"system"}),{handled:!0,operation:this.finish(r.id,"cancelled",{providerCompleted:g,reconciliationRequired:g}),terminalState:"cancelled"}}return{handled:!0,operation:this.complete(r.id,p??{}),terminalState:"succeeded"}}catch(p){if(s||p instanceof le)return this.appendLog(r.id,`Timed out after ${n.timeoutSeconds}s.`,{stream:"system"}),{handled:!0,operation:this.finish(r.id,"timed_out",{reconciliationRequired:n.cancellationMode==="provider_non_cancellable"},p instanceof Error?p.message:String(p)),terminalState:"timed_out"};if(p instanceof K||this.controlPlane.getOperation(r.id)?.cancelRequestedAt)return{handled:!0,operation:this.finish(r.id,"cancelled",{cooperativelyCancelled:!0}),terminalState:"cancelled"};if(p instanceof Ue&&n.retryClasses.includes(p.errorClass)&&r.attempt<n.maxAttempts){let g=this.controlPlane.getOperation(r.id);this.controlPlane.transitionOperation(r.id,{to:"queued",expectedVersion:g.version,error:p.message});let y=Math.min(60000,1000*2**Math.max(0,r.attempt-1)),v=new Date(this.nowFn().getTime()+y).toISOString();return this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason=?, updated_at=? WHERE operation_id=?",[v,`retry_backoff:${p.errorClass}`,this.now(),r.id]),this.release(r.id),this.appendLog(r.id,`Retryable ${p.errorClass} failure; next attempt is delayed.`,{stream:"system"}),{handled:!0,operation:this.controlPlane.getOperation(r.id),requeued:!0}}let l=p instanceof Error?p.message:String(p);return this.appendLog(r.id,l,{stream:"stderr"}),{handled:!0,operation:this.finish(r.id,"failed",{},l),terminalState:"failed"}}finally{clearTimeout(a),clearInterval(d),clearInterval(c)}}recoverExpired(){let e=this.controlPlane.database.query("SELECT o.id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND (o.lease_expires_at IS NULL OR o.lease_expires_at<=?)").all(this.now()),t={requeued:0,failed:0,cancelled:0};for(let r of e){let n=this.controlPlane.getOperation(String(r.id)),o=this.getJob(n.id);if(this.release(n.id),n.cancelRequestedAt){this.finish(n.id,"cancelled",{recoveredAfterWorkerLoss:!0}),t.cancelled++;continue}if(o.resumePolicy==="requeue"&&n.attempt<o.maxAttempts)this.controlPlane.transitionOperation(n.id,{to:"queued",expectedVersion:n.version,error:"Worker lease expired; safely requeued from the last checkpoint."}),this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason='worker_restart', updated_at=? WHERE operation_id=?",[this.now(),this.now(),n.id]),this.appendLog(n.id,"Worker lease expired; operation requeued from its persisted checkpoint.",{stream:"system"}),t.requeued++;else this.finish(n.id,"failed",{recoverable:!0,lastCheckpoint:o.currentStep??null},"Worker lease expired; retry explicitly after reconciling provider state."),t.failed++}return t}clearCompleted(e={}){let t=this.now(),r=[t],n=e.projectId?"AND o.project_id=?":"";if(e.projectId)r.push(e.projectId);let o=e.before?"AND o.finished_at<=?":"";if(e.before)r.push(new Date(e.before).toISOString());let i=this.controlPlane.database.query(`SELECT o.id, o.project_id, o.correlation_id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state IN ('succeeded','failed','cancelled','timed_out') AND j.retention_until<=? ${n} ${o}`).all(...r);for(let s of i)this.controlPlane.appendEvent({projectId:V(s.project_id),actorId:e.actorId,correlationId:String(s.correlation_id),type:"queue.history.cleared",level:"warning",payload:{operationId:String(s.id),retentionCutoff:t}}),this.controlPlane.database.run("DELETE FROM operations WHERE id=?",[String(s.id)]);return i.length}}function it(e,t,r){if(!Number.isFinite(e))return t;return Math.min(r,Math.max(1,Math.floor(e)))}class ys{queue;handlers;parallelism;pollIntervalMs;onResult;onError;waits=new Map;nextWaitId=0;lanes=[];running=!1;unsubscribeAvailability;constructor(e,t,r={}){this.queue=e;this.handlers=t;this.parallelism=it(r.parallelism,4,100),this.pollIntervalMs=it(r.pollIntervalMs,5000,60000),this.onResult=r.onResult,this.onError=r.onError}get active(){return this.running}start(){if(this.running)return this;return this.running=!0,this.unsubscribeAvailability=this.queue.onAvailable(()=>this.wake()),this.lanes=Array.from({length:this.parallelism},(e,t)=>this.runLane(t)),this}stop(){this.running=!1,this.unsubscribeAvailability?.(),this.unsubscribeAvailability=void 0,this.wake()}wake(){for(let{resolve:e,timer:t}of this.waits.values()){if(t)clearTimeout(t);e()}this.waits.clear()}async settled(){await Promise.allSettled(this.lanes)}async drain(){let e=[];while(!0){let t=await Promise.all(Array.from({length:this.parallelism},()=>this.queue.runOne(this.handlers)));if(e.push(...t.filter((r)=>r.handled)),!t.some((r)=>r.handled))return e}}wait(e){return new Promise((t)=>{let r=++this.nextWaitId,n=e?setTimeout(()=>{this.waits.delete(r),t()},this.pollIntervalMs):void 0;n?.unref?.(),this.waits.set(r,{resolve:t,timer:n})})}async runLane(e){while(this.running){try{let t=await this.queue.runOne(this.handlers);if(!this.running)break;if(t.handled){this.onResult?.(t),this.wake();continue}}catch(t){this.onError?.(t)}await this.wait(e===0)}}}import{createHash as ir}from"node:crypto";var ct=/^[a-z0-9](?:[a-z0-9_.-]{0,62})$/,sr=/^[A-Za-z_][A-Za-z0-9_]{0,127}$/,ar=/(?:secret|token|password|passwd|private.?key|api.?key|credential)/i,dr=new Set(["image","build","command","entrypoint","environment","ports","volumes","networks","depends_on","healthcheck","restart","deploy","labels"]),st=new Map([["privileged","Privileged containers are blocked."],["network_mode","Host/custom network modes are blocked."],["pid","Host PID namespaces are blocked."],["ipc","Host IPC namespaces are blocked."],["devices","Device access is blocked."],["cap_add","Additional Linux capabilities require an external policy exception."],["security_opt","Custom security options require an external policy exception."]]);function R(e){return e&&typeof e==="object"&&!Array.isArray(e)?e:{}}function Pe(e){return Array.isArray(e)?e:e==null?[]:[e]}function cr(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,63)||"compose-app"}function G(e){if(Array.isArray(e))return e.map(String);if(typeof e==="string"&&e.trim())return["sh","-c",e];return}function Re(e,t){let r=String(e??""),n=/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(r);if(!n)return t;let o=Number(n[1]);return Math.max(0,Math.round(o*(n[2]==="ms"?0.001:n[2]==="m"?60:n[2]==="h"?3600:1)))}function at(e){let t=/^(\d+(?:\.\d+)?)\s*(b|k|kb|kib|m|mb|mib|g|gb|gib)?$/i.exec(String(e??""));if(!t)return;let r=Number(t[1]),n=String(t[2]??"b").toLowerCase(),o=r*(n.startsWith("g")?1073741824:n.startsWith("m")?1048576:n.startsWith("k")?1024:1);return Math.max(1,Math.round(o/1024/1024))}function lr(e){if(e==null)return"";return/^\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}$/.exec(String(e))?.[1]}function lt(e,t,r){let n={},o=Array.isArray(e)?e.map((i)=>{let[s,...a]=String(i).split("=");return[s,a.length?a.join("="):null]}):Object.entries(R(e));for(let[i,s]of o){let a=String(i);if(!sr.test(a)){r.push({severity:"error",path:`${t}.${a}`,code:"environment.name",message:"Environment variable names must use portable shell identifiers."});continue}let d=lr(s);if(d!==void 0){n[a]={secretRef:d||a};continue}if(ar.test(a)){r.push({severity:"error",path:`${t}.${a}`,code:"secret.literal",message:"Literal secret-like environment values are not stored.",alternative:`Use \${${a}} and supply ${a} through the secret store.`}),n[a]={secretRef:a};continue}n[a]=String(s??"")}return n}function ur(e,t,r){let n=[];for(let[o,i]of Pe(e).entries()){let s,a,d="tcp";if(typeof i==="number")s=i;else if(typeof i==="string"){let[c,u]=i.split("/");d=u==="udp"?"udp":"tcp";let p=c.split(":");s=Number(p.at(-1)),a=p.length>1?Number(p.at(-2)):void 0}else{let c=R(i);s=Number(c.target),a=c.published==null?void 0:Number(c.published),d=c.protocol==="udp"?"udp":"tcp"}if(!Number.isInteger(s)||s<1||s>65535||a!=null&&(!Number.isInteger(a)||a<1||a>65535))r.push({severity:"error",path:`${t}[${o}]`,code:"port.invalid",message:"Ports must be integers from 1 through 65535."});else n.push({target:s,...a?{published:a}:{},protocol:d})}return n}function mr(e,t,r,n){let o=[];for(let[i,s]of Pe(e).entries()){let a="",d="",c=!1,u="volume";if(typeof s==="string"){let p=s.split(":");a=p[0]??"",d=p[1]??"",c=p.slice(2).includes("ro"),u=a.startsWith("/")||a.startsWith(".")?"bind":"volume"}else{let p=R(s);a=String(p.source??""),d=String(p.target??""),c=p.read_only===!0,u=String(p.type??"volume")}if(u!=="volume"||a.startsWith("/")||a.startsWith(".")){n.push({severity:"error",path:`${r}[${i}]`,code:"volume.host_mount",message:"Host and bind mounts are blocked; use a named volume.",alternative:"Declare the volume at the top level and mount it by name."});continue}if(!ct.test(a)||!d.startsWith("/")){n.push({severity:"error",path:`${r}[${i}]`,code:"volume.invalid",message:"A named source and absolute container target are required."});continue}if(!t.has(a))n.push({severity:"warning",path:`${r}[${i}]`,code:"volume.implicit",message:`Named volume ${a} is implicit and will be declared on export.`});t.add(a),o.push({source:a,target:d,readOnly:c})}return o}function pr(e){return Array.isArray(e)?e.map((t)=>({service:String(t),condition:"service_started"})):Object.entries(R(e)).map(([t,r])=>({service:t,condition:["service_started","service_healthy","service_completed_successfully"].includes(String(R(r).condition))?String(R(r).condition):"service_started"}))}function dt(e){let t=R(e);if(!Object.keys(t).length||t.disable===!0)return;let r=G(t.test);return r?{test:r,intervalSeconds:Re(t.interval,30),timeoutSeconds:Re(t.timeout,5),retries:Math.max(1,Number(t.retries)||3),...t.start_period?{startPeriodSeconds:Re(t.start_period,0)}:{}}:void 0}function gr(e,t,r){if(!e)return;let n=typeof e==="string"?{context:e}:R(e),o=String(n.context??"."),i=String(n.dockerfile??"Dockerfile");if(o.startsWith("/")||o.split("/").includes("..")||i.startsWith("/")||i.split("/").includes(".."))r.push({severity:"error",path:t,code:"build.traversal",message:"Build context and Dockerfile must stay inside the repository."});return{context:o,dockerfile:i,...n.target?{target:String(n.target)}:{},args:lt(n.args,`${t}.args`,r)}}function hr(e,t,r){let n=Array.isArray(e)?Object.fromEntries(e.map((i)=>String(i).split("=",2))):R(e),o=String(n["ts-cloud.domains"]??n["ts-cloud.domain"]??"").split(",").map((i)=>i.trim()).filter(Boolean);for(let i of o)if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i.test(i))r.push({severity:"error",path:t,code:"domain.invalid",message:`Invalid service domain ${i}.`});return o.filter((i)=>/\./.test(i))}function fr(e,t){let r=[],n=new Set,o=new Set,i=(s)=>{if(o.has(s))return;if(n.has(s)){t.push({severity:"error",path:`services.${s}.depends_on`,code:"dependency.cycle",message:"Service dependencies contain a cycle."});return}n.add(s);for(let a of e[s]?.dependsOn??[])if(!e[a.service])t.push({severity:"error",path:`services.${s}.depends_on.${a.service}`,code:"dependency.missing",message:`Dependency ${a.service} does not exist.`});else i(a.service);n.delete(s),o.add(s),r.push(s)};return Object.keys(e).sort().forEach(i),r}function Lt(e,t){if(Buffer.byteLength(e)>524288)throw Error("Compose source exceeds the 512 KiB limit");let r;try{r=R(Bun.YAML.parse(e))}catch(l){throw Error(`Compose YAML could not be parsed: ${l instanceof Error?l.message:String(l)}`)}let n=[],o=R(r.services),i=Object.keys(o);if(!i.length)n.push({severity:"error",path:"services",code:"services.required",message:"At least one service is required."});if(i.length>64)n.push({severity:"error",path:"services",code:"services.limit",message:"A Compose application may contain at most 64 services."});let s=new Set(Object.keys(R(r.volumes))),a=new Set(Object.keys(R(r.networks))),d={};for(let l of i.sort()){let f=`services.${l}`,g=R(o[l]);if(!ct.test(l)){n.push({severity:"error",path:f,code:"service.name",message:"Service names must be portable lowercase identifiers."});continue}for(let[A,er]of st)if(g[A]!=null&&g[A]!==!1&&(!Array.isArray(g[A])||g[A].length))n.push({severity:"error",path:`${f}.${A}`,code:`unsafe.${A}`,message:er});for(let A of Object.keys(g))if(!dr.has(A)&&!st.has(A))n.push({severity:"warning",path:`${f}.${A}`,code:"field.unsupported",message:`Compose field ${A} is not in the supported subset and will not be deployed.`});let y=g.image?String(g.image):void 0,v=gr(g.build,`${f}.build`,n);if(!y&&!v)n.push({severity:"error",path:f,code:"service.source",message:"Each service requires image or build."});if(y&&!y.includes("@sha256:")&&(!y.includes(":")||y.endsWith(":latest")))n.push({severity:"warning",path:`${f}.image`,code:"image.floating",message:`Image ${y} is not pinned to a digest or explicit tag.`});let b=Pe(g.networks).map((A)=>typeof A==="string"?A:String(R(A).name??"")).filter(Boolean);b.forEach((A)=>a.add(A));let I=R(g.deploy),_=R(I.resources),w=R(_.limits),C=["no","always","on-failure","unless-stopped"].includes(String(g.restart))?String(g.restart):"unless-stopped";d[l]={name:l,...y?{image:y}:{},...v?{build:v}:{},...G(g.command)?{command:G(g.command)}:{},...G(g.entrypoint)?{entrypoint:G(g.entrypoint)}:{},environment:lt(g.environment,`${f}.environment`,n),ports:ur(g.ports,`${f}.ports`,n),volumes:mr(g.volumes,s,`${f}.volumes`,n),networks:b,dependsOn:pr(g.depends_on),...dt(g.healthcheck)?{healthCheck:dt(g.healthcheck)}:{},restart:C,...Number(w.cpus)>0?{cpu:Number(w.cpus)}:{},...at(w.memory)?{memoryMb:at(w.memory)}:{},replicas:Math.max(1,Math.min(100,Number(I.replicas)||1)),domains:hr(g.labels,`${f}.labels`,n)}}let c=fr(d,n),u={apiVersion:"ts-cloud.dev/v1",kind:"ComposeApplication",metadata:{name:t.name.trim(),slug:cr(t.slug??t.name),projectId:t.projectId,environmentId:t.environmentId},spec:{services:d,networks:[...a].sort(),volumes:[...s].sort(),dependencyOrder:c}},p=bi(u);return{valid:!n.some((l)=>l.severity==="error"),manifest:u,diagnostics:n,redactedSource:p,sourceHash:ir("sha256").update(e).digest("hex")}}function bi(e){let t=Object.fromEntries(Object.entries(e.spec.services).map(([r,n])=>[r,{...n.image?{image:n.image}:{},...n.build?{build:{context:n.build.context,dockerfile:n.build.dockerfile,...n.build.target?{target:n.build.target}:{},...Object.keys(n.build.args).length?{args:Object.fromEntries(Object.entries(n.build.args).map(([o,i])=>[o,typeof i==="string"?i:`\${${i.secretRef}:?required secret ${i.secretRef}}`]))}:{}}}:{},...n.command?{command:n.command}:{},...n.entrypoint?{entrypoint:n.entrypoint}:{},...Object.keys(n.environment).length?{environment:Object.fromEntries(Object.entries(n.environment).map(([o,i])=>[o,typeof i==="string"?i:`\${${i.secretRef}:?required secret ${i.secretRef}}`]))}:{},...n.ports.length?{ports:n.ports.map((o)=>`${o.published?`${o.published}:`:""}${o.target}${o.protocol==="udp"?"/udp":""}`)}:{},...n.volumes.length?{volumes:n.volumes.map((o)=>`${o.source}:${o.target}${o.readOnly?":ro":""}`)}:{},...n.networks.length?{networks:n.networks}:{},...n.dependsOn.length?{depends_on:Object.fromEntries(n.dependsOn.map((o)=>[o.service,{condition:o.condition}]))}:{},...n.healthCheck?{healthcheck:{test:n.healthCheck.test,interval:`${n.healthCheck.intervalSeconds}s`,timeout:`${n.healthCheck.timeoutSeconds}s`,retries:n.healthCheck.retries,...n.healthCheck.startPeriodSeconds!=null?{start_period:`${n.healthCheck.startPeriodSeconds}s`}:{}}}:{},restart:n.restart,...n.cpu||n.memoryMb||n.replicas!==1?{deploy:{replicas:n.replicas,resources:{limits:{...n.cpu?{cpus:String(n.cpu)}:{},...n.memoryMb?{memory:`${n.memoryMb}M`}:{}}}}}:{},...n.domains.length?{labels:{"ts-cloud.domains":n.domains.join(",")}}:{}}]));return Bun.YAML.stringify({services:t,...e.spec.networks.length?{networks:Object.fromEntries(e.spec.networks.map((r)=>[r,{}]))}:{},...e.spec.volumes.length?{volumes:Object.fromEntries(e.spec.volumes.map((r)=>[r,{}]))}:{}})}function bs(e,t){let r=[],n=(o,i,s)=>{if(JSON.stringify(i)===JSON.stringify(s))return;if(i&&s&&typeof i==="object"&&typeof s==="object"&&!Array.isArray(i)&&!Array.isArray(s)){for(let a of[...new Set([...Object.keys(i),...Object.keys(s)])].sort())n(o?`${o}.${a}`:a,i[a],s[a]);return}r.push({path:o,...i!==void 0?{before:i}:{},...s!==void 0?{after:s}:{}})};return n("",e,t),r}import{createHash as ut}from"node:crypto";var yr="2026-07-21T00:00:00.000Z",mt=[{id:"bun-postgres-redis",name:"Bun + Postgres + Redis",description:"Web and worker services with durable Postgres and Redis dependencies.",category:"application",version:"1.0.0",sourceVersion:"oven/bun:1.2.21,postgres:17.5,redis:8.0.3",architecture:"web → Postgres + Redis; worker → Postgres + Redis",minimumResources:{cpu:2,memoryMb:3072},exposedServices:["web"],maintenanceNotes:"Back up the Postgres volume before major upgrades.",inputs:[{name:"domain",label:"Web domain",required:!0,secret:!1}],source:`services:
4
4
  web: