@stacksjs/ts-cloud 0.10.0 → 0.11.1

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 (170) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/chunk-0djsffn6.js +1 -0
  3. package/dist/bin/chunk-0t3sev1j.js +1 -0
  4. package/dist/{chunk-cp54a0qn.js → bin/chunk-0y89hs67.js} +1 -1
  5. package/dist/bin/{chunk-6eat8ezk.js → chunk-21gggxvf.js} +2 -2
  6. package/dist/bin/{chunk-wewcjam5.js → chunk-26cj89s6.js} +1 -1
  7. package/dist/bin/{chunk-eh40fpvj.js → chunk-35xstvnq.js} +1 -1
  8. package/dist/bin/{chunk-d6zzgvtn.js → chunk-4a85nk2q.js} +2 -2
  9. package/dist/bin/{chunk-anm3ae6z.js → chunk-4a97kbk1.js} +2 -2
  10. package/dist/bin/{chunk-svyd4v6c.js → chunk-4kbhbfq8.js} +2 -2
  11. package/dist/bin/{chunk-35ttwn26.js → chunk-4vdv41nh.js} +1 -1
  12. package/dist/bin/{chunk-dvkj4k6h.js → chunk-67jsyn0g.js} +1 -1
  13. package/dist/bin/chunk-6tct7e89.js +1 -0
  14. package/dist/bin/{chunk-jnx4jgw8.js → chunk-6vjrts39.js} +1 -1
  15. package/dist/bin/chunk-7v5ff3vc.js +1 -0
  16. package/dist/bin/chunk-80nra92y.js +1 -0
  17. package/dist/bin/{chunk-sbejksrh.js → chunk-9mydnqr6.js} +1 -1
  18. package/dist/bin/{chunk-m3nqw76h.js → chunk-9rsn48qg.js} +1 -1
  19. package/dist/bin/{chunk-q46zr2tv.js → chunk-a2t1e5yb.js} +1 -1
  20. package/dist/bin/chunk-akbfefwq.js +1 -0
  21. package/dist/bin/chunk-b704nznp.js +1 -0
  22. package/dist/bin/{chunk-8rwhsp5b.js → chunk-c1j9v7ee.js} +1 -1
  23. package/dist/bin/chunk-cjz36ths.js +1 -0
  24. package/dist/bin/{chunk-nb0yjkv5.js → chunk-cxd5cevb.js} +1 -1
  25. package/dist/bin/{chunk-b35989e3.js → chunk-dbv8w56s.js} +2 -2
  26. package/dist/bin/chunk-dxchg0g1.js +1 -0
  27. package/dist/bin/{chunk-axvr7dwa.js → chunk-e1bfd1yv.js} +2 -2
  28. package/dist/bin/{chunk-g90nqfgv.js → chunk-fpcghdr3.js} +47 -47
  29. package/dist/bin/{chunk-dj9a67c3.js → chunk-ftse39wf.js} +2 -2
  30. package/dist/bin/chunk-g0ewbkbq.js +1 -0
  31. package/dist/bin/{chunk-6zjy949y.js → chunk-gskbezam.js} +1 -1
  32. package/dist/bin/chunk-gvs85t2j.js +1 -0
  33. package/dist/bin/{chunk-pkgkfe6s.js → chunk-hej39dwr.js} +2 -2
  34. package/dist/bin/{chunk-b0hj9m5e.js → chunk-jce28gnz.js} +1 -1
  35. package/dist/bin/{chunk-80ar3aty.js → chunk-kbtrr0c3.js} +1 -1
  36. package/dist/bin/chunk-khrye4x9.js +1 -0
  37. package/dist/bin/{chunk-b2ymh8k0.js → chunk-ks4ewy1s.js} +1 -1
  38. package/dist/bin/{chunk-kybdb0ws.js → chunk-mbnwt3r5.js} +2 -2
  39. package/dist/{chunk-xtwjt370.js → bin/chunk-md2k3n21.js} +1 -1
  40. package/dist/bin/chunk-memfxrcn.js +1 -0
  41. package/dist/{chunk-cd0zpxhf.js → bin/chunk-mwgxyc0z.js} +1 -1
  42. package/dist/bin/{chunk-9px3rg4a.js → chunk-neampxq1.js} +2 -2
  43. package/dist/bin/{chunk-da8zpf82.js → chunk-nkpf91d3.js} +1 -1
  44. package/dist/bin/{chunk-pjpa4x52.js → chunk-nmkm1f68.js} +1 -1
  45. package/dist/bin/{chunk-7wzdaqh6.js → chunk-nyc2jxd8.js} +1 -1
  46. package/dist/bin/chunk-pqr8jqnd.js +1 -0
  47. package/dist/bin/{chunk-ckxpgwxw.js → chunk-q182t9ba.js} +2 -2
  48. package/dist/bin/{chunk-pnz5hk8n.js → chunk-r6x7beew.js} +2 -2
  49. package/dist/bin/chunk-rfqk5xym.js +1 -0
  50. package/dist/bin/{chunk-jnsbzqzz.js → chunk-ww770qpn.js} +2 -2
  51. package/dist/bin/chunk-wy20ztb6.js +1 -0
  52. package/dist/bin/{chunk-y9f8649w.js → chunk-wzepfqf4.js} +5 -5
  53. package/dist/bin/chunk-xcqmwphz.js +1 -0
  54. package/dist/bin/{chunk-jt1tndm2.js → chunk-xev7qr2h.js} +1 -1
  55. package/dist/bin/{chunk-1v6bt68w.js → chunk-y3rm37z1.js} +3 -3
  56. package/dist/bin/{chunk-mn6j22zn.js → chunk-zejwh9cy.js} +2 -2
  57. package/dist/bin/{chunk-ezftw2q4.js → chunk-zwwnt4x1.js} +1 -1
  58. package/dist/bin/cli.js +93 -90
  59. package/dist/bin/dashboard-server.js +1 -1
  60. package/dist/{chunk-06jk7ba9.js → chunk-0hj552t7.js} +2 -2
  61. package/dist/{chunk-0e16qt6k.js → chunk-1ypkh8g6.js} +1 -1
  62. package/dist/{chunk-9a22225r.js → chunk-2m09t0c0.js} +2 -2
  63. package/dist/chunk-7fkyfh65.js +1 -0
  64. package/dist/{chunk-hhdx5k96.js → chunk-7xpxzbkr.js} +49 -49
  65. package/dist/{chunk-e1666vjv.js → chunk-8e0az001.js} +2 -2
  66. package/dist/{bin/chunk-936vp7dx.js → chunk-b10cbk8z.js} +1 -1
  67. package/dist/{bin/chunk-ey9fagrr.js → chunk-gk58959n.js} +1 -1
  68. package/dist/{chunk-88z37ey4.js → chunk-h1rc94df.js} +1 -1
  69. package/dist/{chunk-zmxffmmq.js → chunk-hbhxk5a0.js} +2 -2
  70. package/dist/chunk-hz7k9ymh.js +1 -0
  71. package/dist/chunk-kj7gzdj6.js +1 -0
  72. package/dist/{chunk-dckz9xve.js → chunk-ky5c6t5y.js} +1 -1
  73. package/dist/chunk-mch30cyc.js +1 -0
  74. package/dist/chunk-n04a3bgf.js +1 -0
  75. package/dist/{chunk-13hxhzaz.js → chunk-nnqxmh7f.js} +1 -1
  76. package/dist/{chunk-snak8s7m.js → chunk-p6vszgc2.js} +2 -2
  77. package/dist/{chunk-d67xbk4v.js → chunk-q2njk4hx.js} +1 -1
  78. package/dist/{chunk-xd6w0c11.js → chunk-qjk1v1gs.js} +1 -1
  79. package/dist/{chunk-2p89vt3b.js → chunk-qtp90j44.js} +1 -1
  80. package/dist/{bin/chunk-c2b6nk0q.js → chunk-r5natbed.js} +1 -1
  81. package/dist/{chunk-qh9ep11z.js → chunk-rcxq9aaa.js} +5 -5
  82. package/dist/{chunk-kv2ztkp4.js → chunk-s3rpd72x.js} +2 -2
  83. package/dist/{chunk-77t2ctwn.js → chunk-spx89gaw.js} +1 -1
  84. package/dist/{chunk-8c4715hz.js → chunk-t0kh8haz.js} +1 -1
  85. package/dist/{chunk-y26yh5zp.js → chunk-vz95qy3n.js} +1 -1
  86. package/dist/deploy/index.js +1 -1
  87. package/dist/dns/index.js +1 -1
  88. package/dist/drivers/index.js +1 -1
  89. package/dist/drivers/shared/app-updates.d.ts +36 -0
  90. package/dist/index.js +24 -21
  91. package/dist/protection/index.js +1 -1
  92. package/dist/push/index.js +1 -1
  93. package/dist/spend/index.js +1 -1
  94. package/dist/ui/404.html +1 -1
  95. package/dist/ui/accept-invitation.html +1 -1
  96. package/dist/ui/access-denied.html +1 -1
  97. package/dist/ui/account/automation.html +5 -5
  98. package/dist/ui/account/security.html +2 -2
  99. package/dist/ui/applications/compose.html +6 -6
  100. package/dist/ui/applications/new.html +2 -2
  101. package/dist/ui/data/backups.html +6 -6
  102. package/dist/ui/data/services.html +6 -6
  103. package/dist/ui/data/volumes.html +6 -6
  104. package/dist/ui/index.html +6 -6
  105. package/dist/ui/infrastructure/topology.html +5 -5
  106. package/dist/ui/integrations.html +2 -2
  107. package/dist/ui/operations/alerts.html +6 -6
  108. package/dist/ui/operations/configuration.html +6 -6
  109. package/dist/ui/operations/jobs.html +6 -6
  110. package/dist/ui/operations/maintenance.html +5 -5
  111. package/dist/ui/operations/observability.html +6 -6
  112. package/dist/ui/operations/previews.html +6 -6
  113. package/dist/ui/operations/queue.html +6 -6
  114. package/dist/ui/operations/regions.html +6 -6
  115. package/dist/ui/operations/releases.html +6 -6
  116. package/dist/ui/operations/spend.html +6 -6
  117. package/dist/ui/operations/workloads.html +6 -6
  118. package/dist/ui/security.html +2 -2
  119. package/dist/ui/server/actions.html +6 -6
  120. package/dist/ui/server/activity.html +1 -1
  121. package/dist/ui/server/capacity.html +5 -5
  122. package/dist/ui/server/database.html +5 -5
  123. package/dist/ui/server/deployments.html +6 -6
  124. package/dist/ui/server/diagnostics.html +2 -2
  125. package/dist/ui/server/firewall.html +6 -6
  126. package/dist/ui/server/fleet.html +6 -6
  127. package/dist/ui/server/logs.html +6 -6
  128. package/dist/ui/server/metrics.html +6 -6
  129. package/dist/ui/server/security.html +2 -2
  130. package/dist/ui/server/services.html +2 -2
  131. package/dist/ui/server/sites.html +6 -6
  132. package/dist/ui/server/ssh-keys.html +6 -6
  133. package/dist/ui/server/team.html +6 -6
  134. package/dist/ui/server/terminal.html +2 -2
  135. package/dist/ui/serverless/alarms.html +6 -6
  136. package/dist/ui/serverless/assets.html +2 -2
  137. package/dist/ui/serverless/cost.html +2 -2
  138. package/dist/ui/serverless/data.html +6 -6
  139. package/dist/ui/serverless/deployments.html +2 -2
  140. package/dist/ui/serverless/firewall.html +1 -1
  141. package/dist/ui/serverless/functions.html +6 -6
  142. package/dist/ui/serverless/logs.html +6 -6
  143. package/dist/ui/serverless/metrics.html +2 -2
  144. package/dist/ui/serverless/queues.html +6 -6
  145. package/dist/ui/serverless/secrets.html +6 -6
  146. package/dist/ui/serverless/traces.html +6 -6
  147. package/dist/ui/serverless.html +6 -6
  148. package/package.json +3 -3
  149. package/dist/bin/chunk-08c0pzkb.js +0 -1
  150. package/dist/bin/chunk-12210qvj.js +0 -1
  151. package/dist/bin/chunk-3r3be05z.js +0 -1
  152. package/dist/bin/chunk-5rv31chh.js +0 -1
  153. package/dist/bin/chunk-6gktf2m2.js +0 -1
  154. package/dist/bin/chunk-ddmjjstg.js +0 -1
  155. package/dist/bin/chunk-dhhz4zyj.js +0 -1
  156. package/dist/bin/chunk-ds1z880f.js +0 -1
  157. package/dist/bin/chunk-g6a4n3rh.js +0 -1
  158. package/dist/bin/chunk-gs40j75w.js +0 -1
  159. package/dist/bin/chunk-jjjts1vt.js +0 -1
  160. package/dist/bin/chunk-qtdngvs8.js +0 -1
  161. package/dist/bin/chunk-tna7ay8d.js +0 -1
  162. package/dist/bin/chunk-tp4c2mv1.js +0 -1
  163. package/dist/bin/chunk-w5d6tr2x.js +0 -1
  164. package/dist/bin/chunk-xv4bscrm.js +0 -1
  165. package/dist/bin/chunk-y9eyc5pw.js +0 -1
  166. package/dist/chunk-as6by62d.js +0 -1
  167. package/dist/chunk-nrz6zypg.js +0 -1
  168. package/dist/chunk-q816js1y.js +0 -1
  169. package/dist/chunk-rg720cqg.js +0 -1
  170. package/dist/chunk-vq737g82.js +0 -1
@@ -1,4 +1,4 @@
1
- import{ud as Sp}from"./chunk-9a22225r.js";import{Bd as to,Cd as zp,Dd as es,Ed as Mt,Fd as ct,Gd as ns,Hd as Up}from"./chunk-0e16qt6k.js";import{Jd as ai,Kd as Us,Oe as Mv,Pe as Ms,Rd as Zp,Td as Ta,Ud as Yr,Wd as _n,Xd as kt,Yd as ci,nf as Xp}from"./chunk-88z37ey4.js";import{of as Xo}from"./chunk-13hxhzaz.js";import{sf as Rn}from"./chunk-d67xbk4v.js";import{tf as Pp}from"./chunk-dckz9xve.js";import{uf as Fn}from"./chunk-8c4715hz.js";import{$f as jo,Fg as Cy,Fh as Wu,Ih as Ja,Ng as ir,ag as Xy,bg as ev,cg as vu,dg as Cu,eg as gv,fg as yn,kg as zr,th as fv,uh as hv}from"./chunk-hhdx5k96.js";import{Sh as qb}from"./chunk-zmxffmmq.js";import{Th as Er}from"./chunk-e1666vjv.js";import{Uh as Qp,Vh as ur}from"./chunk-snak8s7m.js";import{Xh as pi,Yh as Gp}from"./chunk-cp54a0qn.js";import{Ai as _b,Ak as zb,Di as As,Dk as ec,Ei as $e,Ek as Ub,Fi as Tb,Gi as Bm,Hi as hs,Ki as xb,Li as Db,Qi as Ob,Ri as $b,Rk as ie,Si as Nb,Ti as jb,Tk as Uc,Uk as Jm,Vk as Wm,Yi as ys,ai as ks,bi as fp,di as er,ei as qo,ek as Km,li as Oe,mi as hp,mk as Mb,ni as Cb,pk as Bb,qk as Gi,ri as fs,uk as zo,vk as Lb,wk as Fb,zi as Pb,zj as Hm,zk as db}from"./chunk-kv2ztkp4.js";import{As as Bp,Pl as hh,Rl as ho,Sl as yt,Tl as Cp,Vl as Fr,Xl as gt,am as Zl,cn as Ep,hn as Rp,ht as Lp,nm as li,nt as Fp,om as Dp,pm as Op,us as $p,vs as Np,xs as jp,ys as as,zs as Mp}from"./chunk-06jk7ba9.js";import{yt as rt}from"./chunk-77t2ctwn.js";import{createHash as sS}from"node:crypto";function aS(e){return sS("sha256").update(En(e)).digest("hex")}function En(e){if(Array.isArray(e))return`[${e.map((t)=>En(t)).join(",")}]`;if(e&&typeof e==="object")return`{${Object.entries(e).filter(([,t])=>t!==void 0&&typeof t!=="function").sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>`${JSON.stringify(t)}:${En(r)}`).join(",")}}`;return JSON.stringify(e)??"null"}function Ye(e,t){let r=`dashboard:${t.username.toLowerCase()}`;return e.getActorByExternalId("user",r)??e.createActor({kind:"user",externalId:r,displayName:t.name??t.username,metadata:{source:"dashboard",role:t.role}})}function yp(e,t){let r=new hp({cwd:e}),n=aS(t),i=r.getProjectBySlug(t.project.slug),o=t.project.slug.length>=3?t.project.slug:`${t.project.slug}-org`,s=(i?.organizationId?r.getOrganization(i.organizationId):void 0)??r.getOrganizationBySlug(o)??r.createOrganization({id:i?.organizationId,slug:o,name:t.project.name}),c=i?i.name!==t.project.name||i.desiredConfigHash!==n||i.organizationId!==s.id?r.updateProject(i.id,i.version,{name:t.project.name,organizationId:s.id,desiredConfigHash:n}):i:r.createProject({organizationId:s.id,slug:t.project.slug,name:t.project.name,desiredConfigHash:n}),d=new Map;for(let[h,y]of Object.entries(t.environments??{})){let k=r.getEnvironmentBySlug(c.id,h)??r.createEnvironment({projectId:c.id,slug:h,name:h.replace(/(^|[-_])(\w)/g,(O,U,q)=>q.toUpperCase()),kind:String(y?.type??h),region:y?.region??t.project.region,desiredState:Oe(y)});d.set(h,k);let C=new Map(r.listResources(c.id,k.id).map((O)=>[`${O.kind}:${O.slug}`,O])),T=(O,U,q,N)=>{let Q=`${O}:${U}`,D=C.get(Q),Y=Oe(N);if(D){if(D.name!==q||En(D.desiredState)!==En(Y))C.set(Q,r.updateResource(D.id,D.version,{name:q,desiredState:Y}));return}let se=r.createResource({projectId:c.id,environmentId:k.id,kind:O,slug:U,name:q,provider:t.cloud?.provider,desiredState:Y,metadata:{source:"cloud-config"}});C.set(Q,se)};for(let[O,U]of Object.entries(t.sites??{}))T("application",O,O,U);let M=y?.app;if(M)for(let O of["http","queue","cli"])T("function",O,`${O.toUpperCase()} function`,{...Oe(M),function:O});let P=t.infrastructure;for(let[O,U]of Object.entries(P?.functions??{}))T("function",O,O,U);if(P?.compute)T("server",`${c.slug}-server`,c.name,{...Oe(P.compute),label:c.name});for(let[O,U]of Object.entries(P?.databases??{}))T("database",O,O,U);if(P?.appDatabase)T("database","application-database","Application database",P.appDatabase);else if(P?.database)T("database","application-database","Application database",{engine:P.database})}let a=new $e(r).recoverExpired(),u=r.reconcileOrphanedOperations({policy:"fail"}),m={requeued:a.requeued+u.requeued,failed:a.failed+a.cancelled+u.failed};return{store:r,organization:s,project:c,environments:d,reconciliation:m}}var cS=["project:read","config:read","deployments:read","deployments:create","runtime:read","runtime:logs"];function Zo(e,t){let{store:r,organization:n,project:i}=e,o=new Set;for(let s of t){let c=Ye(r,s);o.add(c.id);let d=r.getMembershipForActor(n.id,c.id);if(d&&d.source!=="legacy")continue;let a=r.listResources(i.id).filter((w)=>w.kind==="application"&&Object.hasOwn(s.sites,w.slug)),u=s.role==="admin"?"owner":"viewer",m=s.role==="admin"||a.length===0?{type:"organization"}:{type:"resource",id:a[0].id},h=d?d.roleTemplate!==u||En(d.scope)!==En(m)?r.updateMembership({id:d.id,roleTemplate:u,scope:m,actorId:c.id}):d:r.createMembership({organizationId:n.id,actorId:c.id,roleTemplate:u,scope:m,source:"legacy"}),y=new Set;if(s.role==="member"&&a.length===0)for(let w of fp("viewer"))y.add(`deny|${w}|organization|`);for(let w of a){let k=s.sites[w.slug];for(let C of cS)y.add(`allow|${C}|resource|${w.id}`);if(k==="owner")y.add(`allow|config:write|resource|${w.id}`)}for(let w of r.listGrants(h.id).filter((k)=>k.source==="legacy")){let k=`${w.effect}|${w.capability}|${w.scope.type}|${w.scope.id??""}`;if(!y.has(k))r.removeGrant(w.id,c.id)}for(let w of y){let[k,C,T,M]=w.split("|");r.upsertGrant({organizationId:n.id,membershipId:h.id,effect:k,capability:C,scope:T==="organization"?{type:"organization"}:{type:T,id:M},source:"legacy"})}}for(let s of r.listMemberships(n.id))if(s.source==="legacy"&&!o.has(s.actorId))r.revokeMembership(s.id)}async function Ir(e){let{controlPlane:t,environment:r,actor:n}=e,i=Ye(t.store,n),o=t.environments.get(r),s=e.resourceSlug&&o?t.store.listResources(t.project.id,o.id).find((u)=>u.slug===e.resourceSlug):void 0,c=new $e(t.store,{workerId:`dashboard:${process.pid}`}),d=c.enqueue({projectId:t.project.id,environmentId:o?.id,resourceId:s?.id,actorId:i.id,kind:e.kind,input:e.input??{},lockKey:s?`resource:${s.id}`:o?`environment:${o.id}`:`project:${t.project.id}`,providerKey:s?.provider??"dashboard",buildSlot:e.kind.includes("deploy"),maxAttempts:1,timeoutSeconds:3600,resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;if(!c.claim(d.id)?.operation)throw Error(`Could not claim control-plane operation ${d.id}`);try{let u=await e.execute(),m=typeof u.stdout==="string"?String(u.stdout):"",h=typeof u.stderr==="string"?String(u.stderr):"";if(m)c.appendLog(d.id,m,{stream:"stdout"});if(h)c.appendLog(d.id,h,{stream:"stderr"});let y=u.ok?c.complete(d.id,gp(u)):c.fail(d.id,dS(u),gp(u));return{result:u,operation:y}}catch(u){throw c.fail(d.id,u instanceof Error?u.message:String(u),{ok:!1,threw:!0}),u}}function dS(e){let t=e;return String(t.error??t.stderr??"Operation failed")}function gp(e){let t=e,r=typeof t.stdout==="string"?t.stdout:"",n=typeof t.stderr==="string"?t.stderr:"",i={ok:e.ok,stdoutBytes:Buffer.byteLength(r),stderrBytes:Buffer.byteLength(n)};if(typeof t.operation==="string")i.operation=t.operation;if(typeof t.error==="string")i.error=t.error;return Oe(i)}var vp=[{id:"server.overview",path:"/",label:"Dashboard",group:"overview",modes:["server"],adminOnly:!0,legacyPaths:["/server"]},{id:"server.activity",path:"/server/activity",label:"Activity",group:"overview",modes:["server"],adminOnly:!0,legacyPaths:["/activity"]},{id:"services.list",path:"/server/sites",label:"Services",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/sites","/services"]},{id:"deployments.list",path:"/server/deployments",label:"Deployments",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/deployments"]},{id:"logs.list",path:"/server/logs",label:"Logs",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/logs"]},{id:"sources.integrations",path:"/integrations",label:"Git integrations",group:"applications",modes:["server","serverless"],adminOnly:!1},{id:"applications.create",path:"/applications/new",label:"Create application",group:"applications",modes:["server","serverless"],adminOnly:!1},{id:"applications.compose",path:"/applications/compose",label:"Compose applications",group:"applications",modes:["server"],adminOnly:!1},{id:"operations.queue",path:"/operations/queue",label:"Deployment queue",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"operations.previews",path:"/operations/previews",label:"Preview environments",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"operations.releases",path:"/operations/releases",label:"Releases & promotion",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"runtime.workloads",path:"/operations/workloads",label:"Workloads",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"observability.overview",path:"/operations/observability",label:"Observability",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"alerts.overview",path:"/operations/alerts",label:"Alerts & health",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"spend.overview",path:"/operations/spend",label:"Spend & budgets",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"automation.jobs",path:"/operations/jobs",label:"Workers & schedules",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/workers","/serverless/scheduler"]},{id:"configuration.entries",path:"/operations/configuration",label:"Environment & secrets",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/serverless/secrets"]},{id:"metrics.overview",path:"/server/metrics",label:"Metrics",group:"operations",modes:["server"],adminOnly:!0},{id:"runtime.services",path:"/server/services",label:"Runtime services",group:"operations",modes:["server"],adminOnly:!0},{id:"backups.list",path:"/data/backups",label:"Backups & recovery",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/backups"]},{id:"volumes.list",path:"/data/volumes",label:"Persistent volumes",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:[]},{id:"fleet.list",path:"/server/fleet",label:"Fleet inventory",group:"operations",modes:["server"],adminOnly:!1,legacyPaths:[]},{id:"operations.run",path:"/server/actions",label:"Run operations",group:"operations",modes:["server"],adminOnly:!0},{id:"infrastructure.topology",path:"/infrastructure/topology",label:"Infrastructure map",group:"infrastructure",modes:["server","serverless"],adminOnly:!0,legacyPaths:["/topology"]},{id:"data.services",path:"/data/services",label:"Data services",group:"infrastructure",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/database","/databases","/server/database","/serverless/data"]},{id:"network.firewall",path:"/server/firewall",label:"Network & firewall",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"security.posture",path:"/security",label:"Security posture",group:"infrastructure",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/security"]},{id:"access.ssh",path:"/server/ssh-keys",label:"SSH keys",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"runtime.terminal",path:"/server/terminal",label:"Terminal",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"organization.people",path:"/server/team",label:"People & access",group:"organization",modes:["server","serverless"],adminOnly:!0,legacyPaths:["/team"]},{id:"organization.automation",path:"/account/automation",label:"API & automation",group:"organization",modes:["server","serverless"],adminOnly:!0},{id:"serverless.overview",path:"/serverless",label:"Dashboard",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.deployments",path:"/serverless/deployments",label:"Deployments",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.logs",path:"/serverless/logs",label:"Logs",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.metrics",path:"/serverless/metrics",label:"Metrics",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.traces",path:"/serverless/traces",label:"Traces",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.functions",path:"/serverless/functions",label:"Functions",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.queues",path:"/serverless/queues",label:"Queues",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.assets",path:"/serverless/assets",label:"Assets",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.network",path:"/serverless/firewall",label:"Network",group:"settings",modes:["serverless"],adminOnly:!0},{id:"serverless.alerts",path:"/serverless/alarms",label:"Alerts",group:"settings",modes:["serverless"],adminOnly:!0},{id:"serverless.cost",path:"/serverless/cost",label:"Costs",group:"settings",modes:["serverless"],adminOnly:!0}],lS=new Map(vp.flatMap((e)=>(e.legacyPaths??[]).map((t)=>[t,e.path])));function bp(e){return lS.get(e)}function j_(e,t){return vp.filter((r)=>r.modes.includes(e)&&(!t||!r.adminOnly))}import Qr from"node:process";import{existsSync as uS}from"node:fs";import{join as pS}from"node:path";async function U_(e){let t=Date.now(),r=e.sourceDir??"dist";if(!uS(pS(r,"index.html")))return pc(t,`${r}/ has no index.html — build first.`);if(!Qr.env.AWS_ACCESS_KEY_ID||!Qr.env.AWS_SECRET_ACCESS_KEY)return pc(t,"Missing AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY in env.");let n=mS(e.dnsProvider);if("error"in n)return pc(t,n.error);let i=await Sp({siteName:e.siteName,region:e.region??"us-east-1",domain:e.domain,bucket:e.bucket,stackName:e.stackName,certificateArn:e.certificateArn,defaultRootObject:e.defaultRootObject??"index.html",errorDocument:e.errorDocument??"404.html",cacheControl:e.cacheControl??"max-age=3600, public",sourceDir:r,cleanBucket:e.cleanBucket??!1,singlePageApp:e.singlePageApp??!1,dnsProvider:n,tags:{ManagedBy:"ts-cloud",Application:e.siteName,...e.tags},onProgress:e.onProgress});return{success:!!i.success,domain:i.domain,url:i.domain?`https://${i.domain}`:i.distributionDomain?`https://${i.distributionDomain}`:void 0,bucket:i.bucket,distributionId:i.distributionId,distributionDomain:i.distributionDomain,certificateArn:i.certificateArn,filesUploaded:i.filesUploaded,filesSkipped:i.filesSkipped,message:i.message,durationMs:Date.now()-t}}function mS(e){let t=typeof e==="string"?{provider:e}:e??{provider:"porkbun"};if(t.provider==="porkbun"){let r=t,n=r?.apiKey??Qr.env.PORKBUN_API_KEY,i=r?.secretKey??Qr.env.PORKBUN_SECRET_KEY??Qr.env.PORKBUN_SECRET_API_KEY;if(!n||!i)return{error:"Missing PORKBUN_API_KEY / PORKBUN_SECRET_KEY in env."};return{provider:"porkbun",apiKey:n,secretKey:i}}if(t.provider==="godaddy"){let r=t,n=r?.apiKey??Qr.env.GODADDY_API_KEY,i=r?.secretKey??Qr.env.GODADDY_API_SECRET,o=r?.environment??Qr.env.GODADDY_ENVIRONMENT;if(!n||!i)return{error:"Missing GODADDY_API_KEY / GODADDY_API_SECRET in env."};return{provider:"godaddy",apiKey:n,apiSecret:i,environment:o}}return{error:`Unsupported DNS provider: ${t.provider}`}}function pc(e,t){return{success:!1,message:t,durationMs:Date.now()-e}}import{createHash as gS}from"node:crypto";var fS=`let coldStart = true
1
+ import{ud as Sp}from"./chunk-2m09t0c0.js";import{Bd as to,Cd as zp,Dd as es,Ed as Mt,Fd as ct,Gd as ns,Hd as Up}from"./chunk-1ypkh8g6.js";import{Jd as ai,Kd as Us,Oe as Mv,Pe as Ms,Rd as Zp,Td as Ta,Ud as Yr,Wd as _n,Xd as kt,Yd as ci,nf as Xp}from"./chunk-h1rc94df.js";import{of as Xo}from"./chunk-nnqxmh7f.js";import{sf as Rn}from"./chunk-q2njk4hx.js";import{tf as Pp}from"./chunk-ky5c6t5y.js";import{uf as Fn}from"./chunk-t0kh8haz.js";import{$f as jo,Gg as Cy,Gh as Wu,Jh as Ja,Og as ir,ag as Xy,bg as ev,cg as vu,dg as Cu,eg as gv,gg as yn,lg as zr,uh as fv,vh as hv}from"./chunk-7xpxzbkr.js";import{Th as qb}from"./chunk-hbhxk5a0.js";import{Uh as Er}from"./chunk-8e0az001.js";import{Vh as Qp,Wh as ur}from"./chunk-p6vszgc2.js";import{Yh as pi,Zh as Gp}from"./chunk-gk58959n.js";import{Ai as Pb,Aj as Hm,Ak as db,Bi as _b,Bk as zb,Ei as As,Ek as ec,Fi as $e,Fk as Ub,Gi as Tb,Hi as Bm,Ii as hs,Li as xb,Mi as Db,Ri as Ob,Si as $b,Sk as ie,Ti as Nb,Ui as jb,Uk as Uc,Vk as Jm,Wk as Wm,Zi as ys,bi as ks,ci as fp,ei as er,fi as qo,fk as Km,mi as Oe,ni as hp,nk as Mb,oi as Cb,qk as Bb,rk as Gi,si as fs,vk as zo,wk as Lb,xk as Fb}from"./chunk-s3rpd72x.js";import{As as Mp,Bs as Bp,Ql as hh,Sl as ho,Tl as yt,Ul as Cp,Wl as Fr,Yl as gt,bm as Zl,dn as Ep,in as Rp,it as Lp,om as li,ot as Fp,pm as Dp,qm as Op,vs as $p,ws as Np,ys as jp,zs as as}from"./chunk-0hj552t7.js";import{zt as rt}from"./chunk-spx89gaw.js";import{createHash as sS}from"node:crypto";function aS(e){return sS("sha256").update(En(e)).digest("hex")}function En(e){if(Array.isArray(e))return`[${e.map((t)=>En(t)).join(",")}]`;if(e&&typeof e==="object")return`{${Object.entries(e).filter(([,t])=>t!==void 0&&typeof t!=="function").sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>`${JSON.stringify(t)}:${En(r)}`).join(",")}}`;return JSON.stringify(e)??"null"}function Ye(e,t){let r=`dashboard:${t.username.toLowerCase()}`;return e.getActorByExternalId("user",r)??e.createActor({kind:"user",externalId:r,displayName:t.name??t.username,metadata:{source:"dashboard",role:t.role}})}function yp(e,t){let r=new hp({cwd:e}),n=aS(t),i=r.getProjectBySlug(t.project.slug),o=t.project.slug.length>=3?t.project.slug:`${t.project.slug}-org`,s=(i?.organizationId?r.getOrganization(i.organizationId):void 0)??r.getOrganizationBySlug(o)??r.createOrganization({id:i?.organizationId,slug:o,name:t.project.name}),c=i?i.name!==t.project.name||i.desiredConfigHash!==n||i.organizationId!==s.id?r.updateProject(i.id,i.version,{name:t.project.name,organizationId:s.id,desiredConfigHash:n}):i:r.createProject({organizationId:s.id,slug:t.project.slug,name:t.project.name,desiredConfigHash:n}),d=new Map;for(let[h,y]of Object.entries(t.environments??{})){let k=r.getEnvironmentBySlug(c.id,h)??r.createEnvironment({projectId:c.id,slug:h,name:h.replace(/(^|[-_])(\w)/g,(O,U,q)=>q.toUpperCase()),kind:String(y?.type??h),region:y?.region??t.project.region,desiredState:Oe(y)});d.set(h,k);let C=new Map(r.listResources(c.id,k.id).map((O)=>[`${O.kind}:${O.slug}`,O])),T=(O,U,q,N)=>{let Q=`${O}:${U}`,D=C.get(Q),Y=Oe(N);if(D){if(D.name!==q||En(D.desiredState)!==En(Y))C.set(Q,r.updateResource(D.id,D.version,{name:q,desiredState:Y}));return}let se=r.createResource({projectId:c.id,environmentId:k.id,kind:O,slug:U,name:q,provider:t.cloud?.provider,desiredState:Y,metadata:{source:"cloud-config"}});C.set(Q,se)};for(let[O,U]of Object.entries(t.sites??{}))T("application",O,O,U);let M=y?.app;if(M)for(let O of["http","queue","cli"])T("function",O,`${O.toUpperCase()} function`,{...Oe(M),function:O});let P=t.infrastructure;for(let[O,U]of Object.entries(P?.functions??{}))T("function",O,O,U);if(P?.compute)T("server",`${c.slug}-server`,c.name,{...Oe(P.compute),label:c.name});for(let[O,U]of Object.entries(P?.databases??{}))T("database",O,O,U);if(P?.appDatabase)T("database","application-database","Application database",P.appDatabase);else if(P?.database)T("database","application-database","Application database",{engine:P.database})}let a=new $e(r).recoverExpired(),u=r.reconcileOrphanedOperations({policy:"fail"}),m={requeued:a.requeued+u.requeued,failed:a.failed+a.cancelled+u.failed};return{store:r,organization:s,project:c,environments:d,reconciliation:m}}var cS=["project:read","config:read","deployments:read","deployments:create","runtime:read","runtime:logs"];function Zo(e,t){let{store:r,organization:n,project:i}=e,o=new Set;for(let s of t){let c=Ye(r,s);o.add(c.id);let d=r.getMembershipForActor(n.id,c.id);if(d&&d.source!=="legacy")continue;let a=r.listResources(i.id).filter((w)=>w.kind==="application"&&Object.hasOwn(s.sites,w.slug)),u=s.role==="admin"?"owner":"viewer",m=s.role==="admin"||a.length===0?{type:"organization"}:{type:"resource",id:a[0].id},h=d?d.roleTemplate!==u||En(d.scope)!==En(m)?r.updateMembership({id:d.id,roleTemplate:u,scope:m,actorId:c.id}):d:r.createMembership({organizationId:n.id,actorId:c.id,roleTemplate:u,scope:m,source:"legacy"}),y=new Set;if(s.role==="member"&&a.length===0)for(let w of fp("viewer"))y.add(`deny|${w}|organization|`);for(let w of a){let k=s.sites[w.slug];for(let C of cS)y.add(`allow|${C}|resource|${w.id}`);if(k==="owner")y.add(`allow|config:write|resource|${w.id}`)}for(let w of r.listGrants(h.id).filter((k)=>k.source==="legacy")){let k=`${w.effect}|${w.capability}|${w.scope.type}|${w.scope.id??""}`;if(!y.has(k))r.removeGrant(w.id,c.id)}for(let w of y){let[k,C,T,M]=w.split("|");r.upsertGrant({organizationId:n.id,membershipId:h.id,effect:k,capability:C,scope:T==="organization"?{type:"organization"}:{type:T,id:M},source:"legacy"})}}for(let s of r.listMemberships(n.id))if(s.source==="legacy"&&!o.has(s.actorId))r.revokeMembership(s.id)}async function Ir(e){let{controlPlane:t,environment:r,actor:n}=e,i=Ye(t.store,n),o=t.environments.get(r),s=e.resourceSlug&&o?t.store.listResources(t.project.id,o.id).find((u)=>u.slug===e.resourceSlug):void 0,c=new $e(t.store,{workerId:`dashboard:${process.pid}`}),d=c.enqueue({projectId:t.project.id,environmentId:o?.id,resourceId:s?.id,actorId:i.id,kind:e.kind,input:e.input??{},lockKey:s?`resource:${s.id}`:o?`environment:${o.id}`:`project:${t.project.id}`,providerKey:s?.provider??"dashboard",buildSlot:e.kind.includes("deploy"),maxAttempts:1,timeoutSeconds:3600,resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;if(!c.claim(d.id)?.operation)throw Error(`Could not claim control-plane operation ${d.id}`);try{let u=await e.execute(),m=typeof u.stdout==="string"?String(u.stdout):"",h=typeof u.stderr==="string"?String(u.stderr):"";if(m)c.appendLog(d.id,m,{stream:"stdout"});if(h)c.appendLog(d.id,h,{stream:"stderr"});let y=u.ok?c.complete(d.id,gp(u)):c.fail(d.id,dS(u),gp(u));return{result:u,operation:y}}catch(u){throw c.fail(d.id,u instanceof Error?u.message:String(u),{ok:!1,threw:!0}),u}}function dS(e){let t=e;return String(t.error??t.stderr??"Operation failed")}function gp(e){let t=e,r=typeof t.stdout==="string"?t.stdout:"",n=typeof t.stderr==="string"?t.stderr:"",i={ok:e.ok,stdoutBytes:Buffer.byteLength(r),stderrBytes:Buffer.byteLength(n)};if(typeof t.operation==="string")i.operation=t.operation;if(typeof t.error==="string")i.error=t.error;return Oe(i)}var vp=[{id:"server.overview",path:"/",label:"Dashboard",group:"overview",modes:["server"],adminOnly:!0,legacyPaths:["/server"]},{id:"server.activity",path:"/server/activity",label:"Activity",group:"overview",modes:["server"],adminOnly:!0,legacyPaths:["/activity"]},{id:"services.list",path:"/server/sites",label:"Services",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/sites","/services"]},{id:"deployments.list",path:"/server/deployments",label:"Deployments",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/deployments"]},{id:"logs.list",path:"/server/logs",label:"Logs",group:"applications",modes:["server"],adminOnly:!1,legacyPaths:["/logs"]},{id:"sources.integrations",path:"/integrations",label:"Git integrations",group:"applications",modes:["server","serverless"],adminOnly:!1},{id:"applications.create",path:"/applications/new",label:"Create application",group:"applications",modes:["server","serverless"],adminOnly:!1},{id:"applications.compose",path:"/applications/compose",label:"Compose applications",group:"applications",modes:["server"],adminOnly:!1},{id:"operations.queue",path:"/operations/queue",label:"Deployment queue",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"operations.previews",path:"/operations/previews",label:"Preview environments",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"operations.releases",path:"/operations/releases",label:"Releases & promotion",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"runtime.workloads",path:"/operations/workloads",label:"Workloads",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"observability.overview",path:"/operations/observability",label:"Observability",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"alerts.overview",path:"/operations/alerts",label:"Alerts & health",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"spend.overview",path:"/operations/spend",label:"Spend & budgets",group:"operations",modes:["server","serverless"],adminOnly:!1},{id:"automation.jobs",path:"/operations/jobs",label:"Workers & schedules",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/workers","/serverless/scheduler"]},{id:"configuration.entries",path:"/operations/configuration",label:"Environment & secrets",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/serverless/secrets"]},{id:"metrics.overview",path:"/server/metrics",label:"Metrics",group:"operations",modes:["server"],adminOnly:!0},{id:"runtime.services",path:"/server/services",label:"Runtime services",group:"operations",modes:["server"],adminOnly:!0},{id:"backups.list",path:"/data/backups",label:"Backups & recovery",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/backups"]},{id:"volumes.list",path:"/data/volumes",label:"Persistent volumes",group:"operations",modes:["server","serverless"],adminOnly:!1,legacyPaths:[]},{id:"fleet.list",path:"/server/fleet",label:"Fleet inventory",group:"operations",modes:["server"],adminOnly:!1,legacyPaths:[]},{id:"operations.run",path:"/server/actions",label:"Run operations",group:"operations",modes:["server"],adminOnly:!0},{id:"infrastructure.topology",path:"/infrastructure/topology",label:"Infrastructure map",group:"infrastructure",modes:["server","serverless"],adminOnly:!0,legacyPaths:["/topology"]},{id:"data.services",path:"/data/services",label:"Data services",group:"infrastructure",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/database","/databases","/server/database","/serverless/data"]},{id:"network.firewall",path:"/server/firewall",label:"Network & firewall",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"security.posture",path:"/security",label:"Security posture",group:"infrastructure",modes:["server","serverless"],adminOnly:!1,legacyPaths:["/server/security"]},{id:"access.ssh",path:"/server/ssh-keys",label:"SSH keys",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"runtime.terminal",path:"/server/terminal",label:"Terminal",group:"infrastructure",modes:["server"],adminOnly:!0},{id:"organization.people",path:"/server/team",label:"People & access",group:"organization",modes:["server","serverless"],adminOnly:!0,legacyPaths:["/team"]},{id:"organization.automation",path:"/account/automation",label:"API & automation",group:"organization",modes:["server","serverless"],adminOnly:!0},{id:"serverless.overview",path:"/serverless",label:"Dashboard",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.deployments",path:"/serverless/deployments",label:"Deployments",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.logs",path:"/serverless/logs",label:"Logs",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.metrics",path:"/serverless/metrics",label:"Metrics",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.traces",path:"/serverless/traces",label:"Traces",group:"overview",modes:["serverless"],adminOnly:!0},{id:"serverless.functions",path:"/serverless/functions",label:"Functions",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.queues",path:"/serverless/queues",label:"Queues",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.assets",path:"/serverless/assets",label:"Assets",group:"compute-data",modes:["serverless"],adminOnly:!0},{id:"serverless.network",path:"/serverless/firewall",label:"Network",group:"settings",modes:["serverless"],adminOnly:!0},{id:"serverless.alerts",path:"/serverless/alarms",label:"Alerts",group:"settings",modes:["serverless"],adminOnly:!0},{id:"serverless.cost",path:"/serverless/cost",label:"Costs",group:"settings",modes:["serverless"],adminOnly:!0}],lS=new Map(vp.flatMap((e)=>(e.legacyPaths??[]).map((t)=>[t,e.path])));function bp(e){return lS.get(e)}function j_(e,t){return vp.filter((r)=>r.modes.includes(e)&&(!t||!r.adminOnly))}import Qr from"node:process";import{existsSync as uS}from"node:fs";import{join as pS}from"node:path";async function U_(e){let t=Date.now(),r=e.sourceDir??"dist";if(!uS(pS(r,"index.html")))return pc(t,`${r}/ has no index.html — build first.`);if(!Qr.env.AWS_ACCESS_KEY_ID||!Qr.env.AWS_SECRET_ACCESS_KEY)return pc(t,"Missing AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY in env.");let n=mS(e.dnsProvider);if("error"in n)return pc(t,n.error);let i=await Sp({siteName:e.siteName,region:e.region??"us-east-1",domain:e.domain,bucket:e.bucket,stackName:e.stackName,certificateArn:e.certificateArn,defaultRootObject:e.defaultRootObject??"index.html",errorDocument:e.errorDocument??"404.html",cacheControl:e.cacheControl??"max-age=3600, public",sourceDir:r,cleanBucket:e.cleanBucket??!1,singlePageApp:e.singlePageApp??!1,dnsProvider:n,tags:{ManagedBy:"ts-cloud",Application:e.siteName,...e.tags},onProgress:e.onProgress});return{success:!!i.success,domain:i.domain,url:i.domain?`https://${i.domain}`:i.distributionDomain?`https://${i.distributionDomain}`:void 0,bucket:i.bucket,distributionId:i.distributionId,distributionDomain:i.distributionDomain,certificateArn:i.certificateArn,filesUploaded:i.filesUploaded,filesSkipped:i.filesSkipped,message:i.message,durationMs:Date.now()-t}}function mS(e){let t=typeof e==="string"?{provider:e}:e??{provider:"porkbun"};if(t.provider==="porkbun"){let r=t,n=r?.apiKey??Qr.env.PORKBUN_API_KEY,i=r?.secretKey??Qr.env.PORKBUN_SECRET_KEY??Qr.env.PORKBUN_SECRET_API_KEY;if(!n||!i)return{error:"Missing PORKBUN_API_KEY / PORKBUN_SECRET_KEY in env."};return{provider:"porkbun",apiKey:n,secretKey:i}}if(t.provider==="godaddy"){let r=t,n=r?.apiKey??Qr.env.GODADDY_API_KEY,i=r?.secretKey??Qr.env.GODADDY_API_SECRET,o=r?.environment??Qr.env.GODADDY_ENVIRONMENT;if(!n||!i)return{error:"Missing GODADDY_API_KEY / GODADDY_API_SECRET in env."};return{provider:"godaddy",apiKey:n,apiSecret:i,environment:o}}return{error:`Unsupported DNS provider: ${t.provider}`}}function pc(e,t){return{success:!1,message:t,durationMs:Date.now()-e}}import{createHash as gS}from"node:crypto";var fS=`let coldStart = true
2
2
  const initializedAt = new Date().toISOString()
3
3
  export const handler = async (event) => {
4
4
  const currentColdStart = coldStart
@@ -11,8 +11,8 @@ export const handler = async (event) => {
11
11
  body: JSON.stringify({ ok: statusCode === 200, service: 'ts-cloud-static-api', path, coldStart: currentColdStart, initializedAt })
12
12
  }
13
13
  }
14
- `;function Ip(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function hS(e){return["NoSuchEntity","ResourceNotFoundException","404"].includes(Ip(e))}function wp(e){return["EntityAlreadyExists","ResourceAlreadyExistsException","ResourceConflictException","409"].includes(Ip(e))}function kp(e,t){let r=e?.Items;if(!r)return[];if(Array.isArray(r))return r;let n=r[t];if(n===void 0)return[];return Array.isArray(n)?n:[n]}function mc(e){let t=e?.Aliases?.Items;if(Array.isArray(t))return t.map(String);if(typeof t==="string")return[t];return[]}function yS(e){if(!/^[A-Z0-9]{8,32}$/.test(e.distributionId))throw Error("CloudFront distribution ID is invalid");if(!/^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z0-9-]{2,63}$/.test(e.expectedAlias))throw Error("Expected CloudFront alias is invalid");if(!/^[A-Za-z0-9-_]{1,64}$/.test(e.functionName))throw Error("Lambda function name is invalid");let t=e.pathPattern?.startsWith("/")?e.pathPattern:`/${e.pathPattern||"api/*"}`;if(t==="/"||t==="/*"||!t.endsWith("*"))throw Error("API path must be a non-default wildcard pattern such as /api/*");let r=e.originId||`${e.functionName}-url`,n=e.roleName||`${e.functionName}-execution`;if(!/^[A-Za-z0-9_.-]{1,64}$/.test(n))throw Error("IAM role name is invalid");let i=e.memorySize??256,o=e.timeout??10,s=e.logRetentionDays??14;if(i<128||i>10240)throw Error("Lambda memory must be between 128 and 10240 MB");if(o<1||o>900)throw Error("Lambda timeout must be between 1 and 900 seconds");return{region:e.region||"us-east-1",pathPattern:t,originId:r,roleName:n,memorySize:i,timeout:o,logRetentionDays:s}}function vS(e){let t=e.region||"us-east-1";return{cloudfront:new Rn(e.profile),iam:new Xo(t,e.profile),lambda:new kt(t,e.profile),logs:new ci(t,e.profile),sts:new ai(t,e.profile),sleep:(r)=>new Promise((n)=>setTimeout(n,r))}}async function Q_(e,t){let r=yS(e),n=t||vS({profile:e.profile,region:r.region}),[i,o,s]=await Promise.all([n.sts.getCallerIdentity(),n.cloudfront.getDistribution(e.distributionId),n.cloudfront.getDistributionConfig(e.distributionId)]);if(!i.Account)throw Error("AWS identity did not return an account ID");if(!o.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!(mc(o).length?mc(o):mc(s.DistributionConfig)).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let d,a=!0;try{d=await n.iam.getRole({RoleName:r.roleName})}catch(de){if(!hS(de))throw de;a=!1}let u=d?.Arn||`arn:aws:iam::${i.Account}:role/${r.roleName}`,m=await n.lambda.functionExists(e.functionName),h=m?await n.lambda.getFunctionUrl(e.functionName):null,y=await n.cloudfront.listOriginAccessControls(),w=`${e.functionName}-lambda-url`,k=y.some((de)=>de.Name===w&&de.OriginAccessControlOriginType==="lambda"),C=kp(s.DistributionConfig.Origins,"Origin"),T=kp(s.DistributionConfig.CacheBehaviors,"CacheBehavior"),M=C.some((de)=>String(de.Id)===r.originId),P=T.some((de)=>String(de.PathPattern)===r.pathPattern),O=[...!a?[`create IAM execution role ${r.roleName}`]:[`reconcile IAM execution policy ${r.roleName}`],...m?[`update Lambda ${e.functionName} code and configuration`]:[`create Lambda ${e.functionName}`],...!h?["create private AWS_IAM function URL"]:[],...!k?[`create Lambda origin access control ${w}`]:[],"grant CloudFront function-URL and invocation permissions",`${P?"reconcile":"add"} ${r.pathPattern} behavior without changing the default behavior`],U={command:`cloud cdn:origin:remove ${e.distributionId} FUNCTION_URL_HOST --id ${r.originId} --path '${r.pathPattern}' --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,removeFunction:!m,removeRole:!a},q={mode:e.apply?"apply":"plan",accountId:i.Account,identityArn:i.Arn,distribution:{id:o.Id,arn:o.ARN,alias:e.expectedAlias,domainName:o.DomainName,status:o.Status},function:{name:e.functionName,existed:m,runtime:"nodejs22.x",urlExisted:!!h,url:h?.FunctionUrl},role:{name:r.roleName,existed:a,arn:u},origin:{id:r.originId,pathPattern:r.pathPattern,existed:M,behaviorExisted:P,accessControlExisted:k},changes:O,rollback:U,applied:!1};if(!e.apply)return q;let N=`${e.distributionId}:${r.pathPattern}`;if(e.confirm!==N)throw Error(`Pass exact confirmation token ${N} to mutate the live distribution`);if(!d)d=await n.iam.createRole({RoleName:r.roleName,Description:`Execution role for ${e.functionName}`,AssumeRolePolicyDocument:JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]}),Tags:[{Key:"ManagedBy",Value:"ts-cloud"}]});await n.iam.putRolePolicy({RoleName:r.roleName,PolicyName:"lambda-logs",PolicyDocument:JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:`arn:aws:logs:${r.region}:${i.Account}:log-group:/aws/lambda/${e.functionName}:*`}]})});try{await n.logs.createLogGroup(`/aws/lambda/${e.functionName}`,{ManagedBy:"ts-cloud"})}catch(de){if(!wp(de))throw de}await n.logs.putRetentionPolicy(`/aws/lambda/${e.functionName}`,r.logRetentionDays);let Q=e.code||fS;if(m)await n.lambda.updateFunctionCodeInline(e.functionName,Q,"index.mjs"),await n.lambda.waitForFunctionActive(e.functionName),await n.lambda.updateFunctionConfiguration({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:d.Arn,Handler:"index.handler",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize});else{let de;for(let Re=0;Re<8;Re++)try{await n.lambda.createFunctionWithCode({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:d.Arn,Handler:"index.handler",Code:Q,Filename:"index.mjs",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize}),de=void 0;break}catch(Me){if(de=Me,!String(Me.message).toLowerCase().includes("role"))throw Me;await n.sleep(1000)}if(de)throw de}await n.lambda.waitForFunctionActive(e.functionName);let D=h||await n.lambda.createFunctionUrl({FunctionName:e.functionName,AuthType:"AWS_IAM",InvokeMode:"BUFFERED"});if(!D.FunctionUrl)throw Error("Lambda did not return a function URL");let Y=new URL(D.FunctionUrl).hostname,se=await n.cloudfront.findOrCreateOriginAccessControl(w,"lambda"),he=o.ARN||`arn:aws:cloudfront::${i.Account}:distribution/${e.distributionId}`,je=[{FunctionName:e.functionName,StatementId:"AllowCloudFrontFunctionUrl",Action:"lambda:InvokeFunctionUrl",Principal:"cloudfront.amazonaws.com",SourceArn:he,FunctionUrlAuthType:"AWS_IAM"},{FunctionName:e.functionName,StatementId:"AllowCloudFrontInvoke",Action:"lambda:InvokeFunction",Principal:"cloudfront.amazonaws.com",SourceArn:he,InvokedViaFunctionUrl:!0}];for(let de of je)try{await n.lambda.addPermission(de)}catch(Re){if(!wp(Re))throw Re}return await n.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:Y,pathPattern:r.pathPattern,originAccessControlId:se.Id}),{...q,function:{...q.function,url:D.FunctionUrl},applied:!0}}async function Y_(e){let t=`https://${e.alias}/`,r=`https://${e.alias}/api/health`,n=await fetch(t,{redirect:"follow",headers:{"cache-control":"no-cache"}}),i=new Uint8Array(await n.arrayBuffer()),o=gS("sha256").update(i).digest("hex"),s=Date.now(),c=await fetch(r,{redirect:"follow",headers:{"cache-control":"no-cache"}}),d=Date.now()-s,a=await c.text(),u=a;try{u=JSON.parse(a)}catch{}let m;if(e.logs&&e.functionName){let h=await e.logs.filterLogEvents({logGroupName:`/aws/lambda/${e.functionName}`,startTime:s-60000,filterPattern:'"Init Duration"',limit:25});for(let y of h.events||[]){let w=y.message?.match(/Init Duration:\s*([0-9.]+)\s*ms/i);if(w)m=Number(w[1])}}return{frontend:{url:t,status:n.status,sha256:o,unchanged:e.expectedFrontendSha256?o===e.expectedFrontendSha256:void 0,bytes:i.byteLength},api:{url:r,status:c.status,latencyMs:d,healthy:c.ok&&!!u?.ok,body:u},coldStart:{observed:m!==void 0,initDurationMs:m},verifiedAt:(e.now?.()||new Date).toISOString()}}function Z_(e){let t=(e.memoryMb||256)/1024,r=Math.max(0,e.requests-(e.includeFreeTier===!1?0:1e6)),n=Math.max(0,e.requests*(e.averageDurationMs/1000)*t-(e.includeFreeTier===!1?0:400000)),i=r/1e6*0.2+n*0.0000166667,o=9.010025,s=16.425;return{lambdaUsd:Number(i.toFixed(2)),alwaysOnFargateAndAlbUsd:Number(25.435025000000003 .toFixed(2)),assumptions:["us-east-1 public list rates snapshot, July 2026","Lambda x86 request and duration pricing with optional monthly free tier","Fargate comparison uses one always-on 0.25 vCPU/0.5 GB task plus one ALB before LCU charges","excludes CloudFront, data transfer, logs, taxes, and application data services"]}}import{createHash as bS}from"node:crypto";function SS(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function wS(e){return SS(e)==="ValidationError"&&String(e.message).includes("does not exist")}function kS(e){return Object.fromEntries((e||[]).map((t)=>[t.OutputKey,t.OutputValue]))}function IS(e){let t=e?.Aliases?.Items??e?.Aliases;if(Array.isArray(t))return t.map(String);if(typeof t==="string")return[t];return[]}function Ap(e){if(!/^[a-z][a-z0-9-]{1,62}$/.test(e.slug))throw Error("Slug must be a lowercase DNS-safe identifier");if(!/^[A-Z0-9]{8,32}$/.test(e.distributionId))throw Error("CloudFront distribution ID is invalid");if(!/^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z0-9-]{2,63}$/.test(e.expectedAlias))throw Error("Expected distribution alias is invalid");let t=e.imageUri.match(/@((?:sha256:)[a-f0-9]{64})$/i)?.[1];if(!t)throw Error("Container image must use an immutable ECR digest URI ending in @sha256:<64 hex>");let r=e.stackName||`${e.slug}-backend`;if(!/^[A-Za-z][A-Za-z0-9-]{0,127}$/.test(r))throw Error("CloudFormation stack name is invalid");let n=e.pathPattern||"/api/*";if(!/^\/[A-Za-z0-9_.*?~!$&'()+,;=:@%/-]+\*$/.test(n)||n==="/*")throw Error("Backend path must be a non-default wildcard pattern");let i=e.originId||`${e.slug}-backend`;if(!/^[A-Za-z0-9_.-]{1,128}$/.test(i))throw Error("CloudFront origin ID is invalid");if(e.originVerifySecret&&e.originVerifySecret.length<24)throw Error("Origin verification secret must contain at least 24 characters");if(!!e.originDomain!==!!e.certificateArn)throw Error("A custom origin domain and matching ACM certificate ARN must be provided together");return{stackName:r,region:e.region||"us-east-1",pathPattern:n,originId:i,digest:t}}function ES(e){let t=e.region||"us-east-1";return{cloudformation:new Er(t,e.profile),cloudfront:new Rn(e.profile),sts:new ai(t,e.profile),fetch,sleep:(r)=>new Promise((n)=>setTimeout(n,r))}}function RS(e){let t=Ap(e),r=Rp({name:e.name,slug:e.slug,domain:e.originDomain||e.expectedAlias,imageUri:e.imageUri,certificateArn:e.certificateArn,originVerifySecret:e.originVerifySecret,desiredCount:e.desiredCount,database:e.database,cache:e.cache,queue:e.queue}),n=Ep(r);return n.Description=`Managed backend for existing static frontend ${e.expectedAlias}`,n.Metadata={ManagedBy:"ts-cloud",ExistingDistributionId:e.distributionId,ExistingDistributionAlias:e.expectedAlias,BackendPathPattern:t.pathPattern,ContainerDigest:t.digest},n}async function AS(e,t,r){let n;for(let i=0;i<30;i++){let o=Date.now();try{let s=await e.fetch(t,{redirect:"manual",headers:r?{"x-origin-verify":r}:void 0}),c=Date.now()-o,d=await s.text(),a=d;try{a=JSON.parse(d)}catch{}if(s.ok)return{url:t,status:s.status,latencyMs:c,body:a};n=Error(`origin returned ${s.status}`)}catch(s){n=s}if(i<29)await e.sleep(1e4)}throw Error(`Backend origin did not become healthy: ${n instanceof Error?n.message:String(n)}`)}async function oT(e,t){let r=Ap(e),n=t||ES({region:r.region,profile:e.profile}),[i,o]=await Promise.all([n.sts.getCallerIdentity(),n.cloudfront.getDistribution(e.distributionId)]);if(!i.Account)throw Error("AWS identity did not return an account ID");if(!o.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!IS(o).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let s;try{s=(await n.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0]}catch(O){if(!wS(O))throw O}let c=RS(e),d=JSON.stringify(c);if(Buffer.byteLength(d)>51200)throw Error("Generated template exceeds the direct CloudFormation template body limit");let a=Object.values(c.Resources||{}).reduce((O,U)=>(O[U.Type]=(O[U.Type]||0)+1,O),{}),u=[`cloud cdn:origin:remove ${e.distributionId} ${e.originDomain||"ALB_HOST"} --id ${r.originId} --path '${r.pathPattern}' --profile ${e.profile||"default"} --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,`After CloudFront is deployed, restore external DNS if changed and delete stack ${r.stackName} only with an approved data-retention decision.`],m={mode:e.apply?"apply":"plan",accountId:i.Account,stack:{name:r.stackName,existed:!!s,status:s?.StackStatus,templateSha256:bS("sha256").update(d).digest("hex"),resourceCount:Object.keys(c.Resources||{}).length,resourceTypes:a},distribution:{id:o.Id,alias:e.expectedAlias,domainName:o.DomainName,status:o.Status,pathPattern:r.pathPattern,originId:r.originId},artifact:{imageUri:e.imageUri,digest:r.digest},services:{database:e.database!==!1,cache:e.cache!==!1,queue:e.queue!==!1,mail:"ses",desiredCount:e.desiredCount||1},cloudFrontApplied:!1,dnsApplied:!1,applied:!1,rollback:u};if(!e.apply)return m;let h=`${e.distributionId}:${r.pathPattern}:${r.stackName}`;if(e.confirm!==h)throw Error(`Pass exact confirmation token ${h} to provision the backend and change live routing`);if(s)try{await n.cloudformation.updateStack({stackName:r.stackName,templateBody:d,capabilities:["CAPABILITY_NAMED_IAM"],tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await n.cloudformation.waitForStack(r.stackName,"stack-update-complete")}catch(O){if(!String(O.message).includes("No updates are to be performed"))throw O}else await n.cloudformation.createStack({stackName:r.stackName,templateBody:d,capabilities:["CAPABILITY_NAMED_IAM"],onFailure:"ROLLBACK",tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await n.cloudformation.waitForStack(r.stackName,"stack-create-complete");let y=(await n.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0],w=kS(y?.Outputs),k=w.AppLoadBalancerDnsName;if(!k)throw Error("Backend stack did not return AppLoadBalancerDnsName");let C=!1;if(e.originDomain&&e.originDomain!==k){if(!n.dns)throw Error(`External DNS provider is required to map ${e.originDomain} to ${k}`);let O=await n.dns.upsertRecord(e.originDomain,{name:e.originDomain,type:"CNAME",content:k,ttl:300});if(!O.success)throw Error(O.message||"External DNS update failed");C=!0}let T=e.originDomain||k,M=e.certificateArn?"https-only":"http-only",P=e.skipHealthCheck?void 0:await AS(n,`${M==="https-only"?"https":"http"}://${T}/api/health`,e.originVerifySecret);return await n.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:T,pathPattern:r.pathPattern,protocolPolicy:M,customHeaders:e.originVerifySecret?{"X-Origin-Verify":e.originVerifySecret}:void 0}),{...m,outputs:w,health:P,cloudFrontApplied:!0,dnsApplied:C,applied:!0}}function sT(e={}){let r={fargate:730*(e.desiredCount||1)*0.012342500000000001,applicationLoadBalancer:16.425,natGateway:32.85,postgres:730*(e.multiAzDatabase?0.032:0.016),redis:23.36};return{monthlyUsd:Number(Object.values(r).reduce((n,i)=>n+i,0).toFixed(2)),components:Object.fromEntries(Object.entries(r).map(([n,i])=>[n,Number(i.toFixed(2))])),assumptions:["us-east-1 public on-demand rate snapshot, July 2026","one 0.25 vCPU/0.5 GB Linux Fargate task unless desiredCount is changed","one ALB before LCU charges and one NAT gateway before data processing","single-AZ db.t4g.micro PostgreSQL by default and two cache.t4g.micro Redis nodes","excludes storage, backups, CloudFront, data transfer, public IPv4, logs, email, queue requests, taxes, and free-tier credits"]}}import{execFileSync as CS}from"node:child_process";import{createHash as PS}from"node:crypto";import{existsSync as _p,mkdirSync as _S,mkdtempSync as TS,readdirSync as xS,readFileSync as DS,rmSync as OS,statSync as Tp,writeFileSync as $S}from"node:fs";import{tmpdir as NS}from"node:os";import{basename as jS,join as di,relative as MS,resolve as gc}from"node:path";var BS=new Set([".git","node_modules","dist","coverage"]);function xp(e,t=e){let r=[];for(let n of xS(e).sort()){if(BS.has(n))continue;let i=di(e,n);if(Cp(i,t))continue;let o=Tp(i);if(o.isDirectory())r.push(...xp(i,t));else if(o.isFile())r.push(MS(t,i))}return r}function LS(e){let t=gc(e);if(!_p(t)||!Tp(t).isDirectory())throw Error(`Container context does not exist: ${t}`);let r=PS("sha256");for(let n of xp(t))r.update(n),r.update("\x00"),r.update(DS(di(t,n))),r.update("\x00");return r.digest("hex")}function FS(e){return{ecr:new Pp(e.region||"us-east-1",e.profile),run:(t,r,n)=>{CS(t,r,{cwd:n?.cwd,env:n?.env,stdio:n?.stdio||"inherit"})}}}async function fT(e,t){let r=gc(e.context),n=gc(e.dockerfile||di(r,"Dockerfile"));if(!_p(n))throw Error(`Dockerfile does not exist: ${n}`);if(!e.repository.split("/").every((w)=>/^[a-z0-9][a-z0-9._-]*$/.test(w)&&!/[._-]$/.test(w)&&!/[._-]{2}/.test(w)))throw Error("ECR repository name is invalid");let s=t||FS(e),c=LS(r),d=`sha-${c.slice(0,20)}`,a="";try{a=(await s.ecr.describeRepositories({repositoryNames:[e.repository]})).repositories?.[0]?.repositoryUri||""}catch{}if(!a)a=(await s.ecr.createRepository({repositoryName:e.repository,imageTagMutability:"IMMUTABLE",imageScanningConfiguration:{scanOnPush:!0},tags:[{Key:"ManagedBy",Value:"ts-cloud"}]})).repository?.repositoryUri||"";if(!a)throw Error(`Could not resolve ECR repository URI for ${e.repository}`);await s.ecr.putLifecyclePolicy({repositoryName:e.repository,lifecyclePolicyText:JSON.stringify({rules:[{rulePriority:1,description:"Retain the newest 25 release images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:25},action:{type:"expire"}}]})});let u=`${a}:${d}`,m=TS(di(NS(),"ts-cloud-container-"));try{s.run("docker",["version"],{stdio:"ignore"}),s.run("docker",["build","--platform",e.platform||"linux/amd64","--provenance=false","--sbom=false","--file",n,"--tag",u,r],{cwd:r});let w=(await s.ecr.getAuthorizationToken()).authorizationData?.[0];if(!w?.authorizationToken||!w.proxyEndpoint)throw Error("ECR did not return Docker authorization data");let k=w.proxyEndpoint.replace(/^https?:\/\//,""),C=di(m,"docker");_S(C,{recursive:!0}),$S(di(C,"config.json"),JSON.stringify({auths:{[k]:{auth:w.authorizationToken}}}),{mode:384}),s.run("docker",["push",u],{env:{...process.env,DOCKER_CONFIG:C}})}finally{OS(m,{recursive:!0,force:!0})}let y=(await s.ecr.describeImages({repositoryName:e.repository,imageIds:[{imageTag:d}]})).imageDetails?.[0]?.imageDigest;if(!y||!/^sha256:[a-f0-9]{64}$/i.test(y))throw Error(`ECR did not return an immutable digest for ${jS(u)}`);return{repository:e.repository,tag:d,imageUri:u,digest:y,digestUri:`${a}@${y}`,contextSha256:c}}import{existsSync as zS,readdirSync as US,readFileSync as qS,statSync as VS}from"node:fs";import{join as qp,relative as WS}from"node:path";function Cn(e,t){let r=e.environments?.[t]?.app;if(!r)throw Error(`No serverless app configured for environment '${t}'. Add environments.${t}.app to your config.`);let n=e.project.slug,i=e.environments?.[t]?.region||e.project.region||"us-east-1";return{app:r,slug:n,region:i,stackName:li(e,t),artifactBucket:Dp(n,t),assetsBucket:Op(n,t)}}async function An(e,t=8){let r;for(let n=0;n<t;n++)try{return await e()}catch(i){let o=i?.code||i?.name||"",s=String(i?.message||"");if(o==="ResourceConflictException"||/update is in progress|currently in the following state/i.test(s)){r=i,await new Promise((c)=>setTimeout(c,3000));continue}throw i}throw r}var Vp=(e,t)=>`releases/${e}/${t}/current.json`;async function is(e,t,r,n){try{return await e.getObjectJson(t,Vp(r,n))}catch{return null}}async function Wp(e,t,r,n,i){await e.putObjectJson(t,Vp(r,n),i)}async function HS(e,t){if(!e.secrets)return{};let r=new Yr(t),n={},i=Array.isArray(e.secrets)?e.secrets.map((o)=>({envName:o.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),secretId:o})):Object.entries(e.secrets).map(([o,s])=>({envName:o,secretId:s}));if(Array.isArray(e.secrets)){let o=new Map;for(let{envName:c,secretId:d}of i)o.set(c,[...o.get(c)??[],d]);let s=[...o.entries()].filter(([,c])=>c.length>1);if(s.length){let c=s.map(([d,a])=>`${d} ← ${a.join(", ")}`).join("; ");throw Error(`serverless secrets: multiple secrets map to the same env var (${c}). Use the map form { ENV_NAME: 'secret/id' } to disambiguate.`)}}for(let{envName:o,secretId:s}of i){let d=(await r.getSecretValue({SecretId:s})).SecretString??"";try{let a=JSON.parse(d);if(a&&typeof a==="object"&&!Array.isArray(a)){for(let[u,m]of Object.entries(a))n[u]=String(m);continue}}catch{}n[o]=d}return n}function Hp(e,t){let r={},n=t.DbProxyEndpoint||t.DbEndpoint;if(n)r.DB_CONNECTION="mysql",r.DB_HOST=n,r.DB_PORT="3306",r.DB_DATABASE=r.DB_DATABASE||"app";if(t.CacheEndpoint){if(r.REDIS_HOST=t.CacheEndpoint,r.REDIS_PORT="6379",e.cache?.driver==="elasticache")r.CACHE_STORE="redis",r.CACHE_DRIVER="redis",r.SESSION_DRIVER="redis"}return r}function ts(e,t,r,n,i,o,s,c={}){let d=e.kind==="php"?Lp({cacheDriver:e.cache?.driver==="elasticache"?"redis":"dynamodb"}):{};return{TSCLOUD_LAMBDA_MODE:n,TSCLOUD_ENV:r,MAINTENANCE_MODE:"0",...e.octane?{TSCLOUD_OCTANE:"1"}:{},...e.serveAssets?{TSCLOUD_SERVE_ASSETS:"1"}:{},...e.redirectRobotsTxt===!1?{TSCLOUD_REDIRECT_ROBOTS_TXT:"0"}:{},...d,...c,...t.app.cache?.driver!=="elasticache"?{TSCLOUD_CACHE_TABLE:`${t.slug}-${r}-cache`}:{},...s?{TSCLOUD_QUEUE:s,SQS_QUEUE:s}:{},...o?{ASSET_URL:o}:{},...e.env??{},...i}}function KS(e){let t=e.slice(e.lastIndexOf(".")).toLowerCase();return{".html":"text/html",".css":"text/css",".js":"text/javascript",".mjs":"text/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain",".map":"application/json"}[t]??"application/octet-stream"}function*Kp(e){for(let t of US(e)){let r=qp(e,t);if(VS(r).isDirectory())yield*Kp(r);else yield r}}async function JS(e,t,r,n,i=!1){let o=0;for(let s of Kp(r)){let c=WS(r,s).replace(/\\/g,"/");if(!i&&c.split("/").some((d)=>d.startsWith(".")))continue;await e.putObject({bucket:t,key:`${n}/${c}`,body:qS(s),contentType:KS(s),cacheControl:"public, max-age=31536000, immutable"}),o++}return o}function GS(e,t){let r=Object.entries(t).reduce((n,[i,o])=>n+Buffer.byteLength(`${i}=${o}`,"utf8"),0);if(r>4096){let n=Object.entries(t).map(([i,o])=>[i,Buffer.byteLength(`${i}=${o}`,"utf8")]).sort((i,o)=>o[1]-i[1]).slice(0,5).map(([i,o])=>`${i} (${o}B)`).join(", ");throw Error(`${e}: environment variables total ${r}B, over AWS's 4096B limit (${r-4096}B too large). Largest: ${n}. Move large/secret values out of env — store them in Secrets Manager and fetch at cold start.`)}}async function eo(e,t,r,n){GS(t,r),await An(()=>e.updateFunctionConfiguration({FunctionName:t,Environment:{Variables:r}})),await e.waitForFunctionActive(t,120);let i=n.kind==="image"?{FunctionName:t,ImageUri:n.imageUri}:{FunctionName:t,S3Bucket:n.bucket,S3Key:n.key};await An(()=>e.updateFunctionCode(i)),await e.waitForFunctionActive(t,120)}async function rs(e,t){let n=(await An(()=>e.publishVersion({FunctionName:t}))).Version;if(!n)throw Error(`publishVersion returned no version for ${t}`);return await An(()=>e.updateAlias({FunctionName:t,Name:"live",FunctionVersion:n})),n}async function QS(e,t,r={}){let n=Cn(e,t),{app:i,slug:o,region:s,stackName:c,artifactBucket:d}=n,a=r.projectRoot??process.cwd();ns(`Deploying serverless app: ${o} (${t})`),Mt(`Stack: ${c}`),Mt(`Region: ${s}`);let u=new ur(s),m=new Er(s),h=new kt(s),y=i.kind==="php",w=i.packaging==="image",k=jp(i),C,T,M,P,O=[];if(w&&k.usesLayer&&k.layerKind!=="php")throw Error(`packaging: 'image' currently supports PHP and managed Node runtimes. ${k.kind}${k.kind==="node"?` ${k.version}`:""} uses a custom runtime — `+"use the default zip packaging (the runtime layer is built + attached automatically).");if(w){ct("Building + pushing container image");let{buildAndPushServerlessImage:F}=await import("./chunk-rg720cqg.js"),K=await F({app:i,projectRoot:a,region:s,repository:`${o}-${t}`,skipBuild:r.skipBuild,onStep:(ye)=>Mt(` ${ye}`)});C=K.handlers,T={kind:"image",imageUri:K.imageUri},M=K.tag,O.push({ParameterKey:"ImageUri",ParameterValue:K.imageUri})}else{ct("Packaging application");let F=y?Fp({projectRoot:a,app:i,skipBuild:r.skipBuild,onStep:(Ae)=>Mt(` ${Ae}`)}):await Np({projectRoot:a,app:i,skipBuild:r.skipBuild,onStep:(Ae)=>Mt(` ${Ae}`)}),K=$p(o,t,F.sha256);if(Mt(`Artifact: ${F.sha256.slice(0,12)} (${(F.zip.length/1024).toFixed(0)} KB)`),C=F.handlers,M=F.sha256,k.usesLayer){let Ae=k.layerEnvVar?process.env[k.layerEnvVar]:void 0;if(P=i.layers??(Ae?[Ae]:void 0),!P?.length){let G=k.layerKind==="php"?"serverless:build-php-layer":k.layerKind==="bun"?"serverless:build-bun-layer":"serverless:build-node-layer";throw Error(`${k.kind} apps on provided.al2023 need a runtime layer. Set environments.<env>.app.layers or the ${k.layerEnvVar} env var (build one with \`cloud ${G}\`)${k.kind==="node"?", or use a managed Node version (18/20/22)":""}.`)}}if(!await u.bucketExists(d))ct(`Creating artifact bucket ${d}`),await u.createBucket(d);if(await u.headObject(d,K).then((Ae)=>Ae!==null).catch(()=>!1))Mt("Artifact already uploaded — reusing");else ct("Uploading artifact"),await u.putObject({bucket:d,key:K,body:F.zip,contentType:"application/zip"});T={kind:"zip",bucket:d,key:K},O.push({ParameterKey:"ArtifactBucket",ParameterValue:d},{ParameterKey:"ArtifactKey",ParameterValue:K})}let U=Bp({config:e,environment:t,app:i,handlers:C,runtimeLayers:P}),q=JSON.stringify(U.template),N=["CAPABILITY_NAMED_IAM"],Q=await m.describeStacks({stackName:c}).then((F)=>F.Stacks[0]?.StackStatus).catch(()=>{return}),D=Q!==void 0;if(Q&&/DELETE_IN_PROGRESS/.test(Q))ct("Waiting for an in-progress stack delete to finish"),await m.waitForStack(c,"stack-delete-complete").catch(()=>{}),D=!1;else if(Q&&/(?:ROLLBACK_COMPLETE|REVIEW_IN_PROGRESS|CREATE_FAILED)/.test(Q))ct(`Deleting unusable stack (status ${Q}) before recreate`),await m.deleteStack(c),await m.waitForStack(c,"stack-delete-complete").catch(()=>{}),D=!1;ct(D?"Updating infrastructure stack":"Creating infrastructure stack");try{if(D)await m.updateStack({stackName:c,templateBody:q,parameters:O,capabilities:N}),await m.waitForStack(c,"stack-update-complete");else await m.createStack({stackName:c,templateBody:q,parameters:O,capabilities:N,onFailure:"DELETE"}),await m.waitForStack(c,"stack-create-complete")}catch(F){if(/No updates are to be performed/i.test(String(F?.message)))Mt("No infrastructure changes");else throw F}let Y=await m.getStackOutputs(c).catch(()=>({})),se;if(i.assets){let F=qp(a,i.assets);if(zS(F)){let K=i.assetDomain||Y.AssetsCdnDomain;se=K?`https://${K}/${M}`:void 0,ct(`Syncing assets from ${i.assets}`);let ye=await JS(u,n.assetsBucket,F,M,i.dotFilesAsAssets);Mt(`Uploaded ${ye} asset(s)${se?` → ${se}`:""}`)}else es(`Assets directory not found: ${F}`)}ct("Resolving secrets");let he=await HS(i,s);if(i.database?.connection==="aurora-serverless")try{let K=await new Yr(s).getSecretValue({SecretId:`${o}/${t}/db`}),ye=JSON.parse(K.SecretString??"{}");if(ye.username)he.DB_USERNAME=ye.username;if(ye.password)he.DB_PASSWORD=ye.password}catch(F){es(`Could not resolve Aurora DB credentials: ${F.message}`)}if(!await u.bucketExists(d))await u.createBucket(d);let je=await is(u,d,o,t),de={},Re=U.queueNames[0],Me=Hp(i,Y);if(ct("Activating functions"),de.http=ts(i,n,t,"http",he,se,Re,Me),await eo(h,U.functionNames.http,de.http,T),de.cli=ts(i,n,t,"cli",he,se,Re,Me),await eo(h,U.functionNames.cli,de.cli,T),U.queueNames.length)de.queue=ts(i,n,t,"queue",he,se,Re,Me),await eo(h,U.functionNames.queue,de.queue,T);let me=(i.provisionedConcurrency??0)>0,R={};if(me){if(ct("Publishing versions + flipping live alias"),R.http=await rs(h,U.functionNames.http),R.cli=await rs(h,U.functionNames.cli),U.queueNames.length)R.queue=await rs(h,U.functionNames.queue)}if(await Wp(u,d,o,t,{sha:M,code:T,previousSha:je?.sha,previousCode:je?.code,previousFunctionEnv:je?.functionEnv,...me?{functionVersions:R,previousFunctionVersions:je?.functionVersions}:{},functionEnv:de,functionNames:{http:U.functionNames.http,cli:U.functionNames.cli,...U.queueNames.length?{queue:U.functionNames.queue}:{}},assetUrl:se,timestamp:new Date().toISOString()}),!r.skipDeployHooks&&i.deploy?.length){ct("Running deploy hooks");for(let F of i.deploy){Mt(` deploy: ${F}`);let K=await h.invoke({FunctionName:U.functionNames.cli,InvocationType:"RequestResponse",Payload:{command:F},LogType:"Tail"});if(K.FunctionError)throw zp("Deploy hook failed — the new build is ALREADY LIVE."),Mt(` Roll back with: cloud serverless:rollback --env ${t}`),Error(`Deploy hook failed (${F}): ${K.Payload}`)}}let j=Y.HttpApiEndpoint;if(!r.skipHealthCheck&&j){ct("Health check");try{let F=await fetch(j,{method:"GET"});Mt(`GET ${j} → ${F.status}`)}catch(F){es(`Health check could not reach ${j}: ${F.message}`)}}Up(["Serverless deploy complete","",j?`URL: ${j}`:"",`Stack: ${c}`,`Build: ${M.slice(0,12)}`].filter(Boolean).join(`
15
- `),"green")}async function fc(e,t){let r=Cn(e,t),n=new ur(r.region),i=new kt(r.region),o=await is(n,r.artifactBucket,r.slug,t);if(!o)throw Error("No previous release to redeploy. Run a full deploy first.");ns(`Redeploying ${r.slug} (${t}) — build ${o.sha.slice(0,12)}`);for(let[s,c]of Object.entries(o.functionNames)){if(!c)continue;ct(`Re-activating ${s} (${c})`),await eo(i,c,o.functionEnv[s]??{},o.code);let d=o.functionVersions?.[s];if(d)await An(()=>i.updateAlias({FunctionName:c,Name:"live",FunctionVersion:d}))}to("Redeploy complete")}async function hc(e,t){let r=Cn(e,t),n=new ur(r.region),i=new kt(r.region),o=await is(n,r.artifactBucket,r.slug,t);if(!o?.previousCode)throw Error("No previous release to roll back to.");ns(`Rolling back ${r.slug} (${t}) → ${o.previousSha?.slice(0,12)}`);for(let[s,c]of Object.entries(o.functionNames)){if(!c)continue;ct(`Restoring ${s} (${c})`);let d=o.previousFunctionEnv?.[s]??o.functionEnv[s]??{};await eo(i,c,d,o.previousCode);let a=o.previousFunctionVersions?.[s];if(a)await An(()=>i.updateAlias({FunctionName:c,Name:"live",FunctionVersion:a}))}await Wp(n,r.artifactBucket,r.slug,t,{...o,sha:o.previousSha??o.sha,code:o.previousCode,functionEnv:o.previousFunctionEnv??o.functionEnv,functionVersions:o.previousFunctionVersions??o.functionVersions,previousSha:void 0,previousCode:void 0,previousFunctionEnv:void 0,previousFunctionVersions:void 0,timestamp:new Date().toISOString()}),to("Rollback complete")}async function os(e,t,r,n){let i=Cn(e,t),o=new kt(i.region),s=`${i.slug}-${t}-http`,d={...(await o.getFunction(s)).Configuration?.Environment?.Variables??{}};if(d.MAINTENANCE_MODE=r?"1":"0",r&&n)d.MAINTENANCE_BYPASS_SECRET=n;if(!r)delete d.MAINTENANCE_BYPASS_SECRET;if(await An(()=>o.updateFunctionConfiguration({FunctionName:s,Environment:{Variables:d}})),(i.app.provisionedConcurrency??0)>0)await o.waitForFunctionActive(s,120),await rs(o,s);to(r?"Application is now in maintenance mode (503)":"Application is live")}async function ui(e,t,r){let n=Cn(e,t),i=new kt(n.region),o=`${n.slug}-${t}-cli`,s=await i.invoke({FunctionName:o,InvocationType:"RequestResponse",Payload:{command:r},LogType:"Tail"});if(s.FunctionError)throw Error(`Command failed: ${s.Payload}`);return s.Payload??""}async function nt(e,t){let r=Cn(e,t),n=new Er(r.region),i=new kt(r.region),o=new ur(r.region),s="not deployed",c={};try{let{Stacks:w}=await n.describeStacks({stackName:r.stackName});s=w?.[0]?.StackStatus??s;for(let k of w?.[0]?.Outputs??[])if(k.OutputKey)c[k.OutputKey]=k.OutputValue??""}catch{}let d=Mp(r.app,r.slug,t),a=r.app.provisionedConcurrency??0,u=["http","cli",...d.length?["queue"]:[]],m=`${r.slug}-${t}`,h=[];for(let w of u){let k=`${m}-${w}`,C={mode:w,name:k,version:"$LATEST"};if(a>0){let T=await i.getAlias(k,"live").catch(()=>null);if(T?.FunctionVersion){C.version=T.FunctionVersion;let M=await i.getProvisionedConcurrencyConfig(k,"live").catch(()=>null);if(M)C.provisioned={status:M.Status??"-",allocated:M.AllocatedProvisionedConcurrentExecutions??0,requested:M.RequestedProvisionedConcurrentExecutions??0}}}h.push(C)}let y=await is(o,r.artifactBucket,r.slug,t).catch(()=>null);return{slug:r.slug,environment:t,region:r.region,stackStatus:s,endpoint:c.HttpApiEndpoint,assetUrl:y?.assetUrl,scheduler:r.app.scheduler??"on",queues:d,provisionedConcurrency:a,functions:h,lastRelease:y?{sha:y.sha,timestamp:y.timestamp}:void 0}}function YS(e,t){return`${e}-${t}-db`}async function Jp(e,t,r,n){let i=Cn(e,t);if(i.app.database?.connection!=="aurora-serverless")throw Error("No Aurora Serverless v2 database is configured for this environment.");let{RDSClient:o}=await import("./chunk-as6by62d.js"),s=new o(i.region),c=YS(i.slug,t);ct(`Scaling ${c} → ${r}–${n} ACUs`),await s.modifyDBCluster({DBClusterIdentifier:c,ServerlessV2ScalingConfiguration:{MinCapacity:r,MaxCapacity:n},ApplyImmediately:!0}),to(`Scaling applied to ${c} (takes effect shortly).`)}class Rr{client;region;constructor(e="us-east-1",t){this.region=e,this.client=new pi(Qp(t))}async query(e){let t=new URLSearchParams(Gp({Version:"2010-08-01",...e})).toString();return this.client.request({service:"monitoring",region:this.region,method:"POST",path:"/",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t})}async getMetricStatistics(e){let t={Action:"GetMetricStatistics",Namespace:e.Namespace,MetricName:e.MetricName,StartTime:e.StartTime.toISOString(),EndTime:e.EndTime.toISOString(),Period:e.Period};(e.Statistics??[]).forEach((o,s)=>{t[`Statistics.member.${s+1}`]=o}),(e.ExtendedStatistics??[]).forEach((o,s)=>{t[`ExtendedStatistics.member.${s+1}`]=o}),(e.Dimensions??[]).forEach((o,s)=>{t[`Dimensions.member.${s+1}.Name`]=o.Name,t[`Dimensions.member.${s+1}.Value`]=o.Value});let r=await this.query(t),i=(r.GetMetricStatisticsResult||r)?.Datapoints?.member??[];if(!Array.isArray(i))i=i?[i]:[];return i.map((o)=>{let s={},c=o.ExtendedStatistics?.entry;if(c){if(!Array.isArray(c))c=[c];for(let d of c)if(d?.key!=null)s[d.key]=Number(d.value)}return{Timestamp:o.Timestamp,Sum:o.Sum!=null?Number(o.Sum):void 0,Average:o.Average!=null?Number(o.Average):void 0,Maximum:o.Maximum!=null?Number(o.Maximum):void 0,Minimum:o.Minimum!=null?Number(o.Minimum):void 0,Percentiles:Object.keys(s).length?s:void 0,Unit:o.Unit}})}async getMetricSeries(e){let t=/^p\d/.test(e.Stat);return(await this.getMetricStatistics({Namespace:e.Namespace,MetricName:e.MetricName,Dimensions:e.Dimensions,StartTime:e.StartTime,EndTime:e.EndTime,Period:e.Period,Statistics:t?[]:[e.Stat],ExtendedStatistics:t?[e.Stat]:[]})).slice().sort((n,i)=>new Date(n.Timestamp??0).getTime()-new Date(i.Timestamp??0).getTime()).map((n)=>t?n.Percentiles?.[e.Stat]??0:n[e.Stat]??0)}async describeAlarms(e){let t={Action:"DescribeAlarms"};if(e?.AlarmNamePrefix)t.AlarmNamePrefix=e.AlarmNamePrefix;if(e?.MaxRecords)t.MaxRecords=e.MaxRecords;let r=await this.query(t),i=(r.DescribeAlarmsResult||r)?.MetricAlarms?.member??[];if(!Array.isArray(i))i=i?[i]:[];return i.map((o)=>({AlarmName:o.AlarmName,StateValue:o.StateValue,MetricName:o.MetricName,ComparisonOperator:o.ComparisonOperator,Threshold:o.Threshold!=null?Number(o.Threshold):void 0,Namespace:o.Namespace}))}async putMetricAlarm(e){let t={Action:"PutMetricAlarm",AlarmName:e.AlarmName,Namespace:e.Namespace,MetricName:e.MetricName,ComparisonOperator:e.ComparisonOperator,Threshold:e.Threshold,EvaluationPeriods:e.EvaluationPeriods,Period:e.Period,Statistic:e.Statistic};if(e.AlarmDescription)t.AlarmDescription=e.AlarmDescription;(e.Dimensions??[]).forEach((r,n)=>{t[`Dimensions.member.${n+1}.Name`]=r.Name,t[`Dimensions.member.${n+1}.Value`]=r.Value}),(e.AlarmActions??[]).forEach((r,n)=>{t[`AlarmActions.member.${n+1}`]=r}),await this.query(t)}async deleteAlarms(e){if(!e.length)return;let t={Action:"DeleteAlarms"};e.forEach((r,n)=>{t[`AlarmNames.member.${n+1}`]=r}),await this.query(t)}}class yc{client;region;constructor(e="us-east-1"){this.region=e,this.client=new pi}async call(e,t){return this.client.request({service:"wafv2",region:this.region,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":`AWSWAF_20190729.${e}`},body:JSON.stringify(t)})}async listWebACLs(e="REGIONAL"){return(await this.call("ListWebACLs",{Scope:e,Limit:100}))?.WebACLs??[]}async getWebACLRules(e,t,r="REGIONAL"){return((await this.call("GetWebACL",{Name:e,Id:t,Scope:r}))?.WebACL?.Rules??[]).map((o)=>({Name:o.Name,Priority:o.Priority,Action:o.Action?Object.keys(o.Action)[0]:o.OverrideAction?Object.keys(o.OverrideAction)[0]:"count"}))}}var ZS=[{index:0,id:"clients",label:"Clients"},{index:1,id:"dns",label:"DNS & TLS"},{index:2,id:"edge",label:"Edge"},{index:3,id:"routing",label:"Routing"},{index:4,id:"apps",label:"Applications"},{index:5,id:"runtime",label:"Background runtime"},{index:6,id:"data",label:"Data services"},{index:7,id:"durability",label:"Durability"}],XS=[{index:0,id:"clients",label:"Clients"},{index:1,id:"dns",label:"DNS & TLS"},{index:2,id:"edge",label:"Edge"},{index:3,id:"entry",label:"Entry points"},{index:4,id:"compute",label:"Compute"},{index:5,id:"messaging",label:"Messaging & pooling"},{index:6,id:"data",label:"Data services"},{index:7,id:"durability",label:"Durability"}],ew=[{match:/^redis/,kind:"cache",label:"Redis"},{match:/^(?:mysql|mariadb)/,kind:"database",label:"MySQL"},{match:/^postgres/,kind:"database",label:"PostgreSQL"},{match:/^meilisearch/,kind:"database",label:"Meilisearch"},{match:/^vitess|^vtgate/,kind:"database",label:"Vitess"},{match:/^memcached/,kind:"cache",label:"Memcached"}],tw=/^(?:rpx-gateway|nginx|caddy|traefik|haproxy)$/;function J(e,t=""){let r=e==null?"":String(e).trim();return r&&r!=="-"&&r!=="—"?r:t}function rw(e){return Array.isArray(e)?e.length:0}function Yt(e){let t=J(e).toLowerCase();if(!t)return"unknown";if(["running","live","active","available","success","ok","healthy","enabled"].includes(t))return"ok";if(["failed","stopped","unreachable","error","critical","disabled"].includes(t))return"bad";if(["configured","creating","pending","degraded","shadowed","warn","unknown"].includes(t))return"warn";return"warn"}function Ue(e,t,r){if(r.has(t.source)&&r.has(t.target))e.push(t)}function Pn(e,t={}){let r=[],n=[],i=[],o=e.server??{},s=Array.isArray(e.sites)?e.sites:[],c=Array.isArray(e.services)?e.services:[],d=Array.isArray(e.workers)?e.workers:[],a=e.security??{},u=!!e._serverReachable&&!e.metricsUnavailable,m="box";if(!u)i.push("The compute box could not be probed, so live service state is missing; the shape comes from your cloud config.");r.push({id:"internet",label:"Internet",kind:"internet",layer:0,status:"ok",sub:"Public traffic",facts:[],external:!0});let h=[...new Set(s.map((N)=>J(N.domain)||J(N.route).split("/")[0]).filter((N)=>N&&N!=="internal"&&N!=="loopback"))],y=Array.isArray(a.tlsCertificates)?a.tlsCertificates:[],w=y.filter((N)=>Number(N?.daysRemaining??999)<21).length;r.push({id:"dns",label:h.length===1?h[0]:"Public domains",kind:"dns",layer:1,status:w?"warn":h.length?"ok":"unknown",sub:h.length>1?`${h.length} domains`:"DNS & certificates",facts:[{label:"Domains",value:h.length?h.slice(0,6).join(", "):"none resolved"},{label:"Certificates",value:y.length?`${y.length} issued`:"none reported"},...w?[{label:"Expiring",value:`${w} within 21 days`}]:[]],href:"/server/security",external:!0});let k=a.firewall??{},C=Array.isArray(a.ports)?a.ports:[];r.push({id:"firewall",label:"Host firewall",kind:"firewall",layer:2,status:Yt(k.status),sub:J(k.summary,"Inbound filtering"),facts:[{label:"State",value:J(k.status,"unknown")},{label:"Open ports",value:C.length?C.map((N)=>J(N.listen)).join(", "):"not reported"}],href:"/server/firewall",group:"box"});let T=c.find((N)=>tw.test(J(N.name)));r.push({id:"proxy",label:J(T?.name,"Reverse proxy"),kind:"proxy",layer:3,status:T?Yt(T.status):"unknown",sub:"TLS termination & routing",facts:[{label:"Service",value:J(T?.name,"not detected")},{label:"State",value:J(T?.status,u?"not running":"not probed")},{label:"Routes",value:`${s.length} site${s.length===1?"":"s"}`}],href:"/server/services",group:"box"});for(let N of s){let Q=`site:${J(N.name)}`;if(!J(N.name))continue;r.push({id:Q,label:J(N.name),kind:"site",layer:4,status:Yt(N.status),sub:J(N.runtime,"runtime"),facts:[{label:"Route",value:J(N.route,"internal")},{label:"Runtime",value:J(N.runtime,"unknown")},{label:"Delivery",value:J(N.deploy,"unknown")},{label:"TLS",value:J(N.tls,"unknown")},...N.responseMs!=null?[{label:"Response",value:`${Math.round(Number(N.responseMs))} ms`}]:[],...N.httpStatus!=null?[{label:"HTTP",value:String(N.httpStatus)}]:[]],href:"/server/sites",group:"box"})}for(let N of d){let Q=`worker:${J(N.name)}`;if(!J(N.name))continue;r.push({id:Q,label:J(N.name),kind:"worker",layer:5,status:Yt(N.status),sub:`${Number(N.processes??1)} process${Number(N.processes??1)===1?"":"es"}`,facts:[{label:"Processes",value:String(N.processes??1)},{label:"State",value:J(N.status,"unknown")},...J(N.site)?[{label:"Site",value:J(N.site)}]:[]],href:"/operations/jobs",group:"box"})}let M=e.serverScheduler??{};if(M.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:5,status:"ok",sub:"Cron dispatch",facts:[{label:"Last run",value:J(M.lastRun,"unknown")}],href:"/operations/jobs",group:"box"});let P=c.map((N)=>{let Q=J(N.name),D=ew.find((Y)=>Y.match.test(Q));return D?{service:N,name:Q,...D}:null}).filter((N)=>!!N);for(let N of P)r.push({id:`data:${N.name}`,label:N.label,kind:N.kind,layer:6,status:Yt(N.service.status),sub:N.name,facts:[{label:"Unit",value:N.name},{label:"State",value:J(N.service.status,"unknown")}],href:"/data/services",group:"box"});let O=e.backup??{};if(O.enabled)r.push({id:"backup",label:"Backups",kind:"backup",layer:7,status:"ok",sub:J(O.destination,"destination"),facts:[{label:"Destination",value:J(O.destination,"unknown")},{label:"Schedule",value:J(O.schedule,"unknown")},{label:"Retention",value:`${O.retention??0} copies`},{label:"Last run",value:J(O.last,"unknown")}],href:"/data/backups"});let U=new Set(r.map((N)=>N.id));Ue(n,{source:"internet",target:"dns",flow:"request",label:"https"},U),Ue(n,{source:"dns",target:"firewall",flow:"request",label:"443/80"},U),Ue(n,{source:"firewall",target:"proxy",flow:"request"},U);for(let N of s){let Q=`site:${J(N.name)}`;Ue(n,{source:"proxy",target:Q,flow:"request",label:J(N.path)||void 0,status:Yt(N.status)},U)}for(let N of d){let Q=`worker:${J(N.name)}`,D=`site:${J(N.site)}`;if(U.has(D))Ue(n,{source:D,target:Q,flow:"async",label:"queue"},U);else Ue(n,{source:"proxy",target:Q,flow:"async",label:"queue"},U)}for(let N of d)Ue(n,{source:"scheduler",target:`worker:${J(N.name)}`,flow:"async",label:"dispatch"},U);let q=[...s.map((N)=>`site:${J(N.name)}`),...d.map((N)=>`worker:${J(N.name)}`)];for(let N of P)for(let Q of q)Ue(n,{source:Q,target:`data:${N.name}`,flow:"data",label:"localhost"},U);if(P.length&&q.length)i.push("Data-service edges show co-location on the box: every process on it can reach localhost. They are not a declared per-site binding.");for(let N of P)Ue(n,{source:`data:${N.name}`,target:"backup",flow:"backup",label:"snapshot"},U);for(let N of s)Ue(n,{source:`site:${J(N.name)}`,target:"backup",flow:"backup"},U);return{mode:"server",project:J(t.project)||J(e.project?.name)||J(o.name,"project"),environment:J(t.environment)||J(e.environment,"production"),provider:J(o.provider,"unknown"),region:J(o.region,"unknown"),generatedAt:new Date().toISOString(),layers:ZS,groups:[{id:"box",label:J(o.name,"App server"),sub:[J(o.provider),J(o.region),J(o.ip)].filter(Boolean).join(" · ")}],nodes:r,links:n,notes:i}}function ss(e,t={}){let r=[],n=[],i=[],o=e.app??{},s=Array.isArray(e.functions)?e.functions:[],c=Array.isArray(e.queues)?e.queues:[],d=e.metrics??{};if(!s.length)i.push("No Lambda functions were read for this environment, so the compute layer is empty rather than assumed.");r.push({id:"internet",label:"Internet",kind:"internet",layer:0,status:"ok",sub:"Public traffic",facts:[],external:!0});let a=J(o.url),u=a.replace(/^https?:\/\//,"").split("/")[0];r.push({id:"dns",label:u||"Application domain",kind:"dns",layer:1,status:u?"ok":"unknown",sub:"DNS & certificates",facts:[{label:"Endpoint",value:a||"not resolved"}],external:!0});let m=e.waf;if(m)r.push({id:"waf",label:"WAF",kind:"waf",layer:2,status:Yt(m.status??"active"),sub:J(m.scope,"Managed rules"),facts:[{label:"Web ACL",value:J(m.name,"unnamed")},...m.blocked!=null?[{label:"Blocked (24h)",value:String(m.blocked)}]:[],{label:"Rules",value:String(rw(e.wafRules))}],href:"/serverless/firewall"});let h=e.assetsInfo;if(h)r.push({id:"cdn",label:"Asset CDN",kind:"cdn",layer:2,status:"ok",sub:J(h.cdn,"CloudFront"),facts:[{label:"Distribution",value:J(h.cdn,"unknown")},{label:"Custom domain",value:J(h.customDomain,"none")}],href:"/serverless/assets"}),r.push({id:"assets",label:"Asset bucket",kind:"storage",layer:6,status:"ok",sub:J(h.bucket,"S3"),facts:[{label:"Bucket",value:J(h.bucket,"unknown")},...h.files?[{label:"Objects",value:String(h.files)}]:[],...h.sizeMb?[{label:"Size",value:`${h.sizeMb} MB`}]:[]],href:"/serverless/assets"});let y=s.find((D)=>J(D.key).startsWith("http"));r.push({id:"gateway",label:"HTTP entry point",kind:"gateway",layer:3,status:y?"ok":"unknown",sub:"Function URL / API Gateway",facts:[{label:"Endpoint",value:a||"not resolved"},{label:"Invocations (24h)",value:String(d.invocations??0)},...d.errorRatePct!=null?[{label:"Error rate",value:`${d.errorRatePct}%`}]:[]],href:"/serverless/metrics"});for(let D of s){let Y=`fn:${J(D.name)}`;if(!J(D.name))continue;let se=Number(D.errors??0),he=Number(D.invocations??0);r.push({id:Y,label:J(D.key,J(D.name)),kind:"function",layer:4,status:se>0?he&&se/he>0.02?"bad":"warn":he?"ok":"idle",sub:J(D.runtime,"lambda"),facts:[{label:"Function",value:J(D.name)},{label:"Memory",value:`${D.memory??0} MB`},{label:"Timeout",value:`${D.timeout??0}s`},{label:"Invocations (24h)",value:String(he)},{label:"Errors (24h)",value:String(se)},{label:"p95",value:`${D.p95??0} ms`},...D.provisioned?[{label:"Provisioned",value:J(D.provisioned)}]:[]],href:"/serverless/functions"})}for(let D of c){let Y=`queue:${J(D.name)}`;if(!J(D.name))continue;let se=Number(D.dlq??0);r.push({id:Y,label:J(D.name),kind:"queue",layer:5,status:se>0?"bad":Number(D.visible??0)>0?"warn":"ok",sub:"SQS",facts:[{label:"Visible",value:String(D.visible??0)},{label:"In flight",value:String(D.inFlight??0)},{label:"Processed (24h)",value:String(D.processed??0)},{label:"Dead letter",value:String(se)}],href:"/serverless/queues"})}let w=e.aurora;if(w)r.push({id:"database",label:"Aurora Serverless",kind:"database",layer:6,status:Yt(w.status),sub:J(w.engine,"aurora"),facts:[{label:"Cluster",value:J(w.id,"unknown")},{label:"Capacity",value:`${w.currentAcu??0} ACU (${w.minAcu??0}–${w.maxAcu??0})`},{label:"Connections",value:String(w.connections??0)}],href:"/serverless/data"});let k=e.proxy;if(k)r.push({id:"rds-proxy",label:"RDS Proxy",kind:"database",layer:5,status:Yt(k.status),sub:"Connection pooling",facts:[{label:"Proxy",value:J(k.name,"unknown")},{label:"Endpoint",value:J(k.endpoint,"unknown")},{label:"Pooled",value:String(k.pooledConns??0)}],href:"/serverless/data"});let C=e.redis;if(C)r.push({id:"cache",label:"ElastiCache",kind:"cache",layer:6,status:Yt(C.status),sub:J(C.node,"redis"),facts:[{label:"Group",value:J(C.id,"unknown")},{label:"Hit rate",value:`${C.hitRate??0}%`}],href:"/serverless/data"});let T=e.efs;if(T)r.push({id:"efs",label:"EFS",kind:"filesystem",layer:6,status:Yt(T.status),sub:J(T.mount,"/mnt/local"),facts:[{label:"File system",value:J(T.id,"unknown")},{label:"Mount",value:J(T.mount,"unknown")},{label:"Size",value:`${T.sizeMb??0} MB`}],href:"/data/volumes"});let M=e.scheduler??{};if(M.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:3,status:"ok",sub:J(M.expression,"rate(1 minute)"),facts:[{label:"Expression",value:J(M.expression,"unknown")},{label:"Last run",value:J(M.lastRun,"unknown")}],href:"/operations/jobs"});let P=new Set(r.map((D)=>D.id)),O=P.has("waf")?"waf":"gateway";Ue(n,{source:"internet",target:"dns",flow:"request",label:"https"},P),Ue(n,{source:"dns",target:O,flow:"request"},P),Ue(n,{source:"dns",target:"cdn",flow:"request",label:"assets"},P),Ue(n,{source:"waf",target:"gateway",flow:"request",label:"allowed"},P),Ue(n,{source:"cdn",target:"assets",flow:"data",label:"origin"},P);let U=s.filter((D)=>J(D.key).startsWith("http")),q=s.filter((D)=>J(D.key).startsWith("queue")),N=s.filter((D)=>J(D.key).startsWith("cli"));for(let D of U)Ue(n,{source:"gateway",target:`fn:${J(D.name)}`,flow:"request",label:"invoke"},P);for(let D of N)Ue(n,{source:"scheduler",target:`fn:${J(D.name)}`,flow:"async",label:"schedule"},P);for(let D of c){for(let Y of U)Ue(n,{source:`fn:${J(Y.name)}`,target:`queue:${J(D.name)}`,flow:"async",label:"publish"},P);for(let Y of q)Ue(n,{source:`queue:${J(D.name)}`,target:`fn:${J(Y.name)}`,flow:"async",label:"consume"},P)}let Q=["rds-proxy","database","cache","efs","assets"];for(let D of s){let Y=`fn:${J(D.name)}`;if(P.has("rds-proxy"))Ue(n,{source:Y,target:"rds-proxy",flow:"data",label:"pooled"},P);else Ue(n,{source:Y,target:"database",flow:"data",label:"sql"},P);for(let se of Q.filter((he)=>he!=="rds-proxy"&&he!=="database"))Ue(n,{source:Y,target:se,flow:"data"},P)}return Ue(n,{source:"rds-proxy",target:"database",flow:"data",label:"sql"},P),{mode:"serverless",project:J(t.project)||J(o.name,"application"),environment:J(t.environment)||J(o.env,"production"),provider:"aws",region:J(o.region,"unknown"),generatedAt:new Date().toISOString(),layers:XS,groups:[],nodes:r,links:n,notes:i}}function nw(e,t,r={}){return e==="serverless"?ss(t,r):Pn(t,r)}function Yp(e){return String(e).padStart(2,"0")}function mi(e){return`${e.getUTCFullYear()}-${Yp(e.getUTCMonth()+1)}-${Yp(e.getUTCDate())}`}function iw(e){let t=Math.max(0,Math.round((Date.now()-e)/1000));if(t<60)return`${t}s ago`;let r=Math.round(t/60);if(r<60)return`${r}m ago`;let n=Math.round(r/60);if(n<48)return`${n}h ago`;return`${Math.round(n/24)}d ago`}async function ro(e,t,r,n,i,o){let s=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:r,Dimensions:[{Name:"FunctionName",Value:t}],StartTime:i,EndTime:o,Period:86400,Statistics:[n]}).catch(()=>[]);if(!s.length)return 0;if(n==="Sum")return s.reduce((c,d)=>c+(d.Sum??0),0);if(n==="Maximum")return Math.max(...s.map((c)=>c.Maximum??0));return s.reduce((c,d)=>c+(d.Average??0),0)/s.length}async function no(e,t,r,n,i,o,s){let c=await e.getMetricStatistics({Namespace:t,MetricName:r,Dimensions:n,StartTime:o,EndTime:s,Period:86400,Statistics:[i]}).catch(()=>[]);if(!c.length)return 0;if(i==="Sum")return c.reduce((d,a)=>d+(a.Sum??0),0);if(i==="Maximum")return Math.max(...c.map((d)=>d.Maximum??0));return c.reduce((d,a)=>d+(a.Average??0),0)/c.length}async function vc(e,t,r,n,i){let o=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:"Duration",Dimensions:[{Name:"FunctionName",Value:t}],StartTime:n,EndTime:i,Period:86400,ExtendedStatistics:[r]}).catch(()=>[]);return Math.round(o.reduce((s,c)=>s+(c.Percentiles?.[r]??0),0))}async function io(e,t){let r=await nt(e,t),n=r.region,i=new Rr(n),o=new kt(n),s=new ci(n),c=new Date,d=new Date(c.getTime()-86400000),a=e.environments?.[t]?.app,u={};u.app={name:r.slug,env:t,region:n,runtime:a?.kind==="php"?`php-${a?.phpVersion??"8.3"} (fpm)`:a?.kind??"node",url:r.endpoint??"",build:r.lastRelease?.sha?.slice(0,7)??"—",deployedAt:r.lastRelease?.timestamp??"—"},u.maintenance={enabled:!1},u.scheduler={enabled:r.scheduler!=="off",expression:r.scheduler==="sub-minute"?"rate(1 minute) · sub-minute":"rate(1 minute)",lastRun:"—"};let m=0,h=0,y=0,w=[],k=[],C=[];for(let O of r.functions){let[U,q,N,Q,D,Y,se,he,je]=await Promise.all([ro(i,O.name,"Invocations","Sum",d,c),ro(i,O.name,"Errors","Sum",d,c),ro(i,O.name,"Throttles","Sum",d,c),ro(i,O.name,"Duration","Average",d,c),o.getFunction(O.name).catch(()=>null),vc(i,O.name,"p50",d,c),vc(i,O.name,"p95",d,c),vc(i,O.name,"p99",d,c),i.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:O.name}],StartTime:new Date(c.getTime()-43200000),EndTime:c,Period:3600,Stat:"Sum"}).catch(()=>[])]);m+=U,h+=q,y=Math.max(y,Q);let de=D?.Configuration?.MemorySize??0,Re=Object.keys(D?.Configuration?.Environment?.Variables??{}),Me=[],me=0;try{let{events:j=[]}=await s.filterLogEvents({logGroupName:`/aws/lambda/${O.name}`,startTime:d.getTime(),limit:120});for(let F of j){let K=(F.message??"").trim(),ye=/Max Memory Used:\s*(\d+)\s*MB/.exec(K);if(ye)me=Math.max(me,Number(ye[1]));if(K&&!/^(?:START|END|REPORT|INIT_START)/.test(K))C.push({source:O.mode||O.name,timestamp:new Date(F.timestamp??0).toISOString(),when:iw(F.timestamp??0),message:K.slice(0,400),level:/error|exception|fatal|panic|traceback/i.test(K)?"error":/warn|warning|timeout|retr(?:y|ies)|throttl/i.test(K)?"warn":"info"})}Me=j.filter((F)=>!/^(?:START|END|REPORT|INIT_START)/.test((F.message??"").trim())).slice(-6).map((F)=>({ts:new Date(F.timestamp??0).toISOString().slice(11,19),msg:(F.message??"").trim().slice(0,120),err:/error|exception|fatal/i.test(F.message??"")}))}catch{}let R=Math.max(1,...je);w.push({key:O.mode,name:O.name,version:O.version,memory:de,timeout:D?.Configuration?.Timeout??0,runtime:D?.Configuration?.Runtime??"provided.al2023",invocations:Math.round(U),errors:Math.round(q),p95:se||Math.round(Q),status:"active",provisioned:O.provisioned?`${O.provisioned.allocated}/${O.provisioned.requested}`:void 0}),k.push({key:O.mode,name:O.name,runtime:D?.Configuration?.Runtime??"provided.al2023",arch:D?.Configuration?.Architectures?.[0]??"x86_64",memory:de,timeout:D?.Configuration?.Timeout??0,ephemeral:D?.Configuration?.EphemeralStorage?.Size??512,version:O.version,concurrency:a?.concurrency??"—",invocations:Math.round(U),errors:Math.round(q),throttles:Math.round(N),p50:Y||Math.round(Q),p95:se||Math.round(Q),p99:he||Math.round(Q),maxMem:me,spark:je.length?je.map((j)=>Math.round(j/R*100)):[0],env:Re.length?Re:["(none)"],recent:Me.length?Me:[{ts:"—",msg:"no recent events",err:!1}]})}u.functions=w,u.functionsDetail=k,u.serverlessLogs=C.sort((O,U)=>String(U.timestamp).localeCompare(String(O.timestamp))).slice(0,600),u.serverlessLogsEmptyReason=C.length?void 0:"No recent function logs were found in CloudWatch for this environment.";let T=m?Number((h/m*100).toFixed(2)):0,M=Math.round(await ro(i,r.functions[0]?.name??"","ConcurrentExecutions","Maximum",d,c));u.metrics={invocations:Math.round(m),errorRatePct:T,p95Ms:Math.round(y),coldStartPct:void 0,concurrency:M,estCostUsd:void 0};try{let O=new _n(n),U=[],q=[],N=0;try{let{QueueUrl:D}=await O.getQueueUrl(`${r.slug}-${t}-dlq`),{Attributes:Y}=await O.getQueueAttributes(D);N=Number(Y.ApproximateNumberOfMessages??0)}catch{}let Q=a?as(a,r.slug,t):[];for(let D of Q){let Y=D.name.replace(`${r.slug}-${t}-`,""),se=0,he=0;try{let{QueueUrl:de}=await O.getQueueUrl(D.name),{Attributes:Re}=await O.getQueueAttributes(de);se=Number(Re.ApproximateNumberOfMessages??0),he=Number(Re.ApproximateNumberOfMessagesNotVisible??0)}catch{}let je=Math.round(await no(i,"AWS/SQS","NumberOfMessagesDeleted",[{Name:"QueueName",Value:D.name}],"Sum",d,c));U.push({name:Y,visible:se,inFlight:he,processed:je,dlq:N}),q.push({name:D.name,short:Y,visible:se,inFlight:he,delayed:0,processed:je,oldestSec:0,concurrency:D.concurrency??a?.queueConcurrency??"—",tries:a?.queueTries??3,visTimeout:(a?.queueTimeout??120)*6,dlq:N})}if(U.length)u.queues=U;if(q.length)u.queuesDetail=q;u.dlqItems=[]}catch{}try{let O=new Er(n),{Stacks:U}=await O.describeStacks({stackName:li(e,t)}),q={};for(let N of U?.[0]?.Outputs??[])if(N.OutputKey)q[N.OutputKey]=N.OutputValue??"";if(a?.database?.connection==="aurora-serverless"){let N=`${r.slug}-${t}-db`,Q=[{Name:"DBClusterIdentifier",Value:N}],[D,Y]=await Promise.all([no(i,"AWS/RDS","ServerlessDatabaseCapacity",Q,"Average",d,c),no(i,"AWS/RDS","DatabaseConnections",Q,"Maximum",d,c)]);if(u.aurora={id:N,engine:"aurora-mysql",minAcu:a?.database?.minCapacity??0.5,maxAcu:a?.database?.maxCapacity??4,currentAcu:D?Number(D.toFixed(1)):a?.database?.minCapacity??0.5,database:"app",connections:Math.round(Y),status:q.DbEndpoint?"available":"creating"},a?.rdsProxy)u.proxy={name:`${r.slug}-${t}-proxy`,endpoint:q.DbProxyEndpoint??"—",pooledConns:Math.round(Y),status:"available"}}if(a?.cache?.driver==="elasticache"){let N=`${r.slug}-${t}-cache`,Q=[{Name:"CacheClusterId",Value:`${N}-001`}],[D,Y]=await Promise.all([no(i,"AWS/ElastiCache","CacheHits",Q,"Sum",d,c),no(i,"AWS/ElastiCache","CacheMisses",Q,"Sum",d,c)]),se=D+Y>0?Number((D/(D+Y)*100).toFixed(1)):0;u.redis={id:N,node:"cache.t4g.micro",engine:"redis",hitRate:se,status:q.CacheEndpoint?"available":"creating"}}if(a?.efs){let N=0;try{if(q.EfsFileSystemId){let Q=new Xp(n),{FileSystems:D}=await Q.describeFileSystems({FileSystemId:q.EfsFileSystemId});N=Number(((D?.[0]?.SizeInBytes?.Value??0)/1048576).toFixed(1))}}catch{}u.efs={id:q.EfsFileSystemId??"efs",mount:"/mnt/local",sizeMb:N,status:"available"}}u.assetsInfo=q.AssetsCdnDomain?{bucket:q.AssetsBucketName??`${r.slug}-${t}-assets`,cdn:q.AssetsCdnDomain,customDomain:a?.assetDomain??"—",assetUrl:r.assetUrl??"—",files:0,sizeMb:0,cacheHitPct:0,build:u.app.build}:void 0}catch{}if(u.assetsInfo)try{let U=await new ur(n).list({bucket:u.assetsInfo.bucket,maxKeys:1000});u.assetsInfo.files=U.length,u.assetsInfo.sizeMb=Number((U.reduce((q,N)=>q+(N.Size??0),0)/1048576).toFixed(1)),u.assetsRecent=U.slice(0,8).map((q)=>({path:`/${q.Key}`,size:`${Math.max(1,Math.round((q.Size??0)/1024))} KB`,type:q.Key.split(".").pop()??""}))}catch{}try{if(a?.secrets){let O=Array.isArray(a.secrets)?a.secrets.map((U)=>({key:U.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),source:U})):Object.entries(a.secrets).map(([U,q])=>({key:U,source:String(q)}));u.secretsList=O.map((U)=>({...U,updated:"—"}))}}catch{}try{let O=new ur(n),U=`${r.slug}-${t}-deployments`,q=await O.getObjectJson(U,`deployments/${r.slug}/${t}/history.json`).catch(()=>null);if(q?.records?.length)u.deploymentsDetail=q.records.slice(-12).reverse().map((N)=>({sha:(N.sha??"").slice(0,7),status:N.status??"success",when:N.timestamp??"—",took:N.took??"—",by:N.by??"—",version:N.version??"—",hooks:N.hooks??[]}))}catch{}u.metricsTotals={invocations:u.metrics.invocations,errors:Math.round(h),errorRatePct:T,p95Ms:u.metrics.p95Ms,throttles:k.reduce((O,U)=>O+U.throttles,0),coldStartPct:void 0,estCostUsd:void 0,concurrency:M},u.metricsPerFn=k.map((O)=>({key:O.key,invocations:O.invocations,errors:O.errors,throttles:O.throttles,avgMs:O.p50,maxMs:O.p99,costUsd:void 0}));try{u.invSpark=await i.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:r.functions.find((O)=>O.mode==="http")?.name??""}],StartTime:new Date(c.getTime()-86400000),EndTime:c,Period:3600,Stat:"Sum"})}catch{}try{let O=new Zp,U=c,q=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth(),1)),N=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth()-1,1)),[Q,D]=await Promise.all([O.getCostByService({start:mi(q),end:mi(U),granularity:"MONTHLY"}).catch(()=>[]),O.getCostByService({start:mi(N),end:mi(q),granularity:"MONTHLY"}).catch(()=>[])]);if(Q.length){let Y=Q.reduce((me,R)=>me+R.amount,0),se=D.reduce((me,R)=>me+R.amount,0),he=U.getUTCDate(),je=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth()+1,0)).getUTCDate();u.costSummary={monthToDateUsd:Number(Y.toFixed(2)),projectedUsd:Number((Y/he*je).toFixed(2)),lastMonthUsd:Number(se.toFixed(2)),dailyAvgUsd:Number((Y/he).toFixed(2))},u.costServices=Q.filter((me)=>me.amount>0).sort((me,R)=>R.amount-me.amount).slice(0,12).map((me)=>({name:me.service,usd:Number(me.amount.toFixed(2)),note:""})),u.metrics.estCostUsd=Number((Y/he).toFixed(2)),u.metricsTotals.estCostUsd=u.metrics.estCostUsd,u.costTrend=await O.getDailyTotals({start:mi(q),end:mi(U)}).catch(()=>[]);let de=Q.find((me)=>/lambda/i.test(me.service))?.amount??0,Re=(me)=>me.invocations*(me.p50/1000)*(me.memory/1024),Me=k.reduce((me,R)=>me+Re(R),0)||1;u.costPerFn=k.map((me)=>({key:me.key,requests:me.invocations,gbSec:Math.round(Re(me)),usd:Number((de*(Re(me)/Me)).toFixed(2))}))}}catch{}if(a?.firewall)try{let O=await i.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"BlockedRequests",StartTime:d,EndTime:c,Period:86400,Statistics:["Sum"]}).catch(()=>[]),U=await i.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"AllowedRequests",StartTime:d,EndTime:c,Period:86400,Statistics:["Sum"]}).catch(()=>[]);u.waf={enabled:!0,scope:"REGIONAL",acl:`${r.slug}-${t}-waf`,allowed24h:Math.round(U.reduce((q,N)=>q+(N.Sum??0),0)),blocked24h:Math.round(O.reduce((q,N)=>q+(N.Sum??0),0))};try{let q=new yc(n),N=await q.listWebACLs("REGIONAL"),Q=N.find((D)=>D.Name?.includes(`${r.slug}-${t}`))??N[0];if(Q?.Name&&Q.Id){u.waf.acl=Q.Name;let D=await q.getWebACLRules(Q.Name,Q.Id,"REGIONAL");if(D.length)u.wafRules=D.map((Y)=>({name:Y.Name??"—",detail:`priority ${Y.Priority??0}`,action:Y.Action??"count",blocked24h:0}))}}catch{}}catch{}let P=[];if(u.aurora)P.push({name:"Aurora Serverless v2",detail:`${u.aurora.id} · ${u.aurora.minAcu}-${u.aurora.maxAcu} ACU`,status:u.aurora.status});if(u.proxy)P.push({name:"RDS Proxy",detail:u.proxy.name,status:u.proxy.status});if(u.redis)P.push({name:`ElastiCache (${u.redis.engine})`,detail:`${u.redis.node} · ${u.redis.hitRate}% hit rate`,status:u.redis.status});if(u.efs)P.push({name:"EFS",detail:`${u.efs.mount} · ${u.efs.sizeMb} MB`,status:u.efs.status});if(P.length)u.dataServices=P;if(r.scheduler!=="off"&&a?.kind==="php")try{let O=await ui(e,t,"schedule:list"),U=[];for(let q of(O||"").split(`
14
+ `;function Ip(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function hS(e){return["NoSuchEntity","ResourceNotFoundException","404"].includes(Ip(e))}function wp(e){return["EntityAlreadyExists","ResourceAlreadyExistsException","ResourceConflictException","409"].includes(Ip(e))}function kp(e,t){let r=e?.Items;if(!r)return[];if(Array.isArray(r))return r;let n=r[t];if(n===void 0)return[];return Array.isArray(n)?n:[n]}function mc(e){let t=e?.Aliases?.Items;if(Array.isArray(t))return t.map(String);if(typeof t==="string")return[t];return[]}function yS(e){if(!/^[A-Z0-9]{8,32}$/.test(e.distributionId))throw Error("CloudFront distribution ID is invalid");if(!/^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z0-9-]{2,63}$/.test(e.expectedAlias))throw Error("Expected CloudFront alias is invalid");if(!/^[A-Za-z0-9-_]{1,64}$/.test(e.functionName))throw Error("Lambda function name is invalid");let t=e.pathPattern?.startsWith("/")?e.pathPattern:`/${e.pathPattern||"api/*"}`;if(t==="/"||t==="/*"||!t.endsWith("*"))throw Error("API path must be a non-default wildcard pattern such as /api/*");let r=e.originId||`${e.functionName}-url`,n=e.roleName||`${e.functionName}-execution`;if(!/^[A-Za-z0-9_.-]{1,64}$/.test(n))throw Error("IAM role name is invalid");let i=e.memorySize??256,o=e.timeout??10,s=e.logRetentionDays??14;if(i<128||i>10240)throw Error("Lambda memory must be between 128 and 10240 MB");if(o<1||o>900)throw Error("Lambda timeout must be between 1 and 900 seconds");return{region:e.region||"us-east-1",pathPattern:t,originId:r,roleName:n,memorySize:i,timeout:o,logRetentionDays:s}}function vS(e){let t=e.region||"us-east-1";return{cloudfront:new Rn(e.profile),iam:new Xo(t,e.profile),lambda:new kt(t,e.profile),logs:new ci(t,e.profile),sts:new ai(t,e.profile),sleep:(r)=>new Promise((n)=>setTimeout(n,r))}}async function Q_(e,t){let r=yS(e),n=t||vS({profile:e.profile,region:r.region}),[i,o,s]=await Promise.all([n.sts.getCallerIdentity(),n.cloudfront.getDistribution(e.distributionId),n.cloudfront.getDistributionConfig(e.distributionId)]);if(!i.Account)throw Error("AWS identity did not return an account ID");if(!o.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!(mc(o).length?mc(o):mc(s.DistributionConfig)).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let d,a=!0;try{d=await n.iam.getRole({RoleName:r.roleName})}catch(de){if(!hS(de))throw de;a=!1}let u=d?.Arn||`arn:aws:iam::${i.Account}:role/${r.roleName}`,m=await n.lambda.functionExists(e.functionName),h=m?await n.lambda.getFunctionUrl(e.functionName):null,y=await n.cloudfront.listOriginAccessControls(),w=`${e.functionName}-lambda-url`,k=y.some((de)=>de.Name===w&&de.OriginAccessControlOriginType==="lambda"),C=kp(s.DistributionConfig.Origins,"Origin"),T=kp(s.DistributionConfig.CacheBehaviors,"CacheBehavior"),M=C.some((de)=>String(de.Id)===r.originId),P=T.some((de)=>String(de.PathPattern)===r.pathPattern),O=[...!a?[`create IAM execution role ${r.roleName}`]:[`reconcile IAM execution policy ${r.roleName}`],...m?[`update Lambda ${e.functionName} code and configuration`]:[`create Lambda ${e.functionName}`],...!h?["create private AWS_IAM function URL"]:[],...!k?[`create Lambda origin access control ${w}`]:[],"grant CloudFront function-URL and invocation permissions",`${P?"reconcile":"add"} ${r.pathPattern} behavior without changing the default behavior`],U={command:`cloud cdn:origin:remove ${e.distributionId} FUNCTION_URL_HOST --id ${r.originId} --path '${r.pathPattern}' --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,removeFunction:!m,removeRole:!a},q={mode:e.apply?"apply":"plan",accountId:i.Account,identityArn:i.Arn,distribution:{id:o.Id,arn:o.ARN,alias:e.expectedAlias,domainName:o.DomainName,status:o.Status},function:{name:e.functionName,existed:m,runtime:"nodejs22.x",urlExisted:!!h,url:h?.FunctionUrl},role:{name:r.roleName,existed:a,arn:u},origin:{id:r.originId,pathPattern:r.pathPattern,existed:M,behaviorExisted:P,accessControlExisted:k},changes:O,rollback:U,applied:!1};if(!e.apply)return q;let N=`${e.distributionId}:${r.pathPattern}`;if(e.confirm!==N)throw Error(`Pass exact confirmation token ${N} to mutate the live distribution`);if(!d)d=await n.iam.createRole({RoleName:r.roleName,Description:`Execution role for ${e.functionName}`,AssumeRolePolicyDocument:JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]}),Tags:[{Key:"ManagedBy",Value:"ts-cloud"}]});await n.iam.putRolePolicy({RoleName:r.roleName,PolicyName:"lambda-logs",PolicyDocument:JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:`arn:aws:logs:${r.region}:${i.Account}:log-group:/aws/lambda/${e.functionName}:*`}]})});try{await n.logs.createLogGroup(`/aws/lambda/${e.functionName}`,{ManagedBy:"ts-cloud"})}catch(de){if(!wp(de))throw de}await n.logs.putRetentionPolicy(`/aws/lambda/${e.functionName}`,r.logRetentionDays);let Q=e.code||fS;if(m)await n.lambda.updateFunctionCodeInline(e.functionName,Q,"index.mjs"),await n.lambda.waitForFunctionActive(e.functionName),await n.lambda.updateFunctionConfiguration({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:d.Arn,Handler:"index.handler",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize});else{let de;for(let Re=0;Re<8;Re++)try{await n.lambda.createFunctionWithCode({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:d.Arn,Handler:"index.handler",Code:Q,Filename:"index.mjs",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize}),de=void 0;break}catch(Me){if(de=Me,!String(Me.message).toLowerCase().includes("role"))throw Me;await n.sleep(1000)}if(de)throw de}await n.lambda.waitForFunctionActive(e.functionName);let D=h||await n.lambda.createFunctionUrl({FunctionName:e.functionName,AuthType:"AWS_IAM",InvokeMode:"BUFFERED"});if(!D.FunctionUrl)throw Error("Lambda did not return a function URL");let Y=new URL(D.FunctionUrl).hostname,se=await n.cloudfront.findOrCreateOriginAccessControl(w,"lambda"),he=o.ARN||`arn:aws:cloudfront::${i.Account}:distribution/${e.distributionId}`,je=[{FunctionName:e.functionName,StatementId:"AllowCloudFrontFunctionUrl",Action:"lambda:InvokeFunctionUrl",Principal:"cloudfront.amazonaws.com",SourceArn:he,FunctionUrlAuthType:"AWS_IAM"},{FunctionName:e.functionName,StatementId:"AllowCloudFrontInvoke",Action:"lambda:InvokeFunction",Principal:"cloudfront.amazonaws.com",SourceArn:he,InvokedViaFunctionUrl:!0}];for(let de of je)try{await n.lambda.addPermission(de)}catch(Re){if(!wp(Re))throw Re}return await n.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:Y,pathPattern:r.pathPattern,originAccessControlId:se.Id}),{...q,function:{...q.function,url:D.FunctionUrl},applied:!0}}async function Y_(e){let t=`https://${e.alias}/`,r=`https://${e.alias}/api/health`,n=await fetch(t,{redirect:"follow",headers:{"cache-control":"no-cache"}}),i=new Uint8Array(await n.arrayBuffer()),o=gS("sha256").update(i).digest("hex"),s=Date.now(),c=await fetch(r,{redirect:"follow",headers:{"cache-control":"no-cache"}}),d=Date.now()-s,a=await c.text(),u=a;try{u=JSON.parse(a)}catch{}let m;if(e.logs&&e.functionName){let h=await e.logs.filterLogEvents({logGroupName:`/aws/lambda/${e.functionName}`,startTime:s-60000,filterPattern:'"Init Duration"',limit:25});for(let y of h.events||[]){let w=y.message?.match(/Init Duration:\s*([0-9.]+)\s*ms/i);if(w)m=Number(w[1])}}return{frontend:{url:t,status:n.status,sha256:o,unchanged:e.expectedFrontendSha256?o===e.expectedFrontendSha256:void 0,bytes:i.byteLength},api:{url:r,status:c.status,latencyMs:d,healthy:c.ok&&!!u?.ok,body:u},coldStart:{observed:m!==void 0,initDurationMs:m},verifiedAt:(e.now?.()||new Date).toISOString()}}function Z_(e){let t=(e.memoryMb||256)/1024,r=Math.max(0,e.requests-(e.includeFreeTier===!1?0:1e6)),n=Math.max(0,e.requests*(e.averageDurationMs/1000)*t-(e.includeFreeTier===!1?0:400000)),i=r/1e6*0.2+n*0.0000166667,o=9.010025,s=16.425;return{lambdaUsd:Number(i.toFixed(2)),alwaysOnFargateAndAlbUsd:Number(25.435025000000003 .toFixed(2)),assumptions:["us-east-1 public list rates snapshot, July 2026","Lambda x86 request and duration pricing with optional monthly free tier","Fargate comparison uses one always-on 0.25 vCPU/0.5 GB task plus one ALB before LCU charges","excludes CloudFront, data transfer, logs, taxes, and application data services"]}}import{createHash as bS}from"node:crypto";function SS(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function wS(e){return SS(e)==="ValidationError"&&String(e.message).includes("does not exist")}function kS(e){return Object.fromEntries((e||[]).map((t)=>[t.OutputKey,t.OutputValue]))}function IS(e){let t=e?.Aliases?.Items??e?.Aliases;if(Array.isArray(t))return t.map(String);if(typeof t==="string")return[t];return[]}function Ap(e){if(!/^[a-z][a-z0-9-]{1,62}$/.test(e.slug))throw Error("Slug must be a lowercase DNS-safe identifier");if(!/^[A-Z0-9]{8,32}$/.test(e.distributionId))throw Error("CloudFront distribution ID is invalid");if(!/^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z0-9-]{2,63}$/.test(e.expectedAlias))throw Error("Expected distribution alias is invalid");let t=e.imageUri.match(/@((?:sha256:)[a-f0-9]{64})$/i)?.[1];if(!t)throw Error("Container image must use an immutable ECR digest URI ending in @sha256:<64 hex>");let r=e.stackName||`${e.slug}-backend`;if(!/^[A-Za-z][A-Za-z0-9-]{0,127}$/.test(r))throw Error("CloudFormation stack name is invalid");let n=e.pathPattern||"/api/*";if(!/^\/[A-Za-z0-9_.*?~!$&'()+,;=:@%/-]+\*$/.test(n)||n==="/*")throw Error("Backend path must be a non-default wildcard pattern");let i=e.originId||`${e.slug}-backend`;if(!/^[A-Za-z0-9_.-]{1,128}$/.test(i))throw Error("CloudFront origin ID is invalid");if(e.originVerifySecret&&e.originVerifySecret.length<24)throw Error("Origin verification secret must contain at least 24 characters");if(!!e.originDomain!==!!e.certificateArn)throw Error("A custom origin domain and matching ACM certificate ARN must be provided together");return{stackName:r,region:e.region||"us-east-1",pathPattern:n,originId:i,digest:t}}function ES(e){let t=e.region||"us-east-1";return{cloudformation:new Er(t,e.profile),cloudfront:new Rn(e.profile),sts:new ai(t,e.profile),fetch,sleep:(r)=>new Promise((n)=>setTimeout(n,r))}}function RS(e){let t=Ap(e),r=Rp({name:e.name,slug:e.slug,domain:e.originDomain||e.expectedAlias,imageUri:e.imageUri,certificateArn:e.certificateArn,originVerifySecret:e.originVerifySecret,desiredCount:e.desiredCount,database:e.database,cache:e.cache,queue:e.queue}),n=Ep(r);return n.Description=`Managed backend for existing static frontend ${e.expectedAlias}`,n.Metadata={ManagedBy:"ts-cloud",ExistingDistributionId:e.distributionId,ExistingDistributionAlias:e.expectedAlias,BackendPathPattern:t.pathPattern,ContainerDigest:t.digest},n}async function AS(e,t,r){let n;for(let i=0;i<30;i++){let o=Date.now();try{let s=await e.fetch(t,{redirect:"manual",headers:r?{"x-origin-verify":r}:void 0}),c=Date.now()-o,d=await s.text(),a=d;try{a=JSON.parse(d)}catch{}if(s.ok)return{url:t,status:s.status,latencyMs:c,body:a};n=Error(`origin returned ${s.status}`)}catch(s){n=s}if(i<29)await e.sleep(1e4)}throw Error(`Backend origin did not become healthy: ${n instanceof Error?n.message:String(n)}`)}async function oT(e,t){let r=Ap(e),n=t||ES({region:r.region,profile:e.profile}),[i,o]=await Promise.all([n.sts.getCallerIdentity(),n.cloudfront.getDistribution(e.distributionId)]);if(!i.Account)throw Error("AWS identity did not return an account ID");if(!o.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!IS(o).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let s;try{s=(await n.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0]}catch(O){if(!wS(O))throw O}let c=RS(e),d=JSON.stringify(c);if(Buffer.byteLength(d)>51200)throw Error("Generated template exceeds the direct CloudFormation template body limit");let a=Object.values(c.Resources||{}).reduce((O,U)=>(O[U.Type]=(O[U.Type]||0)+1,O),{}),u=[`cloud cdn:origin:remove ${e.distributionId} ${e.originDomain||"ALB_HOST"} --id ${r.originId} --path '${r.pathPattern}' --profile ${e.profile||"default"} --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,`After CloudFront is deployed, restore external DNS if changed and delete stack ${r.stackName} only with an approved data-retention decision.`],m={mode:e.apply?"apply":"plan",accountId:i.Account,stack:{name:r.stackName,existed:!!s,status:s?.StackStatus,templateSha256:bS("sha256").update(d).digest("hex"),resourceCount:Object.keys(c.Resources||{}).length,resourceTypes:a},distribution:{id:o.Id,alias:e.expectedAlias,domainName:o.DomainName,status:o.Status,pathPattern:r.pathPattern,originId:r.originId},artifact:{imageUri:e.imageUri,digest:r.digest},services:{database:e.database!==!1,cache:e.cache!==!1,queue:e.queue!==!1,mail:"ses",desiredCount:e.desiredCount||1},cloudFrontApplied:!1,dnsApplied:!1,applied:!1,rollback:u};if(!e.apply)return m;let h=`${e.distributionId}:${r.pathPattern}:${r.stackName}`;if(e.confirm!==h)throw Error(`Pass exact confirmation token ${h} to provision the backend and change live routing`);if(s)try{await n.cloudformation.updateStack({stackName:r.stackName,templateBody:d,capabilities:["CAPABILITY_NAMED_IAM"],tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await n.cloudformation.waitForStack(r.stackName,"stack-update-complete")}catch(O){if(!String(O.message).includes("No updates are to be performed"))throw O}else await n.cloudformation.createStack({stackName:r.stackName,templateBody:d,capabilities:["CAPABILITY_NAMED_IAM"],onFailure:"ROLLBACK",tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await n.cloudformation.waitForStack(r.stackName,"stack-create-complete");let y=(await n.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0],w=kS(y?.Outputs),k=w.AppLoadBalancerDnsName;if(!k)throw Error("Backend stack did not return AppLoadBalancerDnsName");let C=!1;if(e.originDomain&&e.originDomain!==k){if(!n.dns)throw Error(`External DNS provider is required to map ${e.originDomain} to ${k}`);let O=await n.dns.upsertRecord(e.originDomain,{name:e.originDomain,type:"CNAME",content:k,ttl:300});if(!O.success)throw Error(O.message||"External DNS update failed");C=!0}let T=e.originDomain||k,M=e.certificateArn?"https-only":"http-only",P=e.skipHealthCheck?void 0:await AS(n,`${M==="https-only"?"https":"http"}://${T}/api/health`,e.originVerifySecret);return await n.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:T,pathPattern:r.pathPattern,protocolPolicy:M,customHeaders:e.originVerifySecret?{"X-Origin-Verify":e.originVerifySecret}:void 0}),{...m,outputs:w,health:P,cloudFrontApplied:!0,dnsApplied:C,applied:!0}}function sT(e={}){let r={fargate:730*(e.desiredCount||1)*0.012342500000000001,applicationLoadBalancer:16.425,natGateway:32.85,postgres:730*(e.multiAzDatabase?0.032:0.016),redis:23.36};return{monthlyUsd:Number(Object.values(r).reduce((n,i)=>n+i,0).toFixed(2)),components:Object.fromEntries(Object.entries(r).map(([n,i])=>[n,Number(i.toFixed(2))])),assumptions:["us-east-1 public on-demand rate snapshot, July 2026","one 0.25 vCPU/0.5 GB Linux Fargate task unless desiredCount is changed","one ALB before LCU charges and one NAT gateway before data processing","single-AZ db.t4g.micro PostgreSQL by default and two cache.t4g.micro Redis nodes","excludes storage, backups, CloudFront, data transfer, public IPv4, logs, email, queue requests, taxes, and free-tier credits"]}}import{execFileSync as CS}from"node:child_process";import{createHash as PS}from"node:crypto";import{existsSync as _p,mkdirSync as _S,mkdtempSync as TS,readdirSync as xS,readFileSync as DS,rmSync as OS,statSync as Tp,writeFileSync as $S}from"node:fs";import{tmpdir as NS}from"node:os";import{basename as jS,join as di,relative as MS,resolve as gc}from"node:path";var BS=new Set([".git","node_modules","dist","coverage"]);function xp(e,t=e){let r=[];for(let n of xS(e).sort()){if(BS.has(n))continue;let i=di(e,n);if(Cp(i,t))continue;let o=Tp(i);if(o.isDirectory())r.push(...xp(i,t));else if(o.isFile())r.push(MS(t,i))}return r}function LS(e){let t=gc(e);if(!_p(t)||!Tp(t).isDirectory())throw Error(`Container context does not exist: ${t}`);let r=PS("sha256");for(let n of xp(t))r.update(n),r.update("\x00"),r.update(DS(di(t,n))),r.update("\x00");return r.digest("hex")}function FS(e){return{ecr:new Pp(e.region||"us-east-1",e.profile),run:(t,r,n)=>{CS(t,r,{cwd:n?.cwd,env:n?.env,stdio:n?.stdio||"inherit"})}}}async function fT(e,t){let r=gc(e.context),n=gc(e.dockerfile||di(r,"Dockerfile"));if(!_p(n))throw Error(`Dockerfile does not exist: ${n}`);if(!e.repository.split("/").every((w)=>/^[a-z0-9][a-z0-9._-]*$/.test(w)&&!/[._-]$/.test(w)&&!/[._-]{2}/.test(w)))throw Error("ECR repository name is invalid");let s=t||FS(e),c=LS(r),d=`sha-${c.slice(0,20)}`,a="";try{a=(await s.ecr.describeRepositories({repositoryNames:[e.repository]})).repositories?.[0]?.repositoryUri||""}catch{}if(!a)a=(await s.ecr.createRepository({repositoryName:e.repository,imageTagMutability:"IMMUTABLE",imageScanningConfiguration:{scanOnPush:!0},tags:[{Key:"ManagedBy",Value:"ts-cloud"}]})).repository?.repositoryUri||"";if(!a)throw Error(`Could not resolve ECR repository URI for ${e.repository}`);await s.ecr.putLifecyclePolicy({repositoryName:e.repository,lifecyclePolicyText:JSON.stringify({rules:[{rulePriority:1,description:"Retain the newest 25 release images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:25},action:{type:"expire"}}]})});let u=`${a}:${d}`,m=TS(di(NS(),"ts-cloud-container-"));try{s.run("docker",["version"],{stdio:"ignore"}),s.run("docker",["build","--platform",e.platform||"linux/amd64","--provenance=false","--sbom=false","--file",n,"--tag",u,r],{cwd:r});let w=(await s.ecr.getAuthorizationToken()).authorizationData?.[0];if(!w?.authorizationToken||!w.proxyEndpoint)throw Error("ECR did not return Docker authorization data");let k=w.proxyEndpoint.replace(/^https?:\/\//,""),C=di(m,"docker");_S(C,{recursive:!0}),$S(di(C,"config.json"),JSON.stringify({auths:{[k]:{auth:w.authorizationToken}}}),{mode:384}),s.run("docker",["push",u],{env:{...process.env,DOCKER_CONFIG:C}})}finally{OS(m,{recursive:!0,force:!0})}let y=(await s.ecr.describeImages({repositoryName:e.repository,imageIds:[{imageTag:d}]})).imageDetails?.[0]?.imageDigest;if(!y||!/^sha256:[a-f0-9]{64}$/i.test(y))throw Error(`ECR did not return an immutable digest for ${jS(u)}`);return{repository:e.repository,tag:d,imageUri:u,digest:y,digestUri:`${a}@${y}`,contextSha256:c}}import{existsSync as zS,readdirSync as US,readFileSync as qS,statSync as VS}from"node:fs";import{join as qp,relative as WS}from"node:path";function Cn(e,t){let r=e.environments?.[t]?.app;if(!r)throw Error(`No serverless app configured for environment '${t}'. Add environments.${t}.app to your config.`);let n=e.project.slug,i=e.environments?.[t]?.region||e.project.region||"us-east-1";return{app:r,slug:n,region:i,stackName:li(e,t),artifactBucket:Dp(n,t),assetsBucket:Op(n,t)}}async function An(e,t=8){let r;for(let n=0;n<t;n++)try{return await e()}catch(i){let o=i?.code||i?.name||"",s=String(i?.message||"");if(o==="ResourceConflictException"||/update is in progress|currently in the following state/i.test(s)){r=i,await new Promise((c)=>setTimeout(c,3000));continue}throw i}throw r}var Vp=(e,t)=>`releases/${e}/${t}/current.json`;async function is(e,t,r,n){try{return await e.getObjectJson(t,Vp(r,n))}catch{return null}}async function Wp(e,t,r,n,i){await e.putObjectJson(t,Vp(r,n),i)}async function HS(e,t){if(!e.secrets)return{};let r=new Yr(t),n={},i=Array.isArray(e.secrets)?e.secrets.map((o)=>({envName:o.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),secretId:o})):Object.entries(e.secrets).map(([o,s])=>({envName:o,secretId:s}));if(Array.isArray(e.secrets)){let o=new Map;for(let{envName:c,secretId:d}of i)o.set(c,[...o.get(c)??[],d]);let s=[...o.entries()].filter(([,c])=>c.length>1);if(s.length){let c=s.map(([d,a])=>`${d} ← ${a.join(", ")}`).join("; ");throw Error(`serverless secrets: multiple secrets map to the same env var (${c}). Use the map form { ENV_NAME: 'secret/id' } to disambiguate.`)}}for(let{envName:o,secretId:s}of i){let d=(await r.getSecretValue({SecretId:s})).SecretString??"";try{let a=JSON.parse(d);if(a&&typeof a==="object"&&!Array.isArray(a)){for(let[u,m]of Object.entries(a))n[u]=String(m);continue}}catch{}n[o]=d}return n}function Hp(e,t){let r={},n=t.DbProxyEndpoint||t.DbEndpoint;if(n)r.DB_CONNECTION="mysql",r.DB_HOST=n,r.DB_PORT="3306",r.DB_DATABASE=r.DB_DATABASE||"app";if(t.CacheEndpoint){if(r.REDIS_HOST=t.CacheEndpoint,r.REDIS_PORT="6379",e.cache?.driver==="elasticache")r.CACHE_STORE="redis",r.CACHE_DRIVER="redis",r.SESSION_DRIVER="redis"}return r}function ts(e,t,r,n,i,o,s,c={}){let d=e.kind==="php"?Lp({cacheDriver:e.cache?.driver==="elasticache"?"redis":"dynamodb"}):{};return{TSCLOUD_LAMBDA_MODE:n,TSCLOUD_ENV:r,MAINTENANCE_MODE:"0",...e.octane?{TSCLOUD_OCTANE:"1"}:{},...e.serveAssets?{TSCLOUD_SERVE_ASSETS:"1"}:{},...e.redirectRobotsTxt===!1?{TSCLOUD_REDIRECT_ROBOTS_TXT:"0"}:{},...d,...c,...t.app.cache?.driver!=="elasticache"?{TSCLOUD_CACHE_TABLE:`${t.slug}-${r}-cache`}:{},...s?{TSCLOUD_QUEUE:s,SQS_QUEUE:s}:{},...o?{ASSET_URL:o}:{},...e.env??{},...i}}function KS(e){let t=e.slice(e.lastIndexOf(".")).toLowerCase();return{".html":"text/html",".css":"text/css",".js":"text/javascript",".mjs":"text/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain",".map":"application/json"}[t]??"application/octet-stream"}function*Kp(e){for(let t of US(e)){let r=qp(e,t);if(VS(r).isDirectory())yield*Kp(r);else yield r}}async function JS(e,t,r,n,i=!1){let o=0;for(let s of Kp(r)){let c=WS(r,s).replace(/\\/g,"/");if(!i&&c.split("/").some((d)=>d.startsWith(".")))continue;await e.putObject({bucket:t,key:`${n}/${c}`,body:qS(s),contentType:KS(s),cacheControl:"public, max-age=31536000, immutable"}),o++}return o}function GS(e,t){let r=Object.entries(t).reduce((n,[i,o])=>n+Buffer.byteLength(`${i}=${o}`,"utf8"),0);if(r>4096){let n=Object.entries(t).map(([i,o])=>[i,Buffer.byteLength(`${i}=${o}`,"utf8")]).sort((i,o)=>o[1]-i[1]).slice(0,5).map(([i,o])=>`${i} (${o}B)`).join(", ");throw Error(`${e}: environment variables total ${r}B, over AWS's 4096B limit (${r-4096}B too large). Largest: ${n}. Move large/secret values out of env — store them in Secrets Manager and fetch at cold start.`)}}async function eo(e,t,r,n){GS(t,r),await An(()=>e.updateFunctionConfiguration({FunctionName:t,Environment:{Variables:r}})),await e.waitForFunctionActive(t,120);let i=n.kind==="image"?{FunctionName:t,ImageUri:n.imageUri}:{FunctionName:t,S3Bucket:n.bucket,S3Key:n.key};await An(()=>e.updateFunctionCode(i)),await e.waitForFunctionActive(t,120)}async function rs(e,t){let n=(await An(()=>e.publishVersion({FunctionName:t}))).Version;if(!n)throw Error(`publishVersion returned no version for ${t}`);return await An(()=>e.updateAlias({FunctionName:t,Name:"live",FunctionVersion:n})),n}async function QS(e,t,r={}){let n=Cn(e,t),{app:i,slug:o,region:s,stackName:c,artifactBucket:d}=n,a=r.projectRoot??process.cwd();ns(`Deploying serverless app: ${o} (${t})`),Mt(`Stack: ${c}`),Mt(`Region: ${s}`);let u=new ur(s),m=new Er(s),h=new kt(s),y=i.kind==="php",w=i.packaging==="image",k=jp(i),C,T,M,P,O=[];if(w&&k.usesLayer&&k.layerKind!=="php")throw Error(`packaging: 'image' currently supports PHP and managed Node runtimes. ${k.kind}${k.kind==="node"?` ${k.version}`:""} uses a custom runtime — `+"use the default zip packaging (the runtime layer is built + attached automatically).");if(w){ct("Building + pushing container image");let{buildAndPushServerlessImage:F}=await import("./chunk-7fkyfh65.js"),K=await F({app:i,projectRoot:a,region:s,repository:`${o}-${t}`,skipBuild:r.skipBuild,onStep:(ye)=>Mt(` ${ye}`)});C=K.handlers,T={kind:"image",imageUri:K.imageUri},M=K.tag,O.push({ParameterKey:"ImageUri",ParameterValue:K.imageUri})}else{ct("Packaging application");let F=y?Fp({projectRoot:a,app:i,skipBuild:r.skipBuild,onStep:(Ae)=>Mt(` ${Ae}`)}):await Np({projectRoot:a,app:i,skipBuild:r.skipBuild,onStep:(Ae)=>Mt(` ${Ae}`)}),K=$p(o,t,F.sha256);if(Mt(`Artifact: ${F.sha256.slice(0,12)} (${(F.zip.length/1024).toFixed(0)} KB)`),C=F.handlers,M=F.sha256,k.usesLayer){let Ae=k.layerEnvVar?process.env[k.layerEnvVar]:void 0;if(P=i.layers??(Ae?[Ae]:void 0),!P?.length){let G=k.layerKind==="php"?"serverless:build-php-layer":k.layerKind==="bun"?"serverless:build-bun-layer":"serverless:build-node-layer";throw Error(`${k.kind} apps on provided.al2023 need a runtime layer. Set environments.<env>.app.layers or the ${k.layerEnvVar} env var (build one with \`cloud ${G}\`)${k.kind==="node"?", or use a managed Node version (18/20/22)":""}.`)}}if(!await u.bucketExists(d))ct(`Creating artifact bucket ${d}`),await u.createBucket(d);if(await u.headObject(d,K).then((Ae)=>Ae!==null).catch(()=>!1))Mt("Artifact already uploaded — reusing");else ct("Uploading artifact"),await u.putObject({bucket:d,key:K,body:F.zip,contentType:"application/zip"});T={kind:"zip",bucket:d,key:K},O.push({ParameterKey:"ArtifactBucket",ParameterValue:d},{ParameterKey:"ArtifactKey",ParameterValue:K})}let U=Bp({config:e,environment:t,app:i,handlers:C,runtimeLayers:P}),q=JSON.stringify(U.template),N=["CAPABILITY_NAMED_IAM"],Q=await m.describeStacks({stackName:c}).then((F)=>F.Stacks[0]?.StackStatus).catch(()=>{return}),D=Q!==void 0;if(Q&&/DELETE_IN_PROGRESS/.test(Q))ct("Waiting for an in-progress stack delete to finish"),await m.waitForStack(c,"stack-delete-complete").catch(()=>{}),D=!1;else if(Q&&/(?:ROLLBACK_COMPLETE|REVIEW_IN_PROGRESS|CREATE_FAILED)/.test(Q))ct(`Deleting unusable stack (status ${Q}) before recreate`),await m.deleteStack(c),await m.waitForStack(c,"stack-delete-complete").catch(()=>{}),D=!1;ct(D?"Updating infrastructure stack":"Creating infrastructure stack");try{if(D)await m.updateStack({stackName:c,templateBody:q,parameters:O,capabilities:N}),await m.waitForStack(c,"stack-update-complete");else await m.createStack({stackName:c,templateBody:q,parameters:O,capabilities:N,onFailure:"DELETE"}),await m.waitForStack(c,"stack-create-complete")}catch(F){if(/No updates are to be performed/i.test(String(F?.message)))Mt("No infrastructure changes");else throw F}let Y=await m.getStackOutputs(c).catch(()=>({})),se;if(i.assets){let F=qp(a,i.assets);if(zS(F)){let K=i.assetDomain||Y.AssetsCdnDomain;se=K?`https://${K}/${M}`:void 0,ct(`Syncing assets from ${i.assets}`);let ye=await JS(u,n.assetsBucket,F,M,i.dotFilesAsAssets);Mt(`Uploaded ${ye} asset(s)${se?` → ${se}`:""}`)}else es(`Assets directory not found: ${F}`)}ct("Resolving secrets");let he=await HS(i,s);if(i.database?.connection==="aurora-serverless")try{let K=await new Yr(s).getSecretValue({SecretId:`${o}/${t}/db`}),ye=JSON.parse(K.SecretString??"{}");if(ye.username)he.DB_USERNAME=ye.username;if(ye.password)he.DB_PASSWORD=ye.password}catch(F){es(`Could not resolve Aurora DB credentials: ${F.message}`)}if(!await u.bucketExists(d))await u.createBucket(d);let je=await is(u,d,o,t),de={},Re=U.queueNames[0],Me=Hp(i,Y);if(ct("Activating functions"),de.http=ts(i,n,t,"http",he,se,Re,Me),await eo(h,U.functionNames.http,de.http,T),de.cli=ts(i,n,t,"cli",he,se,Re,Me),await eo(h,U.functionNames.cli,de.cli,T),U.queueNames.length)de.queue=ts(i,n,t,"queue",he,se,Re,Me),await eo(h,U.functionNames.queue,de.queue,T);let me=(i.provisionedConcurrency??0)>0,R={};if(me){if(ct("Publishing versions + flipping live alias"),R.http=await rs(h,U.functionNames.http),R.cli=await rs(h,U.functionNames.cli),U.queueNames.length)R.queue=await rs(h,U.functionNames.queue)}if(await Wp(u,d,o,t,{sha:M,code:T,previousSha:je?.sha,previousCode:je?.code,previousFunctionEnv:je?.functionEnv,...me?{functionVersions:R,previousFunctionVersions:je?.functionVersions}:{},functionEnv:de,functionNames:{http:U.functionNames.http,cli:U.functionNames.cli,...U.queueNames.length?{queue:U.functionNames.queue}:{}},assetUrl:se,timestamp:new Date().toISOString()}),!r.skipDeployHooks&&i.deploy?.length){ct("Running deploy hooks");for(let F of i.deploy){Mt(` deploy: ${F}`);let K=await h.invoke({FunctionName:U.functionNames.cli,InvocationType:"RequestResponse",Payload:{command:F},LogType:"Tail"});if(K.FunctionError)throw zp("Deploy hook failed — the new build is ALREADY LIVE."),Mt(` Roll back with: cloud serverless:rollback --env ${t}`),Error(`Deploy hook failed (${F}): ${K.Payload}`)}}let j=Y.HttpApiEndpoint;if(!r.skipHealthCheck&&j){ct("Health check");try{let F=await fetch(j,{method:"GET"});Mt(`GET ${j} → ${F.status}`)}catch(F){es(`Health check could not reach ${j}: ${F.message}`)}}Up(["Serverless deploy complete","",j?`URL: ${j}`:"",`Stack: ${c}`,`Build: ${M.slice(0,12)}`].filter(Boolean).join(`
15
+ `),"green")}async function fc(e,t){let r=Cn(e,t),n=new ur(r.region),i=new kt(r.region),o=await is(n,r.artifactBucket,r.slug,t);if(!o)throw Error("No previous release to redeploy. Run a full deploy first.");ns(`Redeploying ${r.slug} (${t}) — build ${o.sha.slice(0,12)}`);for(let[s,c]of Object.entries(o.functionNames)){if(!c)continue;ct(`Re-activating ${s} (${c})`),await eo(i,c,o.functionEnv[s]??{},o.code);let d=o.functionVersions?.[s];if(d)await An(()=>i.updateAlias({FunctionName:c,Name:"live",FunctionVersion:d}))}to("Redeploy complete")}async function hc(e,t){let r=Cn(e,t),n=new ur(r.region),i=new kt(r.region),o=await is(n,r.artifactBucket,r.slug,t);if(!o?.previousCode)throw Error("No previous release to roll back to.");ns(`Rolling back ${r.slug} (${t}) → ${o.previousSha?.slice(0,12)}`);for(let[s,c]of Object.entries(o.functionNames)){if(!c)continue;ct(`Restoring ${s} (${c})`);let d=o.previousFunctionEnv?.[s]??o.functionEnv[s]??{};await eo(i,c,d,o.previousCode);let a=o.previousFunctionVersions?.[s];if(a)await An(()=>i.updateAlias({FunctionName:c,Name:"live",FunctionVersion:a}))}await Wp(n,r.artifactBucket,r.slug,t,{...o,sha:o.previousSha??o.sha,code:o.previousCode,functionEnv:o.previousFunctionEnv??o.functionEnv,functionVersions:o.previousFunctionVersions??o.functionVersions,previousSha:void 0,previousCode:void 0,previousFunctionEnv:void 0,previousFunctionVersions:void 0,timestamp:new Date().toISOString()}),to("Rollback complete")}async function os(e,t,r,n){let i=Cn(e,t),o=new kt(i.region),s=`${i.slug}-${t}-http`,d={...(await o.getFunction(s)).Configuration?.Environment?.Variables??{}};if(d.MAINTENANCE_MODE=r?"1":"0",r&&n)d.MAINTENANCE_BYPASS_SECRET=n;if(!r)delete d.MAINTENANCE_BYPASS_SECRET;if(await An(()=>o.updateFunctionConfiguration({FunctionName:s,Environment:{Variables:d}})),(i.app.provisionedConcurrency??0)>0)await o.waitForFunctionActive(s,120),await rs(o,s);to(r?"Application is now in maintenance mode (503)":"Application is live")}async function ui(e,t,r){let n=Cn(e,t),i=new kt(n.region),o=`${n.slug}-${t}-cli`,s=await i.invoke({FunctionName:o,InvocationType:"RequestResponse",Payload:{command:r},LogType:"Tail"});if(s.FunctionError)throw Error(`Command failed: ${s.Payload}`);return s.Payload??""}async function nt(e,t){let r=Cn(e,t),n=new Er(r.region),i=new kt(r.region),o=new ur(r.region),s="not deployed",c={};try{let{Stacks:w}=await n.describeStacks({stackName:r.stackName});s=w?.[0]?.StackStatus??s;for(let k of w?.[0]?.Outputs??[])if(k.OutputKey)c[k.OutputKey]=k.OutputValue??""}catch{}let d=Mp(r.app,r.slug,t),a=r.app.provisionedConcurrency??0,u=["http","cli",...d.length?["queue"]:[]],m=`${r.slug}-${t}`,h=[];for(let w of u){let k=`${m}-${w}`,C={mode:w,name:k,version:"$LATEST"};if(a>0){let T=await i.getAlias(k,"live").catch(()=>null);if(T?.FunctionVersion){C.version=T.FunctionVersion;let M=await i.getProvisionedConcurrencyConfig(k,"live").catch(()=>null);if(M)C.provisioned={status:M.Status??"-",allocated:M.AllocatedProvisionedConcurrentExecutions??0,requested:M.RequestedProvisionedConcurrentExecutions??0}}}h.push(C)}let y=await is(o,r.artifactBucket,r.slug,t).catch(()=>null);return{slug:r.slug,environment:t,region:r.region,stackStatus:s,endpoint:c.HttpApiEndpoint,assetUrl:y?.assetUrl,scheduler:r.app.scheduler??"on",queues:d,provisionedConcurrency:a,functions:h,lastRelease:y?{sha:y.sha,timestamp:y.timestamp}:void 0}}function YS(e,t){return`${e}-${t}-db`}async function Jp(e,t,r,n){let i=Cn(e,t);if(i.app.database?.connection!=="aurora-serverless")throw Error("No Aurora Serverless v2 database is configured for this environment.");let{RDSClient:o}=await import("./chunk-hz7k9ymh.js"),s=new o(i.region),c=YS(i.slug,t);ct(`Scaling ${c} → ${r}–${n} ACUs`),await s.modifyDBCluster({DBClusterIdentifier:c,ServerlessV2ScalingConfiguration:{MinCapacity:r,MaxCapacity:n},ApplyImmediately:!0}),to(`Scaling applied to ${c} (takes effect shortly).`)}class Rr{client;region;constructor(e="us-east-1",t){this.region=e,this.client=new pi(Qp(t))}async query(e){let t=new URLSearchParams(Gp({Version:"2010-08-01",...e})).toString();return this.client.request({service:"monitoring",region:this.region,method:"POST",path:"/",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t})}async getMetricStatistics(e){let t={Action:"GetMetricStatistics",Namespace:e.Namespace,MetricName:e.MetricName,StartTime:e.StartTime.toISOString(),EndTime:e.EndTime.toISOString(),Period:e.Period};(e.Statistics??[]).forEach((o,s)=>{t[`Statistics.member.${s+1}`]=o}),(e.ExtendedStatistics??[]).forEach((o,s)=>{t[`ExtendedStatistics.member.${s+1}`]=o}),(e.Dimensions??[]).forEach((o,s)=>{t[`Dimensions.member.${s+1}.Name`]=o.Name,t[`Dimensions.member.${s+1}.Value`]=o.Value});let r=await this.query(t),i=(r.GetMetricStatisticsResult||r)?.Datapoints?.member??[];if(!Array.isArray(i))i=i?[i]:[];return i.map((o)=>{let s={},c=o.ExtendedStatistics?.entry;if(c){if(!Array.isArray(c))c=[c];for(let d of c)if(d?.key!=null)s[d.key]=Number(d.value)}return{Timestamp:o.Timestamp,Sum:o.Sum!=null?Number(o.Sum):void 0,Average:o.Average!=null?Number(o.Average):void 0,Maximum:o.Maximum!=null?Number(o.Maximum):void 0,Minimum:o.Minimum!=null?Number(o.Minimum):void 0,Percentiles:Object.keys(s).length?s:void 0,Unit:o.Unit}})}async getMetricSeries(e){let t=/^p\d/.test(e.Stat);return(await this.getMetricStatistics({Namespace:e.Namespace,MetricName:e.MetricName,Dimensions:e.Dimensions,StartTime:e.StartTime,EndTime:e.EndTime,Period:e.Period,Statistics:t?[]:[e.Stat],ExtendedStatistics:t?[e.Stat]:[]})).slice().sort((n,i)=>new Date(n.Timestamp??0).getTime()-new Date(i.Timestamp??0).getTime()).map((n)=>t?n.Percentiles?.[e.Stat]??0:n[e.Stat]??0)}async describeAlarms(e){let t={Action:"DescribeAlarms"};if(e?.AlarmNamePrefix)t.AlarmNamePrefix=e.AlarmNamePrefix;if(e?.MaxRecords)t.MaxRecords=e.MaxRecords;let r=await this.query(t),i=(r.DescribeAlarmsResult||r)?.MetricAlarms?.member??[];if(!Array.isArray(i))i=i?[i]:[];return i.map((o)=>({AlarmName:o.AlarmName,StateValue:o.StateValue,MetricName:o.MetricName,ComparisonOperator:o.ComparisonOperator,Threshold:o.Threshold!=null?Number(o.Threshold):void 0,Namespace:o.Namespace}))}async putMetricAlarm(e){let t={Action:"PutMetricAlarm",AlarmName:e.AlarmName,Namespace:e.Namespace,MetricName:e.MetricName,ComparisonOperator:e.ComparisonOperator,Threshold:e.Threshold,EvaluationPeriods:e.EvaluationPeriods,Period:e.Period,Statistic:e.Statistic};if(e.AlarmDescription)t.AlarmDescription=e.AlarmDescription;(e.Dimensions??[]).forEach((r,n)=>{t[`Dimensions.member.${n+1}.Name`]=r.Name,t[`Dimensions.member.${n+1}.Value`]=r.Value}),(e.AlarmActions??[]).forEach((r,n)=>{t[`AlarmActions.member.${n+1}`]=r}),await this.query(t)}async deleteAlarms(e){if(!e.length)return;let t={Action:"DeleteAlarms"};e.forEach((r,n)=>{t[`AlarmNames.member.${n+1}`]=r}),await this.query(t)}}class yc{client;region;constructor(e="us-east-1"){this.region=e,this.client=new pi}async call(e,t){return this.client.request({service:"wafv2",region:this.region,method:"POST",path:"/",headers:{"Content-Type":"application/x-amz-json-1.1","X-Amz-Target":`AWSWAF_20190729.${e}`},body:JSON.stringify(t)})}async listWebACLs(e="REGIONAL"){return(await this.call("ListWebACLs",{Scope:e,Limit:100}))?.WebACLs??[]}async getWebACLRules(e,t,r="REGIONAL"){return((await this.call("GetWebACL",{Name:e,Id:t,Scope:r}))?.WebACL?.Rules??[]).map((o)=>({Name:o.Name,Priority:o.Priority,Action:o.Action?Object.keys(o.Action)[0]:o.OverrideAction?Object.keys(o.OverrideAction)[0]:"count"}))}}var ZS=[{index:0,id:"clients",label:"Clients"},{index:1,id:"dns",label:"DNS & TLS"},{index:2,id:"edge",label:"Edge"},{index:3,id:"routing",label:"Routing"},{index:4,id:"apps",label:"Applications"},{index:5,id:"runtime",label:"Background runtime"},{index:6,id:"data",label:"Data services"},{index:7,id:"durability",label:"Durability"}],XS=[{index:0,id:"clients",label:"Clients"},{index:1,id:"dns",label:"DNS & TLS"},{index:2,id:"edge",label:"Edge"},{index:3,id:"entry",label:"Entry points"},{index:4,id:"compute",label:"Compute"},{index:5,id:"messaging",label:"Messaging & pooling"},{index:6,id:"data",label:"Data services"},{index:7,id:"durability",label:"Durability"}],ew=[{match:/^redis/,kind:"cache",label:"Redis"},{match:/^(?:mysql|mariadb)/,kind:"database",label:"MySQL"},{match:/^postgres/,kind:"database",label:"PostgreSQL"},{match:/^meilisearch/,kind:"database",label:"Meilisearch"},{match:/^vitess|^vtgate/,kind:"database",label:"Vitess"},{match:/^memcached/,kind:"cache",label:"Memcached"}],tw=/^(?:rpx-gateway|nginx|caddy|traefik|haproxy)$/;function J(e,t=""){let r=e==null?"":String(e).trim();return r&&r!=="-"&&r!=="—"?r:t}function rw(e){return Array.isArray(e)?e.length:0}function Yt(e){let t=J(e).toLowerCase();if(!t)return"unknown";if(["running","live","active","available","success","ok","healthy","enabled"].includes(t))return"ok";if(["failed","stopped","unreachable","error","critical","disabled"].includes(t))return"bad";if(["configured","creating","pending","degraded","shadowed","warn","unknown"].includes(t))return"warn";return"warn"}function Ue(e,t,r){if(r.has(t.source)&&r.has(t.target))e.push(t)}function Pn(e,t={}){let r=[],n=[],i=[],o=e.server??{},s=Array.isArray(e.sites)?e.sites:[],c=Array.isArray(e.services)?e.services:[],d=Array.isArray(e.workers)?e.workers:[],a=e.security??{},u=!!e._serverReachable&&!e.metricsUnavailable,m="box";if(!u)i.push("The compute box could not be probed, so live service state is missing; the shape comes from your cloud config.");r.push({id:"internet",label:"Internet",kind:"internet",layer:0,status:"ok",sub:"Public traffic",facts:[],external:!0});let h=[...new Set(s.map((N)=>J(N.domain)||J(N.route).split("/")[0]).filter((N)=>N&&N!=="internal"&&N!=="loopback"))],y=Array.isArray(a.tlsCertificates)?a.tlsCertificates:[],w=y.filter((N)=>Number(N?.daysRemaining??999)<21).length;r.push({id:"dns",label:h.length===1?h[0]:"Public domains",kind:"dns",layer:1,status:w?"warn":h.length?"ok":"unknown",sub:h.length>1?`${h.length} domains`:"DNS & certificates",facts:[{label:"Domains",value:h.length?h.slice(0,6).join(", "):"none resolved"},{label:"Certificates",value:y.length?`${y.length} issued`:"none reported"},...w?[{label:"Expiring",value:`${w} within 21 days`}]:[]],href:"/server/security",external:!0});let k=a.firewall??{},C=Array.isArray(a.ports)?a.ports:[];r.push({id:"firewall",label:"Host firewall",kind:"firewall",layer:2,status:Yt(k.status),sub:J(k.summary,"Inbound filtering"),facts:[{label:"State",value:J(k.status,"unknown")},{label:"Open ports",value:C.length?C.map((N)=>J(N.listen)).join(", "):"not reported"}],href:"/server/firewall",group:"box"});let T=c.find((N)=>tw.test(J(N.name)));r.push({id:"proxy",label:J(T?.name,"Reverse proxy"),kind:"proxy",layer:3,status:T?Yt(T.status):"unknown",sub:"TLS termination & routing",facts:[{label:"Service",value:J(T?.name,"not detected")},{label:"State",value:J(T?.status,u?"not running":"not probed")},{label:"Routes",value:`${s.length} site${s.length===1?"":"s"}`}],href:"/server/services",group:"box"});for(let N of s){let Q=`site:${J(N.name)}`;if(!J(N.name))continue;r.push({id:Q,label:J(N.name),kind:"site",layer:4,status:Yt(N.status),sub:J(N.runtime,"runtime"),facts:[{label:"Route",value:J(N.route,"internal")},{label:"Runtime",value:J(N.runtime,"unknown")},{label:"Delivery",value:J(N.deploy,"unknown")},{label:"TLS",value:J(N.tls,"unknown")},...N.responseMs!=null?[{label:"Response",value:`${Math.round(Number(N.responseMs))} ms`}]:[],...N.httpStatus!=null?[{label:"HTTP",value:String(N.httpStatus)}]:[]],href:"/server/sites",group:"box"})}for(let N of d){let Q=`worker:${J(N.name)}`;if(!J(N.name))continue;r.push({id:Q,label:J(N.name),kind:"worker",layer:5,status:Yt(N.status),sub:`${Number(N.processes??1)} process${Number(N.processes??1)===1?"":"es"}`,facts:[{label:"Processes",value:String(N.processes??1)},{label:"State",value:J(N.status,"unknown")},...J(N.site)?[{label:"Site",value:J(N.site)}]:[]],href:"/operations/jobs",group:"box"})}let M=e.serverScheduler??{};if(M.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:5,status:"ok",sub:"Cron dispatch",facts:[{label:"Last run",value:J(M.lastRun,"unknown")}],href:"/operations/jobs",group:"box"});let P=c.map((N)=>{let Q=J(N.name),D=ew.find((Y)=>Y.match.test(Q));return D?{service:N,name:Q,...D}:null}).filter((N)=>!!N);for(let N of P)r.push({id:`data:${N.name}`,label:N.label,kind:N.kind,layer:6,status:Yt(N.service.status),sub:N.name,facts:[{label:"Unit",value:N.name},{label:"State",value:J(N.service.status,"unknown")}],href:"/data/services",group:"box"});let O=e.backup??{};if(O.enabled)r.push({id:"backup",label:"Backups",kind:"backup",layer:7,status:"ok",sub:J(O.destination,"destination"),facts:[{label:"Destination",value:J(O.destination,"unknown")},{label:"Schedule",value:J(O.schedule,"unknown")},{label:"Retention",value:`${O.retention??0} copies`},{label:"Last run",value:J(O.last,"unknown")}],href:"/data/backups"});let U=new Set(r.map((N)=>N.id));Ue(n,{source:"internet",target:"dns",flow:"request",label:"https"},U),Ue(n,{source:"dns",target:"firewall",flow:"request",label:"443/80"},U),Ue(n,{source:"firewall",target:"proxy",flow:"request"},U);for(let N of s){let Q=`site:${J(N.name)}`;Ue(n,{source:"proxy",target:Q,flow:"request",label:J(N.path)||void 0,status:Yt(N.status)},U)}for(let N of d){let Q=`worker:${J(N.name)}`,D=`site:${J(N.site)}`;if(U.has(D))Ue(n,{source:D,target:Q,flow:"async",label:"queue"},U);else Ue(n,{source:"proxy",target:Q,flow:"async",label:"queue"},U)}for(let N of d)Ue(n,{source:"scheduler",target:`worker:${J(N.name)}`,flow:"async",label:"dispatch"},U);let q=[...s.map((N)=>`site:${J(N.name)}`),...d.map((N)=>`worker:${J(N.name)}`)];for(let N of P)for(let Q of q)Ue(n,{source:Q,target:`data:${N.name}`,flow:"data",label:"localhost"},U);if(P.length&&q.length)i.push("Data-service edges show co-location on the box: every process on it can reach localhost. They are not a declared per-site binding.");for(let N of P)Ue(n,{source:`data:${N.name}`,target:"backup",flow:"backup",label:"snapshot"},U);for(let N of s)Ue(n,{source:`site:${J(N.name)}`,target:"backup",flow:"backup"},U);return{mode:"server",project:J(t.project)||J(e.project?.name)||J(o.name,"project"),environment:J(t.environment)||J(e.environment,"production"),provider:J(o.provider,"unknown"),region:J(o.region,"unknown"),generatedAt:new Date().toISOString(),layers:ZS,groups:[{id:"box",label:J(o.name,"App server"),sub:[J(o.provider),J(o.region),J(o.ip)].filter(Boolean).join(" · ")}],nodes:r,links:n,notes:i}}function ss(e,t={}){let r=[],n=[],i=[],o=e.app??{},s=Array.isArray(e.functions)?e.functions:[],c=Array.isArray(e.queues)?e.queues:[],d=e.metrics??{};if(!s.length)i.push("No Lambda functions were read for this environment, so the compute layer is empty rather than assumed.");r.push({id:"internet",label:"Internet",kind:"internet",layer:0,status:"ok",sub:"Public traffic",facts:[],external:!0});let a=J(o.url),u=a.replace(/^https?:\/\//,"").split("/")[0];r.push({id:"dns",label:u||"Application domain",kind:"dns",layer:1,status:u?"ok":"unknown",sub:"DNS & certificates",facts:[{label:"Endpoint",value:a||"not resolved"}],external:!0});let m=e.waf;if(m)r.push({id:"waf",label:"WAF",kind:"waf",layer:2,status:Yt(m.status??"active"),sub:J(m.scope,"Managed rules"),facts:[{label:"Web ACL",value:J(m.name,"unnamed")},...m.blocked!=null?[{label:"Blocked (24h)",value:String(m.blocked)}]:[],{label:"Rules",value:String(rw(e.wafRules))}],href:"/serverless/firewall"});let h=e.assetsInfo;if(h)r.push({id:"cdn",label:"Asset CDN",kind:"cdn",layer:2,status:"ok",sub:J(h.cdn,"CloudFront"),facts:[{label:"Distribution",value:J(h.cdn,"unknown")},{label:"Custom domain",value:J(h.customDomain,"none")}],href:"/serverless/assets"}),r.push({id:"assets",label:"Asset bucket",kind:"storage",layer:6,status:"ok",sub:J(h.bucket,"S3"),facts:[{label:"Bucket",value:J(h.bucket,"unknown")},...h.files?[{label:"Objects",value:String(h.files)}]:[],...h.sizeMb?[{label:"Size",value:`${h.sizeMb} MB`}]:[]],href:"/serverless/assets"});let y=s.find((D)=>J(D.key).startsWith("http"));r.push({id:"gateway",label:"HTTP entry point",kind:"gateway",layer:3,status:y?"ok":"unknown",sub:"Function URL / API Gateway",facts:[{label:"Endpoint",value:a||"not resolved"},{label:"Invocations (24h)",value:String(d.invocations??0)},...d.errorRatePct!=null?[{label:"Error rate",value:`${d.errorRatePct}%`}]:[]],href:"/serverless/metrics"});for(let D of s){let Y=`fn:${J(D.name)}`;if(!J(D.name))continue;let se=Number(D.errors??0),he=Number(D.invocations??0);r.push({id:Y,label:J(D.key,J(D.name)),kind:"function",layer:4,status:se>0?he&&se/he>0.02?"bad":"warn":he?"ok":"idle",sub:J(D.runtime,"lambda"),facts:[{label:"Function",value:J(D.name)},{label:"Memory",value:`${D.memory??0} MB`},{label:"Timeout",value:`${D.timeout??0}s`},{label:"Invocations (24h)",value:String(he)},{label:"Errors (24h)",value:String(se)},{label:"p95",value:`${D.p95??0} ms`},...D.provisioned?[{label:"Provisioned",value:J(D.provisioned)}]:[]],href:"/serverless/functions"})}for(let D of c){let Y=`queue:${J(D.name)}`;if(!J(D.name))continue;let se=Number(D.dlq??0);r.push({id:Y,label:J(D.name),kind:"queue",layer:5,status:se>0?"bad":Number(D.visible??0)>0?"warn":"ok",sub:"SQS",facts:[{label:"Visible",value:String(D.visible??0)},{label:"In flight",value:String(D.inFlight??0)},{label:"Processed (24h)",value:String(D.processed??0)},{label:"Dead letter",value:String(se)}],href:"/serverless/queues"})}let w=e.aurora;if(w)r.push({id:"database",label:"Aurora Serverless",kind:"database",layer:6,status:Yt(w.status),sub:J(w.engine,"aurora"),facts:[{label:"Cluster",value:J(w.id,"unknown")},{label:"Capacity",value:`${w.currentAcu??0} ACU (${w.minAcu??0}–${w.maxAcu??0})`},{label:"Connections",value:String(w.connections??0)}],href:"/serverless/data"});let k=e.proxy;if(k)r.push({id:"rds-proxy",label:"RDS Proxy",kind:"database",layer:5,status:Yt(k.status),sub:"Connection pooling",facts:[{label:"Proxy",value:J(k.name,"unknown")},{label:"Endpoint",value:J(k.endpoint,"unknown")},{label:"Pooled",value:String(k.pooledConns??0)}],href:"/serverless/data"});let C=e.redis;if(C)r.push({id:"cache",label:"ElastiCache",kind:"cache",layer:6,status:Yt(C.status),sub:J(C.node,"redis"),facts:[{label:"Group",value:J(C.id,"unknown")},{label:"Hit rate",value:`${C.hitRate??0}%`}],href:"/serverless/data"});let T=e.efs;if(T)r.push({id:"efs",label:"EFS",kind:"filesystem",layer:6,status:Yt(T.status),sub:J(T.mount,"/mnt/local"),facts:[{label:"File system",value:J(T.id,"unknown")},{label:"Mount",value:J(T.mount,"unknown")},{label:"Size",value:`${T.sizeMb??0} MB`}],href:"/data/volumes"});let M=e.scheduler??{};if(M.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:3,status:"ok",sub:J(M.expression,"rate(1 minute)"),facts:[{label:"Expression",value:J(M.expression,"unknown")},{label:"Last run",value:J(M.lastRun,"unknown")}],href:"/operations/jobs"});let P=new Set(r.map((D)=>D.id)),O=P.has("waf")?"waf":"gateway";Ue(n,{source:"internet",target:"dns",flow:"request",label:"https"},P),Ue(n,{source:"dns",target:O,flow:"request"},P),Ue(n,{source:"dns",target:"cdn",flow:"request",label:"assets"},P),Ue(n,{source:"waf",target:"gateway",flow:"request",label:"allowed"},P),Ue(n,{source:"cdn",target:"assets",flow:"data",label:"origin"},P);let U=s.filter((D)=>J(D.key).startsWith("http")),q=s.filter((D)=>J(D.key).startsWith("queue")),N=s.filter((D)=>J(D.key).startsWith("cli"));for(let D of U)Ue(n,{source:"gateway",target:`fn:${J(D.name)}`,flow:"request",label:"invoke"},P);for(let D of N)Ue(n,{source:"scheduler",target:`fn:${J(D.name)}`,flow:"async",label:"schedule"},P);for(let D of c){for(let Y of U)Ue(n,{source:`fn:${J(Y.name)}`,target:`queue:${J(D.name)}`,flow:"async",label:"publish"},P);for(let Y of q)Ue(n,{source:`queue:${J(D.name)}`,target:`fn:${J(Y.name)}`,flow:"async",label:"consume"},P)}let Q=["rds-proxy","database","cache","efs","assets"];for(let D of s){let Y=`fn:${J(D.name)}`;if(P.has("rds-proxy"))Ue(n,{source:Y,target:"rds-proxy",flow:"data",label:"pooled"},P);else Ue(n,{source:Y,target:"database",flow:"data",label:"sql"},P);for(let se of Q.filter((he)=>he!=="rds-proxy"&&he!=="database"))Ue(n,{source:Y,target:se,flow:"data"},P)}return Ue(n,{source:"rds-proxy",target:"database",flow:"data",label:"sql"},P),{mode:"serverless",project:J(t.project)||J(o.name,"application"),environment:J(t.environment)||J(o.env,"production"),provider:"aws",region:J(o.region,"unknown"),generatedAt:new Date().toISOString(),layers:XS,groups:[],nodes:r,links:n,notes:i}}function nw(e,t,r={}){return e==="serverless"?ss(t,r):Pn(t,r)}function Yp(e){return String(e).padStart(2,"0")}function mi(e){return`${e.getUTCFullYear()}-${Yp(e.getUTCMonth()+1)}-${Yp(e.getUTCDate())}`}function iw(e){let t=Math.max(0,Math.round((Date.now()-e)/1000));if(t<60)return`${t}s ago`;let r=Math.round(t/60);if(r<60)return`${r}m ago`;let n=Math.round(r/60);if(n<48)return`${n}h ago`;return`${Math.round(n/24)}d ago`}async function ro(e,t,r,n,i,o){let s=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:r,Dimensions:[{Name:"FunctionName",Value:t}],StartTime:i,EndTime:o,Period:86400,Statistics:[n]}).catch(()=>[]);if(!s.length)return 0;if(n==="Sum")return s.reduce((c,d)=>c+(d.Sum??0),0);if(n==="Maximum")return Math.max(...s.map((c)=>c.Maximum??0));return s.reduce((c,d)=>c+(d.Average??0),0)/s.length}async function no(e,t,r,n,i,o,s){let c=await e.getMetricStatistics({Namespace:t,MetricName:r,Dimensions:n,StartTime:o,EndTime:s,Period:86400,Statistics:[i]}).catch(()=>[]);if(!c.length)return 0;if(i==="Sum")return c.reduce((d,a)=>d+(a.Sum??0),0);if(i==="Maximum")return Math.max(...c.map((d)=>d.Maximum??0));return c.reduce((d,a)=>d+(a.Average??0),0)/c.length}async function vc(e,t,r,n,i){let o=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:"Duration",Dimensions:[{Name:"FunctionName",Value:t}],StartTime:n,EndTime:i,Period:86400,ExtendedStatistics:[r]}).catch(()=>[]);return Math.round(o.reduce((s,c)=>s+(c.Percentiles?.[r]??0),0))}async function io(e,t){let r=await nt(e,t),n=r.region,i=new Rr(n),o=new kt(n),s=new ci(n),c=new Date,d=new Date(c.getTime()-86400000),a=e.environments?.[t]?.app,u={};u.app={name:r.slug,env:t,region:n,runtime:a?.kind==="php"?`php-${a?.phpVersion??"8.3"} (fpm)`:a?.kind??"node",url:r.endpoint??"",build:r.lastRelease?.sha?.slice(0,7)??"—",deployedAt:r.lastRelease?.timestamp??"—"},u.maintenance={enabled:!1},u.scheduler={enabled:r.scheduler!=="off",expression:r.scheduler==="sub-minute"?"rate(1 minute) · sub-minute":"rate(1 minute)",lastRun:"—"};let m=0,h=0,y=0,w=[],k=[],C=[];for(let O of r.functions){let[U,q,N,Q,D,Y,se,he,je]=await Promise.all([ro(i,O.name,"Invocations","Sum",d,c),ro(i,O.name,"Errors","Sum",d,c),ro(i,O.name,"Throttles","Sum",d,c),ro(i,O.name,"Duration","Average",d,c),o.getFunction(O.name).catch(()=>null),vc(i,O.name,"p50",d,c),vc(i,O.name,"p95",d,c),vc(i,O.name,"p99",d,c),i.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:O.name}],StartTime:new Date(c.getTime()-43200000),EndTime:c,Period:3600,Stat:"Sum"}).catch(()=>[])]);m+=U,h+=q,y=Math.max(y,Q);let de=D?.Configuration?.MemorySize??0,Re=Object.keys(D?.Configuration?.Environment?.Variables??{}),Me=[],me=0;try{let{events:j=[]}=await s.filterLogEvents({logGroupName:`/aws/lambda/${O.name}`,startTime:d.getTime(),limit:120});for(let F of j){let K=(F.message??"").trim(),ye=/Max Memory Used:\s*(\d+)\s*MB/.exec(K);if(ye)me=Math.max(me,Number(ye[1]));if(K&&!/^(?:START|END|REPORT|INIT_START)/.test(K))C.push({source:O.mode||O.name,timestamp:new Date(F.timestamp??0).toISOString(),when:iw(F.timestamp??0),message:K.slice(0,400),level:/error|exception|fatal|panic|traceback/i.test(K)?"error":/warn|warning|timeout|retr(?:y|ies)|throttl/i.test(K)?"warn":"info"})}Me=j.filter((F)=>!/^(?:START|END|REPORT|INIT_START)/.test((F.message??"").trim())).slice(-6).map((F)=>({ts:new Date(F.timestamp??0).toISOString().slice(11,19),msg:(F.message??"").trim().slice(0,120),err:/error|exception|fatal/i.test(F.message??"")}))}catch{}let R=Math.max(1,...je);w.push({key:O.mode,name:O.name,version:O.version,memory:de,timeout:D?.Configuration?.Timeout??0,runtime:D?.Configuration?.Runtime??"provided.al2023",invocations:Math.round(U),errors:Math.round(q),p95:se||Math.round(Q),status:"active",provisioned:O.provisioned?`${O.provisioned.allocated}/${O.provisioned.requested}`:void 0}),k.push({key:O.mode,name:O.name,runtime:D?.Configuration?.Runtime??"provided.al2023",arch:D?.Configuration?.Architectures?.[0]??"x86_64",memory:de,timeout:D?.Configuration?.Timeout??0,ephemeral:D?.Configuration?.EphemeralStorage?.Size??512,version:O.version,concurrency:a?.concurrency??"—",invocations:Math.round(U),errors:Math.round(q),throttles:Math.round(N),p50:Y||Math.round(Q),p95:se||Math.round(Q),p99:he||Math.round(Q),maxMem:me,spark:je.length?je.map((j)=>Math.round(j/R*100)):[0],env:Re.length?Re:["(none)"],recent:Me.length?Me:[{ts:"—",msg:"no recent events",err:!1}]})}u.functions=w,u.functionsDetail=k,u.serverlessLogs=C.sort((O,U)=>String(U.timestamp).localeCompare(String(O.timestamp))).slice(0,600),u.serverlessLogsEmptyReason=C.length?void 0:"No recent function logs were found in CloudWatch for this environment.";let T=m?Number((h/m*100).toFixed(2)):0,M=Math.round(await ro(i,r.functions[0]?.name??"","ConcurrentExecutions","Maximum",d,c));u.metrics={invocations:Math.round(m),errorRatePct:T,p95Ms:Math.round(y),coldStartPct:void 0,concurrency:M,estCostUsd:void 0};try{let O=new _n(n),U=[],q=[],N=0;try{let{QueueUrl:D}=await O.getQueueUrl(`${r.slug}-${t}-dlq`),{Attributes:Y}=await O.getQueueAttributes(D);N=Number(Y.ApproximateNumberOfMessages??0)}catch{}let Q=a?as(a,r.slug,t):[];for(let D of Q){let Y=D.name.replace(`${r.slug}-${t}-`,""),se=0,he=0;try{let{QueueUrl:de}=await O.getQueueUrl(D.name),{Attributes:Re}=await O.getQueueAttributes(de);se=Number(Re.ApproximateNumberOfMessages??0),he=Number(Re.ApproximateNumberOfMessagesNotVisible??0)}catch{}let je=Math.round(await no(i,"AWS/SQS","NumberOfMessagesDeleted",[{Name:"QueueName",Value:D.name}],"Sum",d,c));U.push({name:Y,visible:se,inFlight:he,processed:je,dlq:N}),q.push({name:D.name,short:Y,visible:se,inFlight:he,delayed:0,processed:je,oldestSec:0,concurrency:D.concurrency??a?.queueConcurrency??"—",tries:a?.queueTries??3,visTimeout:(a?.queueTimeout??120)*6,dlq:N})}if(U.length)u.queues=U;if(q.length)u.queuesDetail=q;u.dlqItems=[]}catch{}try{let O=new Er(n),{Stacks:U}=await O.describeStacks({stackName:li(e,t)}),q={};for(let N of U?.[0]?.Outputs??[])if(N.OutputKey)q[N.OutputKey]=N.OutputValue??"";if(a?.database?.connection==="aurora-serverless"){let N=`${r.slug}-${t}-db`,Q=[{Name:"DBClusterIdentifier",Value:N}],[D,Y]=await Promise.all([no(i,"AWS/RDS","ServerlessDatabaseCapacity",Q,"Average",d,c),no(i,"AWS/RDS","DatabaseConnections",Q,"Maximum",d,c)]);if(u.aurora={id:N,engine:"aurora-mysql",minAcu:a?.database?.minCapacity??0.5,maxAcu:a?.database?.maxCapacity??4,currentAcu:D?Number(D.toFixed(1)):a?.database?.minCapacity??0.5,database:"app",connections:Math.round(Y),status:q.DbEndpoint?"available":"creating"},a?.rdsProxy)u.proxy={name:`${r.slug}-${t}-proxy`,endpoint:q.DbProxyEndpoint??"—",pooledConns:Math.round(Y),status:"available"}}if(a?.cache?.driver==="elasticache"){let N=`${r.slug}-${t}-cache`,Q=[{Name:"CacheClusterId",Value:`${N}-001`}],[D,Y]=await Promise.all([no(i,"AWS/ElastiCache","CacheHits",Q,"Sum",d,c),no(i,"AWS/ElastiCache","CacheMisses",Q,"Sum",d,c)]),se=D+Y>0?Number((D/(D+Y)*100).toFixed(1)):0;u.redis={id:N,node:"cache.t4g.micro",engine:"redis",hitRate:se,status:q.CacheEndpoint?"available":"creating"}}if(a?.efs){let N=0;try{if(q.EfsFileSystemId){let Q=new Xp(n),{FileSystems:D}=await Q.describeFileSystems({FileSystemId:q.EfsFileSystemId});N=Number(((D?.[0]?.SizeInBytes?.Value??0)/1048576).toFixed(1))}}catch{}u.efs={id:q.EfsFileSystemId??"efs",mount:"/mnt/local",sizeMb:N,status:"available"}}u.assetsInfo=q.AssetsCdnDomain?{bucket:q.AssetsBucketName??`${r.slug}-${t}-assets`,cdn:q.AssetsCdnDomain,customDomain:a?.assetDomain??"—",assetUrl:r.assetUrl??"—",files:0,sizeMb:0,cacheHitPct:0,build:u.app.build}:void 0}catch{}if(u.assetsInfo)try{let U=await new ur(n).list({bucket:u.assetsInfo.bucket,maxKeys:1000});u.assetsInfo.files=U.length,u.assetsInfo.sizeMb=Number((U.reduce((q,N)=>q+(N.Size??0),0)/1048576).toFixed(1)),u.assetsRecent=U.slice(0,8).map((q)=>({path:`/${q.Key}`,size:`${Math.max(1,Math.round((q.Size??0)/1024))} KB`,type:q.Key.split(".").pop()??""}))}catch{}try{if(a?.secrets){let O=Array.isArray(a.secrets)?a.secrets.map((U)=>({key:U.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),source:U})):Object.entries(a.secrets).map(([U,q])=>({key:U,source:String(q)}));u.secretsList=O.map((U)=>({...U,updated:"—"}))}}catch{}try{let O=new ur(n),U=`${r.slug}-${t}-deployments`,q=await O.getObjectJson(U,`deployments/${r.slug}/${t}/history.json`).catch(()=>null);if(q?.records?.length)u.deploymentsDetail=q.records.slice(-12).reverse().map((N)=>({sha:(N.sha??"").slice(0,7),status:N.status??"success",when:N.timestamp??"—",took:N.took??"—",by:N.by??"—",version:N.version??"—",hooks:N.hooks??[]}))}catch{}u.metricsTotals={invocations:u.metrics.invocations,errors:Math.round(h),errorRatePct:T,p95Ms:u.metrics.p95Ms,throttles:k.reduce((O,U)=>O+U.throttles,0),coldStartPct:void 0,estCostUsd:void 0,concurrency:M},u.metricsPerFn=k.map((O)=>({key:O.key,invocations:O.invocations,errors:O.errors,throttles:O.throttles,avgMs:O.p50,maxMs:O.p99,costUsd:void 0}));try{u.invSpark=await i.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:r.functions.find((O)=>O.mode==="http")?.name??""}],StartTime:new Date(c.getTime()-86400000),EndTime:c,Period:3600,Stat:"Sum"})}catch{}try{let O=new Zp,U=c,q=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth(),1)),N=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth()-1,1)),[Q,D]=await Promise.all([O.getCostByService({start:mi(q),end:mi(U),granularity:"MONTHLY"}).catch(()=>[]),O.getCostByService({start:mi(N),end:mi(q),granularity:"MONTHLY"}).catch(()=>[])]);if(Q.length){let Y=Q.reduce((me,R)=>me+R.amount,0),se=D.reduce((me,R)=>me+R.amount,0),he=U.getUTCDate(),je=new Date(Date.UTC(U.getUTCFullYear(),U.getUTCMonth()+1,0)).getUTCDate();u.costSummary={monthToDateUsd:Number(Y.toFixed(2)),projectedUsd:Number((Y/he*je).toFixed(2)),lastMonthUsd:Number(se.toFixed(2)),dailyAvgUsd:Number((Y/he).toFixed(2))},u.costServices=Q.filter((me)=>me.amount>0).sort((me,R)=>R.amount-me.amount).slice(0,12).map((me)=>({name:me.service,usd:Number(me.amount.toFixed(2)),note:""})),u.metrics.estCostUsd=Number((Y/he).toFixed(2)),u.metricsTotals.estCostUsd=u.metrics.estCostUsd,u.costTrend=await O.getDailyTotals({start:mi(q),end:mi(U)}).catch(()=>[]);let de=Q.find((me)=>/lambda/i.test(me.service))?.amount??0,Re=(me)=>me.invocations*(me.p50/1000)*(me.memory/1024),Me=k.reduce((me,R)=>me+Re(R),0)||1;u.costPerFn=k.map((me)=>({key:me.key,requests:me.invocations,gbSec:Math.round(Re(me)),usd:Number((de*(Re(me)/Me)).toFixed(2))}))}}catch{}if(a?.firewall)try{let O=await i.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"BlockedRequests",StartTime:d,EndTime:c,Period:86400,Statistics:["Sum"]}).catch(()=>[]),U=await i.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"AllowedRequests",StartTime:d,EndTime:c,Period:86400,Statistics:["Sum"]}).catch(()=>[]);u.waf={enabled:!0,scope:"REGIONAL",acl:`${r.slug}-${t}-waf`,allowed24h:Math.round(U.reduce((q,N)=>q+(N.Sum??0),0)),blocked24h:Math.round(O.reduce((q,N)=>q+(N.Sum??0),0))};try{let q=new yc(n),N=await q.listWebACLs("REGIONAL"),Q=N.find((D)=>D.Name?.includes(`${r.slug}-${t}`))??N[0];if(Q?.Name&&Q.Id){u.waf.acl=Q.Name;let D=await q.getWebACLRules(Q.Name,Q.Id,"REGIONAL");if(D.length)u.wafRules=D.map((Y)=>({name:Y.Name??"—",detail:`priority ${Y.Priority??0}`,action:Y.Action??"count",blocked24h:0}))}}catch{}}catch{}let P=[];if(u.aurora)P.push({name:"Aurora Serverless v2",detail:`${u.aurora.id} · ${u.aurora.minAcu}-${u.aurora.maxAcu} ACU`,status:u.aurora.status});if(u.proxy)P.push({name:"RDS Proxy",detail:u.proxy.name,status:u.proxy.status});if(u.redis)P.push({name:`ElastiCache (${u.redis.engine})`,detail:`${u.redis.node} · ${u.redis.hitRate}% hit rate`,status:u.redis.status});if(u.efs)P.push({name:"EFS",detail:`${u.efs.mount} · ${u.efs.sizeMb} MB`,status:u.efs.status});if(P.length)u.dataServices=P;if(r.scheduler!=="off"&&a?.kind==="php")try{let O=await ui(e,t,"schedule:list"),U=[];for(let q of(O||"").split(`
16
16
  `)){let N=/^\s*([\d*/,\-\s]+?)\s{2,}(.+?)(?:\s{2,}Next Due.*)?$/.exec(q);if(N&&/[*\d]/.test(N[1])&&N[1].trim().split(/\s+/).length===5)U.push({command:N[2].trim().replace(/^php artisan /,""),cron:N[1].trim(),desc:"",lastRun:"—",lastStatus:"ok"})}if(U.length)u.schedulerTasks=U}catch{}return u.topology=ss(u,{project:e.project.name,environment:t}),u}function Zr(e){let t=Number(e);return Number.isFinite(t)&&t>=0?t:null}function ow(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return null;let t=Date.parse(`${e}T12:00:00.000Z`);return Number.isFinite(t)?new Date(t).toISOString():null}function em(e,t){if(!e||typeof e!=="object")return[];let r={source:t.name},n=[],i=t.now,o=(a,u,m,h=i)=>{if(u!==null)n.push({name:a,value:u,unit:m,timestamp:h,attributes:r})};o("storage.egress.month",Zr(e.monthBytes),"bytes"),o("storage.egress.today",Zr(e.todayBytes),"bytes"),o("storage.egress.projected_month",Zr(e.projectedMonthBytes),"bytes");let s=Zr(e.budgetBytes);if(s!==null&&s>0){o("storage.egress.budget",s,"bytes");let a=e.budgetUsedPercent,u=typeof a==="number"&&Number.isFinite(a)?a:Zr(e.monthBytes)!==null?Math.round(Zr(e.monthBytes)/s*1000)/10:null;o("storage.egress.budget_used_percent",u,"percent")}let c=t.maxReplayDays??45,d=Array.isArray(e.days)?e.days.slice(-c):[];for(let a of d){let u=ow(String(a?.date??"")),m=Zr(a?.bytes);if(!u||m===null)continue;n.push({name:"storage.egress.day",value:m,unit:"bytes",timestamp:u,attributes:r});let h=Zr(a?.downloads);if(h!==null)n.push({name:"storage.egress.day_downloads",value:h,unit:"count",timestamp:u,attributes:r})}return n}async function tm(e,t=process.env,r=fetch){let n=e.tokenEnv?t[e.tokenEnv]:void 0,i=await r(e.url,{headers:n?{Authorization:`Bearer ${n}`}:{},signal:AbortSignal.timeout(1e4)});if(!i.ok)throw Error(`HTTP ${i.status}`);return await i.json()}async function bc(e,t){let r=[],n=[];if(!Array.isArray(e)||e.length===0)return{metrics:r,errors:n};let i=await Promise.all(e.map(async(o)=>{if(!o?.name||!o?.url)return{endpoint:o,error:"egress endpoint needs both a name and a url"};try{let s=await tm(o,t.env,t.fetchImpl);return{endpoint:o,report:s}}catch(s){return{endpoint:o,error:s instanceof Error?s.message:String(s)}}}));for(let o of i){let s=`egress:${o.endpoint?.name??"unnamed"}`;if("error"in o&&o.error){n.push({source:s,message:o.error});continue}r.push(...em(o.report,{name:o.endpoint.name,now:t.now}))}return{metrics:r,errors:n}}import{createHash as YP}from"node:crypto";import{existsSync as qr,mkdtempSync as Vu,readdirSync as hb,rmSync as ti,statSync as Vb}from"node:fs";import{readFile as br,writeFile as Xn}from"node:fs/promises";import{tmpdir as nc}from"node:os";import{dirname as ZP,extname as Vo,join as Te,normalize as XP,relative as e_,resolve as t_,sep as r_}from"node:path";import{fileURLToPath as n_}from"node:url";class Sc extends Error{status;code;requestId;constructor(e,t,r,n){super(r);this.status=e;this.code=t;this.requestId=n}}class rm{options;baseUrl;fetchFn;constructor(e){this.options=e;this.baseUrl=e.baseUrl.replace(/\/$/,""),this.fetchFn=e.fetch??fetch}async request(e,t={}){let r=await this.fetchFn(`${this.baseUrl}${e}`,{...t,headers:{accept:"application/json",authorization:`Bearer ${this.options.token}`,...t.headers}}),n=await r.json().catch(()=>({}));if(!r.ok)throw new Sc(r.status,n.error?.code??"api_error",n.error?.message??"API request failed.",n.error?.requestId??r.headers.get("x-request-id")??void 0);return n}listProjects(e={}){return this.request(`/api/v1/projects?${new URLSearchParams(Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0).map(([t,r])=>[t,String(r)])))}`)}listEnvironments(e,t={}){return this.request(`/api/v1/projects/${encodeURIComponent(e)}/environments?${new URLSearchParams(Object.fromEntries(Object.entries(t).filter(([,r])=>r!==void 0).map(([r,n])=>[r,String(n)])))}`)}listServices(e,t){return this.request(`/api/v1/services?${new URLSearchParams({projectId:e,...t?{environmentId:t}:{}})}`)}listOperations(e){return this.request(`/api/v1/operations${e?`?projectId=${encodeURIComponent(e)}`:""}`)}listComposeTemplates(){return this.request("/api/v1/compose-templates")}listComposeApplications(e,t){return this.request(`/api/v1/compose-applications?${new URLSearchParams({projectId:e,...t?{environmentId:t}:{}})}`)}previewCompose(e){return this.request("/api/v1/compose-applications/preview",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}createComposeApplication(e){return this.request("/api/v1/compose-applications",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}composeServices(e){return this.request(`/api/v1/compose-applications/${encodeURIComponent(e)}/services`)}composeAction(e,t,r={}){return this.request(`/api/v1/compose-applications/${encodeURIComponent(e)}/${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})}releaseCapabilities(e,t={}){return this.request(`/api/v1/releases/capabilities?${new URLSearchParams({kind:e,health:String(!!t.health),replicas:String(t.replicas??1)})}`)}listReleases(e,t={}){return this.request(`/api/v1/releases?${new URLSearchParams({projectId:e,...t})}`)}createReleaseArtifact(e){return this.request("/api/v1/release-artifacts",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}createRelease(e){return this.request("/api/v1/releases",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}releaseAction(e,t,r={}){return this.request(`/api/v1/releases/${encodeURIComponent(e)}/${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})}createDeployment(e,t){return this.request("/api/v1/deployments",{method:"POST",headers:{"content-type":"application/json","idempotency-key":t},body:JSON.stringify(e)})}detectApplication(e){return this.request("/api/v1/application-detections",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}planApplication(e){return this.request("/api/v1/application-plans",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}listApplicationDrafts(e){return this.request(`/api/v1/application-drafts?projectId=${encodeURIComponent(e)}`)}createApplicationDraft(e){return this.request("/api/v1/application-drafts",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}updateApplicationDraft(e){return this.request("/api/v1/application-drafts",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}createApplication(e,t){return this.request("/api/v1/applications",{method:"POST",headers:{"content-type":"application/json","idempotency-key":t},body:JSON.stringify(e)})}uploadApplicationArtifact(e,t,r){return this.request("/api/v1/application-artifacts",{method:"POST",headers:{"content-type":"application/octet-stream","x-project-id":e,"x-artifact-filename":t},body:r})}listRegistryConnections(){return this.request("/api/v1/registry-connections")}createRegistryConnection(e){return this.request("/api/v1/registry-connections",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}updateRegistryConnection(e){return this.request("/api/v1/registry-connections",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}disconnectRegistryConnection(e){return this.request("/api/v1/registry-connections",{method:"DELETE",headers:{"content-type":"application/json"},body:JSON.stringify({id:e})})}listQueue(e={}){let t=new URLSearchParams(Object.entries(e).filter(([,r])=>r!==void 0).map(([r,n])=>[r,String(n)]));return this.request(`/api/v1/queue?${t}`)}operationLogs(e,t={}){let r=new URLSearchParams(Object.entries(t).filter(([,n])=>n!==void 0).map(([n,i])=>[n,String(i)]));return this.request(`/api/v1/operations/${encodeURIComponent(e)}/logs?${r}`)}streamOperationLogs(e,t=0){return this.fetchFn(`${this.baseUrl}/api/v1/operations/${encodeURIComponent(e)}/logs/stream`,{headers:{accept:"text/event-stream",authorization:`Bearer ${this.options.token}`,"last-event-id":String(t)}})}cancelOperation(e){return this.request(`/api/v1/operations/${encodeURIComponent(e)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"})}retryOperation(e,t,r=0){return this.request(`/api/v1/operations/${encodeURIComponent(e)}/retry`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({errorClass:t,delayMs:r})})}queueSettings(){return this.request("/api/v1/queue/settings")}updateQueueSettings(e){return this.request("/api/v1/queue/settings",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({confirm:"update queue limits",concurrency:e})})}listPreviews(e){return this.request(`/api/v1/previews${e?`?projectId=${encodeURIComponent(e)}`:""}`)}listPreviewDefinitions(e){return this.request(`/api/v1/preview-definitions?projectId=${encodeURIComponent(e)}`)}createPreviewDefinition(e){return this.request("/api/v1/preview-definitions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}createPreview(e){return this.request("/api/v1/previews",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}destroyPreview(e,t){return this.request(`/api/v1/previews/${encodeURIComponent(e)}/destroy`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({confirm:t})})}extendPreview(e,t){return this.request(`/api/v1/previews/${encodeURIComponent(e)}/extend`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({hours:t})})}rebuildPreview(e){return this.request(`/api/v1/previews/${encodeURIComponent(e)}/rebuild`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"})}usage(e={}){let t=new URLSearchParams;for(let[r,n]of Object.entries(e))if(n)t.set(r,String(n));return this.request(`/api/v1/usage${t.size>0?`?${t}`:""}`)}usageRollups(e){let t=new URLSearchParams({from:e.from,to:e.to});if(e.projectId)t.set("projectId",e.projectId);if(e.environmentId)t.set("environmentId",e.environmentId);if(e.limit)t.set("limit",String(e.limit));for(let r of e.meters??[])t.append("meter",r);return this.request(`/api/v1/usage/rollups?${t}`)}allowance(e="deploy",t={}){let r=new URLSearchParams({operation:e});if(t.projectId)r.set("projectId",t.projectId);if(t.environmentId)r.set("environmentId",t.environmentId);return this.request(`/api/v1/spend/allowance?${r}`)}budgets(e={}){let t=new URLSearchParams;for(let[r,n]of Object.entries(e))if(n)t.set(r,String(n));return this.request(`/api/v1/spend/budgets${t.size>0?`?${t}`:""}`)}anomalies(e={}){let t=new URLSearchParams;if(e.projectId)t.set("projectId",e.projectId);if(e.since)t.set("since",e.since);if(e.unacknowledged)t.set("unacknowledged","true");return this.request(`/api/v1/spend/anomalies${t.size>0?`?${t}`:""}`)}}import{createHash as Yw}from"node:crypto";import{lstatSync as sw,readdirSync as aw,readFileSync as cw}from"node:fs";import{relative as dw,resolve as nm,sep as lw}from"node:path";function uw(e){return new Map(e.map((t)=>[t.path.replace(/^\.\//,"").replace(/\\/g,"/"),t]))}function Tn(e,t,r){return{path:e,reason:t,weight:r}}function im(e){try{return e?.content?JSON.parse(e.content):{}}catch{return{}}}function gi(e,t,r,n,i,o){return{framework:e,strategy:t,confidence:r,evidence:n,defaults:{build:i,runtime:{target:t==="static"?"serverless":t==="serverless"?"serverless":t==="dockerfile"||t==="prebuilt_image"?"container":"server",architecture:"x86_64",port:t==="static"||t==="serverless"?void 0:3000,healthCheck:t==="static"?void 0:{protocol:"http",path:"/health"}}},description:o}}function fi(e){let t=uw(e.slice(0,1e4)),r=[];if(t.has("Dockerfile"))r.push(gi("dockerfile","dockerfile",0.99,[Tn("Dockerfile","A root Dockerfile defines an explicit reproducible build.",1)],{kind:"dockerfile",context:".",dockerfile:"Dockerfile"},"Build the repository with its Dockerfile and run the resulting OCI image."));let n=im(t.get("composer.json"));if(t.has("artisan")&&n.require?.["laravel/framework"])r.push(gi("laravel","server",0.98,[Tn("artisan","Laravel Artisan entrypoint is present.",0.45),Tn("composer.json","Requires laravel/framework.",0.55)],{kind:"server",runtime:"php",runtimeVersion:"8.3",installCommand:"composer install --no-dev --prefer-dist --optimize-autoloader",buildCommand:"php artisan config:cache && php artisan route:cache && php artisan view:cache",startCommand:"php artisan serve --host=0.0.0.0 --port=$PORT"},"Install a production Composer tree, warm Laravel caches, and run the HTTP application."));else if(t.has("composer.json"))r.push(gi("php","server",0.82,[Tn("composer.json","Composer metadata identifies a PHP application.",0.8)],{kind:"server",runtime:"php",runtimeVersion:"8.3",installCommand:"composer install --no-dev --prefer-dist --optimize-autoloader",startCommand:"php -S 0.0.0.0:$PORT -t public"},"Install Composer dependencies and run the configured PHP document root."));let i=im(t.get("package.json"));if(t.has("package.json")){let o=t.has("bun.lock")||t.has("bun.lockb")||i.engines?.bun,s=o?"bun":"node",c=o?"bun":"node",d=[Tn("package.json",`Defines ${i.scripts?.build?"build and ":""}${i.scripts?.start?"start ":""}scripts.`,0.55)];if(o)d.push(Tn(t.has("bun.lock")?"bun.lock":t.has("bun.lockb")?"bun.lockb":"package.json","Pins the Bun package manager/runtime.",0.35));let a=!!(i.dependencies?.vite||i.devDependencies?.vite||i.dependencies?.["@stacksjs/bunpress"]||i.devDependencies?.["@stacksjs/bunpress"])&&!i.scripts?.start,u=a?{kind:"static",installCommand:`${s} install --frozen-lockfile`,buildCommand:`${s} run build`,publishDirectory:"dist"}:{kind:"server",runtime:s,installCommand:`${s} install --frozen-lockfile`,buildCommand:i.scripts?.build?`${s} run build`:void 0,startCommand:i.scripts?.start?`${s} run start`:s==="bun"?"bun run index.ts":"node index.js"};r.push(gi(c,u.kind,Math.min(0.94,d.reduce((m,h)=>m+h.weight,0)),d,u,a?"Install dependencies, build static assets, and publish the output directory.":`Install dependencies, build if configured, and start the ${s} server.`))}if(!r.length&&(t.has("index.html")||t.has("public/index.html")))r.push(gi("static","static",0.78,[Tn(t.has("index.html")?"index.html":"public/index.html","A static HTML entrypoint is present.",0.78)],{kind:"static",publishDirectory:t.has("index.html")?".":"public"},"Publish the static directory without a runtime process."));if(!r.length)r.push(gi("unknown","buildpack",0.2,[],{kind:"buildpack",runtime:"node"},"No supported framework signature was conclusive; choose commands and runtime manually."));return r.sort((o,s)=>s.confidence-o.confidence||o.framework.localeCompare(s.framework))}function wc(e,t={}){let r=nm(e),n=t.maxFiles??1e4,i=t.maxContentBytes??262144,o=[],s=new Set(["Dockerfile","package.json","composer.json","index.html","public/index.html","bun.lock","bun.lockb","artisan"]),c=new Set([".git",".ts-cloud",".cache",".next",".nuxt",".output",".turbo",".bun","node_modules","vendor","pantry","dist","build","coverage"]),d=(a)=>{for(let u of aw(a).sort()){if(c.has(u))continue;let m=nm(a,u),h=dw(r,m).split(lw).join("/");if(!h||h.startsWith("../"))throw Error("Detection path escaped the application root");let y=sw(m);if(y.isSymbolicLink())throw Error(`Detection refuses symbolic links: ${h}`);if(y.isDirectory())d(m);else if(y.isFile()){if(o.length>=n)throw Error("Application file-count limit exceeded");let w={path:h,size:y.size};if(s.has(h)&&y.size<=i)w.content=cw(m,"utf8");o.push(w)}}};return d(r),o}function Ic(e){if(Array.isArray(e))return`[${e.map(Ic).join(",")}]`;if(e&&typeof e==="object")return`{${Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>`${JSON.stringify(t)}:${Ic(r)}`).join(",")}}`;return JSON.stringify(e)??"null"}function oo(e){return!!e&&!e.startsWith("/")&&!e.split("/").includes("..")&&!/[\0\r\n]/.test(e)}function Dt(e,t,r,n){return{path:e,code:t,message:r,alternatives:n}}function kc(e){return JSON.parse(JSON.stringify(e))}function pw(e){let t=Object.fromEntries(Object.entries(e.environment??{}).map(([r,n])=>[r,typeof n==="string"?n:`\${${n.secretRef}}`]));if(e.build.kind==="prebuilt_image"||e.build.kind==="dockerfile")return kc({infrastructure:{containers:{[e.slug]:{source:e.source,build:e.build,port:e.runtime.port,cpu:e.runtime.cpu,memory:e.runtime.memoryMb,architecture:e.runtime.architecture,healthCheck:e.runtime.healthCheck,environment:t}}}});if(e.runtime.target==="serverless"||e.build.kind==="serverless")return kc({serverless:{apps:{[e.slug]:{source:e.source,build:e.build,architecture:e.runtime.architecture,environment:t,domain:e.domain}}}});return kc({sites:{[e.slug]:{source:e.source,build:e.build,port:e.runtime.port,architecture:e.runtime.architecture,healthCheck:e.runtime.healthCheck,env:t,domain:e.domain?.hostname}}})}function Zt(e,t=[]){let r=[],n=(w)=>/(?:secret|token|password|passwd|private[_-]?key|api[_-]?key)/i.test(w),i=Object.fromEntries(Object.entries(e.environment??{}).map(([w,k])=>{if(typeof k==="string"&&n(w))return r.push(Dt(`environment.${w}`,"write_only_secret_required",`${w} must be supplied through the write-only secrets boundary.`)),[w,{secretRef:w}];return[w,k]})),o=e.build;if(e.build.kind==="dockerfile"&&e.build.buildArgs){let w=Object.fromEntries(Object.entries(e.build.buildArgs).map(([k,C])=>{if(n(k))return r.push(Dt(`build.buildArgs.${k}`,"write_only_build_secret_required",`${k} must be declared in secretNames instead of buildArgs.`)),[k,"[REDACTED]"];return[k,C]}));o={...e.build,buildArgs:w}}if(!/^[a-z0-9][a-z0-9-]{1,62}$/.test(e.slug))r.push(Dt("slug","invalid_slug","Slug must contain 2-63 lowercase letters, numbers, or hyphens."));if(!oo((e.source.kind==="git"?e.source.monorepoRoot:e.source.kind==="local"?e.source.root:".")??"."))r.push(Dt("source","unsafe_source_root","Source root must stay inside the source tree."));if(e.source.kind==="git"&&e.source.sparsePaths?.some((w)=>!oo(w)))r.push(Dt("source.sparsePaths","unsafe_sparse_path","Sparse checkout paths must stay inside the repository."));if(e.build.kind==="dockerfile"&&(!oo(e.build.context)||!oo(e.build.dockerfile)))r.push(Dt("build","unsafe_docker_path","Docker context and Dockerfile must stay inside the source tree."));if(e.build.kind==="static"&&!oo(e.build.publishDirectory))r.push(Dt("build.publishDirectory","invalid_publish_directory","A safe static publish directory is required."));if(e.build.kind==="server"&&!e.build.startCommand.trim())r.push(Dt("build.startCommand","missing_start_command","A server start command is required.",["Use static output","Use a Dockerfile"]));if(e.source.kind==="image"&&e.build.kind!=="prebuilt_image")r.push(Dt("build.kind","image_requires_prebuilt","An OCI image source must use the prebuilt-image strategy.",["Select prebuilt image"]));if(e.build.kind==="prebuilt_image"&&e.runtime.target!=="container")r.push(Dt("runtime.target","image_requires_container","Prebuilt images require the container runtime target.",["Select container target"]));if(e.runtime.target==="serverless"&&e.build.kind==="dockerfile")r.push(Dt("runtime.target","unsupported_serverless_dockerfile","Dockerfile builds currently target the container service path.",["Select container target","Select serverless package"]));if(e.runtime.port!==void 0&&(!Number.isInteger(e.runtime.port)||e.runtime.port<1||e.runtime.port>65535))r.push(Dt("runtime.port","invalid_port","Port must be an integer from 1 to 65535."));let s=e.runtime.healthCheck;if(s&&s.protocol!=="tcp"&&(!s.path||!s.path.startsWith("/")||/[\r\n]/.test(s.path)))r.push(Dt("runtime.healthCheck.path","invalid_health_path","HTTP health checks require a path beginning with /."));if(e.domain?.hostname&&(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i.test(e.domain.hostname)||e.domain.hostname.includes("..")))r.push(Dt("domain.hostname","invalid_domain","Domain must be a valid DNS hostname."));let c=Object.values(i).flatMap((w)=>typeof w==="object"?[w.secretRef]:[]),d=[...new Set([...e.requiredSecretNames??[],...e.build.kind==="dockerfile"?e.build.secretNames??[]:[],...c])].sort(),a=new Set(t),u=d.filter((w)=>!a.has(w)),m={apiVersion:"ts-cloud.dev/v1",kind:"Application",metadata:{name:e.name,slug:e.slug,projectId:e.projectId,environmentId:e.environmentId},spec:{source:e.source,build:o,runtime:e.runtime,environment:i,domain:e.domain}},h=[...new Set([e.source.kind==="git"?"git:read":e.source.kind==="image"?"registry:pull":e.source.kind==="artifact"?"artifact:inspect":"filesystem:read",e.runtime.target==="container"?"containers":e.runtime.target==="serverless"?"serverless":"servers",e.domain?"dns":""])].filter(Boolean).sort(),y=[...new Set([e.runtime.target,e.runtime.cpu?`${e.runtime.cpu} vCPU`:"",e.runtime.memoryMb?`${e.runtime.memoryMb} MB memory`:"",(e.runtime.minInstances??0)>0?`${e.runtime.minInstances} minimum instances`:"scales from zero where supported",e.domain?"managed DNS/TLS":""])].filter(Boolean);return{valid:r.length===0&&u.length===0,issues:r,missingSecrets:u,manifest:m,configPatch:pw({...e,build:o,environment:i}),capabilityRequirements:h,costDrivers:y,serializedManifest:`${Ic(m)}
17
17
  `}}function om(e){let t=e.replace(/\\/g,"/");return!!t&&!t.startsWith("/")&&!/^[A-Za-z]:\//.test(t)&&!t.split("/").includes("..")&&!/[\0\r\n]/.test(t)}function sm(e,t,r={}){let n=r.maxBytes??104857600,i=r.maxEntries??1e4,o=r.maxExpandedBytes??524288000;if(e.byteLength>n)throw Error("Archive exceeds the compressed size limit");let s=new DataView(e.buffer,e.byteOffset,e.byteLength),c=[],d=0;if(t.toLowerCase().endsWith(".zip")||e[0]===80&&e[1]===75){let u=0;while(u+30<=e.length){let m=s.getUint32(u,!0);if(m===33639248||m===101010256)break;if(m!==67324752)throw Error("Malformed ZIP local header");let h=s.getUint16(u+6,!0),y=s.getUint32(u+18,!0),w=s.getUint32(u+22,!0),k=s.getUint16(u+26,!0),C=s.getUint16(u+28,!0);if(h&8)throw Error("ZIP data descriptors are not accepted for uploaded artifacts");let T=new TextDecoder().decode(e.subarray(u+30,u+30+k));if(!om(T))throw Error(`Unsafe archive path: ${T}`);if(c.push(T),d+=w,c.length>i||d>o)throw Error("Archive expansion limit exceeded");u+=30+k+C+y}return{format:"zip",entries:c.length,expandedBytes:d,paths:c}}if(!t.toLowerCase().match(/\.(?:tar|tar\.gz|tgz)$/))throw Error("Only ZIP and uncompressed TAR artifacts are supported");let a=0;while(a+512<=e.length){let u=e.subarray(a,a+512);if(u.every((k)=>k===0))break;let m=(k,C)=>new TextDecoder().decode(u.subarray(k,k+C)).replace(/\0.*$/,""),h=`${m(345,155)}${m(345,155)?"/":""}${m(0,100)}`,y=Number.parseInt(m(124,12).trim()||"0",8),w=String.fromCharCode(u[156]??0);if(!om(h))throw Error(`Unsafe archive path: ${h}`);if(w==="1"||w==="2")throw Error(`Archive links are not accepted: ${h}`);if(!Number.isFinite(y)||y<0)throw Error("Malformed TAR entry size");if(c.push(h),d+=y,c.length>i||d>o)throw Error("Archive expansion limit exceeded");a+=512+Math.ceil(y/512)*512}return{format:"tar",entries:c.length,expandedBytes:d,paths:c}}var am=new Set(["source","build","runtime","environment","domain","review"]);function cm(e,t){try{return typeof e==="string"?JSON.parse(e):t}catch{return t}}function dm(e){return/(?:secret|token|password|passwd|private[_-]?key|api[_-]?key)/i.test(e)}function lm(e){for(let[r,n]of Object.entries(e.environment??{}))if(typeof n==="string"&&dm(r)&&n)throw Error(`${r} must be stored through the write-only secrets boundary`);if(e.build.kind==="dockerfile"){for(let[r,n]of Object.entries(e.build.buildArgs??{}))if(dm(r)&&n)throw Error(`${r} must be declared as a build secret name`)}let t=JSON.stringify(e);if(/https?:\/\/[^/@\s]+:[^/@\s]+@/i.test(t))throw Error("Drafts cannot contain credential-bearing URLs")}function um(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:String(e.project_id),schemaVersion:Number(e.schema_version),name:String(e.name),step:String(e.step),input:cm(e.input,{}),suppliedSecretNames:cm(e.supplied_secret_names,[]),status:String(e.status),version:Number(e.version),createdByActorId:e.created_by_actor_id?String(e.created_by_actor_id):void 0,createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}class Ec{controlPlane;nowFn;idFn;constructor(e,t={}){this.controlPlane=e;this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID())}now(){return this.nowFn().toISOString()}create(e){if(lm(e.draft),e.draft.projectId!==e.projectId)throw Error("Draft project does not match its storage scope");let t=this.controlPlane.getProject(e.projectId);if(!t||t.organizationId!==e.organizationId)throw Error("Draft project was not found");let r=this.idFn(),n=this.now(),i=e.step??"source";if(!am.has(i))throw Error("Invalid draft step");let o=[...new Set(e.suppliedSecretNames??[])].sort(),s=Zt(e.draft,o).valid?"ready":"draft";return this.controlPlane.database.run("INSERT INTO application_drafts (id, organization_id, project_id, schema_version, name, step, input, supplied_secret_names, status, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?)",[r,e.organizationId,e.projectId,e.name.trim().slice(0,100),i,JSON.stringify(e.draft),JSON.stringify(o),s,e.actorId??null,n,n]),this.controlPlane.appendEvent({organizationId:e.organizationId,projectId:e.projectId,actorId:e.actorId,type:"application.draft.created",payload:{draftId:r,step:i,status:s,requiredSecretNames:e.draft.requiredSecretNames??[]}}),this.get(r)}get(e){let t=this.controlPlane.database.query("SELECT * FROM application_drafts WHERE id=?").get(e);return t?um(t):void 0}list(e){return this.controlPlane.database.query("SELECT * FROM application_drafts WHERE project_id=? ORDER BY updated_at DESC").all(e).map(um)}update(e,t,r){let n=this.get(e);if(!n||n.version!==t)throw Error(`Application draft ${e} changed since version ${t}`);if(!am.has(r.step))throw Error("Invalid draft step");if(r.draft.projectId!==n.projectId)throw Error("Draft project cannot be changed");lm(r.draft);let i=[...new Set(r.suppliedSecretNames??n.suppliedSecretNames)].sort(),o=Zt(r.draft,i).valid?"ready":"draft",s=this.now();if(this.controlPlane.database.run("UPDATE application_drafts SET name=?, step=?, input=?, supplied_secret_names=?, status=?, version=version+1, updated_at=? WHERE id=? AND version=?",[r.draft.name.slice(0,100),r.step,JSON.stringify(r.draft),JSON.stringify(i),o,s,e,t]).changes!==1)throw Error(`Application draft ${e} changed since version ${t}`);return this.controlPlane.appendEvent({organizationId:n.organizationId,projectId:n.projectId,actorId:r.actorId,type:"application.draft.updated",payload:{draftId:e,fromVersion:t,toVersion:t+1,step:r.step,status:o}}),this.get(e)}markApplied(e,t,r){let n=this.get(e);if(!n||n.version!==t)throw Error(`Application draft ${e} changed since version ${t}`);let i=Zt(n.input,n.suppliedSecretNames);if(!i.valid)throw Error(`Draft is not deployable: ${[...i.issues.map((s)=>s.message),...i.missingSecrets.map((s)=>`Missing secret ${s}`)].join("; ")}`);let o=this.now();return this.controlPlane.database.run("UPDATE application_drafts SET status='applied', step='review', version=version+1, updated_at=? WHERE id=? AND version=?",[o,e,t]),this.controlPlane.appendEvent({organizationId:n.organizationId,projectId:n.projectId,actorId:r,type:"application.draft.applied",payload:Oe({draftId:e,manifest:i.manifest})}),this.get(e)}}import{createCipheriv as mw,createDecipheriv as gw,createHash as gm,randomBytes as fw}from"node:crypto";function so(e){return typeof e==="string"&&e?e:void 0}function Rc(e){return gm("sha256").update(e).digest("hex").slice(0,16)}function pm(e){let t=new URL(e.includes("://")?e:`https://${e}`);if(t.protocol!=="https:"&&!["localhost","127.0.0.1","::1"].includes(t.hostname))throw Error("Registry host must use HTTPS");if(t.username||t.password||t.search||t.hash)throw Error("Registry host cannot contain credentials");return`${t.protocol}//${t.host}`}function hw(e){return{id:String(e.id),organizationId:String(e.organization_id),provider:String(e.provider),name:String(e.name),host:String(e.host),credentialConfigured:!!e.credential_ciphertext,credentialFingerprint:so(e.credential_fingerprint),credentialExpiresAt:so(e.credential_expires_at),status:String(e.status),healthMessage:so(e.health_message),lastTestedAt:so(e.last_tested_at),version:Number(e.version),createdByActorId:so(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}class Ac{controlPlane;key;nowFn;idFn;constructor(e,t){this.controlPlane=e;if(!t.encryptionKey)throw Error("Registry encryption key is required");this.key=gm("sha256").update(`ts-cloud:registry:${t.encryptionKey}`).digest(),this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID())}now(){return this.nowFn().toISOString()}encrypt(e){let t=fw(12),r=mw("aes-256-gcm",this.key,t),n=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${n.toString("base64url")}`}decrypt(e){let[t,r,n,i]=e.split(".");if(t!=="v1"||!r||!n||!i)throw Error("Registry credential envelope is invalid");let o=gw("aes-256-gcm",this.key,Buffer.from(r,"base64url"));return o.setAuthTag(Buffer.from(n,"base64url")),Buffer.concat([o.update(Buffer.from(i,"base64url")),o.final()]).toString("utf8")}current(e){let t=hw(e);return t.status!=="disconnected"&&t.credentialExpiresAt&&new Date(t.credentialExpiresAt).getTime()<=this.nowFn().getTime()?{...t,status:"expired",healthMessage:"Registry credential expired; rotate it before pulling images."}:t}create(e){if(!["docker_hub","ghcr","ecr","gcr","generic"].includes(e.provider))throw Error("A supported registry provider is required");let t=e.credential?JSON.stringify(e.credential):void 0,r=this.idFn(),n=this.now();return this.controlPlane.database.run("INSERT INTO registry_connections (id, organization_id, provider, name, host, credential_ciphertext, credential_fingerprint, credential_expires_at, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[r,e.organizationId,e.provider,e.name.trim().slice(0,80),pm(e.host),t?this.encrypt(t):null,t?Rc(t):null,e.credentialExpiresAt??null,e.actorId??null,n,n]),this.controlPlane.appendEvent({organizationId:e.organizationId,actorId:e.actorId,type:"registry.connection.created",payload:{connectionId:r,provider:e.provider,host:pm(e.host),credentialConfigured:!!t}}),this.get(r)}get(e){let t=this.controlPlane.database.query("SELECT * FROM registry_connections WHERE id=?").get(e);return t?this.current(t):void 0}list(e){return this.controlPlane.database.query("SELECT * FROM registry_connections WHERE organization_id=? ORDER BY name").all(e).map((t)=>this.current(t))}credential(e){let t=this.controlPlane.database.query("SELECT credential_ciphertext FROM registry_connections WHERE id=?").get(e);return t?.credential_ciphertext?JSON.parse(this.decrypt(String(t.credential_ciphertext))):void 0}rotate(e,t,r={}){let n=this.get(e);if(!n||n.status==="disconnected")throw Error("Registry connection was not found");let i=JSON.stringify(t);return this.controlPlane.database.run("UPDATE registry_connections SET credential_ciphertext=?, credential_fingerprint=?, credential_expires_at=?, status='pending', health_message=NULL, version=version+1, updated_at=? WHERE id=?",[this.encrypt(i),Rc(i),r.expiresAt??null,this.now(),e]),this.controlPlane.appendEvent({organizationId:n.organizationId,actorId:r.actorId,type:"registry.credential.rotated",payload:{connectionId:e,fingerprint:Rc(i),expiresAt:r.expiresAt??null}}),this.get(e)}disconnect(e,t){let r=this.get(e);if(!r)throw Error("Registry connection was not found");return this.controlPlane.database.run("UPDATE registry_connections SET credential_ciphertext=NULL, credential_fingerprint=NULL, status='disconnected', health_message='Disconnected by an administrator', version=version+1, updated_at=? WHERE id=?",[this.now(),e]),this.controlPlane.appendEvent({organizationId:r.organizationId,actorId:t,type:"registry.connection.disconnected",level:"warning",payload:{connectionId:e}}),this.get(e)}async test(e,t={}){let r=this.get(e);if(!r||["disconnected","expired"].includes(r.status))throw Error("Active registry connection was not found");let n=this.credential(e),i=t.fetch??fetch,o=new AbortController,s=setTimeout(()=>o.abort(),t.timeoutMs??15000),c=n?.token?`Bearer ${n.token}`:n?.username||n?.password?`Basic ${Buffer.from(`${n.username??""}:${n.password??""}`).toString("base64")}`:void 0;try{let d=await i(`${r.host}/v2/`,{method:"GET",redirect:"error",signal:o.signal,headers:c?{Authorization:c}:void 0}),a=d.headers.get("www-authenticate")??"";if(d.status===401&&a.startsWith("Bearer ")&&n){let h=Object.fromEntries([...a.slice(7).matchAll(/(\w+)="([^"]+)"/g)].map((T)=>[T[1],T[2]])),y=new URL(h.realm??"");if(y.protocol!=="https:")throw Error("Registry authentication realm must use HTTPS");if(h.service)y.searchParams.set("service",h.service);if(t.image)y.searchParams.set("scope",`repository:${fm(t.image).repository}:pull`);let w=await i(y,{signal:o.signal,redirect:"error",headers:c?{Authorization:c}:void 0});if(!w.ok)throw Error(`Registry authentication failed (${w.status})`);let k=await w.json(),C=k.token??k.access_token;if(!C)throw Error("Registry did not return an access token");d=t.image?await mm(i,r.host,t.image,C,o.signal):await i(`${r.host}/v2/`,{signal:o.signal,redirect:"error",headers:{Authorization:`Bearer ${C}`}})}else if(d.ok&&t.image)d=await mm(i,r.host,t.image,n?.token,o.signal,c);let u=d.ok?"healthy":"degraded",m=d.ok?t.image?"Registry image is readable.":"Registry connection is healthy.":`Registry request failed (${d.status})`;return this.controlPlane.database.run("UPDATE registry_connections SET status=?, health_message=?, last_tested_at=?, version=version+1, updated_at=? WHERE id=?",[u,m,this.now(),this.now(),e]),this.get(e)}catch(d){let a=o.signal.aborted?"Registry request timed out.":d instanceof Error?d.message:"Registry test failed";return this.controlPlane.database.run("UPDATE registry_connections SET status='degraded', health_message=?, last_tested_at=?, version=version+1, updated_at=? WHERE id=?",[a.slice(0,1000),this.now(),this.now(),e]),this.get(e)}finally{clearTimeout(s)}}}function fm(e){let t=e.replace(/^https?:\/\//,""),r=t.indexOf("/");if(r<1)throw Error("Image must include registry/repository");let n=t.slice(r+1),i=n.lastIndexOf("@"),o=n.lastIndexOf(":"),s=i>=0?i:o>n.lastIndexOf("/")?o:-1,c=s>=0?n.slice(0,s):n,d=s>=0?n.slice(s+1):"latest";if(!/^[A-Za-z0-9_.\/-]+$/.test(c)||!/^[A-Za-z0-9_.:+-]+$/.test(d))throw Error("Image reference is invalid");return{repository:c,reference:d}}async function mm(e,t,r,n,i,o){let s=fm(r);return e(`${t}/v2/${s.repository}/manifests/${encodeURIComponent(s.reference)}`,{method:"HEAD",redirect:"error",signal:i,headers:{Accept:"application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json",...n?{Authorization:`Bearer ${n}`}:o?{Authorization:o}:{}}})}import{createHash as yw}from"node:crypto";import{chmodSync as hm,existsSync as ym,mkdirSync as vw,renameSync as bw,unlinkSync as vm,writeFileSync as Sw}from"node:fs";import{basename as ww,join as kw}from"node:path";function Cc(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:String(e.project_id),filename:String(e.filename),sha256:String(e.sha256),size:Number(e.size),format:String(e.format),entryCount:Number(e.entry_count),expandedBytes:Number(e.expanded_bytes),createdByActorId:e.created_by_actor_id?String(e.created_by_actor_id):void 0,createdAt:String(e.created_at)}}class Pc{controlPlane;root;idFn;nowFn;constructor(e,t){this.controlPlane=e;this.root=yt(t.cwd,"artifacts"),this.idFn=t.id??(()=>crypto.randomUUID()),this.nowFn=t.now??(()=>new Date)}create(e){let t=this.controlPlane.getProject(e.projectId);if(!t||t.organizationId!==e.organizationId)throw Error("Artifact project was not found");let r=ww(e.filename).slice(0,200);if(!r||r!==e.filename)throw Error("Artifact filename must not contain a path");let n=sm(e.bytes,r),i=yw("sha256").update(e.bytes).digest("hex"),o=this.controlPlane.database.query("SELECT * FROM application_artifacts WHERE project_id=? AND sha256=?").get(e.projectId,i);if(o)return Cc(o);let s=this.idFn();vw(this.root,{recursive:!0,mode:448}),hm(this.root,448);let c=kw(this.root,`${s}.archive`),d=`${c}.partial`;try{Sw(d,e.bytes,{mode:384,flag:"wx"}),bw(d,c),hm(c,384),this.controlPlane.database.run("INSERT INTO application_artifacts (id, organization_id, project_id, filename, storage_path, sha256, size, format, entry_count, expanded_bytes, created_by_actor_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[s,e.organizationId,e.projectId,r,c,i,e.bytes.byteLength,n.format,n.entries,n.expandedBytes,e.actorId??null,this.nowFn().toISOString()])}catch(a){if(ym(d))vm(d);if(ym(c))vm(c);throw a}return this.controlPlane.appendEvent({organizationId:e.organizationId,projectId:e.projectId,actorId:e.actorId,type:"application.artifact.created",payload:{artifactId:s,filename:r,sha256:i,size:e.bytes.byteLength,entries:n.entries}}),this.get(s)}get(e){let t=this.controlPlane.database.query("SELECT * FROM application_artifacts WHERE id=?").get(e);return t?Cc(t):void 0}list(e){return this.controlPlane.database.query("SELECT * FROM application_artifacts WHERE project_id=? ORDER BY created_at DESC").all(e).map(Cc)}}function cs(e){let t=e.drafts.get(e.draftId);if(!t||t.version!==e.expectedVersion)throw Error(`Application draft ${e.draftId} changed since version ${e.expectedVersion}`);if(t.status==="applied")throw Error("Application draft was already applied");let r=e.controlPlane.getProject(t.projectId),n=r?e.controlPlane.listEnvironments(r.id).find((a)=>a.id===t.input.environmentId):void 0;if(!r||!n||n.projectId!==r.id||r.organizationId!==t.organizationId)throw Error("Draft deployment scope was not found");if(e.confirmEnvironment!==n.slug)throw Error(`Type ${n.slug} to confirm this deployment target`);let i=Zt(t.input,t.suppliedSecretNames);if(!i.valid)throw Error(`Application plan is invalid: ${[...i.issues.map((a)=>a.message),...i.missingSecrets.map((a)=>`Missing secret ${a}`)].join("; ")}`);let o=e.controlPlane.listResources(r.id,n.id).find((a)=>a.kind==="application"&&a.slug===t.input.slug),s=JSON.parse(JSON.stringify({manifest:i.manifest,configPatch:i.configPatch})),c=o?e.controlPlane.updateResource(o.id,o.version,{name:t.input.name,desiredState:s}):e.controlPlane.createResource({projectId:r.id,environmentId:n.id,kind:"application",slug:t.input.slug,name:t.input.name,desiredState:s,metadata:{source:"application-onboarding",draftId:t.id}}),d=new $e(e.controlPlane).enqueue({projectId:r.id,environmentId:n.id,resourceId:c.id,actorId:e.actorId,kind:"application.create",idempotencyKey:`application-draft:${t.id}:v${t.version}`,correlationId:`application-draft:${t.id}`,input:s,lockKey:`resource:${c.id}`,providerKey:c.provider??"default",buildSlot:t.input.build.kind!=="prebuilt_image",maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return e.drafts.markApplied(t.id,t.version,e.actorId),e.controlPlane.appendEvent({organizationId:t.organizationId,projectId:r.id,resourceId:c.id,operationId:d.id,actorId:e.actorId,type:"application.create.queued",payload:{draftId:t.id,environment:n.slug,strategy:t.input.build.kind,costDrivers:i.costDrivers}}),{plan:i,resource:c,operation:d}}function ao(e){let t=["static","compute","serverless_zip","serverless_image"].includes(e.kind),r=["container","compose"].includes(e.kind)&&(e.replicas??1)>1,n=e.kind==="container"||e.kind==="serverless_zip"||e.kind==="serverless_image",i=(o,s)=>s&&(o==="atomic"?e.kind==="static"||e.hasHealthGate:e.hasHealthGate);return[{strategy:"atomic",supported:i("atomic",t),explanation:t?e.hasHealthGate||e.kind==="static"?"Activate an immutable version with an atomic pointer/alias switch.":"Atomic activation needs a readiness gate for this runtime.":"This driver has no atomic pointer or alias primitive.",capacityMultiplier:1,costImpact:"none",rollback:"Switch the pointer/alias back to the previous immutable release."},{strategy:"rolling",supported:i("rolling",r),explanation:r?e.hasHealthGate?"Replace healthy replicas within the configured capacity envelope.":"Rolling activation requires a health/readiness gate.":"Rolling activation requires a capable container/Compose driver and at least two replicas.",capacityMultiplier:1.5,costImpact:"temporary",rollback:"Stop replacement and restore the prior task/service definition."},{strategy:"blue_green",supported:i("blue_green",n),explanation:n?e.hasHealthGate?"Provision a complete green target and switch traffic after health passes.":"Blue-green requires a health gate before traffic can switch.":"The provider does not expose two traffic-addressable revisions.",capacityMultiplier:2,costImpact:"temporary",rollback:"Return all traffic to the preserved blue target."},{strategy:"canary",supported:i("canary",n),explanation:n?e.hasHealthGate?"Shift bounded traffic steps while evaluating health.":"Canary requires a health gate and measurable traffic target.":"The provider does not expose weighted traffic primitives.",capacityMultiplier:1.25,costImpact:"temporary",rollback:"Set canary weight to zero and preserve its diagnostics."}]}function ds(e,t){let r=ao(e).find((n)=>n.strategy===t);if(!r.supported)throw Error(`${t} is unavailable: ${r.explanation}`);return r}import{createHash as Iw}from"node:crypto";var Ew=/^sha256:[a-f0-9]{64}$/,Rw=/^[a-f0-9]{40,64}$/i;function pr(e){return typeof e==="string"&&e?e:void 0}function xn(e,t){try{return JSON.parse(String(e))}catch{return t}}function bm(e){return{id:String(e.id),organizationId:String(e.organization_id),digest:String(e.digest),kind:String(e.kind),uri:String(e.uri),size:Number(e.size),mediaType:String(e.media_type),provenance:xn(e.provenance,{}),attestation:xn(e.attestation,{}),verifiedAt:String(e.verified_at),createdAt:String(e.created_at)}}function Sm(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:String(e.project_id),environmentId:String(e.environment_id),resourceId:String(e.resource_id),artifactId:String(e.artifact_id),kind:String(e.kind),sourceSha:pr(e.source_sha),configHash:String(e.config_hash),manifest:xn(e.manifest,{}),provenance:xn(e.provenance,{}),strategy:String(e.strategy),status:String(e.status),healthGate:e.health_gate==null?void 0:xn(e.health_gate,void 0),hooks:xn(e.hooks,{migrations:"none",preActivate:[],postActivate:[]}),drainSeconds:Number(e.drain_seconds),graceSeconds:Number(e.grace_seconds),automaticRollback:Number(e.automatic_rollback)===1,rollbackAttempts:Number(e.rollback_attempts),previousReleaseId:pr(e.previous_release_id),promotedFromReleaseId:pr(e.promoted_from_release_id),actorId:pr(e.actor_id),trigger:String(e.trigger),pinned:Number(e.pinned)===1,pinReason:pr(e.pin_reason),activatedAt:pr(e.activated_at),failedAt:pr(e.failed_at),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Aw(e){return{sequence:Number(e.sequence),id:String(e.id),releaseId:String(e.release_id),fromStatus:pr(e.from_status),toStatus:String(e.to_status),trafficPercent:e.traffic_percent==null?void 0:Number(e.traffic_percent),health:xn(e.health,{}),message:String(e.message),operationId:pr(e.operation_id),createdAt:String(e.created_at)}}function Cw(e,t){let r=[],n=(i,o,s)=>{if(JSON.stringify(o)===JSON.stringify(s))return;if(o&&s&&typeof o==="object"&&typeof s==="object"&&!Array.isArray(o)&&!Array.isArray(s)){for(let c of[...new Set([...Object.keys(o),...Object.keys(s)])].sort())n(i?`${i}.${c}`:c,o[c],s[c]);return}r.push({path:i,...o!==void 0?{before:o}:{},...s!==void 0?{after:s}:{}})};return n("",e,t),r}class _c{controlPlane;now;id;constructor(e,t={}){this.controlPlane=e;this.now=t.now??(()=>new Date),this.id=t.id??(()=>crypto.randomUUID())}registerArtifact(e){if(!Ew.test(e.digest)||!/^(?:s3|https|oci|file):/.test(e.uri)||!Number.isInteger(e.size)||e.size<0)throw Error("Artifact requires a SHA-256 digest, supported immutable URI, and non-negative byte size");let t=this.controlPlane.database.query("SELECT * FROM release_artifacts WHERE organization_id=? AND digest=?").get(e.organizationId,e.digest);if(t)return bm(t);let r=this.id(),n=this.now().toISOString();return this.controlPlane.database.run("INSERT INTO release_artifacts (id, organization_id, digest, kind, uri, size, media_type, provenance, attestation, verified_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[r,e.organizationId,e.digest,e.kind,e.uri,e.size,e.mediaType??"application/octet-stream",JSON.stringify(Oe(e.provenance??{})),JSON.stringify(Oe(e.attestation??{})),n,n]),this.getArtifact(r)}getArtifact(e){let t=this.controlPlane.database.query("SELECT * FROM release_artifacts WHERE id=?").get(e);return t?bm(t):void 0}create(e){let t=this.getArtifact(e.artifactId),r=this.controlPlane.getResource(e.resourceId),n=this.controlPlane.listEnvironments(e.projectId).find((m)=>m.id===e.environmentId);if(!t||t.organizationId!==e.organizationId||t.kind!==e.kind)throw Error("Release artifact does not match the organization and deployable kind");if(!r||r.projectId!==e.projectId||r.environmentId!==e.environmentId||!n)throw Error("Release target scope does not match the resource");if(e.sourceSha&&!Rw.test(e.sourceSha))throw Error("Release source must be an immutable commit SHA");ds({kind:e.kind,provider:r.provider,hasHealthGate:!!e.healthGate,replicas:e.replicas},e.strategy);let i=Oe(e.config),o=Iw("sha256").update(JSON.stringify(i)).digest("hex"),s=this.active(e.resourceId),c=this.id(),d=this.now().toISOString(),a=e.approvalRequired?"awaiting_approval":"built",u=e.hooks??{migrations:"none",preActivate:[],postActivate:[]};return this.controlPlane.database.run("INSERT INTO releases (id, organization_id, project_id, environment_id, resource_id, artifact_id, kind, source_sha, config_hash, manifest, provenance, strategy, status, health_gate, hooks, drain_seconds, grace_seconds, automatic_rollback, previous_release_id, promoted_from_release_id, actor_id, trigger, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[c,e.organizationId,e.projectId,e.environmentId,e.resourceId,e.artifactId,e.kind,e.sourceSha??null,o,JSON.stringify(Oe(e.manifest)),JSON.stringify(Oe(e.provenance??{})),e.strategy,a,e.healthGate?JSON.stringify(e.healthGate):null,JSON.stringify(u),Math.max(0,Math.min(3600,Math.floor(e.drainSeconds??30))),Math.max(0,Math.min(3600,Math.floor(e.graceSeconds??30))),e.automaticRollback===!1?0:1,s?.id??null,e.promotedFromReleaseId??null,e.actorId??null,e.trigger??"manual",d,d]),this.recordTransition(c,void 0,a,{message:e.promotedFromReleaseId?"Immutable artifact promoted without rebuild.":"Immutable release record created."}),this.get(c)}get(e){let t=this.controlPlane.database.query("SELECT * FROM releases WHERE id=?").get(e);return t?Sm(t):void 0}list(e={}){return this.controlPlane.database.query("SELECT * FROM releases ORDER BY created_at DESC, rowid DESC").all().map(Sm).filter((t)=>(!e.projectId||t.projectId===e.projectId)&&(!e.environmentId||t.environmentId===e.environmentId)&&(!e.resourceId||t.resourceId===e.resourceId)&&(!e.status||t.status===e.status))}active(e){return this.list({resourceId:e,status:"active"})[0]}transitions(e){return this.controlPlane.database.query("SELECT * FROM release_transitions WHERE release_id=? ORDER BY sequence").all(e).map(Aw)}recordTransition(e,t,r,n){this.controlPlane.database.run("INSERT INTO release_transitions (id, release_id, from_status, to_status, traffic_percent, health, message, operation_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",[this.id(),e,t??null,r,n.trafficPercent??null,JSON.stringify(Oe(n.health??{})),n.message.slice(0,1000),n.operationId??null,this.now().toISOString()])}progress(e,t){let r=this.get(e);if(!r)throw Error(`Release ${e} was not found`);return this.recordTransition(e,r.status,r.status,t),this.transitions(e).at(-1)}transition(e,t,r){let n=this.get(e);if(!n)throw Error(`Release ${e} was not found`);if(!{built:["awaiting_approval","activating","failed"],awaiting_approval:["built","failed"],activating:["active","failed","rolled_back"],active:["superseded","failed","rolled_back"],failed:["activating","rolled_back"],rolled_back:["activating"],superseded:["activating"]}[n.status].includes(t))throw Error(`Invalid release transition ${n.status} → ${t}`);let o=this.now().toISOString();if(t==="active"){let s=this.active(n.resourceId);if(s&&s.id!==e)this.controlPlane.database.run("UPDATE releases SET status='superseded', updated_at=? WHERE id=?",[o,s.id]),this.recordTransition(s.id,"active","superseded",{message:`Superseded by ${e}.`,operationId:r.operationId})}return this.controlPlane.database.run("UPDATE releases SET status=?, rollback_attempts=rollback_attempts+?, activated_at=CASE WHEN ?='active' THEN ? ELSE activated_at END, failed_at=CASE WHEN ?='failed' THEN ? ELSE failed_at END, updated_at=? WHERE id=?",[t,t==="rolled_back"?1:0,t,o,t,o,o,e]),this.recordTransition(e,n.status,t,r),this.get(e)}approve(e,t){let r=this.get(e);if(!r||r.status!=="awaiting_approval")throw Error("Release is not awaiting approval");let n=this.id(),i=this.now().toISOString();return this.controlPlane.database.run("INSERT INTO release_approvals (id, release_id, environment_id, decision, actor_id, comment, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[n,e,r.environmentId,t.decision,t.actorId,t.comment?.slice(0,1000)??null,i]),this.transition(e,t.decision==="approved"?"built":"failed",{message:t.decision==="approved"?"Environment gate approved.":"Environment gate rejected."})}approvals(e){return this.controlPlane.database.query("SELECT * FROM release_approvals WHERE release_id=? ORDER BY created_at").all(e).map((t)=>({id:String(t.id),releaseId:String(t.release_id),environmentId:String(t.environment_id),decision:String(t.decision),actorId:String(t.actor_id),comment:pr(t.comment),createdAt:String(t.created_at)}))}promote(e,t){let r=this.get(e);if(!r||!["active","superseded"].includes(r.status))throw Error("Only a tested active/superseded release can be promoted");return this.create({organizationId:r.organizationId,projectId:r.projectId,environmentId:t.targetEnvironmentId,resourceId:t.targetResourceId,artifactId:r.artifactId,kind:r.kind,sourceSha:r.sourceSha,config:t.config,manifest:r.manifest,provenance:r.provenance,strategy:t.strategy??r.strategy,healthGate:t.healthGate??r.healthGate,hooks:r.hooks,drainSeconds:r.drainSeconds,graceSeconds:r.graceSeconds,automaticRollback:r.automaticRollback,promotedFromReleaseId:r.id,actorId:t.actorId,trigger:"promotion",approvalRequired:t.approvalRequired})}compare(e,t){let r=this.get(e),n=this.get(t);if(!r||!n)throw Error("Both releases are required for comparison");return{artifactChanged:r.artifactId!==n.artifactId,sourceChanged:r.sourceSha!==n.sourceSha,configChanged:r.configHash!==n.configHash,manifestChanges:Cw(r.manifest,n.manifest),dataCaveat:n.hooks.migrations==="none"?"No database migration is recorded.":`Database hooks are ${n.hooks.migrations}; release rollback does not roll back data.`}}pin(e,t,r){if(!this.get(e))throw Error("Release was not found");return this.controlPlane.database.run("UPDATE releases SET pinned=?, pin_reason=?, updated_at=? WHERE id=?",[t?1:0,t?r?.slice(0,500)??"operator":null,this.now().toISOString(),e]),this.get(e)}retentionCandidates(e){let t=Math.max(1,Math.min(100,Math.floor(e.keepPerResource??10))),r=new Map;for(let n of this.list()){let i=r.get(n.resourceId)??[];i.push(n),r.set(n.resourceId,i)}return[...r.values()].flatMap((n)=>n.slice(t)).filter((n)=>new Date(n.createdAt)<e.before&&!n.pinned&&!["active","activating","awaiting_approval"].includes(n.status)&&!this.list().some((i)=>i.previousReleaseId===n.id&&["active","activating"].includes(i.status)))}}class Dn{controlPlane;releases;queue;constructor(e){this.controlPlane=e;this.releases=new _c(e),this.queue=new $e(e)}enqueueActivation(e,t={}){let r=this.releases.get(e.id);if(!r)throw Error("Release was not found");if(!["built","failed","rolled_back","superseded"].includes(r.status))throw Error(`Release ${r.status} cannot be activated`);let n=t.action??"activate",i=this.queue.enqueue({projectId:r.projectId,environmentId:r.environmentId,resourceId:r.resourceId,actorId:t.actorId,kind:`release.${n}`,idempotencyKey:`release:${r.id}:${n}:${r.rollbackAttempts}`,correlationId:`release:${r.id}`,input:{releaseId:r.id,targetReleaseId:t.targetReleaseId??null},lockKey:`resource:${r.resourceId}`,providerKey:this.controlPlane.getResource(r.resourceId)?.provider??"default",maxAttempts:r.automaticRollback?2:1,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:365}).operation;return this.releases.transition(r.id,"activating",{message:`${n} queued.`,operationId:i.id,trafficPercent:0}),i}completeHealthGate(e,t){let r=this.releases.get(e);if(!r||r.status!=="activating")throw Error("Release is not activating");if(t.healthy)return{release:this.releases.transition(r.id,"active",{message:t.message??"Health gate passed; activation completed.",operationId:t.operationId,trafficPercent:100,health:t.health})};let n=this.releases.transition(r.id,"failed",{message:t.message??"Health gate failed.",operationId:t.operationId,trafficPercent:0,health:t.health}),i=r.previousReleaseId?this.releases.get(r.previousReleaseId):void 0;if(!r.automaticRollback||r.rollbackAttempts>=1||!i)return{release:n};let o=this.queue.enqueue({projectId:r.projectId,environmentId:r.environmentId,resourceId:r.resourceId,kind:"release.rollback",idempotencyKey:`release:${r.id}:automatic-rollback`,correlationId:`release:${r.id}`,input:{releaseId:r.id,targetReleaseId:i.id,automatic:!0},lockKey:`resource:${r.resourceId}`,providerKey:this.controlPlane.getResource(r.resourceId)?.provider??"default",maxAttempts:1,retryClasses:[],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:365}).operation;return{release:n,rollbackOperation:o}}enqueueRollback(e,t={}){let r=this.releases.get(e.id);if(!r||r.status!=="active")throw Error("Only the active release can be rolled back");let n=t.targetReleaseId?this.releases.get(t.targetReleaseId):r.previousReleaseId?this.releases.get(r.previousReleaseId):void 0;if(!n||n.resourceId!==r.resourceId||!["superseded","active"].includes(n.status))throw Error("Rollback requires a preserved prior release for the same resource");return this.queue.enqueue({projectId:r.projectId,environmentId:r.environmentId,resourceId:r.resourceId,actorId:t.actorId,kind:"release.rollback",idempotencyKey:`release:${r.id}:manual-rollback:${n.id}`,correlationId:`release:${r.id}`,input:{releaseId:r.id,targetReleaseId:n.id,automatic:!1},lockKey:`resource:${r.resourceId}`,providerKey:this.controlPlane.getResource(r.resourceId)?.provider??"default",maxAttempts:1,retryClasses:[],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:365}).operation}}function Pw(e){if(e.strategy==="canary")return[5,25,50,100].map((t,r)=>({step:`canary-${t}`,trafficPercent:t,waitSeconds:r===3?e.drainSeconds:e.graceSeconds,requiresHealth:!0}));if(e.strategy==="blue_green")return[{step:"green-health",trafficPercent:0,waitSeconds:e.graceSeconds,requiresHealth:!0},{step:"traffic-switch",trafficPercent:100,waitSeconds:e.drainSeconds,requiresHealth:!0}];if(e.strategy==="rolling")return[{step:"rolling-replacement",trafficPercent:50,waitSeconds:e.graceSeconds,requiresHealth:!0},{step:"rolling-complete",trafficPercent:100,waitSeconds:e.drainSeconds,requiresHealth:!0}];return[{step:"immutable-switch",trafficPercent:100,waitSeconds:e.drainSeconds,requiresHealth:!!e.healthGate}]}async function wm(e,t){if(t.release.artifactId!==t.artifact.id)throw Error("Release activation artifact identity changed");ds({kind:t.release.kind,hasHealthGate:!!t.release.healthGate,replicas:Number(t.release.manifest?.replicas)||void 0},t.release.strategy);let r=e.capability(t);if(!r.supported)throw Error(`${t.release.strategy} is unavailable in ${e.name}: ${r.explanation}`);return e.activate({...t,transitions:Pw(t.release)})}async function km(e,t){if(!t.previous)throw Error("Rollback requires the preserved previous release");return e.rollback({...t,transitions:[{step:"rollback",trafficPercent:0,waitSeconds:t.release.drainSeconds,requiresHealth:!0}]})}var _w=["release.activate","release.rollback"];function Tw(e){return e&&typeof e==="object"&&!Array.isArray(e)?e:{}}function Im(e){let t=new Dn(e.store),r=async(n)=>{let i=Tw(n.operation.input),o=typeof i.releaseId==="string"?i.releaseId:"",s=t.releases.get(o);if(!s)throw Error(`Queued release ${o||"(missing)"} was not found`);if(s.projectId!==n.operation.projectId||s.environmentId!==n.operation.environmentId||s.resourceId!==n.operation.resourceId)throw Error("Queued release does not match the operation scope");let c=t.releases.getArtifact(s.artifactId);if(!c||c.digest!==t.releases.getArtifact(s.artifactId)?.digest)throw Error("Immutable release artifact is unavailable");let d=typeof i.targetReleaseId==="string"&&i.targetReleaseId?i.targetReleaseId:s.previousReleaseId,a=d?t.releases.get(d):void 0;if(a&&(a.resourceId!==s.resourceId||a.artifactId===s.artifactId&&a.id===s.id))throw Error("Rollback target does not match the release resource");let u=await e.resolveDriver(s);n.checkpoint("verify",`Verifying ${c.digest} and ${s.configHash} for ${u.name}.`),n.log(`Artifact ${c.digest}; source ${s.sourceSha??"not recorded"}; config ${s.configHash}.`,{stream:"system"}),n.throwIfCancellationRequested();let m;try{m=n.operation.kind==="release.rollback"?await km(u,{release:s,artifact:c,previous:a}):await wm(u,{release:s,artifact:c,previous:a})}catch(h){if(n.operation.kind==="release.activate"&&t.releases.get(s.id)?.status==="activating")t.completeHealthGate(s.id,{healthy:!1,operationId:n.operation.id,message:h instanceof Error?h.message:String(h)});throw h}for(let h of m.transitions)t.releases.progress(s.id,{message:`${n.operation.kind==="release.rollback"?"Rollback":"Activation"} traffic at ${h.trafficPercent}%.`,trafficPercent:h.trafficPercent,health:h.observed,operationId:n.operation.id}),n.log(`Traffic ${h.trafficPercent}%: ${h.healthy?"healthy":"unhealthy"}.`,{stream:h.healthy?"step":"stderr",step:"health"});if(n.checkpoint("health","Evaluating the provider health result."),!m.activated||!m.healthy){if(n.operation.kind==="release.activate"&&t.releases.get(s.id)?.status==="activating")t.completeHealthGate(s.id,{healthy:!1,operationId:n.operation.id,health:{resourceVersions:m.resourceVersions},message:m.error??"Provider health gate failed."});throw Error(m.error??`${u.name} reported an unhealthy release`)}if(n.operation.kind==="release.activate"&&s.healthGate?.name){if(!e.resolveHealthGate)throw t.completeHealthGate(s.id,{healthy:!1,operationId:n.operation.id,message:`Named health gate ${s.healthGate.name} is not available to this worker.`}),Error(`Named health gate ${s.healthGate.name} is unavailable`);n.checkpoint("named-health-gate",`Waiting on ${s.healthGate.name}.`);let h=await e.resolveHealthGate(s.healthGate.name,s);if(n.log(`${s.healthGate.name}: ${h.healthy?"healthy":"unhealthy"}${h.message?` — ${h.message}`:""}.`,{stream:h.healthy?"step":"stderr",step:"health"}),!h.healthy)throw t.completeHealthGate(s.id,{healthy:!1,operationId:n.operation.id,health:h.evidence,message:h.message??`Named health gate ${s.healthGate.name} failed.`}),Error(h.message??`Named health gate ${s.healthGate.name} failed`)}if(n.operation.kind==="release.rollback"){let h=t.releases.get(s.id);if(h.status!=="rolled_back")t.releases.transition(h.id,"rolled_back",{message:`Traffic restored through ${u.name}.`,operationId:n.operation.id,trafficPercent:0,health:{resourceVersions:m.resourceVersions}});if(a&&a.status!=="active"){let y=a.status==="activating"?a:t.releases.transition(a.id,"activating",{message:"Rollback target restoring traffic.",operationId:n.operation.id,trafficPercent:0});t.releases.transition(y.id,"active",{message:"Previous immutable release restored.",operationId:n.operation.id,trafficPercent:100,health:{resourceVersions:m.resourceVersions}})}}else t.completeHealthGate(s.id,{healthy:!0,operationId:n.operation.id,health:{providerVersion:m.providerVersion??null,resourceVersions:m.resourceVersions},message:"Provider activation and health gates completed."});return n.checkpoint("finalize","Persisted the terminal release state."),{releaseId:s.id,artifactDigest:c.digest,provider:u.name,providerVersion:m.providerVersion??null,resourceVersions:m.resourceVersions,status:t.releases.get(s.id).status}};return Object.fromEntries(_w.map((n)=>[n,r]))}import{createCipheriv as xw,createDecipheriv as Dw,createHash as Pm,randomBytes as Tc}from"node:crypto";var _m={github:{repositories:!0,branches:!0,tags:!0,webhooks:!0,pullRequests:!0,tokenRefresh:!0,deployKeys:!0},gitlab:{repositories:!0,branches:!0,tags:!0,webhooks:!0,pullRequests:!0,tokenRefresh:!0,deployKeys:!0},bitbucket:{repositories:!0,branches:!0,tags:!0,webhooks:!0,pullRequests:!0,tokenRefresh:!0,deployKeys:!0},gitea:{repositories:!0,branches:!0,tags:!0,webhooks:!0,pullRequests:!0,tokenRefresh:!1,deployKeys:!0},generic_https:{repositories:!1,branches:!0,tags:!0,webhooks:!1,pullRequests:!1,tokenRefresh:!1,deployKeys:!1},generic_ssh:{repositories:!1,branches:!0,tags:!0,webhooks:!1,pullRequests:!1,tokenRefresh:!1,deployKeys:!0}};function De(e){return typeof e==="string"&&e?e:void 0}function $n(e,t){try{return typeof e==="string"?JSON.parse(e):t}catch{return t}}function mr(e){return JSON.stringify(Oe(e))}function On(e){return Pm("sha256").update(e).digest("hex")}function Em(e){let t=e.trim().replace(/\/$/,""),r=new URL(t.includes("://")?t:`https://${t}`);if(r.username||r.password||r.search||r.hash)throw Error("Source host cannot contain credentials, a query, or a fragment");if(r.protocol!=="https:"&&!(r.protocol==="http:"&&["localhost","127.0.0.1","::1"].includes(r.hostname)))throw Error("Source host must use HTTPS");return`${r.protocol}//${r.host}${r.pathname.replace(/\/$/,"")}`}function Rm(e){let t=e.trim();if(t.length<2||t.length>80)throw Error("Connection name must contain 2-80 characters");return t}function xc(e){let t=e.trim().replace(/^\/+|\/+$/g,"");if(!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(t))throw Error("Repository must use owner/name format");return t}function Am(e){let t=e.trim()||".";if(t.startsWith("/")||t.split("/").includes("..")||/[\0\r\n]/.test(t))throw Error("Monorepo root must stay inside the repository");return t.replace(/^\.\//,"")||"."}function ls(e){return[...new Set((e??[]).map((t)=>t.trim()).filter(Boolean))].slice(0,100)}function Ow(e){let t=e.trim();if(/\r|\n/.test(t)||/https?:\/\/[^/@\s]+:[^/@\s]+@/i.test(t))throw Error("Clone URL cannot contain credentials or control characters");if(!/^(?:https?:\/\/|ssh:\/\/|git@[A-Za-z0-9.-]+:)/.test(t))throw Error("Clone URL must use HTTPS or SSH");return t}function $w(e){return{id:String(e.id),organizationId:String(e.organization_id),provider:String(e.provider),name:String(e.name),host:String(e.host),owner:De(e.owner),authKind:String(e.auth_kind),credentialConfigured:!!e.credential_ciphertext,credentialFingerprint:De(e.credential_fingerprint),grantedScopes:$n(e.granted_scopes,[]),capabilities:$n(e.capabilities,_m[String(e.provider)]),status:String(e.status),healthMessage:De(e.health_message),lastTestedAt:De(e.last_tested_at),lastSyncedAt:De(e.last_synced_at),credentialExpiresAt:De(e.credential_expires_at),version:Number(e.version),createdByActorId:De(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Dc(e){return{id:String(e.id),connectionId:String(e.connection_id),providerRepositoryId:String(e.provider_repository_id),fullName:String(e.full_name),cloneUrl:String(e.clone_url),defaultBranch:String(e.default_branch),visibility:String(e.visibility),archived:Number(e.archived)===1,metadata:$n(e.metadata,{}),syncedAt:String(e.synced_at)}}function Cm(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:De(e.environment_id),resourceId:De(e.resource_id),connectionId:String(e.connection_id),repositoryId:De(e.repository_id),repositoryFullName:String(e.repository_full_name),defaultBranch:String(e.default_branch),branchRule:De(e.branch_rule),tagRule:De(e.tag_rule),monorepoRoot:String(e.monorepo_root),includePaths:$n(e.include_paths,[]),excludePaths:$n(e.exclude_paths,[]),submodules:Number(e.submodules)===1,cloneDepth:e.clone_depth==null?void 0:Number(e.clone_depth),deployKeyId:De(e.deploy_key_id),autoDeploy:Number(e.auto_deploy)===1,pullRequestPreviews:Number(e.pull_request_previews)===1,status:String(e.status),disabledReason:De(e.disabled_reason),version:Number(e.version),createdByActorId:De(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Oc(e){return{id:String(e.id),connectionId:String(e.connection_id),name:String(e.name),publicKey:String(e.public_key),publicKeyFingerprint:String(e.public_key_fingerprint),host:String(e.host),hostKey:String(e.host_key),hostKeyFingerprint:String(e.host_key_fingerprint),createdByActorId:De(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function $c(e){return{id:String(e.id),connectionId:String(e.connection_id),repositoryId:De(e.repository_id),repositoryFullName:String(e.repository_full_name),providerWebhookId:De(e.provider_webhook_id),events:$n(e.events,[]),status:String(e.status),healthMessage:De(e.health_message),lastDeliveryAt:De(e.last_delivery_at),lastReconciledAt:De(e.last_reconciled_at),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Nc(e){return{id:String(e.id),connectionId:String(e.connection_id),webhookId:String(e.webhook_id),providerDeliveryId:String(e.provider_delivery_id),event:String(e.event),action:De(e.action),commitSha:De(e.commit_sha),signatureStatus:String(e.signature_status),status:String(e.status),payloadSummary:$n(e.payload_summary,{}),operationId:De(e.operation_id),error:De(e.error),receivedAt:String(e.received_at),processedAt:De(e.processed_at)}}class jc{controlPlane;key;nowFn;idFn;constructor(e,t={}){this.controlPlane=e;this.key=t.encryptionKey?Pm("sha256").update(t.encryptionKey).digest():void 0,this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID())}now(){return this.nowFn().toISOString()}run(e,t){this.controlPlane.database.run(e,t)}encrypt(e){if(!this.key)throw Error("Source credential encryption key is not configured");let t=Tc(12),r=xw("aes-256-gcm",this.key,t),n=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${n.toString("base64url")}`}decrypt(e){if(!this.key)throw Error("Source credential encryption key is not configured");let[t,r,n,i]=e.split(".");if(t!=="v1"||!r||!n||!i)throw Error("Encrypted source credential is unavailable");let o=Dw("aes-256-gcm",this.key,Buffer.from(r,"base64url"));return o.setAuthTag(Buffer.from(n,"base64url")),Buffer.concat([o.update(Buffer.from(i,"base64url")),o.final()]).toString("utf8")}createConnection(e){if(!this.controlPlane.getOrganization(e.organizationId))throw Error("Source connection organization was not found");let t=this.now(),r=this.idFn(),n=e.credential?JSON.stringify(e.credential):void 0;return this.run(`INSERT INTO source_connections (id, organization_id, provider, name, host, owner, auth_kind, credential_ciphertext, credential_fingerprint, granted_scopes, capabilities, status, credential_expires_at, created_by_actor_id, created_at, updated_at)
18
18
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?)`,[r,e.organizationId,e.provider,Rm(e.name),Em(e.host),e.owner?.trim()||null,e.authKind??(n?"access_token":"none"),n?this.encrypt(n):null,n?On(n).slice(0,16):null,mr([...new Set(e.grantedScopes??[])].sort()),mr(_m[e.provider]),e.credentialExpiresAt??null,e.createdByActorId??null,t,t]),this.controlPlane.appendEvent({organizationId:e.organizationId,actorId:e.createdByActorId,type:"source.connection.created",payload:{connectionId:r,provider:e.provider,host:Em(e.host),owner:e.owner??null,scopes:e.grantedScopes??[]}}),this.getConnection(r)}getConnection(e){let t=this.controlPlane.database.query("SELECT * FROM source_connections WHERE id = ?").get(e);return t?this.currentConnection(t):void 0}listConnections(e){return this.controlPlane.database.query("SELECT * FROM source_connections WHERE organization_id = ? ORDER BY name").all(e).map((t)=>this.currentConnection(t))}currentConnection(e){let t=$w(e);if(t.status!=="disconnected"&&t.credentialExpiresAt&&new Date(t.credentialExpiresAt).getTime()<=this.nowFn().getTime())return{...t,status:"expired",healthMessage:"Source credential expired; rotate it before deploying."};return t}getCredential(e){let t=this.controlPlane.database.query("SELECT credential_ciphertext FROM source_connections WHERE id = ?").get(e);return t?.credential_ciphertext?JSON.parse(this.decrypt(String(t.credential_ciphertext))):void 0}rotateCredential(e,t,r={}){let n=this.getConnection(e);if(!n||n.status==="disconnected")throw Error("Active source connection was not found");let i=JSON.stringify(t);return this.run("UPDATE source_connections SET credential_ciphertext = ?, credential_fingerprint = ?, credential_expires_at = ?, status = 'pending', health_message = NULL, version = version + 1, updated_at = ? WHERE id = ?",[this.encrypt(i),On(i).slice(0,16),r.expiresAt??null,this.now(),e]),this.controlPlane.appendEvent({organizationId:n.organizationId,actorId:r.actorId,type:"source.credential.rotated",payload:{connectionId:e,fingerprint:On(i).slice(0,16),expiresAt:r.expiresAt??null}}),this.getConnection(e)}updateHealth(e,t){let r=this.getConnection(e);if(!r||["disconnected","expired"].includes(r.status))throw Error("Active source connection was not found");let n=this.now(),i=t.grantedScopes?[...new Set(t.grantedScopes.map((o)=>o.trim()).filter(Boolean))].sort():void 0;if(this.run("UPDATE source_connections SET status = ?, health_message = ?, granted_scopes = COALESCE(?, granted_scopes), last_tested_at = COALESCE(?, last_tested_at), last_synced_at = COALESCE(?, last_synced_at), version = version + 1, updated_at = ? WHERE id = ?",[t.status,t.message?.slice(0,1000)??null,i?mr(i):null,t.tested?n:null,t.synced?n:null,n,e]),i&&JSON.stringify(i)!==JSON.stringify([...r.grantedScopes].sort()))this.controlPlane.appendEvent({organizationId:r.organizationId,type:"source.connection.scopes_updated",payload:{connectionId:e,grantedScopes:i}});return this.getConnection(e)}upsertRepository(e){let t=this.getConnection(e.connectionId);if(!t||["disconnected","expired"].includes(t.status))throw Error("Active source connection was not found");let r=this.now(),n=this.controlPlane.database.query("SELECT id FROM source_repositories WHERE connection_id = ? AND provider_repository_id = ?").get(e.connectionId,e.providerRepositoryId),i=n?String(n.id):this.idFn();return this.run(`INSERT INTO source_repositories (id, connection_id, provider_repository_id, full_name, clone_url, default_branch, visibility, archived, metadata, synced_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
@@ -45,7 +45,7 @@ data: ${JSON.stringify(ge)}
45
45
  default_role = ?, enabled = ?, enforce_sso = ?, updated_at = ? WHERE id = ?`,[t,r,n,i,e.clientSecret?this.encrypt(e.clientSecret):null,JSON.stringify(o),JSON.stringify(s),e.defaultRole??c.defaultRole,e.enabled??c.enabled?1:0,e.enforceSso??c.enforceSso?1:0,d,c.id]),this.getOidcProvider(c.id)}if(!e.clientSecret)throw Error("OIDC client secret is required for a new provider");let a=e.id??this.idFn();return this.run(`INSERT INTO auth_oidc_providers (id, organization_id, slug, name, issuer, client_id,
46
46
  client_secret_ciphertext, scopes, allowed_domains, default_role, enabled, enforce_sso, created_at, updated_at)
47
47
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[a,e.organizationId,t,r,n,i,this.encrypt(e.clientSecret),JSON.stringify(o),JSON.stringify(s),e.defaultRole??"viewer",e.enabled===!1?0:1,e.enforceSso?1:0,d,d]),this.getOidcProvider(a)}getOidcProvider(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_providers WHERE id = ?").get(e);return t?bs(t):void 0}getOidcProviderBySlug(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_providers WHERE slug = ? COLLATE NOCASE").get(e.trim());return t?bs(t):void 0}listOidcProviders(e,t={}){return(e?this.controlPlane.database.query("SELECT * FROM auth_oidc_providers WHERE organization_id = ? ORDER BY name COLLATE NOCASE").all(e):this.controlPlane.database.query("SELECT * FROM auth_oidc_providers ORDER BY name COLLATE NOCASE").all()).map(bs).filter((n)=>t.includeDisabled||n.enabled)}setOidcProviderEnabled(e,t){let r=this.now();if(this.controlPlane.database.run("UPDATE auth_oidc_providers SET enabled = ?, enforce_sso = CASE WHEN ? = 0 THEN 0 ELSE enforce_sso END, updated_at = ? WHERE id = ?",[t?1:0,t?1:0,r,e]).changes!==1)throw Error("OIDC provider was not found");if(!t)this.run("UPDATE auth_oidc_transactions SET consumed_at = ? WHERE provider_id = ? AND consumed_at IS NULL",[r,e]);return this.getOidcProvider(e)}getOidcProviderCredentials(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_providers WHERE id = ?").get(e);if(!t||typeof t.client_secret_ciphertext!=="string")throw Error("OIDC provider credentials are unavailable");return{provider:bs(t),clientSecret:this.decrypt(t.client_secret_ciphertext)}}beginOidcTransaction(e,t,r){if(!this.getOidcProvider(e)?.enabled)throw Error("OIDC provider is unavailable");let i=this.idFn(),o=Ar(32).toString("base64url"),s=Ar(32).toString("base64url"),c=Ar(64).toString("base64url"),d=this.now(),a=new Date(this.nowFn().getTime()+ig).toISOString();return this.run(`INSERT INTO auth_oidc_transactions (id, provider_id, state_hash, nonce_ciphertext, verifier_ciphertext,
48
- redirect_uri, return_path, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[i,e,Xt(o),this.encrypt(s),this.encrypt(c),t,r,a,d]),{transaction:this.getOidcTransaction(i),state:o,nonce:s,verifier:c}}getOidcTransaction(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE id = ?").get(e);return t?Xm(t,this.now()):void 0}consumeOidcTransaction(e,t){return this.controlPlane.transaction(()=>{let r=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE provider_id = ? AND state_hash = ?").get(e,Xt(t));if(!r)throw Error("OIDC transaction is invalid");let n=Xm(r,this.now());if(n.state!=="pending")throw Error(`OIDC transaction is ${n.state}`);if(this.controlPlane.database.run("UPDATE auth_oidc_transactions SET consumed_at = ? WHERE id = ? AND consumed_at IS NULL AND expires_at > ?",[this.now(),n.id,this.now()]).changes!==1)throw Error("OIDC transaction is no longer available");return{transaction:this.getOidcTransaction(n.id),nonce:this.decrypt(String(r.nonce_ciphertext)),verifier:this.decrypt(String(r.verifier_ciphertext))}})}getOidcSubject(e,t){let r=this.controlPlane.database.query("SELECT * FROM auth_oidc_subjects WHERE provider_id = ? AND subject = ?").get(e,t);return r?uk(r):void 0}linkOidcSubject(e,t,r,n){let i=this.getOidcProvider(e),o=this.getIdentity(t);if(!i||!o)throw Error("OIDC provider or identity was not found");let s=Kc(n);if(!r.trim()||r.length>512)throw Error("OIDC subject is invalid");let c=this.getOidcSubject(e,r);if(c&&c.identityId!==t)throw Error("OIDC subject is already linked to another identity");let d=this.now();if(c)return this.run("UPDATE auth_oidc_subjects SET email = ?, last_login_at = ? WHERE id = ?",[s,d,c.id]),this.getOidcSubject(e,r);let a=this.idFn();return this.run("INSERT INTO auth_oidc_subjects (id, provider_id, identity_id, subject, email, linked_at, last_login_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[a,e,t,r,s,d,d]),this.getOidcSubject(e,r)}purgeExpired(){let e=this.now(),t=this.controlPlane.database.run("DELETE FROM auth_action_tokens WHERE expires_at < ? OR consumed_at IS NOT NULL",[e]).changes,r=this.controlPlane.database.run("DELETE FROM auth_sessions WHERE revoked_at IS NOT NULL OR idle_expires_at < ? OR absolute_expires_at < ?",[e,e]).changes;return this.controlPlane.database.run("DELETE FROM auth_mfa_challenges WHERE consumed_at IS NOT NULL OR expires_at < ?",[e]),this.controlPlane.database.run("DELETE FROM auth_oidc_transactions WHERE consumed_at IS NOT NULL OR expires_at < ?",[e]),{actionTokens:t,sessions:r}}}async function fo(e,t){let r=e.notifications?.email?.from;if(!r)return!1;try{let{EmailClient:n}=await import("./chunk-q816js1y.js");return await new n({region:e.project.region,defaultFrom:r}).send(t),!0}catch{return!1}}import{randomBytes as pk}from"node:crypto";import{chmodSync as mk,existsSync as gk,mkdirSync as fk,readFileSync as hk,writeFileSync as yk}from"node:fs";import{dirname as vk}from"node:path";function bk(){return ho("auth-encryption-key")}function on(e){let t=process.env.TS_CLOUD_AUTH_ENCRYPTION_KEY?.trim();if(t)return t;let r=yt(e,"auth-encryption-key");try{if(gk(r)){let i=hk(r,"utf8").trim();if(i)return i}}catch{}let n=pk(32).toString("base64url");try{fk(vk(r),{recursive:!0,mode:448}),yk(r,`${n}
48
+ redirect_uri, return_path, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[i,e,Xt(o),this.encrypt(s),this.encrypt(c),t,r,a,d]),{transaction:this.getOidcTransaction(i),state:o,nonce:s,verifier:c}}getOidcTransaction(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE id = ?").get(e);return t?Xm(t,this.now()):void 0}consumeOidcTransaction(e,t){return this.controlPlane.transaction(()=>{let r=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE provider_id = ? AND state_hash = ?").get(e,Xt(t));if(!r)throw Error("OIDC transaction is invalid");let n=Xm(r,this.now());if(n.state!=="pending")throw Error(`OIDC transaction is ${n.state}`);if(this.controlPlane.database.run("UPDATE auth_oidc_transactions SET consumed_at = ? WHERE id = ? AND consumed_at IS NULL AND expires_at > ?",[this.now(),n.id,this.now()]).changes!==1)throw Error("OIDC transaction is no longer available");return{transaction:this.getOidcTransaction(n.id),nonce:this.decrypt(String(r.nonce_ciphertext)),verifier:this.decrypt(String(r.verifier_ciphertext))}})}getOidcSubject(e,t){let r=this.controlPlane.database.query("SELECT * FROM auth_oidc_subjects WHERE provider_id = ? AND subject = ?").get(e,t);return r?uk(r):void 0}linkOidcSubject(e,t,r,n){let i=this.getOidcProvider(e),o=this.getIdentity(t);if(!i||!o)throw Error("OIDC provider or identity was not found");let s=Kc(n);if(!r.trim()||r.length>512)throw Error("OIDC subject is invalid");let c=this.getOidcSubject(e,r);if(c&&c.identityId!==t)throw Error("OIDC subject is already linked to another identity");let d=this.now();if(c)return this.run("UPDATE auth_oidc_subjects SET email = ?, last_login_at = ? WHERE id = ?",[s,d,c.id]),this.getOidcSubject(e,r);let a=this.idFn();return this.run("INSERT INTO auth_oidc_subjects (id, provider_id, identity_id, subject, email, linked_at, last_login_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[a,e,t,r,s,d,d]),this.getOidcSubject(e,r)}purgeExpired(){let e=this.now(),t=this.controlPlane.database.run("DELETE FROM auth_action_tokens WHERE expires_at < ? OR consumed_at IS NOT NULL",[e]).changes,r=this.controlPlane.database.run("DELETE FROM auth_sessions WHERE revoked_at IS NOT NULL OR idle_expires_at < ? OR absolute_expires_at < ?",[e,e]).changes;return this.controlPlane.database.run("DELETE FROM auth_mfa_challenges WHERE consumed_at IS NOT NULL OR expires_at < ?",[e]),this.controlPlane.database.run("DELETE FROM auth_oidc_transactions WHERE consumed_at IS NOT NULL OR expires_at < ?",[e]),{actionTokens:t,sessions:r}}}async function fo(e,t){let r=e.notifications?.email?.from;if(!r)return!1;try{let{EmailClient:n}=await import("./chunk-kj7gzdj6.js");return await new n({region:e.project.region,defaultFrom:r}).send(t),!0}catch{return!1}}import{randomBytes as pk}from"node:crypto";import{chmodSync as mk,existsSync as gk,mkdirSync as fk,readFileSync as hk,writeFileSync as yk}from"node:fs";import{dirname as vk}from"node:path";function bk(){return ho("auth-encryption-key")}function on(e){let t=process.env.TS_CLOUD_AUTH_ENCRYPTION_KEY?.trim();if(t)return t;let r=yt(e,"auth-encryption-key");try{if(gk(r)){let i=hk(r,"utf8").trim();if(i)return i}}catch{}let n=pk(32).toString("base64url");try{fk(vk(r),{recursive:!0,mode:448}),yk(r,`${n}
49
49
  `,{mode:384}),mk(r,384)}catch{}return n}import{constants as sg,createHash as Qc,createPublicKey as Sk,createVerify as wk,timingSafeEqual as kk}from"node:crypto";var cg=new Set(["RS256","PS256","ES256"]),ag=60;function ws(e,t){let r=new URL(e),n=["127.0.0.1","::1","localhost"].includes(r.hostname);if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n))throw Error(`${t} must use HTTPS`);if(r.username||r.password||r.hash)throw Error(`${t} contains unsupported URL components`);return r}function Yc(e,t){if(!e||typeof e!=="object"||Array.isArray(e))throw Error(`${t} is invalid`);return e}async function Zc(e,t){if(!e.ok)throw Error(`${t} failed with HTTP ${e.status}`);if(!(e.headers.get("content-type")??"").toLowerCase().includes("application/json"))throw Error(`${t} returned an unsupported content type`);if(Number(e.headers.get("content-length")??0)>1048576)throw Error(`${t} response is too large`);let i=await e.text();if(i.length>1048576)throw Error(`${t} response is too large`);try{return Yc(JSON.parse(i),t)}catch(o){if(o instanceof Error&&o.message===`${t} is invalid`)throw o;throw Error(`${t} returned invalid JSON`)}}function Ik(e,t){let r=Qc("sha256").update(e).digest(),n=Qc("sha256").update(t).digest();return kk(r,n)}function dg(e){if(!e)return"/";let t=e.trim();if(!t.startsWith("/")||t.startsWith("//")||t.includes("\\")||/[\r\n]/.test(t))return"/";try{let r=new URL(t,"https://local.invalid");return r.origin==="https://local.invalid"?`${r.pathname}${r.search}${r.hash}`:"/"}catch{return"/"}}async function Xc(e,t=fetch){let r=ws(e.issuer,"OIDC issuer"),n=new URL(`${r.pathname.replace(/\/$/,"")}/.well-known/openid-configuration`,r.origin),i=await Zc(await t(n,{headers:{accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC discovery");if(i.issuer!==e.issuer)throw Error("OIDC discovery issuer does not match the configured issuer");for(let s of["authorization_endpoint","token_endpoint","jwks_uri"]){if(typeof i[s]!=="string")throw Error(`OIDC discovery is missing ${s}`);ws(i[s],`OIDC ${s}`)}if(Array.isArray(i.response_types_supported)&&!i.response_types_supported.includes("code"))throw Error("OIDC provider does not support authorization code flow");if(Array.isArray(i.code_challenge_methods_supported)&&!i.code_challenge_methods_supported.includes("S256"))throw Error("OIDC provider does not support PKCE S256");let o=Array.isArray(i.id_token_signing_alg_values_supported)?i.id_token_signing_alg_values_supported.filter((s)=>typeof s==="string"):[];if(o.length>0&&!o.some((s)=>cg.has(s)))throw Error("OIDC provider does not offer a supported ID-token signing algorithm");return i}async function ed(e,t,r,n,i=fetch){let o=e.getOidcProviderBySlug(t);if(!o?.enabled)throw Error("OIDC provider is unavailable");let s=ws(r,"Application origin").origin,c=await Xc(o,i),d=`${s}/auth/oidc/${encodeURIComponent(o.slug)}/callback`,a=e.beginOidcTransaction(o.id,d,dg(n)),u=new URL(c.authorization_endpoint);return u.searchParams.set("response_type","code"),u.searchParams.set("client_id",o.clientId),u.searchParams.set("redirect_uri",d),u.searchParams.set("scope",o.scopes.join(" ")),u.searchParams.set("state",a.state),u.searchParams.set("nonce",a.nonce),u.searchParams.set("code_challenge",Qc("sha256").update(a.verifier).digest("base64url")),u.searchParams.set("code_challenge_method","S256"),{authorizationUrl:u.href,expiresAt:a.transaction.expiresAt}}function Ek(e){if(e.length>32768)throw Error("OIDC ID token is too large");let t=e.split(".");if(t.length!==3||t.some((r)=>!r))throw Error("OIDC ID token is malformed");try{return{header:Yc(JSON.parse(Buffer.from(t[0],"base64url").toString("utf8")),"OIDC ID-token header"),claims:Yc(JSON.parse(Buffer.from(t[1],"base64url").toString("utf8")),"OIDC ID-token claims"),signingInput:`${t[0]}.${t[1]}`,signature:Buffer.from(t[2],"base64url")}}catch(r){if(r instanceof Error&&r.message.startsWith("OIDC"))throw r;throw Error("OIDC ID token is malformed")}}async function Rk(e,t,r){let n=Ek(e),i=typeof n.header.alg==="string"?n.header.alg:"",o=typeof n.header.kid==="string"?n.header.kid:"";if(!cg.has(i)||!o)throw Error("OIDC ID token uses an unsupported signing key");if(t.id_token_signing_alg_values_supported&&!t.id_token_signing_alg_values_supported.includes(i))throw Error("OIDC ID-token algorithm was not advertised by the provider");let s=await Zc(await r(t.jwks_uri,{headers:{accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC signing-key request");if(!Array.isArray(s.keys))throw Error("OIDC signing-key response is invalid");let c=s.keys.find((m)=>{if(!m||typeof m!=="object"||Array.isArray(m))return!1;let h=m;return h.kid===o&&(!h.alg||h.alg===i)&&(!h.use||h.use==="sig")});if(!c)throw Error("OIDC ID-token signing key was not found");let d=Sk({key:c,format:"jwk"}),a=wk("SHA256").update(n.signingInput).end();if(!(i==="PS256"?a.verify({key:d,padding:sg.RSA_PKCS1_PSS_PADDING,saltLength:32},n.signature):i==="ES256"?a.verify({key:d,dsaEncoding:"ieee-p1363"},n.signature):a.verify(d,n.signature)))throw Error("OIDC ID-token signature is invalid");return n.claims}function Ak(e,t,r,n){if(e.iss!==t.issuer)throw Error("OIDC ID-token issuer is invalid");let i=typeof e.aud==="string"?[e.aud]:Array.isArray(e.aud)?e.aud.filter((d)=>typeof d==="string"):[];if(!i.includes(t.clientId))throw Error("OIDC ID-token audience is invalid");if((i.length>1||e.azp!==void 0)&&e.azp!==t.clientId)throw Error("OIDC ID-token authorized party is invalid");let o=Math.floor(n.getTime()/1000);if(typeof e.exp!=="number"||e.exp<o-ag)throw Error("OIDC ID token is expired");if(typeof e.iat!=="number"||e.iat>o+ag)throw Error("OIDC ID-token issued-at time is invalid");if(typeof e.nonce!=="string"||!Ik(e.nonce,r))throw Error("OIDC ID-token nonce is invalid");if(typeof e.sub!=="string"||!e.sub||e.sub.length>512)throw Error("OIDC ID-token subject is invalid");if(e.email_verified!==!0||typeof e.email!=="string")throw Error("OIDC provider did not return a verified email address");let s=e.email.trim().toLowerCase();if(s.length>254||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s))throw Error("OIDC provider returned an invalid email address");let c=s.split("@")[1];if(!c||!t.allowedDomains.includes(c))throw Error("OIDC email domain is not allowed for this organization");return{provider:t,subject:e.sub,email:s,name:typeof e.name==="string"?e.name.slice(0,120):void 0,claims:e}}async function td(e,t,r=fetch){let n=e.getOidcProviderBySlug(t.providerSlug);if(!n?.enabled)throw Error("OIDC provider is unavailable");if(!t.state||t.state.length>512||!t.code||t.code.length>4096)throw Error("OIDC callback is incomplete");let i=ws(t.origin,"Application origin").origin,o=e.consumeOidcTransaction(n.id,t.state),s=`${i}/auth/oidc/${encodeURIComponent(n.slug)}/callback`;if(o.transaction.redirectUri!==s)throw Error("OIDC callback redirect URI does not match the original request");let{clientSecret:c}=e.getOidcProviderCredentials(n.id),d=await Xc(n,r),a=new URLSearchParams({grant_type:"authorization_code",code:t.code,redirect_uri:o.transaction.redirectUri,code_verifier:o.verifier}),u={accept:"application/json","content-type":"application/x-www-form-urlencoded"},m=d.token_endpoint_auth_methods_supported??["client_secret_basic"];if(m.includes("client_secret_basic")){let w=(C)=>new URLSearchParams({value:C}).toString().slice(6),k=`${w(n.clientId)}:${w(c)}`;u.authorization=`Basic ${Buffer.from(k).toString("base64")}`}else if(m.includes("client_secret_post"))a.set("client_id",n.clientId),a.set("client_secret",c);else throw Error("OIDC provider does not support a configured client authentication method");let h=await Zc(await r(d.token_endpoint,{method:"POST",headers:u,body:a,redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC token exchange");if(typeof h.id_token!=="string")throw Error("OIDC token response did not include an ID token");let y=await Rk(h.id_token,d,r);return{identity:Ak(y,n,o.nonce,t.now??new Date),returnPath:o.transaction.returnPath}}import{createHash as Ck,randomBytes as Pk}from"node:crypto";var ug=new Set(ks),pg=7776000000,mg=31536000000,gg=86400000;function Cr(e){return typeof e==="string"?e:void 0}function lg(e){return Ck("sha256").update(e).digest("hex")}function _k(e){try{let t=JSON.parse(String(e));return Array.isArray(t)?t.filter((r)=>typeof r==="string"&&ug.has(r)):[]}catch{return[]}}function Tk(e){let t=String(e.scope_type);return t==="organization"?{type:t}:{type:t,id:String(e.scope_id)}}function rd(e){let t=Cr(e.disabled_at);return{id:String(e.id),organizationId:String(e.organization_id),actorId:String(e.actor_id),slug:String(e.slug),name:String(e.name),description:Cr(e.description),createdByActorId:Cr(e.created_by_actor_id),disabledAt:t,createdAt:String(e.created_at),updatedAt:String(e.updated_at),state:t?"disabled":"active"}}function nd(e,t){let r=Cr(e.revoked_at),n=String(e.expires_at);return{id:String(e.id),serviceAccountId:String(e.service_account_id),name:String(e.name),prefix:String(e.token_prefix),capabilities:_k(e.capabilities),scope:Tk(e),expiresAt:n,lastUsedAt:Cr(e.last_used_at),lastNetworkHint:Cr(e.last_network_hint),revokedAt:r,rotatedFromTokenId:Cr(e.rotated_from_token_id),createdByActorId:Cr(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at),state:r?"revoked":n<=t?"expired":"active"}}function xk(e){let t={};try{t=JSON.parse(String(e.response_body))}catch{}return{id:String(e.id),tokenId:String(e.token_id),key:String(e.idempotency_key),requestHash:String(e.request_hash),operationId:Cr(e.operation_id),responseStatus:Number(e.response_status),responseBody:t,expiresAt:String(e.expires_at),createdAt:String(e.created_at)}}class Is{controlPlane;nowFn;idFn;constructor(e,t={}){this.controlPlane=e;this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID())}now(){return this.nowFn().toISOString()}run(e,t){this.controlPlane.database.run(e,t)}createServiceAccount(e){if(!this.controlPlane.getOrganization(e.organizationId))throw Error("Service-account organization was not found");let t=e.slug.trim().toLowerCase();if(!/^[a-z0-9][a-z0-9-]{1,47}$/.test(t))throw Error("Service-account slug must be 2-48 lowercase letters, numbers or dashes");let r=e.name.trim().slice(0,100);if(!r)throw Error("Service-account name is required");let n=this.controlPlane.createActor({kind:"service_account",externalId:`service-account:${e.organizationId}:${t}`,displayName:r,metadata:{source:"api",serviceAccountSlug:t}}),i=this.idFn(),o=this.now();this.run(`INSERT INTO service_accounts (id, organization_id, actor_id, slug, name, description, created_by_actor_id, created_at, updated_at)
50
50
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[i,e.organizationId,n.id,t,r,e.description?.trim().slice(0,500)||null,e.createdByActorId??null,o,o]);let s=this.controlPlane.createMembership({organizationId:e.organizationId,actorId:n.id,roleTemplate:e.roleTemplate,scope:e.scope,source:"manual",performedByActorId:e.createdByActorId}),c=e.scope??{type:"organization"};return this.controlPlane.appendEvent({organizationId:e.organizationId,actorId:e.createdByActorId,type:"api.service_account.created",payload:{serviceAccountId:i,roleTemplate:e.roleTemplate,scope:{type:c.type,id:c.id??null}}}),{serviceAccount:this.getServiceAccount(i),membership:s}}getServiceAccount(e){let t=this.controlPlane.database.query("SELECT * FROM service_accounts WHERE id = ?").get(e);return t?rd(t):void 0}getServiceAccountBySlug(e,t){let r=this.controlPlane.database.query("SELECT * FROM service_accounts WHERE organization_id = ? AND slug = ? COLLATE NOCASE").get(e,t.trim());return r?rd(r):void 0}listServiceAccounts(e,t={}){return this.controlPlane.database.query("SELECT * FROM service_accounts WHERE organization_id = ? ORDER BY name COLLATE NOCASE").all(e).map(rd).filter((r)=>t.includeDisabled||r.state==="active")}disableServiceAccount(e,t){let r=this.getServiceAccount(e);if(!r)throw Error("Service account was not found");let n=this.now();return this.controlPlane.transaction(()=>{this.run("UPDATE service_accounts SET disabled_at = ?, updated_at = ? WHERE id = ?",[n,n,e]),this.run("UPDATE api_tokens SET revoked_at = ?, updated_at = ? WHERE service_account_id = ? AND revoked_at IS NULL",[n,n,e]);let i=this.controlPlane.getMembershipForActor(r.organizationId,r.actorId);if(i?.status==="active")this.controlPlane.revokeMembership(i.id)}),this.controlPlane.appendEvent({organizationId:r.organizationId,actorId:t,type:"api.service_account.disabled",payload:{serviceAccountId:e}}),this.getServiceAccount(e)}createToken(e){let t=this.getServiceAccount(e.serviceAccountId);if(!t||t.state!=="active")throw Error("Service account is unavailable");let r=this.controlPlane.getMembershipForActor(t.organizationId,t.actorId);if(!r||r.status!=="active")throw Error("Service-account membership is unavailable");let n=[...new Set(e.capabilities)];if(n.length===0||n.some((h)=>!ug.has(h)))throw Error("API token requires valid explicit capabilities");let i=e.scope??r.scope,o=this.controlPlane.resolveAuthorizationTarget(t.organizationId,i);if(!o)throw Error("API token scope was not found in this organization");for(let h of n)if(!er({membership:r,grants:this.controlPlane.listGrants(r.id),capability:h,target:o}).allowed)throw Error(`Service-account membership does not grant ${h} at the token scope`);let s=e.expiresAt?new Date(e.expiresAt):new Date(this.nowFn().getTime()+pg);if(!Number.isFinite(s.getTime())||s.getTime()<=this.nowFn().getTime()+60000||s.getTime()>this.nowFn().getTime()+mg)throw Error("API token expiry must be between one minute and one year from now");let c=this.idFn(),d=Pk(32).toString("base64url"),a=`tsc_v1.${c}.${d}`,u=`tsc_v1.${c.slice(0,8)}`,m=this.now();return this.run(`INSERT INTO api_tokens (id, service_account_id, name, token_hash, token_prefix, capabilities, scope_type, scope_id,
51
51
  expires_at, rotated_from_token_id, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[c,t.id,e.name.trim().slice(0,100)||"API token",lg(a),u,JSON.stringify(n.sort()),i.type,i.type==="organization"?null:i.id??null,s.toISOString(),e.rotatedFromTokenId??null,e.createdByActorId??null,m,m]),this.controlPlane.appendEvent({organizationId:t.organizationId,actorId:e.createdByActorId,type:"api.token.created",payload:{serviceAccountId:t.id,tokenId:c,prefix:u,capabilities:n,scope:{type:i.type,id:i.id??null},expiresAt:s.toISOString(),rotatedFromTokenId:e.rotatedFromTokenId??null}}),{token:this.getToken(c),secret:a}}getToken(e){let t=this.controlPlane.database.query("SELECT * FROM api_tokens WHERE id = ?").get(e);return t?nd(t,this.now()):void 0}listTokens(e,t={}){return this.controlPlane.database.query("SELECT * FROM api_tokens WHERE service_account_id = ? ORDER BY created_at DESC").all(e).map((r)=>nd(r,this.now())).filter((r)=>t.includeInactive||r.state==="active")}verifyToken(e,t){let r=/^tsc_v1\.([^.]+)\.[A-Za-z0-9_-]{40,}$/.exec(e);if(!r)return;let n=this.controlPlane.database.query("SELECT * FROM api_tokens WHERE id = ? AND token_hash = ?").get(r[1],lg(e));if(!n)return;let i=nd(n,this.now()),o=this.getServiceAccount(i.serviceAccountId);if(!o||o.state!=="active"||i.state!=="active")return;let s=this.controlPlane.getActor(o.actorId),c=this.controlPlane.getMembershipForActor(o.organizationId,o.actorId);if(!s||s.disabledAt||!c||c.status!=="active")return;let d=this.now(),a=!i.lastUsedAt||this.nowFn().getTime()-new Date(i.lastUsedAt).getTime()>=3600000;if(this.run("UPDATE api_tokens SET last_used_at = ?, last_network_hint = ?, updated_at = ? WHERE id = ?",[d,t?.slice(0,128)??null,d,i.id]),a)this.controlPlane.appendEvent({organizationId:o.organizationId,actorId:s.id,type:"api.token.used",payload:{serviceAccountId:o.id,tokenId:i.id,prefix:i.prefix}});return{serviceAccount:o,token:this.getToken(i.id),actor:s,membership:c}}rotateToken(e,t){let r=this.getToken(e);if(!r||r.state!=="active")throw Error("Active API token was not found");let n=this.createToken({serviceAccountId:r.serviceAccountId,name:`${r.name} (rotated)`,capabilities:r.capabilities,scope:r.scope,expiresAt:r.expiresAt,createdByActorId:t,rotatedFromTokenId:r.id}),i=this.getServiceAccount(r.serviceAccountId);return this.controlPlane.appendEvent({organizationId:i?.organizationId,actorId:t,type:"api.token.rotated",payload:{serviceAccountId:r.serviceAccountId,previousTokenId:r.id,tokenId:n.token.id}}),n}revokeToken(e,t){let r=this.getToken(e);if(!r)throw Error("API token was not found");if(r.state==="active"){let n=this.now();this.run("UPDATE api_tokens SET revoked_at = ?, updated_at = ? WHERE id = ?",[n,n,e]);let i=this.getServiceAccount(r.serviceAccountId);this.controlPlane.appendEvent({organizationId:i?.organizationId,actorId:t,type:"api.token.revoked",payload:{serviceAccountId:r.serviceAccountId,tokenId:e}})}return this.getToken(e)}getIdempotency(e,t){let r=this.controlPlane.database.query("SELECT * FROM api_idempotency_records WHERE token_id = ? AND idempotency_key = ? AND expires_at > ?").get(e,t,this.now());return r?xk(r):void 0}saveIdempotency(e){if(!/^[A-Za-z0-9._:-]{8,128}$/.test(e.key))throw Error("Idempotency-Key must contain 8-128 safe characters");let t=this.getIdempotency(e.tokenId,e.key);if(t){if(t.requestHash!==e.requestHash)throw Error("Idempotency-Key was already used for a different request");return t}let r=this.idFn(),n=this.now(),i=new Date(this.nowFn().getTime()+gg).toISOString();return this.run(`INSERT INTO api_idempotency_records (id, token_id, idempotency_key, request_hash, operation_id, response_status, response_body, expires_at, created_at)
@@ -668,7 +668,7 @@ data: ${JSON.stringify({cursor:o,at:new Date().toISOString()})}
668
668
  ${c}
669
669
  ${d}`);return null}return n}catch(i){if(n)ti(n,{recursive:!0,force:!0});if(process.env.TSCLOUD_DASHBOARD_VERBOSE)console.warn(`ts-cloud dashboard: live UI build errored; serving the pre-built UI. ${i.message}`);return null}}function Hb(e){let t=e.infrastructure?.compute?.managedServices?JSON.parse(JSON.stringify(e.infrastructure.compute.managedServices)):void 0;if(t?.vitess?.password)t.vitess.password="";return{project:{name:e.project?.name,slug:e.project?.slug,region:e.project?.region},provider:e.provider,environments:Object.keys(e.environments??{}),compute:e.infrastructure?.compute?{provider:e.infrastructure.compute.provider,runtime:e.infrastructure.compute.runtime,webServer:e.infrastructure.compute.webServer,proxy:e.infrastructure.compute.proxy?{engine:e.infrastructure.compute.proxy.engine,onDemandTls:e.infrastructure.compute.proxy.onDemandTls,cdn:!!e.infrastructure.compute.proxy.cdn}:void 0,managedServices:t,sshKeys:hn(Yi(e)).map((r)=>({name:r.name,type:r.type,fingerprint:r.fingerprint,added:r.added}))}:void 0,sites:Object.fromEntries(Object.entries(e.sites??{}).map(([r,n])=>[r,{domain:n.domain,path:n.path,type:n.type,deploy:n.deploy,root:n.root,port:n.port,ssl:n.ssl}]))}}function Hu(e){return[{id:"status",label:"Refresh Cloud Status",description:"Runs the local ts-cloud status checks against configured providers.",command:["status","--env",e],mutates:!1},{id:"doctor",label:"Run Doctor",description:"Checks local tooling, credentials, and provider access.",command:["doctor"],mutates:!1},{id:"security-scan",label:"Security Scan",description:"Runs the pre-deploy scanner from this checkout.",command:["deploy:security-scan","--source",".","--fail-on","critical"],mutates:!1},{id:"deploy",label:"Deploy Environment",description:"Deploys the selected environment from the local checkout.",command:["deploy","--env",e,"--yes"],mutates:!0,confirm:"deploy"}]}function Kb(e,t){return Hu(t).find((r)=>r.id===e)}function wb(e){if(e.length<=yb)return e;return`${e.slice(0,yb)}
670
670
 
671
- [output truncated]`}async function kb(e,t,r){let n=e.getReader(),i=new TextDecoder,o="";while(!0){let{done:c,value:d}=await n.read();if(c)break;let a=i.decode(d,{stream:!0});if(o+=a,a)r?.(t,a)}let s=i.decode();if(s)o+=s,r?.(t,s);return o}async function qu(e,t){let r=Bun.spawn([process.execPath,t.cliEntry,...e.command],{cwd:t.cwd,stdout:"pipe",stderr:"pipe",env:{...process.env,...t.env}}),n=()=>{try{r.kill()}catch{}};if(t.signal?.aborted)n();else t.signal?.addEventListener("abort",n,{once:!0});try{let[i,o,s]=await Promise.all([kb(r.stdout,"stdout",t.onOutput),kb(r.stderr,"stderr",t.onOutput),r.exited]);return{action:e.id,command:["cloud",...e.command].join(" "),exitCode:s,ok:s===0,stdout:wb(i),stderr:wb(o)}}finally{t.signal?.removeEventListener("abort",n)}}function A_(){return Object.entries(process.env).filter(([e,t])=>!!t&&t.length>=8&&/(?:secret|token|password|passwd|private|credential|api.?key|access.?key)/i.test(e)).map(([,e])=>e)}var C_=new Set(["/server/sites","/server/deployments","/server/logs","/integrations","/applications/new","/applications/compose","/operations/queue","/operations/previews","/operations/releases","/operations/workloads","/operations/observability","/operations/alerts","/operations/jobs","/data/backups","/account/security","/security","/access-denied"]);function P_(e){let t=Vo(e);if(t&&t!==".html")return!1;let r=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(r==="/")return!1;return!C_.has(r)}var __={"/":"runtime:read","/server/activity":"audit:read","/server/sites":"project:read","/server/deployments":"deployments:read","/server/logs":"runtime:logs","/server/metrics":"runtime:read","/server/services":"runtime:read","/data/backups":"backups:read","/data/volumes":"data:read","/server/fleet":"fleet:read","/server/capacity":"fleet:read","/server/actions":"runtime:restart","/server/database":"data:read","/server/firewall":"fleet:read","/infrastructure/topology":"fleet:read","/server/security":"security:read","/security":"security:read","/integrations":"sources:read","/applications/new":"applications:read","/applications/compose":"applications:read","/operations/queue":"deployments:read","/operations/previews":"deployments:read","/operations/releases":"deployments:read","/operations/regions":"deployments:read","/operations/maintenance":"deployments:read","/operations/workloads":"runtime:read","/operations/observability":"runtime:logs","/operations/alerts":"runtime:read","/operations/jobs":"automation:read","/operations/configuration":"config:read","/server/ssh-keys":"fleet:read","/server/terminal":"runtime:terminal","/server/team":"users:read","/account/security":"project:read","/account/automation":"users:read","/serverless":"project:read","/serverless/deployments":"deployments:read","/serverless/logs":"runtime:logs","/serverless/metrics":"runtime:read","/serverless/traces":"runtime:read","/serverless/functions":"config:read","/serverless/queues":"data:read","/serverless/data":"data:read","/serverless/assets":"project:read","/serverless/secrets":"secrets:read","/serverless/firewall":"fleet:read","/serverless/alarms":"runtime:read","/serverless/cost":"project:read"};function Ib(e,t){if(t.role==="admin")return!0;let r=Vo(e);if(r&&r!==".html")return!0;if(t.organizationSource==="legacy")return!P_(e);let n=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(n==="/access-denied")return!0;let i=__[n];return!!i&&!!t.capabilities?.includes(i)}function T_(e,t){let r=decodeURIComponent(t).replace(/^\/+/,""),i=XP(r===""?"index.html":r);if(i.startsWith("..")||i.includes("/../"))return null;let o=Te(e,i);if(qr(o)&&!Vb(o).isDirectory())return o;if(!Vo(o)&&qr(`${o}.html`))return`${o}.html`;if(!Vo(o)&&qr(Te(o,"index.html")))return Te(o,"index.html");return null}async function Eb(e,t){let r=T_(e,t);if(!r){let o=Te(e,"404.html");if(qr(o))return new Response(await br(o),{status:404,headers:{"content-type":"text/html; charset=utf-8"}});return ic("Not found",404)}if(Vb(r).isDirectory())return ic("Not found",404);let n=await br(r),i=c_[Vo(r)]??"application/octet-stream";return new Response(n,{headers:{"content-type":i}})}var rc=["observe","backup","restore","restart","resize","version","rotate","expose","delete","logs","slow_queries","users","databases"],Rb=new WeakMap;async function Ab(e){let t=Rb.get(e);if(t)return t;let r=await import("./spend/index.js"),n=new r.SpendStore(e),i={store:n,service:new r.SpendService(n),gate:new r.SpendGate(e)};return Rb.set(e,i),i}async function x_(e={}){a_();let t=e.cwd??process.cwd(),r=e.host??i_,n=e.port??o_,i=e.cliEntry??process.argv[1];if(e.box)process.env.TS_CLOUD_DASHBOARD_BOX="1";await h_(t);let o=e.config??await yh(),s=process.env.TS_CLOUD_DASHBOARD_DB_PASSWORD,c=gt(o);if(s&&c&&!c.password)c.password=s;let d=o.infrastructure?.compute?.managedServices?.vitess;if(s&&d&&typeof d==="object"&&!d.password)d.password=s;let a=yp(t,o);if(a.reconciliation.failed>0)console.warn(` ts-cloud dashboard: marked ${a.reconciliation.failed} orphaned operation(s) as failed after restart.`);let u=Object.keys(o.environments??{}),m=g_(o,e.environment),h=y_(t),y=await ei(o,m),w=new Map([[m,y]]),k=new Map([[m,Date.now()]]),C=new Map([[m,Date.now()]]),T=new Map,M=Math.min(300000,Math.max(5000,Number(process.env.TS_CLOUD_DASHBOARD_REFRESH_MS)||30000)),P=Math.min(1800000,Math.max(60000,Number(process.env.TS_CLOUD_DASHBOARD_SITE_REFRESH_MS)||300000)),O=Fr(o)!=="serverless",U=(f)=>{let X=w.get(f);if(X&&!vb(k.get(f),Date.now(),M))return Promise.resolve(X);let te=T.get(f);if(te)return te;let Z=!O||vb(C.get(f),Date.now(),P),ae=ei(o,f,{includeSiteHealth:Z}).then((Ie)=>{let S=w.get(f),ht=Z?Ie:I_(S,Ie);if(w.set(f,ht),k.set(f,Date.now()),Z)C.set(f,Date.now());if(S?._serverReachable!==ht._serverReachable||S?._metricsStatus!==ht._metricsStatus||(S?.sitesDetail?.length??0)!==(ht.sitesDetail?.length??0))de();return ht}).finally(()=>T.delete(f));return T.set(f,ae),ae},q=Wu(t),N=process.env.TS_CLOUD_DASHBOARD_TELEMETRY?.trim();if(e.box&&N!=="0"&&(N==="1"||!o.cloud?.attachTo)){let f=!1,X=Date.now()+300000,te=async()=>{if(f)return;f=!0;try{let ae=Date.now(),Ie=ae>=X;if(Ie)X=ae+300000;let S=a.environments.get(m);await zu({controlPlane:a.store,projectId:a.project.id,environmentId:S?.id,config:o,environment:m,force:!0,lightweight:!0,includeSiteHealth:Ie})}catch(ae){if(e.verbose)console.warn(` ts-cloud dashboard: background telemetry collection failed: ${ae instanceof Error?ae.message:String(ae)}`)}finally{f=!1}};te(),setInterval(()=>void te(),60000).unref?.()}let D=new Map,Y=new Map,se=new Set,he=0;function je(f,X){if(f.role==="admin"&&!a.store.getActorByExternalId("user",`dashboard:${f.username.toLowerCase()}`))return f;let te=a.store.getActorByExternalId("user",`dashboard:${f.username.toLowerCase()}`),Z=te?a.store.getMembershipForActor(a.organization.id,te.id):void 0;if(!Z||Z.status!=="active")return{...f,role:"member",sites:{},capabilities:[]};let ae=a.store.listGrants(Z.id),Ie=a.store.resolveAuthorizationTarget(a.organization.id,Z.scope)??a.store.resolveAuthorizationTarget(a.organization.id,{type:"project",id:a.project.id}),S=qo({membership:Z,grants:ae,target:Ie});if(Z.roleTemplate==="owner"||Z.roleTemplate==="admin")return{...f,role:"admin",sites:{},organizationRole:Z.roleTemplate,organizationSource:Z.source,capabilities:S};let ht=a.environments.get(X),Ke={};for(let ue of a.store.listResources(a.project.id,ht?.id).filter((fe)=>fe.kind==="application")){let fe=a.store.resolveAuthorizationTarget(a.organization.id,{type:"resource",id:ue.id});if(!fe||!er({membership:Z,grants:ae,capability:"project:read",target:fe}).allowed)continue;Ke[ue.slug]=er({membership:Z,grants:ae,capability:"config:write",target:fe}).allowed?"owner":"collaborator"}return{...f,role:"member",sites:Ke,organizationRole:Z.roleTemplate,organizationSource:Z.source,capabilities:S}}function de(){he+=1,D.clear();for(let f of se)ti(f,{recursive:!0,force:!0});se.clear()}let Re=(f,X)=>`${X}:${f.role==="admin"?"admin":`member:${Object.entries(f.sites).sort(([te],[Z])=>te.localeCompare(Z)).map(([te,Z])=>`${te}=${Z}`).join(",")}`}:${[...f.capabilities??[]].sort().join(",")}`;async function Me(f,X){let te=je(f,X),Z=Re(te,X),ae=D.get(Z);if(ae)return ae;let Ie=Y.get(Z);if(Ie)return Ie;let S=he,ht=(async()=>{let Ke=w.get(X)??await ei(o,X);w.set(X,Ke);let ue={..._u(Ke,{user:te,slug:o.project.slug}),viewer:{role:te.role,organizationRole:te.organizationRole,organizationSource:te.organizationSource,capabilities:te.capabilities??[]}},fe=await R_(t,ue);if(fe&&S!==he)return ti(fe,{recursive:!0,force:!0}),q?.uiRoot;if(fe)se.add(fe);let at=fe??q?.uiRoot;if(at)D.set(Z,at);return at})();Y.set(Z,ht);try{return await ht}finally{Y.delete(Z)}}let me=await Me({username:"",passwordHash:"",role:"admin",sites:{}},m);if(!me)throw Error("ts-cloud dashboard UI not found. Run `bun run build` in ts-cloud or reinstall the package.");let R=new WeakMap,j=process.env.TS_CLOUD_DASHBOARD_TERMINAL!=="0",F=process.env.TS_CLOUD_DASHBOARD_AUTH==="0";if(F&&e.box)throw Error("TS_CLOUD_DASHBOARD_AUTH=0 is refused in box mode: the dashboard is internet-facing there, and disabling auth would expose a root shell.");let K=!F,ye=rv(t),Ae=K?sv(t,process.env.TS_CLOUD_UI_USERNAME?.trim()||"admin"):void 0,G=new Ss(a.store,{encryptionKey:on(t)}),be=new Is(a.store),ge=new To(a.store),oe=new jc(a.store,{encryptionKey:on(t)}),ft=new Ec(a.store),ri=new Pc(a.store,{cwd:t}),dr=new Ac(a.store,{encryptionKey:on(t)}),xe=new $e(a.store,{workerId:`dashboard:${process.pid}`}),Be=new hd(a.store),Sr=new Ad(a.store,on(t)),Vr=new Pl(a.store),Wo=new $s(Be,xe,Sr),Wr=o.project?.region??"us-east-1",Ku=on(t),xt=new Dl(Vr,{encryptionKey:Ku,backends:[new Ao(a.store,Ku),new _l(new Yr(Wr),Wr),new Tl(new qb(Wr),Wr),new xl]});await Rh(xt,a,o);let oc=new Fn(Wr),Jb={aws_rds:new yd(new Id(oc)),aws_aurora:new vd(new Ed(oc)),aws_elasticache:new bd(new Rd(new Ms(Wr))),server:new Sd(new Ii),container:new wd(new Ii)},Ju=(f)=>Jb[f.provider],Je=new pd(a.store),Sn=new xs(Je,xe),Gu=new gd(Sr),Gb={managed_database:new fd(Be,oc),logical_database:new Td(Be,Sr),volume:new Dd,files:new _d(t),control_plane:new $d(a.store,t),infrastructure:new jd(new Us(Wr))},Qb=(f)=>Gb[f.resourceKind],Yb=(f)=>f.provider==="aws_backup"?void 0:Gu,sc=new Db(a.store),ac=[new Nb,new jb(yt(t,"volumes"))],wr=new Ob(sc,ac,xe),Zi=new $l(a.store),lr=new Nl(Zi,[new Co("aws"),new Co("hetzner"),new Co("ssh")],xe),Hr=new Ul(a.store),Qu=new ql(Hr,Zi),wn=new Kl(a.store),Yu=new Jl(wn,xe),kr=new Bl(a.store),cc=new Ll(kr,xe),Zu=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((f)=>new zl(f,a.store,a.project.id,a.organization.id)),ot=new cd(a.store),Xu=new sd(ot,{queue:xe}),He=new hs(a.store),Kr=new ys(a.store),zt=new Dn(a.store),le=new Mb(a.store,{encryptionKey:on(t)}),Zb=()=>Ab(a.store);for(let f of a.environments.values())od(ot,o,{organization:a.organization,project:a.project,environment:f,resources:a.store.listResources(a.project.id,f.id)});let Ut=new Bb(le,{emailImpl:async(f)=>{let{email:X}=await import("./chunk-q816js1y.js");return X.send(f)}}),ep=async(f)=>{let X=Ub(le,a.project.id,f),te=[];for(let Z of X.filter((ae)=>ae.notify&&ae.alert))te.push(...await Ut.deliverAll(Ut.enqueue(a.organization.id,Z.alert,Z.transition)));return te.push(...await Ut.deliverAll(Ut.enqueueRemindersAndEscalations(a.organization.id,le.listAlerts(a.project.id,{environmentId:f,states:["firing"]})))),te.push(...await Ut.retryDue()),{evaluations:X,deliveries:te}},dc=!1,Xb=async()=>{if(dc)return;dc=!0;try{for(let f of a.environments.values())for(let X of le.listHealthChecks(a.project.id,f.id).filter((te)=>te.enabled)){let te=le.listHealthResults(X.id,1)[0];if(te&&Date.now()-new Date(te.checkedAt).getTime()<X.intervalSeconds*1000)continue;let Z=await new Gi(le).runAndEvaluate(X);for(let ae of Z.evaluations.filter((Ie)=>Ie.notify&&Ie.alert))await Ut.deliverAll(Ut.enqueue(a.organization.id,ae.alert,ae.transition))}}finally{dc=!1}},tp=setInterval(()=>{for(let f of a.environments.values())ep(f.id).catch((X)=>console.error("ts-cloud alert evaluation failed:",X))},60000);tp.unref?.();let rp=setInterval(()=>{Xb().catch((f)=>console.error("ts-cloud health check evaluation failed:",f))},30000);rp.unref?.();let np=setInterval(()=>{try{Xu.tick()}catch(f){console.error("ts-cloud scheduled job evaluation failed:",f)}},30000);np.unref?.();let ip=setInterval(()=>{try{Sn.enqueueDue(),Sn.enqueueRetention()}catch(f){console.error("ts-cloud backup policy evaluation failed:",f)}},30000);ip.unref?.(),He.cleanup();let op=setInterval(()=>{try{He.cleanup()}catch(f){console.error("ts-cloud preview cleanup failed:",f)}},3600000);op.unref?.();let eS=e.queueWorker??!0,tS=A_(),rS=async(f,X)=>{let Z=(f.environmentId?a.store.listEnvironments(f.projectId).find((ae)=>ae.id===f.environmentId):void 0)?.slug??String(m);if(X.kind==="dashboard_operation"&&X.operationId){let ae=w.get(Z)??y,Ie=Pu(X.operationId,o,ae);if(!Ie||Ie.danger||!["scheduler","backup","worker"].includes(Ie.group))return{ok:!1,stderr:"The allowlisted dashboard operation is no longer available."};let S=await Qa(o,Z,Ie);return{ok:S.ok,stdout:S.stdout,stderr:S.stderr??S.error,retryable:/temporar|unavailable|timeout|network/i.test(S.stderr??S.error??""),output:{command:S.command??null,operation:S.operation}}}if(X.kind==="serverless_scheduler"){let ae=await Mu(o,Z,"run");return{ok:ae.ok,stdout:ae.stdout,stderr:ae.error,retryable:/temporar|unavailable|timeout|network/i.test(ae.error??""),output:{command:ae.command??null,operation:"serverless_scheduler"}}}return{ok:!1,stderr:`No safe executor is configured for ${X.kind}.`}},Ho=eS?new Tb(xe,{...xb({store:a.store,execute:async(f,X)=>{let te=X.operation.input&&typeof X.operation.input==="object"&&!Array.isArray(X.operation.input)?X.operation.input:{},Z=te.source&&typeof te.source==="object"?te.source:void 0,ae=t,Ie,S,ht;try{if(Z?.bindingId&&Z?.connectionId&&Z?.commitSha){let ue=oe.getBinding(String(Z.bindingId)),fe=oe.getConnection(String(Z.connectionId));if(!ue||!fe||ue.connectionId!==fe.id)throw Error("Queued source binding is no longer available");let tt=(ue.repositoryId?oe.getRepository(ue.repositoryId):oe.listRepositories(fe.id).find((oi)=>oi.fullName.toLowerCase()===ue.repositoryFullName.toLowerCase()))?.cloneUrl;if(!tt&&fe.provider==="generic_ssh")tt=`git@${new URL(fe.host).hostname}:${ue.repositoryFullName}.git`;if(!tt)tt=new URL(`/${ue.repositoryFullName}.git`,fe.host.endsWith("/")?fe.host:`${fe.host}/`).href;let V=ue.deployKeyId?oe.getDeployKey(ue.deployKeyId):void 0,Le=V&&ue.deployKeyId?{...V,privateKey:oe.getDeployPrivateKey(ue.deployKeyId)}:void 0;if(["github","gitlab","bitbucket","gitea"].includes(fe.provider)&&f.target.previewId){let oi=tn(fe,oe.getCredential(fe.id)),B=He.previews.getInstance(f.target.previewId);ht=async(qt,Yo)=>{try{await oi.setCommitStatus(ue.repositoryFullName,String(Z.commitSha),{state:qt,url:B?.url,description:Yo})}catch(si){X.log(`Could not publish source status: ${si instanceof Error?si.message:String(si)}`,{stream:"stderr"})}},await ht("pending",`Preview deployment started for ${String(Z.commitSha).slice(0,12)}`)}Ie=Vu(Te(nc(),"ts-cloud-queued-source-")),X.log(`Checking out immutable source commit ${Z.commitSha}.`,{stream:"system"}),ae=(await Lc({remote:tt,binding:ue,destination:Te(Ie,"checkout"),ref:String(Z.branch??ue.defaultBranch),commitSha:String(Z.commitSha)},{credential:oe.getCredential(fe.id),deployKey:Le})).directory}if(X.operation.kind!=="preview.destroy"){let ue=f.target.previewId?He.previews.getInstance(f.target.previewId):void 0,fe=ue?He.previews.getDefinition(ue.definitionId):void 0,at=X.operation.resourceId?a.store.getResource(X.operation.resourceId):void 0;if(S=await xt.resolve({projectId:a.project.id,environmentId:X.operation.environmentId,resourceId:X.operation.resourceId,functionId:at?.kind==="function"?at.id:void 0,previewId:ue?.id,trustedPreview:!!ue&&!ue.fork,allowedPreviewSecrets:fe?.inheritedSecrets}),S.warnings.some((tt)=>tt.code==="missing_required"))throw Error(`Required deployment configuration is unavailable: ${S.warnings.filter((tt)=>tt.code==="missing_required").map((tt)=>tt.key).join(", ")}`);if(X.operation.resourceId)for(let tt of Object.values(S.entries))Vr.setDependency({entryId:tt.id,resourceId:X.operation.resourceId,injectionTarget:"environment",required:tt.required,requiresRedeploy:!0});X.log(`Resolved configuration ${S.configurationHash.slice(0,18)} for ${Object.keys(S.values).length} keys.`,{stream:"system"})}let Ke=await qu(f,{cwd:ae,cliEntry:i,signal:X.signal,env:S?.values,onOutput:(ue,fe)=>X.log(fe,{stream:ue,step:"execute",secrets:[...tS,...Object.entries(S?.entries??{}).filter(([,at])=>at.kind==="secret").map(([at])=>S.values[at]).filter(Boolean)]})});if(Ke.ok&&X.operation.resourceId&&S)for(let ue of Object.values(S.entries))Vr.setDependency({entryId:ue.id,resourceId:X.operation.resourceId,injectionTarget:"environment",required:ue.required,requiresRedeploy:!1,lastDeployedVersion:ue.version});return await ht?.(Ke.ok?"success":"failure",Ke.ok?`Preview is ready at ${String(Z?.commitSha).slice(0,12)}`:`Preview deployment failed at ${String(Z?.commitSha).slice(0,12)}`),Ke}catch(Ke){throw await ht?.("error",`Preview deployment could not complete at ${String(Z?.commitSha).slice(0,12)}`),Ke}finally{if(Ie)ti(Ie,{recursive:!0,force:!0})}}}),...Sg({store:ot,executor:rS}),...Dg({store:Be,secrets:Sr,resolveAdapter:Ju}),...Ph(Zi,lr.drivers),...Gh(wn,[new Gl("aws","AWS regional execution requires an injected AwsRegionalTransport; topology and plans were preserved without provider mutation.")]),...zh({store:kr,cleanup:Zu}),...$b(sc,ac),...Pg({store:Je,queue:xe,resolveSource:Qb,resolveDestination:Yb,validateHealth:async(f,X)=>{if(!f.healthCheckId)return{healthy:!0,mode:"adapter"};let te=le.getHealthCheck(f.healthCheckId);if(!te||te.projectId!==f.projectId)return{healthy:!1,error:"Configured restore health check was not found."};let Z=await new Gi(le).runAndEvaluate(te);return{healthy:Z.result.status==="healthy",healthCheckId:te.id,healthResultId:Z.result.id,target:X}}}),...Im({store:a.store,resolveDriver:e.releaseDriver??((f)=>({name:`${a.store.getResource(f.resourceId)?.provider??"provider"} release driver`,capability:()=>({strategy:f.strategy,supported:!1,explanation:"This dashboard process has no immutable activation driver configured for the target provider.",capacityMultiplier:1,costImpact:"none",rollback:"The previous release remains preserved; configure a release driver before retrying."}),activate:async()=>{throw Error("Immutable activation driver is not configured")},rollback:async()=>{throw Error("Immutable rollback driver is not configured")}})),resolveHealthGate:async(f,X)=>{let te=le.listHealthChecks(X.projectId,X.environmentId).find((ae)=>ae.enabled&&ae.name===f&&(!ae.resourceId||ae.resourceId===X.resourceId));if(!te)return{healthy:!1,message:`Named health gate ${f} was not found for this release.`};let Z=await new Gi(le).runAndEvaluate(te);return{healthy:Z.result.status==="healthy",evidence:{healthCheckId:te.id,healthResultId:Z.result.id,status:Z.result.status,timings:Z.result.timings},message:Z.result.message}}})},{parallelism:e.queueParallelism??(Number(process.env.TS_CLOUD_QUEUE_PARALLELISM)||8),onError:(f)=>console.error("ts-cloud deployment queue worker failed:",f)}):void 0;if(vy(a),$a(ge,ar(a,String(m)),y),Ae)Zo(a,Ae.users),dv(G,a,Ae.users);let ze=av({cwd:t,enabled:K,secret:ye,authentication:G,authorization:{store:a.store,organizationId:a.organization.id,projectId:a.project.id,defaultEnvironment:String(m)}}),Ge=new Xl,sp=setInterval(()=>Ge.sweep(),60000);sp.unref?.();let Ko=new Bo,lc=new Bo(3,900000,900000),Jo=new Bo(8,900000,900000),ap=setInterval(()=>Ko.prune(),300000),cp=setInterval(()=>lc.prune(),300000),dp=setInterval(()=>Jo.prune(),300000);if(ap.unref?.(),cp.unref?.(),dp.unref?.(),K){if(Ae?.generated)console.warn(`
671
+ [output truncated]`}async function kb(e,t,r){let n=e.getReader(),i=new TextDecoder,o="";while(!0){let{done:c,value:d}=await n.read();if(c)break;let a=i.decode(d,{stream:!0});if(o+=a,a)r?.(t,a)}let s=i.decode();if(s)o+=s,r?.(t,s);return o}async function qu(e,t){let r=Bun.spawn([process.execPath,t.cliEntry,...e.command],{cwd:t.cwd,stdout:"pipe",stderr:"pipe",env:{...process.env,...t.env}}),n=()=>{try{r.kill()}catch{}};if(t.signal?.aborted)n();else t.signal?.addEventListener("abort",n,{once:!0});try{let[i,o,s]=await Promise.all([kb(r.stdout,"stdout",t.onOutput),kb(r.stderr,"stderr",t.onOutput),r.exited]);return{action:e.id,command:["cloud",...e.command].join(" "),exitCode:s,ok:s===0,stdout:wb(i),stderr:wb(o)}}finally{t.signal?.removeEventListener("abort",n)}}function A_(){return Object.entries(process.env).filter(([e,t])=>!!t&&t.length>=8&&/(?:secret|token|password|passwd|private|credential|api.?key|access.?key)/i.test(e)).map(([,e])=>e)}var C_=new Set(["/server/sites","/server/deployments","/server/logs","/integrations","/applications/new","/applications/compose","/operations/queue","/operations/previews","/operations/releases","/operations/workloads","/operations/observability","/operations/alerts","/operations/jobs","/data/backups","/account/security","/security","/access-denied"]);function P_(e){let t=Vo(e);if(t&&t!==".html")return!1;let r=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(r==="/")return!1;return!C_.has(r)}var __={"/":"runtime:read","/server/activity":"audit:read","/server/sites":"project:read","/server/deployments":"deployments:read","/server/logs":"runtime:logs","/server/metrics":"runtime:read","/server/services":"runtime:read","/data/backups":"backups:read","/data/volumes":"data:read","/server/fleet":"fleet:read","/server/capacity":"fleet:read","/server/actions":"runtime:restart","/server/database":"data:read","/server/firewall":"fleet:read","/infrastructure/topology":"fleet:read","/server/security":"security:read","/security":"security:read","/integrations":"sources:read","/applications/new":"applications:read","/applications/compose":"applications:read","/operations/queue":"deployments:read","/operations/previews":"deployments:read","/operations/releases":"deployments:read","/operations/regions":"deployments:read","/operations/maintenance":"deployments:read","/operations/workloads":"runtime:read","/operations/observability":"runtime:logs","/operations/alerts":"runtime:read","/operations/jobs":"automation:read","/operations/configuration":"config:read","/server/ssh-keys":"fleet:read","/server/terminal":"runtime:terminal","/server/team":"users:read","/account/security":"project:read","/account/automation":"users:read","/serverless":"project:read","/serverless/deployments":"deployments:read","/serverless/logs":"runtime:logs","/serverless/metrics":"runtime:read","/serverless/traces":"runtime:read","/serverless/functions":"config:read","/serverless/queues":"data:read","/serverless/data":"data:read","/serverless/assets":"project:read","/serverless/secrets":"secrets:read","/serverless/firewall":"fleet:read","/serverless/alarms":"runtime:read","/serverless/cost":"project:read"};function Ib(e,t){if(t.role==="admin")return!0;let r=Vo(e);if(r&&r!==".html")return!0;if(t.organizationSource==="legacy")return!P_(e);let n=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(n==="/access-denied")return!0;let i=__[n];return!!i&&!!t.capabilities?.includes(i)}function T_(e,t){let r=decodeURIComponent(t).replace(/^\/+/,""),i=XP(r===""?"index.html":r);if(i.startsWith("..")||i.includes("/../"))return null;let o=Te(e,i);if(qr(o)&&!Vb(o).isDirectory())return o;if(!Vo(o)&&qr(`${o}.html`))return`${o}.html`;if(!Vo(o)&&qr(Te(o,"index.html")))return Te(o,"index.html");return null}async function Eb(e,t){let r=T_(e,t);if(!r){let o=Te(e,"404.html");if(qr(o))return new Response(await br(o),{status:404,headers:{"content-type":"text/html; charset=utf-8"}});return ic("Not found",404)}if(Vb(r).isDirectory())return ic("Not found",404);let n=await br(r),i=c_[Vo(r)]??"application/octet-stream";return new Response(n,{headers:{"content-type":i}})}var rc=["observe","backup","restore","restart","resize","version","rotate","expose","delete","logs","slow_queries","users","databases"],Rb=new WeakMap;async function Ab(e){let t=Rb.get(e);if(t)return t;let r=await import("./spend/index.js"),n=new r.SpendStore(e),i={store:n,service:new r.SpendService(n),gate:new r.SpendGate(e)};return Rb.set(e,i),i}async function x_(e={}){a_();let t=e.cwd??process.cwd(),r=e.host??i_,n=e.port??o_,i=e.cliEntry??process.argv[1];if(e.box)process.env.TS_CLOUD_DASHBOARD_BOX="1";await h_(t);let o=e.config??await yh(),s=process.env.TS_CLOUD_DASHBOARD_DB_PASSWORD,c=gt(o);if(s&&c&&!c.password)c.password=s;let d=o.infrastructure?.compute?.managedServices?.vitess;if(s&&d&&typeof d==="object"&&!d.password)d.password=s;let a=yp(t,o);if(a.reconciliation.failed>0)console.warn(` ts-cloud dashboard: marked ${a.reconciliation.failed} orphaned operation(s) as failed after restart.`);let u=Object.keys(o.environments??{}),m=g_(o,e.environment),h=y_(t),y=await ei(o,m),w=new Map([[m,y]]),k=new Map([[m,Date.now()]]),C=new Map([[m,Date.now()]]),T=new Map,M=Math.min(300000,Math.max(5000,Number(process.env.TS_CLOUD_DASHBOARD_REFRESH_MS)||30000)),P=Math.min(1800000,Math.max(60000,Number(process.env.TS_CLOUD_DASHBOARD_SITE_REFRESH_MS)||300000)),O=Fr(o)!=="serverless",U=(f)=>{let X=w.get(f);if(X&&!vb(k.get(f),Date.now(),M))return Promise.resolve(X);let te=T.get(f);if(te)return te;let Z=!O||vb(C.get(f),Date.now(),P),ae=ei(o,f,{includeSiteHealth:Z}).then((Ie)=>{let S=w.get(f),ht=Z?Ie:I_(S,Ie);if(w.set(f,ht),k.set(f,Date.now()),Z)C.set(f,Date.now());if(S?._serverReachable!==ht._serverReachable||S?._metricsStatus!==ht._metricsStatus||(S?.sitesDetail?.length??0)!==(ht.sitesDetail?.length??0))de();return ht}).finally(()=>T.delete(f));return T.set(f,ae),ae},q=Wu(t),N=process.env.TS_CLOUD_DASHBOARD_TELEMETRY?.trim();if(e.box&&N!=="0"&&(N==="1"||!o.cloud?.attachTo)){let f=!1,X=Date.now()+300000,te=async()=>{if(f)return;f=!0;try{let ae=Date.now(),Ie=ae>=X;if(Ie)X=ae+300000;let S=a.environments.get(m);await zu({controlPlane:a.store,projectId:a.project.id,environmentId:S?.id,config:o,environment:m,force:!0,lightweight:!0,includeSiteHealth:Ie})}catch(ae){if(e.verbose)console.warn(` ts-cloud dashboard: background telemetry collection failed: ${ae instanceof Error?ae.message:String(ae)}`)}finally{f=!1}};te(),setInterval(()=>void te(),60000).unref?.()}let D=new Map,Y=new Map,se=new Set,he=0;function je(f,X){if(f.role==="admin"&&!a.store.getActorByExternalId("user",`dashboard:${f.username.toLowerCase()}`))return f;let te=a.store.getActorByExternalId("user",`dashboard:${f.username.toLowerCase()}`),Z=te?a.store.getMembershipForActor(a.organization.id,te.id):void 0;if(!Z||Z.status!=="active")return{...f,role:"member",sites:{},capabilities:[]};let ae=a.store.listGrants(Z.id),Ie=a.store.resolveAuthorizationTarget(a.organization.id,Z.scope)??a.store.resolveAuthorizationTarget(a.organization.id,{type:"project",id:a.project.id}),S=qo({membership:Z,grants:ae,target:Ie});if(Z.roleTemplate==="owner"||Z.roleTemplate==="admin")return{...f,role:"admin",sites:{},organizationRole:Z.roleTemplate,organizationSource:Z.source,capabilities:S};let ht=a.environments.get(X),Ke={};for(let ue of a.store.listResources(a.project.id,ht?.id).filter((fe)=>fe.kind==="application")){let fe=a.store.resolveAuthorizationTarget(a.organization.id,{type:"resource",id:ue.id});if(!fe||!er({membership:Z,grants:ae,capability:"project:read",target:fe}).allowed)continue;Ke[ue.slug]=er({membership:Z,grants:ae,capability:"config:write",target:fe}).allowed?"owner":"collaborator"}return{...f,role:"member",sites:Ke,organizationRole:Z.roleTemplate,organizationSource:Z.source,capabilities:S}}function de(){he+=1,D.clear();for(let f of se)ti(f,{recursive:!0,force:!0});se.clear()}let Re=(f,X)=>`${X}:${f.role==="admin"?"admin":`member:${Object.entries(f.sites).sort(([te],[Z])=>te.localeCompare(Z)).map(([te,Z])=>`${te}=${Z}`).join(",")}`}:${[...f.capabilities??[]].sort().join(",")}`;async function Me(f,X){let te=je(f,X),Z=Re(te,X),ae=D.get(Z);if(ae)return ae;let Ie=Y.get(Z);if(Ie)return Ie;let S=he,ht=(async()=>{let Ke=w.get(X)??await ei(o,X);w.set(X,Ke);let ue={..._u(Ke,{user:te,slug:o.project.slug}),viewer:{role:te.role,organizationRole:te.organizationRole,organizationSource:te.organizationSource,capabilities:te.capabilities??[]}},fe=await R_(t,ue);if(fe&&S!==he)return ti(fe,{recursive:!0,force:!0}),q?.uiRoot;if(fe)se.add(fe);let at=fe??q?.uiRoot;if(at)D.set(Z,at);return at})();Y.set(Z,ht);try{return await ht}finally{Y.delete(Z)}}let me=await Me({username:"",passwordHash:"",role:"admin",sites:{}},m);if(!me)throw Error("ts-cloud dashboard UI not found. Run `bun run build` in ts-cloud or reinstall the package.");let R=new WeakMap,j=process.env.TS_CLOUD_DASHBOARD_TERMINAL!=="0",F=process.env.TS_CLOUD_DASHBOARD_AUTH==="0";if(F&&e.box)throw Error("TS_CLOUD_DASHBOARD_AUTH=0 is refused in box mode: the dashboard is internet-facing there, and disabling auth would expose a root shell.");let K=!F,ye=rv(t),Ae=K?sv(t,process.env.TS_CLOUD_UI_USERNAME?.trim()||"admin"):void 0,G=new Ss(a.store,{encryptionKey:on(t)}),be=new Is(a.store),ge=new To(a.store),oe=new jc(a.store,{encryptionKey:on(t)}),ft=new Ec(a.store),ri=new Pc(a.store,{cwd:t}),dr=new Ac(a.store,{encryptionKey:on(t)}),xe=new $e(a.store,{workerId:`dashboard:${process.pid}`}),Be=new hd(a.store),Sr=new Ad(a.store,on(t)),Vr=new Pl(a.store),Wo=new $s(Be,xe,Sr),Wr=o.project?.region??"us-east-1",Ku=on(t),xt=new Dl(Vr,{encryptionKey:Ku,backends:[new Ao(a.store,Ku),new _l(new Yr(Wr),Wr),new Tl(new qb(Wr),Wr),new xl]});await Rh(xt,a,o);let oc=new Fn(Wr),Jb={aws_rds:new yd(new Id(oc)),aws_aurora:new vd(new Ed(oc)),aws_elasticache:new bd(new Rd(new Ms(Wr))),server:new Sd(new Ii),container:new wd(new Ii)},Ju=(f)=>Jb[f.provider],Je=new pd(a.store),Sn=new xs(Je,xe),Gu=new gd(Sr),Gb={managed_database:new fd(Be,oc),logical_database:new Td(Be,Sr),volume:new Dd,files:new _d(t),control_plane:new $d(a.store,t),infrastructure:new jd(new Us(Wr))},Qb=(f)=>Gb[f.resourceKind],Yb=(f)=>f.provider==="aws_backup"?void 0:Gu,sc=new Db(a.store),ac=[new Nb,new jb(yt(t,"volumes"))],wr=new Ob(sc,ac,xe),Zi=new $l(a.store),lr=new Nl(Zi,[new Co("aws"),new Co("hetzner"),new Co("ssh")],xe),Hr=new Ul(a.store),Qu=new ql(Hr,Zi),wn=new Kl(a.store),Yu=new Jl(wn,xe),kr=new Bl(a.store),cc=new Ll(kr,xe),Zu=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((f)=>new zl(f,a.store,a.project.id,a.organization.id)),ot=new cd(a.store),Xu=new sd(ot,{queue:xe}),He=new hs(a.store),Kr=new ys(a.store),zt=new Dn(a.store),le=new Mb(a.store,{encryptionKey:on(t)}),Zb=()=>Ab(a.store);for(let f of a.environments.values())od(ot,o,{organization:a.organization,project:a.project,environment:f,resources:a.store.listResources(a.project.id,f.id)});let Ut=new Bb(le,{emailImpl:async(f)=>{let{email:X}=await import("./chunk-kj7gzdj6.js");return X.send(f)}}),ep=async(f)=>{let X=Ub(le,a.project.id,f),te=[];for(let Z of X.filter((ae)=>ae.notify&&ae.alert))te.push(...await Ut.deliverAll(Ut.enqueue(a.organization.id,Z.alert,Z.transition)));return te.push(...await Ut.deliverAll(Ut.enqueueRemindersAndEscalations(a.organization.id,le.listAlerts(a.project.id,{environmentId:f,states:["firing"]})))),te.push(...await Ut.retryDue()),{evaluations:X,deliveries:te}},dc=!1,Xb=async()=>{if(dc)return;dc=!0;try{for(let f of a.environments.values())for(let X of le.listHealthChecks(a.project.id,f.id).filter((te)=>te.enabled)){let te=le.listHealthResults(X.id,1)[0];if(te&&Date.now()-new Date(te.checkedAt).getTime()<X.intervalSeconds*1000)continue;let Z=await new Gi(le).runAndEvaluate(X);for(let ae of Z.evaluations.filter((Ie)=>Ie.notify&&Ie.alert))await Ut.deliverAll(Ut.enqueue(a.organization.id,ae.alert,ae.transition))}}finally{dc=!1}},tp=setInterval(()=>{for(let f of a.environments.values())ep(f.id).catch((X)=>console.error("ts-cloud alert evaluation failed:",X))},60000);tp.unref?.();let rp=setInterval(()=>{Xb().catch((f)=>console.error("ts-cloud health check evaluation failed:",f))},30000);rp.unref?.();let np=setInterval(()=>{try{Xu.tick()}catch(f){console.error("ts-cloud scheduled job evaluation failed:",f)}},30000);np.unref?.();let ip=setInterval(()=>{try{Sn.enqueueDue(),Sn.enqueueRetention()}catch(f){console.error("ts-cloud backup policy evaluation failed:",f)}},30000);ip.unref?.(),He.cleanup();let op=setInterval(()=>{try{He.cleanup()}catch(f){console.error("ts-cloud preview cleanup failed:",f)}},3600000);op.unref?.();let eS=e.queueWorker??!0,tS=A_(),rS=async(f,X)=>{let Z=(f.environmentId?a.store.listEnvironments(f.projectId).find((ae)=>ae.id===f.environmentId):void 0)?.slug??String(m);if(X.kind==="dashboard_operation"&&X.operationId){let ae=w.get(Z)??y,Ie=Pu(X.operationId,o,ae);if(!Ie||Ie.danger||!["scheduler","backup","worker"].includes(Ie.group))return{ok:!1,stderr:"The allowlisted dashboard operation is no longer available."};let S=await Qa(o,Z,Ie);return{ok:S.ok,stdout:S.stdout,stderr:S.stderr??S.error,retryable:/temporar|unavailable|timeout|network/i.test(S.stderr??S.error??""),output:{command:S.command??null,operation:S.operation}}}if(X.kind==="serverless_scheduler"){let ae=await Mu(o,Z,"run");return{ok:ae.ok,stdout:ae.stdout,stderr:ae.error,retryable:/temporar|unavailable|timeout|network/i.test(ae.error??""),output:{command:ae.command??null,operation:"serverless_scheduler"}}}return{ok:!1,stderr:`No safe executor is configured for ${X.kind}.`}},Ho=eS?new Tb(xe,{...xb({store:a.store,execute:async(f,X)=>{let te=X.operation.input&&typeof X.operation.input==="object"&&!Array.isArray(X.operation.input)?X.operation.input:{},Z=te.source&&typeof te.source==="object"?te.source:void 0,ae=t,Ie,S,ht;try{if(Z?.bindingId&&Z?.connectionId&&Z?.commitSha){let ue=oe.getBinding(String(Z.bindingId)),fe=oe.getConnection(String(Z.connectionId));if(!ue||!fe||ue.connectionId!==fe.id)throw Error("Queued source binding is no longer available");let tt=(ue.repositoryId?oe.getRepository(ue.repositoryId):oe.listRepositories(fe.id).find((oi)=>oi.fullName.toLowerCase()===ue.repositoryFullName.toLowerCase()))?.cloneUrl;if(!tt&&fe.provider==="generic_ssh")tt=`git@${new URL(fe.host).hostname}:${ue.repositoryFullName}.git`;if(!tt)tt=new URL(`/${ue.repositoryFullName}.git`,fe.host.endsWith("/")?fe.host:`${fe.host}/`).href;let V=ue.deployKeyId?oe.getDeployKey(ue.deployKeyId):void 0,Le=V&&ue.deployKeyId?{...V,privateKey:oe.getDeployPrivateKey(ue.deployKeyId)}:void 0;if(["github","gitlab","bitbucket","gitea"].includes(fe.provider)&&f.target.previewId){let oi=tn(fe,oe.getCredential(fe.id)),B=He.previews.getInstance(f.target.previewId);ht=async(qt,Yo)=>{try{await oi.setCommitStatus(ue.repositoryFullName,String(Z.commitSha),{state:qt,url:B?.url,description:Yo})}catch(si){X.log(`Could not publish source status: ${si instanceof Error?si.message:String(si)}`,{stream:"stderr"})}},await ht("pending",`Preview deployment started for ${String(Z.commitSha).slice(0,12)}`)}Ie=Vu(Te(nc(),"ts-cloud-queued-source-")),X.log(`Checking out immutable source commit ${Z.commitSha}.`,{stream:"system"}),ae=(await Lc({remote:tt,binding:ue,destination:Te(Ie,"checkout"),ref:String(Z.branch??ue.defaultBranch),commitSha:String(Z.commitSha)},{credential:oe.getCredential(fe.id),deployKey:Le})).directory}if(X.operation.kind!=="preview.destroy"){let ue=f.target.previewId?He.previews.getInstance(f.target.previewId):void 0,fe=ue?He.previews.getDefinition(ue.definitionId):void 0,at=X.operation.resourceId?a.store.getResource(X.operation.resourceId):void 0;if(S=await xt.resolve({projectId:a.project.id,environmentId:X.operation.environmentId,resourceId:X.operation.resourceId,functionId:at?.kind==="function"?at.id:void 0,previewId:ue?.id,trustedPreview:!!ue&&!ue.fork,allowedPreviewSecrets:fe?.inheritedSecrets}),S.warnings.some((tt)=>tt.code==="missing_required"))throw Error(`Required deployment configuration is unavailable: ${S.warnings.filter((tt)=>tt.code==="missing_required").map((tt)=>tt.key).join(", ")}`);if(X.operation.resourceId)for(let tt of Object.values(S.entries))Vr.setDependency({entryId:tt.id,resourceId:X.operation.resourceId,injectionTarget:"environment",required:tt.required,requiresRedeploy:!0});X.log(`Resolved configuration ${S.configurationHash.slice(0,18)} for ${Object.keys(S.values).length} keys.`,{stream:"system"})}let Ke=await qu(f,{cwd:ae,cliEntry:i,signal:X.signal,env:S?.values,onOutput:(ue,fe)=>X.log(fe,{stream:ue,step:"execute",secrets:[...tS,...Object.entries(S?.entries??{}).filter(([,at])=>at.kind==="secret").map(([at])=>S.values[at]).filter(Boolean)]})});if(Ke.ok&&X.operation.resourceId&&S)for(let ue of Object.values(S.entries))Vr.setDependency({entryId:ue.id,resourceId:X.operation.resourceId,injectionTarget:"environment",required:ue.required,requiresRedeploy:!1,lastDeployedVersion:ue.version});return await ht?.(Ke.ok?"success":"failure",Ke.ok?`Preview is ready at ${String(Z?.commitSha).slice(0,12)}`:`Preview deployment failed at ${String(Z?.commitSha).slice(0,12)}`),Ke}catch(Ke){throw await ht?.("error",`Preview deployment could not complete at ${String(Z?.commitSha).slice(0,12)}`),Ke}finally{if(Ie)ti(Ie,{recursive:!0,force:!0})}}}),...Sg({store:ot,executor:rS}),...Dg({store:Be,secrets:Sr,resolveAdapter:Ju}),...Ph(Zi,lr.drivers),...Gh(wn,[new Gl("aws","AWS regional execution requires an injected AwsRegionalTransport; topology and plans were preserved without provider mutation.")]),...zh({store:kr,cleanup:Zu}),...$b(sc,ac),...Pg({store:Je,queue:xe,resolveSource:Qb,resolveDestination:Yb,validateHealth:async(f,X)=>{if(!f.healthCheckId)return{healthy:!0,mode:"adapter"};let te=le.getHealthCheck(f.healthCheckId);if(!te||te.projectId!==f.projectId)return{healthy:!1,error:"Configured restore health check was not found."};let Z=await new Gi(le).runAndEvaluate(te);return{healthy:Z.result.status==="healthy",healthCheckId:te.id,healthResultId:Z.result.id,target:X}}}),...Im({store:a.store,resolveDriver:e.releaseDriver??((f)=>({name:`${a.store.getResource(f.resourceId)?.provider??"provider"} release driver`,capability:()=>({strategy:f.strategy,supported:!1,explanation:"This dashboard process has no immutable activation driver configured for the target provider.",capacityMultiplier:1,costImpact:"none",rollback:"The previous release remains preserved; configure a release driver before retrying."}),activate:async()=>{throw Error("Immutable activation driver is not configured")},rollback:async()=>{throw Error("Immutable rollback driver is not configured")}})),resolveHealthGate:async(f,X)=>{let te=le.listHealthChecks(X.projectId,X.environmentId).find((ae)=>ae.enabled&&ae.name===f&&(!ae.resourceId||ae.resourceId===X.resourceId));if(!te)return{healthy:!1,message:`Named health gate ${f} was not found for this release.`};let Z=await new Gi(le).runAndEvaluate(te);return{healthy:Z.result.status==="healthy",evidence:{healthCheckId:te.id,healthResultId:Z.result.id,status:Z.result.status,timings:Z.result.timings},message:Z.result.message}}})},{parallelism:e.queueParallelism??(Number(process.env.TS_CLOUD_QUEUE_PARALLELISM)||8),onError:(f)=>console.error("ts-cloud deployment queue worker failed:",f)}):void 0;if(vy(a),$a(ge,ar(a,String(m)),y),Ae)Zo(a,Ae.users),dv(G,a,Ae.users);let ze=av({cwd:t,enabled:K,secret:ye,authentication:G,authorization:{store:a.store,organizationId:a.organization.id,projectId:a.project.id,defaultEnvironment:String(m)}}),Ge=new Xl,sp=setInterval(()=>Ge.sweep(),60000);sp.unref?.();let Ko=new Bo,lc=new Bo(3,900000,900000),Jo=new Bo(8,900000,900000),ap=setInterval(()=>Ko.prune(),300000),cp=setInterval(()=>lc.prune(),300000),dp=setInterval(()=>Jo.prune(),300000);if(ap.unref?.(),cp.unref?.(),dp.unref?.(),K){if(Ae?.generated)console.warn(`
672
672
  ts-cloud dashboard: created the first admin.
673
673
  username: ${Ae.generated.username}
674
674
  password: ${Ae.generated.password}