@stacksjs/ts-cloud 0.16.26 → 0.16.27

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 (139) hide show
  1. package/dist/aws/client.d.ts +6 -0
  2. package/dist/aws/index.js +1 -1
  3. package/dist/bin/{chunk-w23en85y.js → chunk-13htvxgc.js} +1 -1
  4. package/dist/bin/chunk-2ar52zq0.js +1 -0
  5. package/dist/bin/{chunk-4xfwb21f.js → chunk-2chec65b.js} +1 -1
  6. package/dist/bin/{chunk-8tp6srfc.js → chunk-45v1azhc.js} +1 -1
  7. package/dist/bin/{chunk-f4rp62j4.js → chunk-494fg5c6.js} +1 -1
  8. package/dist/bin/chunk-4fwbwjjj.js +1 -0
  9. package/dist/bin/chunk-57f4mqzk.js +1 -0
  10. package/dist/bin/{chunk-qsyna6ng.js → chunk-5810132y.js} +1 -1
  11. package/dist/bin/{chunk-ccykpema.js → chunk-66f51kn2.js} +1 -1
  12. package/dist/bin/chunk-ank4fmbx.js +1 -0
  13. package/dist/bin/{chunk-y6rgvb7r.js → chunk-az5vvf5d.js} +1 -1
  14. package/dist/bin/chunk-azcxgwhm.js +1 -0
  15. package/dist/bin/{chunk-3rzabz10.js → chunk-b4p9zknk.js} +1 -1
  16. package/dist/bin/{chunk-r2ft7vek.js → chunk-djtt70tn.js} +1 -1
  17. package/dist/bin/chunk-f922vrbs.js +1 -0
  18. package/dist/bin/{chunk-5ky6qf18.js → chunk-ffyhp5tk.js} +2 -2
  19. package/dist/bin/chunk-k0akp8k0.js +1 -0
  20. package/dist/bin/{chunk-4r46kw46.js → chunk-k545r9bk.js} +1 -1
  21. package/dist/bin/chunk-k6dxgzm6.js +1 -0
  22. package/dist/bin/{chunk-fjxsj9z9.js → chunk-kbwczaa8.js} +1 -1
  23. package/dist/bin/{chunk-dh6kj6ce.js → chunk-kcprsn33.js} +1 -1
  24. package/dist/bin/{chunk-0apv4e8e.js → chunk-kfj4w903.js} +2 -2
  25. package/dist/bin/{chunk-92rhkvpx.js → chunk-ne5zevtf.js} +2 -2
  26. package/dist/bin/{chunk-z3962as2.js → chunk-qfgvvwmb.js} +1 -1
  27. package/dist/bin/{chunk-1j9vy88a.js → chunk-qx05kccj.js} +1 -1
  28. package/dist/bin/{chunk-6nm91cfw.js → chunk-s5hq7v1h.js} +1 -1
  29. package/dist/bin/chunk-s7gk1qx2.js +1 -0
  30. package/dist/bin/{chunk-3jjggqfj.js → chunk-st7s9k78.js} +1 -1
  31. package/dist/bin/chunk-t644w5rw.js +1 -0
  32. package/dist/bin/chunk-twq6s0nd.js +1 -0
  33. package/dist/bin/chunk-vknq0ap2.js +1 -0
  34. package/dist/bin/{chunk-85733wwc.js → chunk-vsgq1d3s.js} +3 -3
  35. package/dist/bin/{chunk-h3shxxh4.js → chunk-x6y663t7.js} +1 -1
  36. package/dist/bin/{chunk-q3xwh0r8.js → chunk-y5e7dmvc.js} +4 -4
  37. package/dist/bin/{chunk-2q27v6vz.js → chunk-ypsgkj91.js} +1 -1
  38. package/dist/bin/chunk-za9np4pg.js +1 -0
  39. package/dist/bin/chunk-zqa6jarz.js +1 -0
  40. package/dist/bin/{chunk-hwqvx1zb.js → chunk-zrjf1pqy.js} +1 -1
  41. package/dist/bin/cli.js +81 -81
  42. package/dist/bin/dashboard-server.js +1 -1
  43. package/dist/chunk-2p85fnx5.js +1 -0
  44. package/dist/chunk-3q242cqb.js +1 -0
  45. package/dist/{chunk-7p1653g6.js → chunk-4ka2s5d8.js} +2 -2
  46. package/dist/{chunk-wrpnnrdf.js → chunk-55yda01s.js} +4 -4
  47. package/dist/{chunk-mte9da2p.js → chunk-6eqx6gt8.js} +2 -2
  48. package/dist/{chunk-0p7ddjt6.js → chunk-818d8w7e.js} +1 -1
  49. package/dist/{chunk-x9bpm5s1.js → chunk-bx1znp1q.js} +1 -1
  50. package/dist/chunk-cykr6zyj.js +1 -0
  51. package/dist/{chunk-setpnrtg.js → chunk-cymsceq6.js} +1 -1
  52. package/dist/{chunk-3zv0e36t.js → chunk-dygr8ewz.js} +1 -1
  53. package/dist/{chunk-mdqnpbbc.js → chunk-fvgk05df.js} +1 -1
  54. package/dist/{chunk-e4z4tfh6.js → chunk-h5gvh859.js} +1 -1
  55. package/dist/chunk-mqscxx2z.js +1 -0
  56. package/dist/{chunk-k75jv8s6.js → chunk-ne0e6484.js} +5 -5
  57. package/dist/{chunk-5db32a4x.js → chunk-njz7scff.js} +1 -1
  58. package/dist/{chunk-2nma0bd8.js → chunk-q70pfhcn.js} +1 -1
  59. package/dist/{chunk-08tswmb3.js → chunk-qx6nwvgn.js} +1 -1
  60. package/dist/{chunk-e44ajkha.js → chunk-twj83txn.js} +1 -1
  61. package/dist/{chunk-tvwrthfq.js → chunk-wyfpz6be.js} +1 -1
  62. package/dist/{chunk-dm6kyz6e.js → chunk-ys5318bg.js} +1 -1
  63. package/dist/deploy/index.js +1 -1
  64. package/dist/dns/index.js +1 -1
  65. package/dist/drivers/index.js +1 -1
  66. package/dist/index.js +1 -1
  67. package/dist/ui/404.html +1 -1
  68. package/dist/ui/accept-invitation.html +1 -1
  69. package/dist/ui/access-denied.html +1 -1
  70. package/dist/ui/account/automation.html +6 -6
  71. package/dist/ui/account/security.html +2 -2
  72. package/dist/ui/applications/compose.html +6 -6
  73. package/dist/ui/applications/new.html +1 -1
  74. package/dist/ui/data/backups.html +5 -5
  75. package/dist/ui/data/services.html +6 -6
  76. package/dist/ui/data/volumes.html +6 -6
  77. package/dist/ui/index.html +6 -6
  78. package/dist/ui/infrastructure/topology.html +5 -5
  79. package/dist/ui/integrations.html +1 -1
  80. package/dist/ui/operations/alerts.html +6 -6
  81. package/dist/ui/operations/configuration.html +6 -6
  82. package/dist/ui/operations/jobs.html +5 -5
  83. package/dist/ui/operations/maintenance.html +5 -5
  84. package/dist/ui/operations/observability.html +5 -5
  85. package/dist/ui/operations/previews.html +6 -6
  86. package/dist/ui/operations/queue.html +6 -6
  87. package/dist/ui/operations/regions.html +5 -5
  88. package/dist/ui/operations/releases.html +6 -6
  89. package/dist/ui/operations/spend.html +6 -6
  90. package/dist/ui/operations/workloads.html +6 -6
  91. package/dist/ui/security.html +2 -2
  92. package/dist/ui/server/actions.html +6 -6
  93. package/dist/ui/server/activity.html +1 -1
  94. package/dist/ui/server/capacity.html +5 -5
  95. package/dist/ui/server/database.html +6 -6
  96. package/dist/ui/server/deployments.html +5 -5
  97. package/dist/ui/server/diagnostics.html +1 -1
  98. package/dist/ui/server/firewall.html +6 -6
  99. package/dist/ui/server/fleet.html +6 -6
  100. package/dist/ui/server/logs.html +5 -5
  101. package/dist/ui/server/metrics.html +5 -5
  102. package/dist/ui/server/security.html +2 -2
  103. package/dist/ui/server/services.html +2 -2
  104. package/dist/ui/server/sites.html +6 -6
  105. package/dist/ui/server/ssh-keys.html +6 -6
  106. package/dist/ui/server/team.html +6 -6
  107. package/dist/ui/server/terminal.html +2 -2
  108. package/dist/ui/serverless/alarms.html +6 -6
  109. package/dist/ui/serverless/assets.html +2 -2
  110. package/dist/ui/serverless/cost.html +2 -2
  111. package/dist/ui/serverless/data.html +6 -6
  112. package/dist/ui/serverless/deployments.html +2 -2
  113. package/dist/ui/serverless/firewall.html +1 -1
  114. package/dist/ui/serverless/functions.html +6 -6
  115. package/dist/ui/serverless/logs.html +6 -6
  116. package/dist/ui/serverless/metrics.html +1 -1
  117. package/dist/ui/serverless/queues.html +6 -6
  118. package/dist/ui/serverless/secrets.html +6 -6
  119. package/dist/ui/serverless/traces.html +6 -6
  120. package/dist/ui/serverless.html +6 -6
  121. package/package.json +3 -3
  122. package/dist/bin/chunk-08hxbrmv.js +0 -1
  123. package/dist/bin/chunk-0cwbg3pf.js +0 -1
  124. package/dist/bin/chunk-19tmmwmt.js +0 -1
  125. package/dist/bin/chunk-2qrr4ydb.js +0 -1
  126. package/dist/bin/chunk-4jgespb7.js +0 -1
  127. package/dist/bin/chunk-8hnph1yy.js +0 -1
  128. package/dist/bin/chunk-aqreqn37.js +0 -1
  129. package/dist/bin/chunk-eh3235zq.js +0 -1
  130. package/dist/bin/chunk-ff888cnm.js +0 -1
  131. package/dist/bin/chunk-kxmq7r53.js +0 -1
  132. package/dist/bin/chunk-mh172wt8.js +0 -1
  133. package/dist/bin/chunk-swnef46q.js +0 -1
  134. package/dist/bin/chunk-v95b2dy0.js +0 -1
  135. package/dist/bin/chunk-wjwxtz68.js +0 -1
  136. package/dist/chunk-31qham3c.js +0 -1
  137. package/dist/chunk-7fbfmpyx.js +0 -1
  138. package/dist/chunk-dschvakr.js +0 -1
  139. package/dist/chunk-nkd35khb.js +0 -1
@@ -1,4 +1,4 @@
1
- import{Cd,L,d,bd,M,p,ge,g,Gt,Dd,uo,po,_d,Ld,$d,Ud,Kr,So,Jt,Qd,Hd,Wd,Jd}from"./chunk-w23wrsa4.js";import{x,u}from"./chunk-q0g0rjn3.js";import{pe,Lt,D,$t,s,mi,Us,kr,qc,Vc,Z,c,Gs,qe,Br,jc,Mt,Vs,zc,_r,js,xr,Ai,Qt,Ci,Ei,Ve,Ht,md,hd,vi,Ti,ht,so,i,wi,ao,co}from"./chunk-49p5cx21.js";import{n}from"./chunk-wrpnnrdf.js";import{o}from"./chunk-2nma0bd8.js";import{hn}from"./chunk-mte9da2p.js";import{Ie}from"./chunk-3zv0e36t.js";import{fn,Cu,cs,k,w,ds,Eu}from"./chunk-e44ajkha.js";import{Ae,nr,gs,tt,z,se,b,ye,or,oe,nt,cr}from"./chunk-0p7ddjt6.js";import{K}from"./chunk-tvwrthfq.js";import{v,mr,Ds,_t,hr,xu,xt,Lu,pc,Ue,ct,jn,_,Ot,vr}from"./chunk-7p1653g6.js";import{y}from"./chunk-mdqnpbbc.js";import{Le}from"./chunk-dm6kyz6e.js";import{we}from"./chunk-x9bpm5s1.js";import{f}from"./chunk-08tswmb3.js";function an(e){let t=Dc(e.name),r=Xu(e.configText);if(ww(e.configText,r.start,r.end,t))throw Error(`Site '${t}' already exists in cloud.config.ts`);let a=mh({...e,name:t}),l=e.configText.slice(0,r.end).trimEnd(),m=e.configText.slice(r.end),h=l.endsWith("{")?`
1
+ import{Cd,L,d,bd,M,p,ge,g,Gt,Dd,uo,po,_d,Ld,$d,Ud,Kr,So,Jt,Qd,Hd,Wd,Jd}from"./chunk-w23wrsa4.js";import{x,u}from"./chunk-q0g0rjn3.js";import{pe,Lt,D,$t,s,mi,Us,kr,qc,Vc,Z,c,Gs,qe,Br,jc,Mt,Vs,zc,_r,js,xr,Ai,Qt,Ci,Ei,Ve,Ht,md,hd,vi,Ti,ht,so,i,wi,ao,co}from"./chunk-49p5cx21.js";import{n}from"./chunk-55yda01s.js";import{o}from"./chunk-q70pfhcn.js";import{hn}from"./chunk-6eqx6gt8.js";import{Ie}from"./chunk-dygr8ewz.js";import{fn,Cu,cs,k,w,ds,Eu}from"./chunk-twj83txn.js";import{Ae,nr,gs,tt,z,se,b,ye,or,oe,nt,cr}from"./chunk-818d8w7e.js";import{K}from"./chunk-wyfpz6be.js";import{v,mr,Ds,_t,hr,xu,xt,Lu,pc,Ue,ct,jn,_,Ot,vr}from"./chunk-4ka2s5d8.js";import{y}from"./chunk-fvgk05df.js";import{Le}from"./chunk-ys5318bg.js";import{we}from"./chunk-bx1znp1q.js";import{f}from"./chunk-qx6nwvgn.js";function an(e){let t=Dc(e.name),r=Xu(e.configText);if(ww(e.configText,r.start,r.end,t))throw Error(`Site '${t}' already exists in cloud.config.ts`);let a=mh({...e,name:t}),l=e.configText.slice(0,r.end).trimEnd(),m=e.configText.slice(r.end),h=l.endsWith("{")?`
2
2
  `:l.endsWith(",")?`
3
3
 
4
4
  `:`,
@@ -36,8 +36,8 @@ export const handler = async (event) => {
36
36
  body: JSON.stringify({ ok: statusCode === 200, service: 'ts-cloud-static-api', path, coldStart: currentColdStart, initializedAt })
37
37
  }
38
38
  }
39
- `;function af(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function Dw(e){return["NoSuchEntity","ResourceNotFoundException","404"].includes(af(e))}function of(e){return["EntityAlreadyExists","ResourceAlreadyExistsException","ResourceConflictException","409"].includes(af(e))}function sf(e,t){let r=e?.Items;if(!r)return[];if(Array.isArray(r))return r;let a=r[t];if(a===void 0)return[];return Array.isArray(a)?a:[a]}function rp(e){let t=e?.Aliases?.Items,r=t?.CNAME??t;if(Array.isArray(r))return r.map(String);if(typeof r==="string")return[r];return[]}function Ow(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`,a=e.roleName||`${e.functionName}-execution`;if(!/^[A-Za-z0-9_.-]{1,64}$/.test(a))throw Error("IAM role name is invalid");let l=e.memorySize??256,m=e.timeout??10,h=e.logRetentionDays??14;if(l<128||l>10240)throw Error("Lambda memory must be between 128 and 10240 MB");if(m<1||m>900)throw Error("Lambda timeout must be between 1 and 900 seconds");return{region:e.region||"us-east-1",pathPattern:t,originId:r,roleName:a,memorySize:l,timeout:m,logRetentionDays:h}}function hh(e){let t=e.region||"us-east-1";return{cloudfront:new y(e.profile),iam:new Ie(t,e.profile),lambda:new b(t,e.profile),logs:new ye(t,e.profile),sts:new Ae(t,e.profile),sleep:(r)=>new Promise((a)=>setTimeout(a,r))}}async function vy(e,t){let r=Ow(e),a=t||hh({profile:e.profile,region:r.region}),[l,m,h]=await Promise.all([a.sts.getCallerIdentity(),a.cloudfront.getDistribution(e.distributionId),a.cloudfront.getDistributionConfig(e.distributionId)]);if(!l.Account)throw Error("AWS identity did not return an account ID");if(!m.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!(rp(m).length?rp(m):rp(h.DistributionConfig)).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let R,S=!0;try{R=await a.iam.getRole({RoleName:r.roleName})}catch(ot){if(!Dw(ot))throw ot;S=!1}let C=R?.Arn||`arn:aws:iam::${l.Account}:role/${r.roleName}`,T=await a.lambda.functionExists(e.functionName),j=T?await a.lambda.getFunctionUrl(e.functionName):null,B=await a.cloudfront.listOriginAccessControls(),V=`${e.functionName}-lambda-url`,W=B.some((ot)=>ot.Name===V&&ot.OriginAccessControlOriginType==="lambda"),Y=sf(h.DistributionConfig.Origins,"Origin"),te=sf(h.DistributionConfig.CacheBehaviors,"CacheBehavior"),le=Y.some((ot)=>String(ot.Id)===r.originId),X=te.some((ot)=>String(ot.PathPattern)===r.pathPattern),ce=[...!S?[`create IAM execution role ${r.roleName}`]:[`reconcile IAM execution policy ${r.roleName}`],...T?[`update Lambda ${e.functionName} code and configuration`]:[`create Lambda ${e.functionName}`],...!j?["create private AWS_IAM function URL"]:[],...!W?[`create Lambda origin access control ${V}`]:[],"grant CloudFront function-URL and invocation permissions",`${X?"reconcile":"add"} ${r.pathPattern} behavior without changing the default behavior`],Ee={command:`cloud cdn:origin:remove ${e.distributionId} FUNCTION_URL_HOST --id ${r.originId} --path '${r.pathPattern}' --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,removeFunction:!T,removeRole:!S},Re={mode:e.apply?"apply":"plan",accountId:l.Account,identityArn:l.Arn,distribution:{id:m.Id,arn:m.ARN,alias:e.expectedAlias,domainName:m.DomainName,status:m.Status},function:{name:e.functionName,existed:T,runtime:"nodejs22.x",urlExisted:!!j,url:j?.FunctionUrl},role:{name:r.roleName,existed:S,arn:C},origin:{id:r.originId,pathPattern:r.pathPattern,existed:le,behaviorExisted:X,accessControlExisted:W},changes:ce,rollback:Ee,applied:!1};if(!e.apply)return Re;let de=`${e.distributionId}:${r.pathPattern}`;if(e.confirm!==de)throw Error(`Pass exact confirmation token ${de} to mutate the live distribution`);if(!R)R=await a.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 a.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}:${l.Account}:log-group:/aws/lambda/${e.functionName}:*`}]})});try{await a.logs.createLogGroup(`/aws/lambda/${e.functionName}`,{ManagedBy:"ts-cloud"})}catch(ot){if(!of(ot))throw ot}await a.logs.putRetentionPolicy(`/aws/lambda/${e.functionName}`,r.logRetentionDays);let Ne=e.code||xw;if(T)await a.lambda.updateFunctionCodeInline(e.functionName,Ne,"index.mjs"),await a.lambda.waitForFunctionActive(e.functionName),await a.lambda.updateFunctionConfiguration({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:R.Arn,Handler:"index.handler",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize});else{let ot;for(let Pt=0;Pt<8;Pt++)try{await a.lambda.createFunctionWithCode({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:R.Arn,Handler:"index.handler",Code:Ne,Filename:"index.mjs",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize}),ot=void 0;break}catch(ir){if(ot=ir,!String(ir.message).toLowerCase().includes("role"))throw ir;await a.sleep(1000)}if(ot)throw ot}await a.lambda.waitForFunctionActive(e.functionName);let ae=j||await a.lambda.createFunctionUrl({FunctionName:e.functionName,AuthType:"AWS_IAM",InvokeMode:"BUFFERED"});if(!ae.FunctionUrl)throw Error("Lambda did not return a function URL");let je=new URL(ae.FunctionUrl).hostname,Qe=await a.cloudfront.findOrCreateOriginAccessControl(V,"lambda"),gt=m.ARN||`arn:aws:cloudfront::${l.Account}:distribution/${e.distributionId}`,Kt=[{FunctionName:e.functionName,StatementId:"AllowCloudFrontFunctionUrl",Action:"lambda:InvokeFunctionUrl",Principal:"cloudfront.amazonaws.com",SourceArn:gt,FunctionUrlAuthType:"AWS_IAM"},{FunctionName:e.functionName,StatementId:"AllowCloudFrontInvoke",Action:"lambda:InvokeFunction",Principal:"cloudfront.amazonaws.com",SourceArn:gt,InvokedViaFunctionUrl:!0}];for(let ot of Kt)try{await a.lambda.addPermission(ot)}catch(Pt){if(!of(Pt))throw Pt}return await a.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:je,pathPattern:r.pathPattern,originAccessControlId:Qe.Id}),{...Re,function:{...Re.function,url:ae.FunctionUrl},applied:!0}}async function Ty(e){let t=`https://${e.alias}/`,r=`https://${e.alias}/api/health`,a=await fetch(t,{redirect:"follow",headers:{"cache-control":"no-cache"}}),l=new Uint8Array(await a.arrayBuffer()),m=Tw("sha256").update(l).digest("hex"),h=Date.now(),I=await fetch(r,{redirect:"follow",headers:{"cache-control":"no-cache"}}),R=Date.now()-h,S=await I.text(),C=S;try{C=JSON.parse(S)}catch{}let T;if(e.logs&&e.functionName){let j=await e.logs.filterLogEvents({logGroupName:`/aws/lambda/${e.functionName}`,startTime:h-60000,filterPattern:'"Init Duration"',limit:25});for(let B of j.events||[]){let V=B.message?.match(/Init Duration:\s*([0-9.]+)\s*ms/i);if(V)T=Number(V[1])}}return{frontend:{url:t,status:a.status,sha256:m,unchanged:e.expectedFrontendSha256?m===e.expectedFrontendSha256:void 0,bytes:l.byteLength},api:{url:r,status:I.status,latencyMs:R,healthy:I.ok&&!!C?.ok,body:C},coldStart:{observed:T!==void 0,initDurationMs:T},verifiedAt:(e.now?.()||new Date).toISOString()}}function wy(e){let t=(e.memoryMb||256)/1024,r=Math.max(0,e.requests-(e.includeFreeTier===!1?0:1e6)),a=Math.max(0,e.requests*(e.averageDurationMs/1000)*t-(e.includeFreeTier===!1?0:400000)),l=r/1e6*0.2+a*0.0000166667,m=9.010025,h=16.425;return{lambdaUsd:Number(l.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 $w}from"node:crypto";function Nw(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function jw(e){return Nw(e)==="ValidationError"&&String(e.message).includes("does not exist")}function Bw(e){return Object.fromEntries((e||[]).map((t)=>[t.OutputKey,t.OutputValue]))}function Mw(e){let t=e?.Aliases?.Items??e?.Aliases,r=t?.CNAME??t;if(Array.isArray(r))return r.map(String);if(typeof r==="string")return[r];return[]}function cf(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 a=e.pathPattern||"/api/*";if(!/^\/[A-Za-z0-9_.*?~!$&'()+,;=:@%/-]+\*$/.test(a)||a==="/*")throw Error("Backend path must be a non-default wildcard pattern");let l=e.originId||`${e.slug}-backend`;if(!/^[A-Za-z0-9_.-]{1,128}$/.test(l))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:a,originId:l,digest:t}}function fh(e){let t=e.region||"us-east-1";return{cloudformation:new f(t,e.profile),cloudfront:new y(e.profile),sts:new Ae(t,e.profile),fetch,sleep:(r)=>new Promise((a)=>setTimeout(a,r))}}function Ah(e){let t=cf(e),r=$d({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}),a=Ld(r);return a.Description=`Managed backend for existing static frontend ${e.expectedAlias}`,a.Metadata={ManagedBy:"ts-cloud",ExistingDistributionId:e.distributionId,ExistingDistributionAlias:e.expectedAlias,BackendPathPattern:t.pathPattern,ContainerDigest:t.digest},a}async function Lw(e,t,r){let a;for(let l=0;l<30;l++){let m=Date.now();try{let h=await e.fetch(t,{redirect:"manual",headers:r?{"x-origin-verify":r}:void 0}),I=Date.now()-m,R=await h.text(),S=R;try{S=JSON.parse(R)}catch{}if(h.ok)return{url:t,status:h.status,latencyMs:I,body:S};a=Error(`origin returned ${h.status}`)}catch(h){a=h}if(l<29)await e.sleep(1e4)}throw Error(`Backend origin did not become healthy: ${a instanceof Error?a.message:String(a)}`)}async function Ry(e,t){let r=cf(e),a=t||fh({region:r.region,profile:e.profile}),[l,m]=await Promise.all([a.sts.getCallerIdentity(),a.cloudfront.getDistribution(e.distributionId)]);if(!l.Account)throw Error("AWS identity did not return an account ID");if(!m.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!Mw(m).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let h;try{h=(await a.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0]}catch(ce){if(!jw(ce))throw ce}let I=Ah(e),R=JSON.stringify(I);if(Buffer.byteLength(R)>51200)throw Error("Generated template exceeds the direct CloudFormation template body limit");let S=Object.values(I.Resources||{}).reduce((ce,Ee)=>(ce[Ee.Type]=(ce[Ee.Type]||0)+1,ce),{}),C=[`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.`],T={mode:e.apply?"apply":"plan",accountId:l.Account,stack:{name:r.stackName,existed:!!h,status:h?.StackStatus,templateSha256:$w("sha256").update(R).digest("hex"),resourceCount:Object.keys(I.Resources||{}).length,resourceTypes:S},distribution:{id:m.Id,alias:e.expectedAlias,domainName:m.DomainName,status:m.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:C};if(!e.apply)return T;let j=`${e.distributionId}:${r.pathPattern}:${r.stackName}`;if(e.confirm!==j)throw Error(`Pass exact confirmation token ${j} to provision the backend and change live routing`);if(h)try{await a.cloudformation.updateStack({stackName:r.stackName,templateBody:R,capabilities:["CAPABILITY_NAMED_IAM"],tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await a.cloudformation.waitForStack(r.stackName,"stack-update-complete")}catch(ce){if(!String(ce.message).includes("No updates are to be performed"))throw ce}else await a.cloudformation.createStack({stackName:r.stackName,templateBody:R,capabilities:["CAPABILITY_NAMED_IAM"],onFailure:"ROLLBACK",tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await a.cloudformation.waitForStack(r.stackName,"stack-create-complete");let B=(await a.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0],V=Bw(B?.Outputs),W=V.AppLoadBalancerDnsName;if(!W)throw Error("Backend stack did not return AppLoadBalancerDnsName");let Y=!1;if(e.originDomain&&e.originDomain!==W){if(!a.dns)throw Error(`External DNS provider is required to map ${e.originDomain} to ${W}`);let ce=await a.dns.upsertRecord(e.originDomain,{name:e.originDomain,type:"CNAME",content:W,ttl:300});if(!ce.success)throw Error(ce.message||"External DNS update failed");Y=!0}let te=e.originDomain||W,le=e.certificateArn?"https-only":"http-only",X=e.skipHealthCheck?void 0:await Lw(a,`${le==="https-only"?"https":"http"}://${te}/api/health`,e.originVerifySecret);return await a.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:te,pathPattern:r.pathPattern,protocolPolicy:le,customHeaders:e.originVerifySecret?{"X-Origin-Verify":e.originVerifySecret}:void 0}),{...T,outputs:V,health:X,cloudFrontApplied:!0,dnsApplied:Y,applied:!0}}function Dy(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((a,l)=>a+l,0).toFixed(2)),components:Object.fromEntries(Object.entries(r).map(([a,l])=>[a,Number(l.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 Fw}from"node:child_process";import{createHash as zw}from"node:crypto";import{existsSync as df,mkdirSync as Uw,mkdtempSync as qw,readdirSync as Vw,readFileSync as Ww,rmSync as Hw,statSync as lf,writeFileSync as Kw}from"node:fs";import{tmpdir as Jw}from"node:os";import{basename as Gw,join as As,relative as Qw,resolve as np}from"node:path";var Yw=new Set([".git","node_modules","dist","coverage"]);function uf(e,t=e){let r=[];for(let a of Vw(e).sort()){if(Yw.has(a))continue;let l=As(e,a);if(bd(l,t))continue;let m=lf(l);if(m.isDirectory())r.push(...uf(l,t));else if(m.isFile())r.push(Qw(t,l))}return r}function yh(e){let t=np(e);if(!df(t)||!lf(t).isDirectory())throw Error(`Container context does not exist: ${t}`);let r=zw("sha256");for(let a of uf(t))r.update(a),r.update("\x00"),r.update(Ww(As(t,a))),r.update("\x00");return r.digest("hex")}function Ih(e){return{ecr:new Le(e.region||"us-east-1",e.profile),run:(t,r,a)=>{Fw(t,r,{cwd:a?.cwd,env:a?.env,stdio:a?.stdio||"inherit"})}}}async function Py(e,t){let r=np(e.context),a=np(e.dockerfile||As(r,"Dockerfile"));if(!df(a))throw Error(`Dockerfile does not exist: ${a}`);if(!e.repository.split("/").every((V)=>/^[a-z0-9][a-z0-9._-]*$/.test(V)&&!/[._-]$/.test(V)&&!/[._-]{2}/.test(V)))throw Error("ECR repository name is invalid");let h=t||Ih(e),I=yh(r),R=`sha-${I.slice(0,20)}`,S="";try{S=(await h.ecr.describeRepositories({repositoryNames:[e.repository]})).repositories?.[0]?.repositoryUri||""}catch{}if(!S)S=(await h.ecr.createRepository({repositoryName:e.repository,imageTagMutability:"IMMUTABLE",imageScanningConfiguration:{scanOnPush:!0},tags:[{Key:"ManagedBy",Value:"ts-cloud"}]})).repository?.repositoryUri||"";if(!S)throw Error(`Could not resolve ECR repository URI for ${e.repository}`);await h.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 C=`${S}:${R}`,T=qw(As(Jw(),"ts-cloud-container-"));try{h.run("docker",["version"],{stdio:"ignore"}),h.run("docker",["build","--platform",e.platform||"linux/amd64","--provenance=false","--sbom=false","--file",a,"--tag",C,r],{cwd:r});let V=(await h.ecr.getAuthorizationToken()).authorizationData?.[0];if(!V?.authorizationToken||!V.proxyEndpoint)throw Error("ECR did not return Docker authorization data");let W=V.proxyEndpoint.replace(/^https?:\/\//,""),Y=As(T,"docker");Uw(Y,{recursive:!0}),Kw(As(Y,"config.json"),JSON.stringify({auths:{[W]:{auth:V.authorizationToken}}}),{mode:384}),h.run("docker",["push",C],{env:{...process.env,DOCKER_CONFIG:Y}})}finally{Hw(T,{recursive:!0,force:!0})}let B=(await h.ecr.describeImages({repositoryName:e.repository,imageIds:[{imageTag:R}]})).imageDetails?.[0]?.imageDigest;if(!B||!/^sha256:[a-f0-9]{64}$/i.test(B))throw Error(`ECR did not return an immutable digest for ${Gw(C)}`);return{repository:e.repository,tag:R,imageUri:C,digest:B,digestUri:`${S}@${B}`,contextSha256:I}}import{existsSync as Zw,readdirSync as Xw,readFileSync as ek,statSync as tk}from"node:fs";import{join as pf,relative as rk}from"node:path";function Ao(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 a=e.project.slug,l=e.environments?.[t]?.region||e.project.region||"us-east-1";return{app:r,slug:a,region:l,stackName:Gt(e,t),artifactBucket:Dd(a,t),assetsBucket:uo(a,t)}}async function Ro(e,t=8){let r;for(let a=0;a<t;a++)try{return await e()}catch(l){let m=l?.code||l?.name||"",h=String(l?.message||"");if(m==="ResourceConflictException"||/update is in progress|currently in the following state/i.test(h)){r=l,await new Promise((I)=>setTimeout(I,3000));continue}throw l}throw r}var gf=(e,t)=>`releases/${e}/${t}/current.json`;async function Nc(e,t,r,a){try{return await e.getObjectJson(t,gf(r,a))}catch{return null}}async function mf(e,t,r,a,l){await e.putObjectJson(t,gf(r,a),l)}async function nk(e,t){if(!e.secrets)return{};let r=new z(t),a={},l=Array.isArray(e.secrets)?e.secrets.map((m)=>({envName:m.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),secretId:m})):Object.entries(e.secrets).map(([m,h])=>({envName:m,secretId:h}));if(Array.isArray(e.secrets)){let m=new Map;for(let{envName:I,secretId:R}of l)m.set(I,[...m.get(I)??[],R]);let h=[...m.entries()].filter(([,I])=>I.length>1);if(h.length){let I=h.map(([R,S])=>`${R} ← ${S.join(", ")}`).join("; ");throw Error(`serverless secrets: multiple secrets map to the same env var (${I}). Use the map form { ENV_NAME: 'secret/id' } to disambiguate.`)}}for(let{envName:m,secretId:h}of l){let R=(await r.getSecretValue({SecretId:h})).SecretString??"";try{let S=JSON.parse(R);if(S&&typeof S==="object"&&!Array.isArray(S)){for(let[C,T]of Object.entries(S))a[C]=String(T);continue}}catch{}a[m]=R}return a}function Zi(e,t){let r={},a=t.DbProxyEndpoint||t.DbEndpoint;if(a)r.DB_CONNECTION="mysql",r.DB_HOST=a,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 tr(e,t,r,a,l,m,h,I={}){let R=e.kind==="php"?Wd({cacheDriver:e.cache?.driver==="elasticache"?"redis":"dynamodb"}):{};return{TSCLOUD_LAMBDA_MODE:a,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"}:{},...R,...I,...t.app.cache?.driver!=="elasticache"?{TSCLOUD_CACHE_TABLE:`${t.slug}-${r}-cache`}:{},...h?{TSCLOUD_QUEUE:h,SQS_QUEUE:h}:{},...m?{ASSET_URL:m}:{},...e.env??{},...l}}function ik(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*ff(e){for(let t of Xw(e)){let r=pf(e,t);if(tk(r).isDirectory())yield*ff(r);else yield r}}async function ok(e,t,r,a,l=!1){let m=0;for(let h of ff(r)){let I=rk(r,h).replace(/\\/g,"/");if(!l&&I.split("/").some((R)=>R.startsWith(".")))continue;await e.putObject({bucket:t,key:`${a}/${I}`,body:ek(h),contentType:ik(h),cacheControl:"public, max-age=31536000, immutable"}),m++}return m}function sk(e,t){let r=Object.entries(t).reduce((a,[l,m])=>a+Buffer.byteLength(`${l}=${m}`,"utf8"),0);if(r>4096){let a=Object.entries(t).map(([l,m])=>[l,Buffer.byteLength(`${l}=${m}`,"utf8")]).sort((l,m)=>m[1]-l[1]).slice(0,5).map(([l,m])=>`${l} (${m}B)`).join(", ");throw Error(`${e}: environment variables total ${r}B, over AWS's 4096B limit (${r-4096}B too large). Largest: ${a}. Move large/secret values out of env — store them in Secrets Manager and fetch at cold start.`)}}async function Qa(e,t,r,a){sk(t,r),await Ro(()=>e.updateFunctionConfiguration({FunctionName:t,Environment:{Variables:r}})),await e.waitForFunctionActive(t,120);let l=a.kind==="image"?{FunctionName:t,ImageUri:a.imageUri}:{FunctionName:t,S3Bucket:a.bucket,S3Key:a.key};await Ro(()=>e.updateFunctionCode(l)),await e.waitForFunctionActive(t,120)}async function $c(e,t){let a=(await Ro(()=>e.publishVersion({FunctionName:t}))).Version;if(!a)throw Error(`publishVersion returned no version for ${t}`);return await Ro(()=>e.updateAlias({FunctionName:t,Name:"live",FunctionVersion:a})),a}async function Ca(e,t,r={}){let a=Ao(e,t),{app:l,slug:m,region:h,stackName:I,artifactBucket:R}=a,S=r.projectRoot??process.cwd();ds(`Deploying serverless app: ${m} (${t})`),k(`Stack: ${I}`),k(`Region: ${h}`);let C=new o(h),T=new f(h),j=new b(h),B=l.kind==="php",V=l.packaging==="image",W=So(l),Y,te,le,X,ce=[];if(V&&W.usesLayer&&W.layerKind!=="php")throw Error(`packaging: 'image' currently supports PHP and managed Node runtimes. ${W.kind}${W.kind==="node"?` ${W.version}`:""} uses a custom runtime — `+"use the default zip packaging (the runtime layer is built + attached automatically).");if(V){w("Building + pushing container image");let{buildAndPushServerlessImage:be}=await import("./chunk-31qham3c.js"),De=await be({app:l,projectRoot:S,region:h,repository:`${m}-${t}`,skipBuild:r.skipBuild,onStep:(mt)=>k(` ${mt}`)});Y=De.handlers,te={kind:"image",imageUri:De.imageUri},le=De.tag,ce.push({ParameterKey:"ImageUri",ParameterValue:De.imageUri})}else{w("Packaging application");let be=B?Jd({projectRoot:S,app:l,skipBuild:r.skipBuild,onStep:(Dt)=>k(` ${Dt}`)}):await Kr({projectRoot:S,app:l,skipBuild:r.skipBuild,onStep:(Dt)=>k(` ${Dt}`)}),De=Ud(m,t,be.sha256);if(k(`Artifact: ${be.sha256.slice(0,12)} (${(be.zip.length/1024).toFixed(0)} KB)`),Y=be.handlers,le=be.sha256,W.usesLayer){let Dt=W.layerEnvVar?process.env[W.layerEnvVar]:void 0;if(X=l.layers??(Dt?[Dt]:void 0),!X?.length){let $e=W.layerKind==="php"?"serverless:build-php-layer":W.layerKind==="bun"?"serverless:build-bun-layer":"serverless:build-node-layer";throw Error(`${W.kind} apps on provided.al2023 need a runtime layer. Set environments.<env>.app.layers or the ${W.layerEnvVar} env var (build one with \`cloud ${$e}\`)${W.kind==="node"?", or use a managed Node version (18/20/22)":""}.`)}}if(!await C.bucketExists(R))w(`Creating artifact bucket ${R}`),await C.createBucket(R);if(await C.headObject(R,De).then((Dt)=>Dt!==null).catch(()=>!1))k("Artifact already uploaded — reusing");else w("Uploading artifact"),await C.putObject({bucket:R,key:De,body:be.zip,contentType:"application/zip"});te={kind:"zip",bucket:R,key:De},ce.push({ParameterKey:"ArtifactBucket",ParameterValue:R},{ParameterKey:"ArtifactKey",ParameterValue:De})}let Ee=Hd({config:e,environment:t,app:l,handlers:Y,runtimeLayers:X}),Re=JSON.stringify(Ee.template),de=["CAPABILITY_NAMED_IAM"],Ne=await T.describeStacks({stackName:I}).then((be)=>be.Stacks[0]?.StackStatus).catch(()=>{return}),ae=Ne!==void 0;if(Ne&&/DELETE_IN_PROGRESS/.test(Ne))w("Waiting for an in-progress stack delete to finish"),await T.waitForStack(I,"stack-delete-complete").catch(()=>{}),ae=!1;else if(Ne&&/(?:ROLLBACK_COMPLETE|REVIEW_IN_PROGRESS|CREATE_FAILED)/.test(Ne))w(`Deleting unusable stack (status ${Ne}) before recreate`),await T.deleteStack(I),await T.waitForStack(I,"stack-delete-complete").catch(()=>{}),ae=!1;w(ae?"Updating infrastructure stack":"Creating infrastructure stack");try{if(ae)await T.updateStack({stackName:I,templateBody:Re,parameters:ce,capabilities:de}),await T.waitForStack(I,"stack-update-complete");else await T.createStack({stackName:I,templateBody:Re,parameters:ce,capabilities:de,onFailure:"DELETE"}),await T.waitForStack(I,"stack-create-complete")}catch(be){if(/No updates are to be performed/i.test(String(be?.message)))k("No infrastructure changes");else throw be}let je=await T.getStackOutputs(I).catch(()=>({})),Qe;if(l.assets){let be=pf(S,l.assets);if(Zw(be)){let De=l.assetDomain||je.AssetsCdnDomain;Qe=De?`https://${De}/${le}`:void 0,w(`Syncing assets from ${l.assets}`);let mt=await ok(C,a.assetsBucket,be,le,l.dotFilesAsAssets);k(`Uploaded ${mt} asset(s)${Qe?` → ${Qe}`:""}`)}else cs(`Assets directory not found: ${be}`)}w("Resolving secrets");let gt=await nk(l,h);if(l.database?.connection==="aurora-serverless")try{let De=await new z(h).getSecretValue({SecretId:`${m}/${t}/db`}),mt=JSON.parse(De.SecretString??"{}");if(mt.username)gt.DB_USERNAME=mt.username;if(mt.password)gt.DB_PASSWORD=mt.password}catch(be){cs(`Could not resolve Aurora DB credentials: ${be.message}`)}if(!await C.bucketExists(R))await C.createBucket(R);let Kt=await Nc(C,R,m,t),ot={},Pt=Ee.queueNames[0],ir=Zi(l,je);if(w("Activating functions"),ot.http=tr(l,a,t,"http",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.http,ot.http,te),ot.cli=tr(l,a,t,"cli",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.cli,ot.cli,te),Ee.queueNames.length)ot.queue=tr(l,a,t,"queue",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.queue,ot.queue,te);let lt=(l.provisionedConcurrency??0)>0,G={};if(lt){if(w("Publishing versions + flipping live alias"),G.http=await $c(j,Ee.functionNames.http),G.cli=await $c(j,Ee.functionNames.cli),Ee.queueNames.length)G.queue=await $c(j,Ee.functionNames.queue)}if(await mf(C,R,m,t,{sha:le,code:te,previousSha:Kt?.sha,previousCode:Kt?.code,previousFunctionEnv:Kt?.functionEnv,...lt?{functionVersions:G,previousFunctionVersions:Kt?.functionVersions}:{},functionEnv:ot,functionNames:{http:Ee.functionNames.http,cli:Ee.functionNames.cli,...Ee.queueNames.length?{queue:Ee.functionNames.queue}:{}},assetUrl:Qe,timestamp:new Date().toISOString()}),!r.skipDeployHooks&&l.deploy?.length){w("Running deploy hooks");for(let be of l.deploy){k(` deploy: ${be}`);let De=await j.invoke({FunctionName:Ee.functionNames.cli,InvocationType:"RequestResponse",Payload:{command:be},LogType:"Tail"});if(De.FunctionError)throw Cu("Deploy hook failed — the new build is ALREADY LIVE."),k(` Roll back with: cloud serverless:rollback --env ${t}`),Error(`Deploy hook failed (${be}): ${De.Payload}`)}}let ue=je.HttpApiEndpoint;if(!r.skipHealthCheck&&ue){w("Health check");try{let be=await fetch(ue,{method:"GET"});k(`GET ${ue} → ${be.status}`)}catch(be){cs(`Health check could not reach ${ue}: ${be.message}`)}}Eu(["Serverless deploy complete","",ue?`URL: ${ue}`:"",`Stack: ${I}`,`Build: ${le.slice(0,12)}`].filter(Boolean).join(`
40
- `),"green")}async function dn(e,t){let r=Ao(e,t),a=new o(r.region),l=new b(r.region),m=await Nc(a,r.artifactBucket,r.slug,t);if(!m)throw Error("No previous release to redeploy. Run a full deploy first.");ds(`Redeploying ${r.slug} (${t}) — build ${m.sha.slice(0,12)}`);for(let[h,I]of Object.entries(m.functionNames)){if(!I)continue;w(`Re-activating ${h} (${I})`),await Qa(l,I,m.functionEnv[h]??{},m.code);let R=m.functionVersions?.[h];if(R)await Ro(()=>l.updateAlias({FunctionName:I,Name:"live",FunctionVersion:R}))}fn("Redeploy complete")}async function ln(e,t){let r=Ao(e,t),a=new o(r.region),l=new b(r.region),m=await Nc(a,r.artifactBucket,r.slug,t);if(!m?.previousCode)throw Error("No previous release to roll back to.");ds(`Rolling back ${r.slug} (${t}) → ${m.previousSha?.slice(0,12)}`);for(let[h,I]of Object.entries(m.functionNames)){if(!I)continue;w(`Restoring ${h} (${I})`);let R=m.previousFunctionEnv?.[h]??m.functionEnv[h]??{};await Qa(l,I,R,m.previousCode);let S=m.previousFunctionVersions?.[h];if(S)await Ro(()=>l.updateAlias({FunctionName:I,Name:"live",FunctionVersion:S}))}await mf(a,r.artifactBucket,r.slug,t,{...m,sha:m.previousSha??m.sha,code:m.previousCode,functionEnv:m.previousFunctionEnv??m.functionEnv,functionVersions:m.previousFunctionVersions??m.functionVersions,previousSha:void 0,previousCode:void 0,previousFunctionEnv:void 0,previousFunctionVersions:void 0,timestamp:new Date().toISOString()}),fn("Rollback complete")}async function rr(e,t,r,a){let l=Ao(e,t),m=new b(l.region),h=`${l.slug}-${t}-http`,R={...(await m.getFunction(h)).Configuration?.Environment?.Variables??{}};if(R.MAINTENANCE_MODE=r?"1":"0",r&&a)R.MAINTENANCE_BYPASS_SECRET=a;if(!r)delete R.MAINTENANCE_BYPASS_SECRET;if(await Ro(()=>m.updateFunctionConfiguration({FunctionName:h,Environment:{Variables:R}})),(l.app.provisionedConcurrency??0)>0)await m.waitForFunctionActive(h,120),await $c(m,h);fn(r?"Application is now in maintenance mode (503)":"Application is live")}async function et(e,t,r){let a=Ao(e,t),l=new b(a.region),m=`${a.slug}-${t}-cli`,h=await l.invoke({FunctionName:m,InvocationType:"RequestResponse",Payload:{command:r},LogType:"Tail"});if(h.FunctionError)throw Error(`Command failed: ${h.Payload}`);return h.Payload??""}async function Pr(e,t){let r=Ao(e,t),a=new f(r.region),l=new b(r.region),m=new o(r.region),h="not deployed",I={};try{let{Stacks:V}=await a.describeStacks({stackName:r.stackName});h=V?.[0]?.StackStatus??h;for(let W of V?.[0]?.Outputs??[])if(W.OutputKey)I[W.OutputKey]=W.OutputValue??""}catch{}let R=Qd(r.app,r.slug,t),S=r.app.provisionedConcurrency??0,C=["http","cli",...R.length?["queue"]:[]],T=`${r.slug}-${t}`,j=[];for(let V of C){let W=`${T}-${V}`,Y={mode:V,name:W,version:"$LATEST"};if(S>0){let te=await l.getAlias(W,"live").catch(()=>null);if(te?.FunctionVersion){Y.version=te.FunctionVersion;let le=await l.getProvisionedConcurrencyConfig(W,"live").catch(()=>null);if(le)Y.provisioned={status:le.Status??"-",allocated:le.AllocatedProvisionedConcurrentExecutions??0,requested:le.RequestedProvisionedConcurrentExecutions??0}}}j.push(Y)}let B=await Nc(m,r.artifactBucket,r.slug,t).catch(()=>null);return{slug:r.slug,environment:t,region:r.region,stackStatus:h,endpoint:I.HttpApiEndpoint,assetUrl:B?.assetUrl,scheduler:r.app.scheduler??"on",queues:R,provisionedConcurrency:S,functions:j,lastRelease:B?{sha:B.sha,timestamp:B.timestamp}:void 0}}function ak(e,t){return`${e}-${t}-db`}async function hf(e,t,r,a){let l=Ao(e,t);if(l.app.database?.connection!=="aurora-serverless")throw Error("No Aurora Serverless v2 database is configured for this environment.");let{RDSClient:m}=await import("./chunk-dschvakr.js"),h=new m(l.region),I=ak(l.slug,t);w(`Scaling ${I} → ${r}–${a} ACUs`),await h.modifyDBCluster({DBClusterIdentifier:I,ServerlessV2ScalingConfiguration:{MinCapacity:r,MaxCapacity:a},ApplyImmediately:!0}),fn(`Scaling applied to ${I} (takes effect shortly).`)}class ip{client;region;constructor(e="us-east-1"){this.region=e,this.client=new n}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((m)=>({Name:m.Name,Priority:m.Priority,Action:m.Action?Object.keys(m.Action)[0]:m.OverrideAction?Object.keys(m.OverrideAction)[0]:"count"}))}}var ck=[{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"}],dk=[{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"}],lk=[{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"}],uk=/^(?:rpx-gateway|nginx|caddy|traefik|haproxy)$/;function Oe(e,t=""){let r=e==null?"":String(e).trim();return r&&r!=="-"&&r!=="—"?r:t}function pk(e){return Array.isArray(e)?e.length:0}function Un(e){let t=Oe(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 ur(e,t,r){if(r.has(t.source)&&r.has(t.target))e.push(t)}function vt(e,t={}){let r=[],a=[],l=[],m=e.server??{},h=Array.isArray(e.sites)?e.sites:[],I=Array.isArray(e.services)?e.services:[],R=Array.isArray(e.workers)?e.workers:[],S=e.security??{},C=!!e._serverReachable&&!e.metricsUnavailable,T="box";if(!C)l.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 j=[...new Set(h.map((de)=>Oe(de.domain)||Oe(de.route).split("/")[0]).filter((de)=>de&&de!=="internal"&&de!=="loopback"))],B=Array.isArray(S.tlsCertificates)?S.tlsCertificates:[],V=B.filter((de)=>Number(de?.daysRemaining??999)<21).length;r.push({id:"dns",label:j.length===1?j[0]:"Public domains",kind:"dns",layer:1,status:V?"warn":j.length?"ok":"unknown",sub:j.length>1?`${j.length} domains`:"DNS & certificates",facts:[{label:"Domains",value:j.length?j.slice(0,6).join(", "):"none resolved"},{label:"Certificates",value:B.length?`${B.length} issued`:"none reported"},...V?[{label:"Expiring",value:`${V} within 21 days`}]:[]],href:"/server/security",external:!0});let W=S.firewall??{},Y=Array.isArray(S.ports)?S.ports:[];r.push({id:"firewall",label:"Host firewall",kind:"firewall",layer:2,status:Un(W.status),sub:Oe(W.summary,"Inbound filtering"),facts:[{label:"State",value:Oe(W.status,"unknown")},{label:"Open ports",value:Y.length?Y.map((de)=>Oe(de.listen)).join(", "):"not reported"}],href:"/server/firewall",group:"box"});let te=I.find((de)=>uk.test(Oe(de.name)));r.push({id:"proxy",label:Oe(te?.name,"Reverse proxy"),kind:"proxy",layer:3,status:te?Un(te.status):"unknown",sub:"TLS termination & routing",facts:[{label:"Service",value:Oe(te?.name,"not detected")},{label:"State",value:Oe(te?.status,C?"not running":"not probed")},{label:"Routes",value:`${h.length} site${h.length===1?"":"s"}`}],href:"/server/services",group:"box"});for(let de of h){let Ne=`site:${Oe(de.name)}`;if(!Oe(de.name))continue;r.push({id:Ne,label:Oe(de.name),kind:"site",layer:4,status:Un(de.status),sub:Oe(de.runtime,"runtime"),facts:[{label:"Route",value:Oe(de.route,"internal")},{label:"Runtime",value:Oe(de.runtime,"unknown")},{label:"Delivery",value:Oe(de.deploy,"unknown")},{label:"TLS",value:Oe(de.tls,"unknown")},...de.responseMs!=null?[{label:"Response",value:`${Math.round(Number(de.responseMs))} ms`}]:[],...de.httpStatus!=null?[{label:"HTTP",value:String(de.httpStatus)}]:[]],href:"/server/sites",group:"box"})}for(let de of R){let Ne=`worker:${Oe(de.name)}`;if(!Oe(de.name))continue;r.push({id:Ne,label:Oe(de.name),kind:"worker",layer:5,status:Un(de.status),sub:`${Number(de.processes??1)} process${Number(de.processes??1)===1?"":"es"}`,facts:[{label:"Processes",value:String(de.processes??1)},{label:"State",value:Oe(de.status,"unknown")},...Oe(de.site)?[{label:"Site",value:Oe(de.site)}]:[]],href:"/operations/jobs",group:"box"})}let le=e.serverScheduler??{};if(le.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:5,status:"ok",sub:"Cron dispatch",facts:[{label:"Last run",value:Oe(le.lastRun,"unknown")}],href:"/operations/jobs",group:"box"});let X=I.map((de)=>{let Ne=Oe(de.name),ae=lk.find((je)=>je.match.test(Ne));return ae?{service:de,name:Ne,...ae}:null}).filter((de)=>!!de);for(let de of X)r.push({id:`data:${de.name}`,label:de.label,kind:de.kind,layer:6,status:Un(de.service.status),sub:de.name,facts:[{label:"Unit",value:de.name},{label:"State",value:Oe(de.service.status,"unknown")}],href:"/data/services",group:"box"});let ce=e.backup??{};if(ce.enabled)r.push({id:"backup",label:"Backups",kind:"backup",layer:7,status:"ok",sub:Oe(ce.destination,"destination"),facts:[{label:"Destination",value:Oe(ce.destination,"unknown")},{label:"Schedule",value:Oe(ce.schedule,"unknown")},{label:"Retention",value:`${ce.retention??0} copies`},{label:"Last run",value:Oe(ce.last,"unknown")}],href:"/data/backups"});let Ee=new Set(r.map((de)=>de.id));ur(a,{source:"internet",target:"dns",flow:"request",label:"https"},Ee),ur(a,{source:"dns",target:"firewall",flow:"request",label:"443/80"},Ee),ur(a,{source:"firewall",target:"proxy",flow:"request"},Ee);for(let de of h){let Ne=`site:${Oe(de.name)}`;ur(a,{source:"proxy",target:Ne,flow:"request",label:Oe(de.path)||void 0,status:Un(de.status)},Ee)}for(let de of R){let Ne=`worker:${Oe(de.name)}`,ae=`site:${Oe(de.site)}`;if(Ee.has(ae))ur(a,{source:ae,target:Ne,flow:"async",label:"queue"},Ee);else ur(a,{source:"proxy",target:Ne,flow:"async",label:"queue"},Ee)}for(let de of R)ur(a,{source:"scheduler",target:`worker:${Oe(de.name)}`,flow:"async",label:"dispatch"},Ee);let Re=[...h.map((de)=>`site:${Oe(de.name)}`),...R.map((de)=>`worker:${Oe(de.name)}`)];for(let de of X)for(let Ne of Re)ur(a,{source:Ne,target:`data:${de.name}`,flow:"data",label:"localhost"},Ee);if(X.length&&Re.length)l.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 de of X)ur(a,{source:`data:${de.name}`,target:"backup",flow:"backup",label:"snapshot"},Ee);for(let de of h)ur(a,{source:`site:${Oe(de.name)}`,target:"backup",flow:"backup"},Ee);return{mode:"server",project:Oe(t.project)||Oe(e.project?.name)||Oe(m.name,"project"),environment:Oe(t.environment)||Oe(e.environment,"production"),provider:Oe(m.provider,"unknown"),region:Oe(m.region,"unknown"),generatedAt:new Date().toISOString(),layers:ck,groups:[{id:"box",label:Oe(m.name,"App server"),sub:[Oe(m.provider),Oe(m.region),Oe(m.ip)].filter(Boolean).join(" · ")}],nodes:r,links:a,notes:l}}function es(e,t={}){let r=[],a=[],l=[],m=e.app??{},h=Array.isArray(e.functions)?e.functions:[],I=Array.isArray(e.queues)?e.queues:[],R=e.metrics??{};if(!h.length)l.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 S=Oe(m.url),C=S.replace(/^https?:\/\//,"").split("/")[0];r.push({id:"dns",label:C||"Application domain",kind:"dns",layer:1,status:C?"ok":"unknown",sub:"DNS & certificates",facts:[{label:"Endpoint",value:S||"not resolved"}],external:!0});let T=e.waf;if(T)r.push({id:"waf",label:"WAF",kind:"waf",layer:2,status:Un(T.status??"active"),sub:Oe(T.scope,"Managed rules"),facts:[{label:"Web ACL",value:Oe(T.name,"unnamed")},...T.blocked!=null?[{label:"Blocked (24h)",value:String(T.blocked)}]:[],{label:"Rules",value:String(pk(e.wafRules))}],href:"/serverless/firewall"});let j=e.assetsInfo;if(j)r.push({id:"cdn",label:"Asset CDN",kind:"cdn",layer:2,status:"ok",sub:Oe(j.cdn,"CloudFront"),facts:[{label:"Distribution",value:Oe(j.cdn,"unknown")},{label:"Custom domain",value:Oe(j.customDomain,"none")}],href:"/serverless/assets"}),r.push({id:"assets",label:"Asset bucket",kind:"storage",layer:6,status:"ok",sub:Oe(j.bucket,"S3"),facts:[{label:"Bucket",value:Oe(j.bucket,"unknown")},...j.files?[{label:"Objects",value:String(j.files)}]:[],...j.sizeMb?[{label:"Size",value:`${j.sizeMb} MB`}]:[]],href:"/serverless/assets"});let B=h.find((ae)=>Oe(ae.key).startsWith("http"));r.push({id:"gateway",label:"HTTP entry point",kind:"gateway",layer:3,status:B?"ok":"unknown",sub:"Function URL / API Gateway",facts:[{label:"Endpoint",value:S||"not resolved"},{label:"Invocations (24h)",value:String(R.invocations??0)},...R.errorRatePct!=null?[{label:"Error rate",value:`${R.errorRatePct}%`}]:[]],href:"/serverless/metrics"});for(let ae of h){let je=`fn:${Oe(ae.name)}`;if(!Oe(ae.name))continue;let Qe=Number(ae.errors??0),gt=Number(ae.invocations??0);r.push({id:je,label:Oe(ae.key,Oe(ae.name)),kind:"function",layer:4,status:Qe>0?gt&&Qe/gt>0.02?"bad":"warn":gt?"ok":"idle",sub:Oe(ae.runtime,"lambda"),facts:[{label:"Function",value:Oe(ae.name)},{label:"Memory",value:`${ae.memory??0} MB`},{label:"Timeout",value:`${ae.timeout??0}s`},{label:"Invocations (24h)",value:String(gt)},{label:"Errors (24h)",value:String(Qe)},{label:"p95",value:`${ae.p95??0} ms`},...ae.provisioned?[{label:"Provisioned",value:Oe(ae.provisioned)}]:[]],href:"/serverless/functions"})}for(let ae of I){let je=`queue:${Oe(ae.name)}`;if(!Oe(ae.name))continue;let Qe=Number(ae.dlq??0);r.push({id:je,label:Oe(ae.name),kind:"queue",layer:5,status:Qe>0?"bad":Number(ae.visible??0)>0?"warn":"ok",sub:"SQS",facts:[{label:"Visible",value:String(ae.visible??0)},{label:"In flight",value:String(ae.inFlight??0)},{label:"Processed (24h)",value:String(ae.processed??0)},{label:"Dead letter",value:String(Qe)}],href:"/serverless/queues"})}let V=e.aurora;if(V)r.push({id:"database",label:"Aurora Serverless",kind:"database",layer:6,status:Un(V.status),sub:Oe(V.engine,"aurora"),facts:[{label:"Cluster",value:Oe(V.id,"unknown")},{label:"Capacity",value:`${V.currentAcu??0} ACU (${V.minAcu??0}–${V.maxAcu??0})`},{label:"Connections",value:String(V.connections??0)}],href:"/serverless/data"});let W=e.proxy;if(W)r.push({id:"rds-proxy",label:"RDS Proxy",kind:"database",layer:5,status:Un(W.status),sub:"Connection pooling",facts:[{label:"Proxy",value:Oe(W.name,"unknown")},{label:"Endpoint",value:Oe(W.endpoint,"unknown")},{label:"Pooled",value:String(W.pooledConns??0)}],href:"/serverless/data"});let Y=e.redis;if(Y)r.push({id:"cache",label:"ElastiCache",kind:"cache",layer:6,status:Un(Y.status),sub:Oe(Y.node,"redis"),facts:[{label:"Group",value:Oe(Y.id,"unknown")},{label:"Hit rate",value:`${Y.hitRate??0}%`}],href:"/serverless/data"});let te=e.efs;if(te)r.push({id:"efs",label:"EFS",kind:"filesystem",layer:6,status:Un(te.status),sub:Oe(te.mount,"/mnt/local"),facts:[{label:"File system",value:Oe(te.id,"unknown")},{label:"Mount",value:Oe(te.mount,"unknown")},{label:"Size",value:`${te.sizeMb??0} MB`}],href:"/data/volumes"});let le=e.scheduler??{};if(le.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:3,status:"ok",sub:Oe(le.expression,"rate(1 minute)"),facts:[{label:"Expression",value:Oe(le.expression,"unknown")},{label:"Last run",value:Oe(le.lastRun,"unknown")}],href:"/operations/jobs"});let X=new Set(r.map((ae)=>ae.id)),ce=X.has("waf")?"waf":"gateway";ur(a,{source:"internet",target:"dns",flow:"request",label:"https"},X),ur(a,{source:"dns",target:ce,flow:"request"},X),ur(a,{source:"dns",target:"cdn",flow:"request",label:"assets"},X),ur(a,{source:"waf",target:"gateway",flow:"request",label:"allowed"},X),ur(a,{source:"cdn",target:"assets",flow:"data",label:"origin"},X);let Ee=h.filter((ae)=>Oe(ae.key).startsWith("http")),Re=h.filter((ae)=>Oe(ae.key).startsWith("queue")),de=h.filter((ae)=>Oe(ae.key).startsWith("cli"));for(let ae of Ee)ur(a,{source:"gateway",target:`fn:${Oe(ae.name)}`,flow:"request",label:"invoke"},X);for(let ae of de)ur(a,{source:"scheduler",target:`fn:${Oe(ae.name)}`,flow:"async",label:"schedule"},X);for(let ae of I){for(let je of Ee)ur(a,{source:`fn:${Oe(je.name)}`,target:`queue:${Oe(ae.name)}`,flow:"async",label:"publish"},X);for(let je of Re)ur(a,{source:`queue:${Oe(ae.name)}`,target:`fn:${Oe(je.name)}`,flow:"async",label:"consume"},X)}let Ne=["rds-proxy","database","cache","efs","assets"];for(let ae of h){let je=`fn:${Oe(ae.name)}`;if(X.has("rds-proxy"))ur(a,{source:je,target:"rds-proxy",flow:"data",label:"pooled"},X);else ur(a,{source:je,target:"database",flow:"data",label:"sql"},X);for(let Qe of Ne.filter((gt)=>gt!=="rds-proxy"&&gt!=="database"))ur(a,{source:je,target:Qe,flow:"data"},X)}return ur(a,{source:"rds-proxy",target:"database",flow:"data",label:"sql"},X),{mode:"serverless",project:Oe(t.project)||Oe(m.name,"application"),environment:Oe(t.environment)||Oe(m.env,"production"),provider:"aws",region:Oe(m.region,"unknown"),generatedAt:new Date().toISOString(),layers:dk,groups:[],nodes:r,links:a,notes:l}}function Sh(e,t,r={}){return e==="serverless"?es(t,r):vt(t,r)}function yf(e){return String(e).padStart(2,"0")}function Cs(e){return`${e.getUTCFullYear()}-${yf(e.getUTCMonth()+1)}-${yf(e.getUTCDate())}`}function gk(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 a=Math.round(r/60);if(a<48)return`${a}h ago`;return`${Math.round(a/24)}d ago`}async function Ya(e,t,r,a,l,m){let h=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:r,Dimensions:[{Name:"FunctionName",Value:t}],StartTime:l,EndTime:m,Period:86400,Statistics:[a]}).catch(()=>[]);if(!h.length)return 0;if(a==="Sum")return h.reduce((I,R)=>I+(R.Sum??0),0);if(a==="Maximum")return Math.max(...h.map((I)=>I.Maximum??0));return h.reduce((I,R)=>I+(R.Average??0),0)/h.length}async function Za(e,t,r,a,l,m,h){let I=await e.getMetricStatistics({Namespace:t,MetricName:r,Dimensions:a,StartTime:m,EndTime:h,Period:86400,Statistics:[l]}).catch(()=>[]);if(!I.length)return 0;if(l==="Sum")return I.reduce((R,S)=>R+(S.Sum??0),0);if(l==="Maximum")return Math.max(...I.map((R)=>R.Maximum??0));return I.reduce((R,S)=>R+(S.Average??0),0)/I.length}async function op(e,t,r,a,l){let m=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:"Duration",Dimensions:[{Name:"FunctionName",Value:t}],StartTime:a,EndTime:l,Period:86400,ExtendedStatistics:[r]}).catch(()=>[]);return Math.round(m.reduce((h,I)=>h+(I.Percentiles?.[r]??0),0))}async function un(e,t){let r=await Pr(e,t),a=r.region,l=new oe(a),m=new b(a),h=new ye(a),I=new Date,R=new Date(I.getTime()-86400000),S=e.environments?.[t]?.app,C={};C.app={name:r.slug,env:t,region:a,runtime:S?.kind==="php"?`php-${S?.phpVersion??"8.3"} (fpm)`:S?.kind??"node",url:r.endpoint??"",build:r.lastRelease?.sha?.slice(0,7)??"—",deployedAt:r.lastRelease?.timestamp??"—"},C.maintenance={enabled:!1},C.scheduler={enabled:r.scheduler!=="off",expression:r.scheduler==="sub-minute"?"rate(1 minute) · sub-minute":"rate(1 minute)",lastRun:"—"};let T=0,j=0,B=0,V=[],W=[],Y=[];for(let ce of r.functions){let[Ee,Re,de,Ne,ae,je,Qe,gt,Kt]=await Promise.all([Ya(l,ce.name,"Invocations","Sum",R,I),Ya(l,ce.name,"Errors","Sum",R,I),Ya(l,ce.name,"Throttles","Sum",R,I),Ya(l,ce.name,"Duration","Average",R,I),m.getFunction(ce.name).catch(()=>null),op(l,ce.name,"p50",R,I),op(l,ce.name,"p95",R,I),op(l,ce.name,"p99",R,I),l.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:ce.name}],StartTime:new Date(I.getTime()-43200000),EndTime:I,Period:3600,Stat:"Sum"}).catch(()=>[])]);T+=Ee,j+=Re,B=Math.max(B,Ne);let ot=ae?.Configuration?.MemorySize??0,Pt=Object.keys(ae?.Configuration?.Environment?.Variables??{}),ir=[],lt=0;try{let{events:ue=[]}=await h.filterLogEvents({logGroupName:`/aws/lambda/${ce.name}`,startTime:R.getTime(),limit:120});for(let be of ue){let De=(be.message??"").trim(),mt=/Max Memory Used:\s*(\d+)\s*MB/.exec(De);if(mt)lt=Math.max(lt,Number(mt[1]));if(De&&!/^(?:START|END|REPORT|INIT_START)/.test(De))Y.push({source:ce.mode||ce.name,timestamp:new Date(be.timestamp??0).toISOString(),when:gk(be.timestamp??0),message:De.slice(0,400),level:/error|exception|fatal|panic|traceback/i.test(De)?"error":/warn|warning|timeout|retr(?:y|ies)|throttl/i.test(De)?"warn":"info"})}ir=ue.filter((be)=>!/^(?:START|END|REPORT|INIT_START)/.test((be.message??"").trim())).slice(-6).map((be)=>({ts:new Date(be.timestamp??0).toISOString().slice(11,19),msg:(be.message??"").trim().slice(0,120),err:/error|exception|fatal/i.test(be.message??"")}))}catch{}let G=Math.max(1,...Kt);V.push({key:ce.mode,name:ce.name,version:ce.version,memory:ot,timeout:ae?.Configuration?.Timeout??0,runtime:ae?.Configuration?.Runtime??"provided.al2023",invocations:Math.round(Ee),errors:Math.round(Re),p95:Qe||Math.round(Ne),status:"active",provisioned:ce.provisioned?`${ce.provisioned.allocated}/${ce.provisioned.requested}`:void 0}),W.push({key:ce.mode,name:ce.name,runtime:ae?.Configuration?.Runtime??"provided.al2023",arch:ae?.Configuration?.Architectures?.[0]??"x86_64",memory:ot,timeout:ae?.Configuration?.Timeout??0,ephemeral:ae?.Configuration?.EphemeralStorage?.Size??512,version:ce.version,concurrency:S?.concurrency??"—",invocations:Math.round(Ee),errors:Math.round(Re),throttles:Math.round(de),p50:je||Math.round(Ne),p95:Qe||Math.round(Ne),p99:gt||Math.round(Ne),maxMem:lt,spark:Kt.length?Kt.map((ue)=>Math.round(ue/G*100)):[0],env:Pt.length?Pt:["(none)"],recent:ir.length?ir:[{ts:"—",msg:"no recent events",err:!1}]})}C.functions=V,C.functionsDetail=W,C.serverlessLogs=Y.sort((ce,Ee)=>String(Ee.timestamp).localeCompare(String(ce.timestamp))).slice(0,600),C.serverlessLogsEmptyReason=Y.length?void 0:"No recent function logs were found in CloudWatch for this environment.";let te=T?Number((j/T*100).toFixed(2)):0,le=Math.round(await Ya(l,r.functions[0]?.name??"","ConcurrentExecutions","Maximum",R,I));C.metrics={invocations:Math.round(T),errorRatePct:te,p95Ms:Math.round(B),coldStartPct:void 0,concurrency:le,estCostUsd:void 0};try{let ce=new se(a),Ee=[],Re=[],de=0;try{let{QueueUrl:ae}=await ce.getQueueUrl(`${r.slug}-${t}-dlq`),{Attributes:je}=await ce.getQueueAttributes(ae);de=Number(je.ApproximateNumberOfMessages??0)}catch{}let Ne=S?Jt(S,r.slug,t):[];for(let ae of Ne){let je=ae.name.replace(`${r.slug}-${t}-`,""),Qe=0,gt=0;try{let{QueueUrl:ot}=await ce.getQueueUrl(ae.name),{Attributes:Pt}=await ce.getQueueAttributes(ot);Qe=Number(Pt.ApproximateNumberOfMessages??0),gt=Number(Pt.ApproximateNumberOfMessagesNotVisible??0)}catch{}let Kt=Math.round(await Za(l,"AWS/SQS","NumberOfMessagesDeleted",[{Name:"QueueName",Value:ae.name}],"Sum",R,I));Ee.push({name:je,visible:Qe,inFlight:gt,processed:Kt,dlq:de}),Re.push({name:ae.name,short:je,visible:Qe,inFlight:gt,delayed:0,processed:Kt,oldestSec:0,concurrency:ae.concurrency??S?.queueConcurrency??"—",tries:S?.queueTries??3,visTimeout:(S?.queueTimeout??120)*6,dlq:de})}if(Ee.length)C.queues=Ee;if(Re.length)C.queuesDetail=Re;C.dlqItems=[]}catch{}try{let ce=new f(a),{Stacks:Ee}=await ce.describeStacks({stackName:Gt(e,t)}),Re={};for(let de of Ee?.[0]?.Outputs??[])if(de.OutputKey)Re[de.OutputKey]=de.OutputValue??"";if(S?.database?.connection==="aurora-serverless"){let de=`${r.slug}-${t}-db`,Ne=[{Name:"DBClusterIdentifier",Value:de}],[ae,je]=await Promise.all([Za(l,"AWS/RDS","ServerlessDatabaseCapacity",Ne,"Average",R,I),Za(l,"AWS/RDS","DatabaseConnections",Ne,"Maximum",R,I)]);if(C.aurora={id:de,engine:"aurora-mysql",minAcu:S?.database?.minCapacity??0.5,maxAcu:S?.database?.maxCapacity??4,currentAcu:ae?Number(ae.toFixed(1)):S?.database?.minCapacity??0.5,database:"app",connections:Math.round(je),status:Re.DbEndpoint?"available":"creating"},S?.rdsProxy)C.proxy={name:`${r.slug}-${t}-proxy`,endpoint:Re.DbProxyEndpoint??"—",pooledConns:Math.round(je),status:"available"}}if(S?.cache?.driver==="elasticache"){let de=`${r.slug}-${t}-cache`,Ne=[{Name:"CacheClusterId",Value:`${de}-001`}],[ae,je]=await Promise.all([Za(l,"AWS/ElastiCache","CacheHits",Ne,"Sum",R,I),Za(l,"AWS/ElastiCache","CacheMisses",Ne,"Sum",R,I)]),Qe=ae+je>0?Number((ae/(ae+je)*100).toFixed(1)):0;C.redis={id:de,node:"cache.t4g.micro",engine:"redis",hitRate:Qe,status:Re.CacheEndpoint?"available":"creating"}}if(S?.efs){let de=0;try{if(Re.EfsFileSystemId){let Ne=new cr(a),{FileSystems:ae}=await Ne.describeFileSystems({FileSystemId:Re.EfsFileSystemId});de=Number(((ae?.[0]?.SizeInBytes?.Value??0)/1048576).toFixed(1))}}catch{}C.efs={id:Re.EfsFileSystemId??"efs",mount:"/mnt/local",sizeMb:de,status:"available"}}C.assetsInfo=Re.AssetsCdnDomain?{bucket:Re.AssetsBucketName??`${r.slug}-${t}-assets`,cdn:Re.AssetsCdnDomain,customDomain:S?.assetDomain??"—",assetUrl:r.assetUrl??"—",files:0,sizeMb:0,cacheHitPct:0,build:C.app.build}:void 0}catch{}if(C.assetsInfo)try{let Ee=await new o(a).list({bucket:C.assetsInfo.bucket,maxKeys:1000});C.assetsInfo.files=Ee.length,C.assetsInfo.sizeMb=Number((Ee.reduce((Re,de)=>Re+(de.Size??0),0)/1048576).toFixed(1)),C.assetsRecent=Ee.slice(0,8).map((Re)=>({path:`/${Re.Key}`,size:`${Math.max(1,Math.round((Re.Size??0)/1024))} KB`,type:Re.Key.split(".").pop()??""}))}catch{}try{if(S?.secrets){let ce=Array.isArray(S.secrets)?S.secrets.map((Ee)=>({key:Ee.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),source:Ee})):Object.entries(S.secrets).map(([Ee,Re])=>({key:Ee,source:String(Re)}));C.secretsList=ce.map((Ee)=>({...Ee,updated:"—"}))}}catch{}try{let ce=new o(a),Ee=`${r.slug}-${t}-deployments`,Re=await ce.getObjectJson(Ee,`deployments/${r.slug}/${t}/history.json`).catch(()=>null);if(Re?.records?.length)C.deploymentsDetail=Re.records.slice(-12).reverse().map((de)=>({sha:(de.sha??"").slice(0,7),status:de.status??"success",when:de.timestamp??"—",took:de.took??"—",by:de.by??"—",version:de.version??"—",hooks:de.hooks??[]}))}catch{}C.metricsTotals={invocations:C.metrics.invocations,errors:Math.round(j),errorRatePct:te,p95Ms:C.metrics.p95Ms,throttles:W.reduce((ce,Ee)=>ce+Ee.throttles,0),coldStartPct:void 0,estCostUsd:void 0,concurrency:le},C.metricsPerFn=W.map((ce)=>({key:ce.key,invocations:ce.invocations,errors:ce.errors,throttles:ce.throttles,avgMs:ce.p50,maxMs:ce.p99,costUsd:void 0}));try{C.invSpark=await l.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:r.functions.find((ce)=>ce.mode==="http")?.name??""}],StartTime:new Date(I.getTime()-86400000),EndTime:I,Period:3600,Stat:"Sum"})}catch{}try{let ce=new gs,Ee=I,Re=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth(),1)),de=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth()-1,1)),[Ne,ae]=await Promise.all([ce.getCostByService({start:Cs(Re),end:Cs(Ee),granularity:"MONTHLY"}).catch(()=>[]),ce.getCostByService({start:Cs(de),end:Cs(Re),granularity:"MONTHLY"}).catch(()=>[])]);if(Ne.length){let je=Ne.reduce((lt,G)=>lt+G.amount,0),Qe=ae.reduce((lt,G)=>lt+G.amount,0),gt=Ee.getUTCDate(),Kt=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth()+1,0)).getUTCDate();C.costSummary={monthToDateUsd:Number(je.toFixed(2)),projectedUsd:Number((je/gt*Kt).toFixed(2)),lastMonthUsd:Number(Qe.toFixed(2)),dailyAvgUsd:Number((je/gt).toFixed(2))},C.costServices=Ne.filter((lt)=>lt.amount>0).sort((lt,G)=>G.amount-lt.amount).slice(0,12).map((lt)=>({name:lt.service,usd:Number(lt.amount.toFixed(2)),note:""})),C.metrics.estCostUsd=Number((je/gt).toFixed(2)),C.metricsTotals.estCostUsd=C.metrics.estCostUsd,C.costTrend=await ce.getDailyTotals({start:Cs(Re),end:Cs(Ee)}).catch(()=>[]);let ot=Ne.find((lt)=>/lambda/i.test(lt.service))?.amount??0,Pt=(lt)=>lt.invocations*(lt.p50/1000)*(lt.memory/1024),ir=W.reduce((lt,G)=>lt+Pt(G),0)||1;C.costPerFn=W.map((lt)=>({key:lt.key,requests:lt.invocations,gbSec:Math.round(Pt(lt)),usd:Number((ot*(Pt(lt)/ir)).toFixed(2))}))}}catch{}if(S?.firewall)try{let ce=await l.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"BlockedRequests",StartTime:R,EndTime:I,Period:86400,Statistics:["Sum"]}).catch(()=>[]),Ee=await l.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"AllowedRequests",StartTime:R,EndTime:I,Period:86400,Statistics:["Sum"]}).catch(()=>[]);C.waf={enabled:!0,scope:"REGIONAL",acl:`${r.slug}-${t}-waf`,allowed24h:Math.round(Ee.reduce((Re,de)=>Re+(de.Sum??0),0)),blocked24h:Math.round(ce.reduce((Re,de)=>Re+(de.Sum??0),0))};try{let Re=new ip(a),de=await Re.listWebACLs("REGIONAL"),Ne=de.find((ae)=>ae.Name?.includes(`${r.slug}-${t}`))??de[0];if(Ne?.Name&&Ne.Id){C.waf.acl=Ne.Name;let ae=await Re.getWebACLRules(Ne.Name,Ne.Id,"REGIONAL");if(ae.length)C.wafRules=ae.map((je)=>({name:je.Name??"—",detail:`priority ${je.Priority??0}`,action:je.Action??"count",blocked24h:0}))}}catch{}}catch{}let X=[];if(C.aurora)X.push({name:"Aurora Serverless v2",detail:`${C.aurora.id} · ${C.aurora.minAcu}-${C.aurora.maxAcu} ACU`,status:C.aurora.status});if(C.proxy)X.push({name:"RDS Proxy",detail:C.proxy.name,status:C.proxy.status});if(C.redis)X.push({name:`ElastiCache (${C.redis.engine})`,detail:`${C.redis.node} · ${C.redis.hitRate}% hit rate`,status:C.redis.status});if(C.efs)X.push({name:"EFS",detail:`${C.efs.mount} · ${C.efs.sizeMb} MB`,status:C.efs.status});if(X.length)C.dataServices=X;if(r.scheduler!=="off"&&S?.kind==="php")try{let ce=await et(e,t,"schedule:list"),Ee=[];for(let Re of(ce||"").split(`
39
+ `;function af(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function Dw(e){return["NoSuchEntity","ResourceNotFoundException","404"].includes(af(e))}function of(e){return["EntityAlreadyExists","ResourceAlreadyExistsException","ResourceConflictException","409"].includes(af(e))}function sf(e,t){let r=e?.Items;if(!r)return[];if(Array.isArray(r))return r;let a=r[t];if(a===void 0)return[];return Array.isArray(a)?a:[a]}function rp(e){let t=e?.Aliases?.Items,r=t?.CNAME??t;if(Array.isArray(r))return r.map(String);if(typeof r==="string")return[r];return[]}function Ow(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`,a=e.roleName||`${e.functionName}-execution`;if(!/^[A-Za-z0-9_.-]{1,64}$/.test(a))throw Error("IAM role name is invalid");let l=e.memorySize??256,m=e.timeout??10,h=e.logRetentionDays??14;if(l<128||l>10240)throw Error("Lambda memory must be between 128 and 10240 MB");if(m<1||m>900)throw Error("Lambda timeout must be between 1 and 900 seconds");return{region:e.region||"us-east-1",pathPattern:t,originId:r,roleName:a,memorySize:l,timeout:m,logRetentionDays:h}}function hh(e){let t=e.region||"us-east-1";return{cloudfront:new y(e.profile),iam:new Ie(t,e.profile),lambda:new b(t,e.profile),logs:new ye(t,e.profile),sts:new Ae(t,e.profile),sleep:(r)=>new Promise((a)=>setTimeout(a,r))}}async function vy(e,t){let r=Ow(e),a=t||hh({profile:e.profile,region:r.region}),[l,m,h]=await Promise.all([a.sts.getCallerIdentity(),a.cloudfront.getDistribution(e.distributionId),a.cloudfront.getDistributionConfig(e.distributionId)]);if(!l.Account)throw Error("AWS identity did not return an account ID");if(!m.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!(rp(m).length?rp(m):rp(h.DistributionConfig)).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let R,S=!0;try{R=await a.iam.getRole({RoleName:r.roleName})}catch(ot){if(!Dw(ot))throw ot;S=!1}let C=R?.Arn||`arn:aws:iam::${l.Account}:role/${r.roleName}`,T=await a.lambda.functionExists(e.functionName),j=T?await a.lambda.getFunctionUrl(e.functionName):null,B=await a.cloudfront.listOriginAccessControls(),V=`${e.functionName}-lambda-url`,W=B.some((ot)=>ot.Name===V&&ot.OriginAccessControlOriginType==="lambda"),Y=sf(h.DistributionConfig.Origins,"Origin"),te=sf(h.DistributionConfig.CacheBehaviors,"CacheBehavior"),le=Y.some((ot)=>String(ot.Id)===r.originId),X=te.some((ot)=>String(ot.PathPattern)===r.pathPattern),ce=[...!S?[`create IAM execution role ${r.roleName}`]:[`reconcile IAM execution policy ${r.roleName}`],...T?[`update Lambda ${e.functionName} code and configuration`]:[`create Lambda ${e.functionName}`],...!j?["create private AWS_IAM function URL"]:[],...!W?[`create Lambda origin access control ${V}`]:[],"grant CloudFront function-URL and invocation permissions",`${X?"reconcile":"add"} ${r.pathPattern} behavior without changing the default behavior`],Ee={command:`cloud cdn:origin:remove ${e.distributionId} FUNCTION_URL_HOST --id ${r.originId} --path '${r.pathPattern}' --apply --confirm 'remove:${e.distributionId}:${r.pathPattern}'`,removeFunction:!T,removeRole:!S},Re={mode:e.apply?"apply":"plan",accountId:l.Account,identityArn:l.Arn,distribution:{id:m.Id,arn:m.ARN,alias:e.expectedAlias,domainName:m.DomainName,status:m.Status},function:{name:e.functionName,existed:T,runtime:"nodejs22.x",urlExisted:!!j,url:j?.FunctionUrl},role:{name:r.roleName,existed:S,arn:C},origin:{id:r.originId,pathPattern:r.pathPattern,existed:le,behaviorExisted:X,accessControlExisted:W},changes:ce,rollback:Ee,applied:!1};if(!e.apply)return Re;let de=`${e.distributionId}:${r.pathPattern}`;if(e.confirm!==de)throw Error(`Pass exact confirmation token ${de} to mutate the live distribution`);if(!R)R=await a.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 a.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}:${l.Account}:log-group:/aws/lambda/${e.functionName}:*`}]})});try{await a.logs.createLogGroup(`/aws/lambda/${e.functionName}`,{ManagedBy:"ts-cloud"})}catch(ot){if(!of(ot))throw ot}await a.logs.putRetentionPolicy(`/aws/lambda/${e.functionName}`,r.logRetentionDays);let Ne=e.code||xw;if(T)await a.lambda.updateFunctionCodeInline(e.functionName,Ne,"index.mjs"),await a.lambda.waitForFunctionActive(e.functionName),await a.lambda.updateFunctionConfiguration({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:R.Arn,Handler:"index.handler",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize});else{let ot;for(let Pt=0;Pt<8;Pt++)try{await a.lambda.createFunctionWithCode({FunctionName:e.functionName,Runtime:"nodejs22.x",Role:R.Arn,Handler:"index.handler",Code:Ne,Filename:"index.mjs",Description:`Private API origin for ${e.expectedAlias}`,Timeout:r.timeout,MemorySize:r.memorySize}),ot=void 0;break}catch(ir){if(ot=ir,!String(ir.message).toLowerCase().includes("role"))throw ir;await a.sleep(1000)}if(ot)throw ot}await a.lambda.waitForFunctionActive(e.functionName);let ae=j||await a.lambda.createFunctionUrl({FunctionName:e.functionName,AuthType:"AWS_IAM",InvokeMode:"BUFFERED"});if(!ae.FunctionUrl)throw Error("Lambda did not return a function URL");let je=new URL(ae.FunctionUrl).hostname,Qe=await a.cloudfront.findOrCreateOriginAccessControl(V,"lambda"),gt=m.ARN||`arn:aws:cloudfront::${l.Account}:distribution/${e.distributionId}`,Kt=[{FunctionName:e.functionName,StatementId:"AllowCloudFrontFunctionUrl",Action:"lambda:InvokeFunctionUrl",Principal:"cloudfront.amazonaws.com",SourceArn:gt,FunctionUrlAuthType:"AWS_IAM"},{FunctionName:e.functionName,StatementId:"AllowCloudFrontInvoke",Action:"lambda:InvokeFunction",Principal:"cloudfront.amazonaws.com",SourceArn:gt,InvokedViaFunctionUrl:!0}];for(let ot of Kt)try{await a.lambda.addPermission(ot)}catch(Pt){if(!of(Pt))throw Pt}return await a.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:je,pathPattern:r.pathPattern,originAccessControlId:Qe.Id}),{...Re,function:{...Re.function,url:ae.FunctionUrl},applied:!0}}async function Ty(e){let t=`https://${e.alias}/`,r=`https://${e.alias}/api/health`,a=await fetch(t,{redirect:"follow",headers:{"cache-control":"no-cache"}}),l=new Uint8Array(await a.arrayBuffer()),m=Tw("sha256").update(l).digest("hex"),h=Date.now(),I=await fetch(r,{redirect:"follow",headers:{"cache-control":"no-cache"}}),R=Date.now()-h,S=await I.text(),C=S;try{C=JSON.parse(S)}catch{}let T;if(e.logs&&e.functionName){let j=await e.logs.filterLogEvents({logGroupName:`/aws/lambda/${e.functionName}`,startTime:h-60000,filterPattern:'"Init Duration"',limit:25});for(let B of j.events||[]){let V=B.message?.match(/Init Duration:\s*([0-9.]+)\s*ms/i);if(V)T=Number(V[1])}}return{frontend:{url:t,status:a.status,sha256:m,unchanged:e.expectedFrontendSha256?m===e.expectedFrontendSha256:void 0,bytes:l.byteLength},api:{url:r,status:I.status,latencyMs:R,healthy:I.ok&&!!C?.ok,body:C},coldStart:{observed:T!==void 0,initDurationMs:T},verifiedAt:(e.now?.()||new Date).toISOString()}}function wy(e){let t=(e.memoryMb||256)/1024,r=Math.max(0,e.requests-(e.includeFreeTier===!1?0:1e6)),a=Math.max(0,e.requests*(e.averageDurationMs/1000)*t-(e.includeFreeTier===!1?0:400000)),l=r/1e6*0.2+a*0.0000166667,m=9.010025,h=16.425;return{lambdaUsd:Number(l.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 $w}from"node:crypto";function Nw(e){let t=e;return String(t?.code||t?.name||t?.statusCode||"")}function jw(e){return Nw(e)==="ValidationError"&&String(e.message).includes("does not exist")}function Bw(e){return Object.fromEntries((e||[]).map((t)=>[t.OutputKey,t.OutputValue]))}function Mw(e){let t=e?.Aliases?.Items??e?.Aliases,r=t?.CNAME??t;if(Array.isArray(r))return r.map(String);if(typeof r==="string")return[r];return[]}function cf(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 a=e.pathPattern||"/api/*";if(!/^\/[A-Za-z0-9_.*?~!$&'()+,;=:@%/-]+\*$/.test(a)||a==="/*")throw Error("Backend path must be a non-default wildcard pattern");let l=e.originId||`${e.slug}-backend`;if(!/^[A-Za-z0-9_.-]{1,128}$/.test(l))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:a,originId:l,digest:t}}function fh(e){let t=e.region||"us-east-1";return{cloudformation:new f(t,e.profile),cloudfront:new y(e.profile),sts:new Ae(t,e.profile),fetch,sleep:(r)=>new Promise((a)=>setTimeout(a,r))}}function Ah(e){let t=cf(e),r=$d({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}),a=Ld(r);return a.Description=`Managed backend for existing static frontend ${e.expectedAlias}`,a.Metadata={ManagedBy:"ts-cloud",ExistingDistributionId:e.distributionId,ExistingDistributionAlias:e.expectedAlias,BackendPathPattern:t.pathPattern,ContainerDigest:t.digest},a}async function Lw(e,t,r){let a;for(let l=0;l<30;l++){let m=Date.now();try{let h=await e.fetch(t,{redirect:"manual",headers:r?{"x-origin-verify":r}:void 0}),I=Date.now()-m,R=await h.text(),S=R;try{S=JSON.parse(R)}catch{}if(h.ok)return{url:t,status:h.status,latencyMs:I,body:S};a=Error(`origin returned ${h.status}`)}catch(h){a=h}if(l<29)await e.sleep(1e4)}throw Error(`Backend origin did not become healthy: ${a instanceof Error?a.message:String(a)}`)}async function Ry(e,t){let r=cf(e),a=t||fh({region:r.region,profile:e.profile}),[l,m]=await Promise.all([a.sts.getCallerIdentity(),a.cloudfront.getDistribution(e.distributionId)]);if(!l.Account)throw Error("AWS identity did not return an account ID");if(!m.Enabled)throw Error(`CloudFront distribution ${e.distributionId} is disabled`);if(!Mw(m).includes(e.expectedAlias))throw Error(`Distribution ${e.distributionId} does not contain expected alias ${e.expectedAlias}`);let h;try{h=(await a.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0]}catch(ce){if(!jw(ce))throw ce}let I=Ah(e),R=JSON.stringify(I);if(Buffer.byteLength(R)>51200)throw Error("Generated template exceeds the direct CloudFormation template body limit");let S=Object.values(I.Resources||{}).reduce((ce,Ee)=>(ce[Ee.Type]=(ce[Ee.Type]||0)+1,ce),{}),C=[`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.`],T={mode:e.apply?"apply":"plan",accountId:l.Account,stack:{name:r.stackName,existed:!!h,status:h?.StackStatus,templateSha256:$w("sha256").update(R).digest("hex"),resourceCount:Object.keys(I.Resources||{}).length,resourceTypes:S},distribution:{id:m.Id,alias:e.expectedAlias,domainName:m.DomainName,status:m.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:C};if(!e.apply)return T;let j=`${e.distributionId}:${r.pathPattern}:${r.stackName}`;if(e.confirm!==j)throw Error(`Pass exact confirmation token ${j} to provision the backend and change live routing`);if(h)try{await a.cloudformation.updateStack({stackName:r.stackName,templateBody:R,capabilities:["CAPABILITY_NAMED_IAM"],tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await a.cloudformation.waitForStack(r.stackName,"stack-update-complete")}catch(ce){if(!String(ce.message).includes("No updates are to be performed"))throw ce}else await a.cloudformation.createStack({stackName:r.stackName,templateBody:R,capabilities:["CAPABILITY_NAMED_IAM"],onFailure:"ROLLBACK",tags:[{Key:"ManagedBy",Value:"ts-cloud"},{Key:"Application",Value:e.slug}]}),await a.cloudformation.waitForStack(r.stackName,"stack-create-complete");let B=(await a.cloudformation.describeStacks({stackName:r.stackName})).Stacks[0],V=Bw(B?.Outputs),W=V.AppLoadBalancerDnsName;if(!W)throw Error("Backend stack did not return AppLoadBalancerDnsName");let Y=!1;if(e.originDomain&&e.originDomain!==W){if(!a.dns)throw Error(`External DNS provider is required to map ${e.originDomain} to ${W}`);let ce=await a.dns.upsertRecord(e.originDomain,{name:e.originDomain,type:"CNAME",content:W,ttl:300});if(!ce.success)throw Error(ce.message||"External DNS update failed");Y=!0}let te=e.originDomain||W,le=e.certificateArn?"https-only":"http-only",X=e.skipHealthCheck?void 0:await Lw(a,`${le==="https-only"?"https":"http"}://${te}/api/health`,e.originVerifySecret);return await a.cloudfront.upsertExistingDistributionOrigin(e.distributionId,{id:r.originId,domainName:te,pathPattern:r.pathPattern,protocolPolicy:le,customHeaders:e.originVerifySecret?{"X-Origin-Verify":e.originVerifySecret}:void 0}),{...T,outputs:V,health:X,cloudFrontApplied:!0,dnsApplied:Y,applied:!0}}function Dy(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((a,l)=>a+l,0).toFixed(2)),components:Object.fromEntries(Object.entries(r).map(([a,l])=>[a,Number(l.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 Fw}from"node:child_process";import{createHash as zw}from"node:crypto";import{existsSync as df,mkdirSync as Uw,mkdtempSync as qw,readdirSync as Vw,readFileSync as Ww,rmSync as Hw,statSync as lf,writeFileSync as Kw}from"node:fs";import{tmpdir as Jw}from"node:os";import{basename as Gw,join as As,relative as Qw,resolve as np}from"node:path";var Yw=new Set([".git","node_modules","dist","coverage"]);function uf(e,t=e){let r=[];for(let a of Vw(e).sort()){if(Yw.has(a))continue;let l=As(e,a);if(bd(l,t))continue;let m=lf(l);if(m.isDirectory())r.push(...uf(l,t));else if(m.isFile())r.push(Qw(t,l))}return r}function yh(e){let t=np(e);if(!df(t)||!lf(t).isDirectory())throw Error(`Container context does not exist: ${t}`);let r=zw("sha256");for(let a of uf(t))r.update(a),r.update("\x00"),r.update(Ww(As(t,a))),r.update("\x00");return r.digest("hex")}function Ih(e){return{ecr:new Le(e.region||"us-east-1",e.profile),run:(t,r,a)=>{Fw(t,r,{cwd:a?.cwd,env:a?.env,stdio:a?.stdio||"inherit"})}}}async function Py(e,t){let r=np(e.context),a=np(e.dockerfile||As(r,"Dockerfile"));if(!df(a))throw Error(`Dockerfile does not exist: ${a}`);if(!e.repository.split("/").every((V)=>/^[a-z0-9][a-z0-9._-]*$/.test(V)&&!/[._-]$/.test(V)&&!/[._-]{2}/.test(V)))throw Error("ECR repository name is invalid");let h=t||Ih(e),I=yh(r),R=`sha-${I.slice(0,20)}`,S="";try{S=(await h.ecr.describeRepositories({repositoryNames:[e.repository]})).repositories?.[0]?.repositoryUri||""}catch{}if(!S)S=(await h.ecr.createRepository({repositoryName:e.repository,imageTagMutability:"IMMUTABLE",imageScanningConfiguration:{scanOnPush:!0},tags:[{Key:"ManagedBy",Value:"ts-cloud"}]})).repository?.repositoryUri||"";if(!S)throw Error(`Could not resolve ECR repository URI for ${e.repository}`);await h.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 C=`${S}:${R}`,T=qw(As(Jw(),"ts-cloud-container-"));try{h.run("docker",["version"],{stdio:"ignore"}),h.run("docker",["build","--platform",e.platform||"linux/amd64","--provenance=false","--sbom=false","--file",a,"--tag",C,r],{cwd:r});let V=(await h.ecr.getAuthorizationToken()).authorizationData?.[0];if(!V?.authorizationToken||!V.proxyEndpoint)throw Error("ECR did not return Docker authorization data");let W=V.proxyEndpoint.replace(/^https?:\/\//,""),Y=As(T,"docker");Uw(Y,{recursive:!0}),Kw(As(Y,"config.json"),JSON.stringify({auths:{[W]:{auth:V.authorizationToken}}}),{mode:384}),h.run("docker",["push",C],{env:{...process.env,DOCKER_CONFIG:Y}})}finally{Hw(T,{recursive:!0,force:!0})}let B=(await h.ecr.describeImages({repositoryName:e.repository,imageIds:[{imageTag:R}]})).imageDetails?.[0]?.imageDigest;if(!B||!/^sha256:[a-f0-9]{64}$/i.test(B))throw Error(`ECR did not return an immutable digest for ${Gw(C)}`);return{repository:e.repository,tag:R,imageUri:C,digest:B,digestUri:`${S}@${B}`,contextSha256:I}}import{existsSync as Zw,readdirSync as Xw,readFileSync as ek,statSync as tk}from"node:fs";import{join as pf,relative as rk}from"node:path";function Ao(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 a=e.project.slug,l=e.environments?.[t]?.region||e.project.region||"us-east-1";return{app:r,slug:a,region:l,stackName:Gt(e,t),artifactBucket:Dd(a,t),assetsBucket:uo(a,t)}}async function Ro(e,t=8){let r;for(let a=0;a<t;a++)try{return await e()}catch(l){let m=l?.code||l?.name||"",h=String(l?.message||"");if(m==="ResourceConflictException"||/update is in progress|currently in the following state/i.test(h)){r=l,await new Promise((I)=>setTimeout(I,3000));continue}throw l}throw r}var gf=(e,t)=>`releases/${e}/${t}/current.json`;async function Nc(e,t,r,a){try{return await e.getObjectJson(t,gf(r,a))}catch{return null}}async function mf(e,t,r,a,l){await e.putObjectJson(t,gf(r,a),l)}async function nk(e,t){if(!e.secrets)return{};let r=new z(t),a={},l=Array.isArray(e.secrets)?e.secrets.map((m)=>({envName:m.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),secretId:m})):Object.entries(e.secrets).map(([m,h])=>({envName:m,secretId:h}));if(Array.isArray(e.secrets)){let m=new Map;for(let{envName:I,secretId:R}of l)m.set(I,[...m.get(I)??[],R]);let h=[...m.entries()].filter(([,I])=>I.length>1);if(h.length){let I=h.map(([R,S])=>`${R} ← ${S.join(", ")}`).join("; ");throw Error(`serverless secrets: multiple secrets map to the same env var (${I}). Use the map form { ENV_NAME: 'secret/id' } to disambiguate.`)}}for(let{envName:m,secretId:h}of l){let R=(await r.getSecretValue({SecretId:h})).SecretString??"";try{let S=JSON.parse(R);if(S&&typeof S==="object"&&!Array.isArray(S)){for(let[C,T]of Object.entries(S))a[C]=String(T);continue}}catch{}a[m]=R}return a}function Zi(e,t){let r={},a=t.DbProxyEndpoint||t.DbEndpoint;if(a)r.DB_CONNECTION="mysql",r.DB_HOST=a,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 tr(e,t,r,a,l,m,h,I={}){let R=e.kind==="php"?Wd({cacheDriver:e.cache?.driver==="elasticache"?"redis":"dynamodb"}):{};return{TSCLOUD_LAMBDA_MODE:a,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"}:{},...R,...I,...t.app.cache?.driver!=="elasticache"?{TSCLOUD_CACHE_TABLE:`${t.slug}-${r}-cache`}:{},...h?{TSCLOUD_QUEUE:h,SQS_QUEUE:h}:{},...m?{ASSET_URL:m}:{},...e.env??{},...l}}function ik(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*ff(e){for(let t of Xw(e)){let r=pf(e,t);if(tk(r).isDirectory())yield*ff(r);else yield r}}async function ok(e,t,r,a,l=!1){let m=0;for(let h of ff(r)){let I=rk(r,h).replace(/\\/g,"/");if(!l&&I.split("/").some((R)=>R.startsWith(".")))continue;await e.putObject({bucket:t,key:`${a}/${I}`,body:ek(h),contentType:ik(h),cacheControl:"public, max-age=31536000, immutable"}),m++}return m}function sk(e,t){let r=Object.entries(t).reduce((a,[l,m])=>a+Buffer.byteLength(`${l}=${m}`,"utf8"),0);if(r>4096){let a=Object.entries(t).map(([l,m])=>[l,Buffer.byteLength(`${l}=${m}`,"utf8")]).sort((l,m)=>m[1]-l[1]).slice(0,5).map(([l,m])=>`${l} (${m}B)`).join(", ");throw Error(`${e}: environment variables total ${r}B, over AWS's 4096B limit (${r-4096}B too large). Largest: ${a}. Move large/secret values out of env — store them in Secrets Manager and fetch at cold start.`)}}async function Qa(e,t,r,a){sk(t,r),await Ro(()=>e.updateFunctionConfiguration({FunctionName:t,Environment:{Variables:r}})),await e.waitForFunctionActive(t,120);let l=a.kind==="image"?{FunctionName:t,ImageUri:a.imageUri}:{FunctionName:t,S3Bucket:a.bucket,S3Key:a.key};await Ro(()=>e.updateFunctionCode(l)),await e.waitForFunctionActive(t,120)}async function $c(e,t){let a=(await Ro(()=>e.publishVersion({FunctionName:t}))).Version;if(!a)throw Error(`publishVersion returned no version for ${t}`);return await Ro(()=>e.updateAlias({FunctionName:t,Name:"live",FunctionVersion:a})),a}async function Ca(e,t,r={}){let a=Ao(e,t),{app:l,slug:m,region:h,stackName:I,artifactBucket:R}=a,S=r.projectRoot??process.cwd();ds(`Deploying serverless app: ${m} (${t})`),k(`Stack: ${I}`),k(`Region: ${h}`);let C=new o(h),T=new f(h),j=new b(h),B=l.kind==="php",V=l.packaging==="image",W=So(l),Y,te,le,X,ce=[];if(V&&W.usesLayer&&W.layerKind!=="php")throw Error(`packaging: 'image' currently supports PHP and managed Node runtimes. ${W.kind}${W.kind==="node"?` ${W.version}`:""} uses a custom runtime — `+"use the default zip packaging (the runtime layer is built + attached automatically).");if(V){w("Building + pushing container image");let{buildAndPushServerlessImage:be}=await import("./chunk-cykr6zyj.js"),De=await be({app:l,projectRoot:S,region:h,repository:`${m}-${t}`,skipBuild:r.skipBuild,onStep:(mt)=>k(` ${mt}`)});Y=De.handlers,te={kind:"image",imageUri:De.imageUri},le=De.tag,ce.push({ParameterKey:"ImageUri",ParameterValue:De.imageUri})}else{w("Packaging application");let be=B?Jd({projectRoot:S,app:l,skipBuild:r.skipBuild,onStep:(Dt)=>k(` ${Dt}`)}):await Kr({projectRoot:S,app:l,skipBuild:r.skipBuild,onStep:(Dt)=>k(` ${Dt}`)}),De=Ud(m,t,be.sha256);if(k(`Artifact: ${be.sha256.slice(0,12)} (${(be.zip.length/1024).toFixed(0)} KB)`),Y=be.handlers,le=be.sha256,W.usesLayer){let Dt=W.layerEnvVar?process.env[W.layerEnvVar]:void 0;if(X=l.layers??(Dt?[Dt]:void 0),!X?.length){let $e=W.layerKind==="php"?"serverless:build-php-layer":W.layerKind==="bun"?"serverless:build-bun-layer":"serverless:build-node-layer";throw Error(`${W.kind} apps on provided.al2023 need a runtime layer. Set environments.<env>.app.layers or the ${W.layerEnvVar} env var (build one with \`cloud ${$e}\`)${W.kind==="node"?", or use a managed Node version (18/20/22)":""}.`)}}if(!await C.bucketExists(R))w(`Creating artifact bucket ${R}`),await C.createBucket(R);if(await C.headObject(R,De).then((Dt)=>Dt!==null).catch(()=>!1))k("Artifact already uploaded — reusing");else w("Uploading artifact"),await C.putObject({bucket:R,key:De,body:be.zip,contentType:"application/zip"});te={kind:"zip",bucket:R,key:De},ce.push({ParameterKey:"ArtifactBucket",ParameterValue:R},{ParameterKey:"ArtifactKey",ParameterValue:De})}let Ee=Hd({config:e,environment:t,app:l,handlers:Y,runtimeLayers:X}),Re=JSON.stringify(Ee.template),de=["CAPABILITY_NAMED_IAM"],Ne=await T.describeStacks({stackName:I}).then((be)=>be.Stacks[0]?.StackStatus).catch(()=>{return}),ae=Ne!==void 0;if(Ne&&/DELETE_IN_PROGRESS/.test(Ne))w("Waiting for an in-progress stack delete to finish"),await T.waitForStack(I,"stack-delete-complete").catch(()=>{}),ae=!1;else if(Ne&&/(?:ROLLBACK_COMPLETE|REVIEW_IN_PROGRESS|CREATE_FAILED)/.test(Ne))w(`Deleting unusable stack (status ${Ne}) before recreate`),await T.deleteStack(I),await T.waitForStack(I,"stack-delete-complete").catch(()=>{}),ae=!1;w(ae?"Updating infrastructure stack":"Creating infrastructure stack");try{if(ae)await T.updateStack({stackName:I,templateBody:Re,parameters:ce,capabilities:de}),await T.waitForStack(I,"stack-update-complete");else await T.createStack({stackName:I,templateBody:Re,parameters:ce,capabilities:de,onFailure:"DELETE"}),await T.waitForStack(I,"stack-create-complete")}catch(be){if(/No updates are to be performed/i.test(String(be?.message)))k("No infrastructure changes");else throw be}let je=await T.getStackOutputs(I).catch(()=>({})),Qe;if(l.assets){let be=pf(S,l.assets);if(Zw(be)){let De=l.assetDomain||je.AssetsCdnDomain;Qe=De?`https://${De}/${le}`:void 0,w(`Syncing assets from ${l.assets}`);let mt=await ok(C,a.assetsBucket,be,le,l.dotFilesAsAssets);k(`Uploaded ${mt} asset(s)${Qe?` → ${Qe}`:""}`)}else cs(`Assets directory not found: ${be}`)}w("Resolving secrets");let gt=await nk(l,h);if(l.database?.connection==="aurora-serverless")try{let De=await new z(h).getSecretValue({SecretId:`${m}/${t}/db`}),mt=JSON.parse(De.SecretString??"{}");if(mt.username)gt.DB_USERNAME=mt.username;if(mt.password)gt.DB_PASSWORD=mt.password}catch(be){cs(`Could not resolve Aurora DB credentials: ${be.message}`)}if(!await C.bucketExists(R))await C.createBucket(R);let Kt=await Nc(C,R,m,t),ot={},Pt=Ee.queueNames[0],ir=Zi(l,je);if(w("Activating functions"),ot.http=tr(l,a,t,"http",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.http,ot.http,te),ot.cli=tr(l,a,t,"cli",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.cli,ot.cli,te),Ee.queueNames.length)ot.queue=tr(l,a,t,"queue",gt,Qe,Pt,ir),await Qa(j,Ee.functionNames.queue,ot.queue,te);let lt=(l.provisionedConcurrency??0)>0,G={};if(lt){if(w("Publishing versions + flipping live alias"),G.http=await $c(j,Ee.functionNames.http),G.cli=await $c(j,Ee.functionNames.cli),Ee.queueNames.length)G.queue=await $c(j,Ee.functionNames.queue)}if(await mf(C,R,m,t,{sha:le,code:te,previousSha:Kt?.sha,previousCode:Kt?.code,previousFunctionEnv:Kt?.functionEnv,...lt?{functionVersions:G,previousFunctionVersions:Kt?.functionVersions}:{},functionEnv:ot,functionNames:{http:Ee.functionNames.http,cli:Ee.functionNames.cli,...Ee.queueNames.length?{queue:Ee.functionNames.queue}:{}},assetUrl:Qe,timestamp:new Date().toISOString()}),!r.skipDeployHooks&&l.deploy?.length){w("Running deploy hooks");for(let be of l.deploy){k(` deploy: ${be}`);let De=await j.invoke({FunctionName:Ee.functionNames.cli,InvocationType:"RequestResponse",Payload:{command:be},LogType:"Tail"});if(De.FunctionError)throw Cu("Deploy hook failed — the new build is ALREADY LIVE."),k(` Roll back with: cloud serverless:rollback --env ${t}`),Error(`Deploy hook failed (${be}): ${De.Payload}`)}}let ue=je.HttpApiEndpoint;if(!r.skipHealthCheck&&ue){w("Health check");try{let be=await fetch(ue,{method:"GET"});k(`GET ${ue} → ${be.status}`)}catch(be){cs(`Health check could not reach ${ue}: ${be.message}`)}}Eu(["Serverless deploy complete","",ue?`URL: ${ue}`:"",`Stack: ${I}`,`Build: ${le.slice(0,12)}`].filter(Boolean).join(`
40
+ `),"green")}async function dn(e,t){let r=Ao(e,t),a=new o(r.region),l=new b(r.region),m=await Nc(a,r.artifactBucket,r.slug,t);if(!m)throw Error("No previous release to redeploy. Run a full deploy first.");ds(`Redeploying ${r.slug} (${t}) — build ${m.sha.slice(0,12)}`);for(let[h,I]of Object.entries(m.functionNames)){if(!I)continue;w(`Re-activating ${h} (${I})`),await Qa(l,I,m.functionEnv[h]??{},m.code);let R=m.functionVersions?.[h];if(R)await Ro(()=>l.updateAlias({FunctionName:I,Name:"live",FunctionVersion:R}))}fn("Redeploy complete")}async function ln(e,t){let r=Ao(e,t),a=new o(r.region),l=new b(r.region),m=await Nc(a,r.artifactBucket,r.slug,t);if(!m?.previousCode)throw Error("No previous release to roll back to.");ds(`Rolling back ${r.slug} (${t}) → ${m.previousSha?.slice(0,12)}`);for(let[h,I]of Object.entries(m.functionNames)){if(!I)continue;w(`Restoring ${h} (${I})`);let R=m.previousFunctionEnv?.[h]??m.functionEnv[h]??{};await Qa(l,I,R,m.previousCode);let S=m.previousFunctionVersions?.[h];if(S)await Ro(()=>l.updateAlias({FunctionName:I,Name:"live",FunctionVersion:S}))}await mf(a,r.artifactBucket,r.slug,t,{...m,sha:m.previousSha??m.sha,code:m.previousCode,functionEnv:m.previousFunctionEnv??m.functionEnv,functionVersions:m.previousFunctionVersions??m.functionVersions,previousSha:void 0,previousCode:void 0,previousFunctionEnv:void 0,previousFunctionVersions:void 0,timestamp:new Date().toISOString()}),fn("Rollback complete")}async function rr(e,t,r,a){let l=Ao(e,t),m=new b(l.region),h=`${l.slug}-${t}-http`,R={...(await m.getFunction(h)).Configuration?.Environment?.Variables??{}};if(R.MAINTENANCE_MODE=r?"1":"0",r&&a)R.MAINTENANCE_BYPASS_SECRET=a;if(!r)delete R.MAINTENANCE_BYPASS_SECRET;if(await Ro(()=>m.updateFunctionConfiguration({FunctionName:h,Environment:{Variables:R}})),(l.app.provisionedConcurrency??0)>0)await m.waitForFunctionActive(h,120),await $c(m,h);fn(r?"Application is now in maintenance mode (503)":"Application is live")}async function et(e,t,r){let a=Ao(e,t),l=new b(a.region),m=`${a.slug}-${t}-cli`,h=await l.invoke({FunctionName:m,InvocationType:"RequestResponse",Payload:{command:r},LogType:"Tail"});if(h.FunctionError)throw Error(`Command failed: ${h.Payload}`);return h.Payload??""}async function Pr(e,t){let r=Ao(e,t),a=new f(r.region),l=new b(r.region),m=new o(r.region),h="not deployed",I={};try{let{Stacks:V}=await a.describeStacks({stackName:r.stackName});h=V?.[0]?.StackStatus??h;for(let W of V?.[0]?.Outputs??[])if(W.OutputKey)I[W.OutputKey]=W.OutputValue??""}catch{}let R=Qd(r.app,r.slug,t),S=r.app.provisionedConcurrency??0,C=["http","cli",...R.length?["queue"]:[]],T=`${r.slug}-${t}`,j=[];for(let V of C){let W=`${T}-${V}`,Y={mode:V,name:W,version:"$LATEST"};if(S>0){let te=await l.getAlias(W,"live").catch(()=>null);if(te?.FunctionVersion){Y.version=te.FunctionVersion;let le=await l.getProvisionedConcurrencyConfig(W,"live").catch(()=>null);if(le)Y.provisioned={status:le.Status??"-",allocated:le.AllocatedProvisionedConcurrentExecutions??0,requested:le.RequestedProvisionedConcurrentExecutions??0}}}j.push(Y)}let B=await Nc(m,r.artifactBucket,r.slug,t).catch(()=>null);return{slug:r.slug,environment:t,region:r.region,stackStatus:h,endpoint:I.HttpApiEndpoint,assetUrl:B?.assetUrl,scheduler:r.app.scheduler??"on",queues:R,provisionedConcurrency:S,functions:j,lastRelease:B?{sha:B.sha,timestamp:B.timestamp}:void 0}}function ak(e,t){return`${e}-${t}-db`}async function hf(e,t,r,a){let l=Ao(e,t);if(l.app.database?.connection!=="aurora-serverless")throw Error("No Aurora Serverless v2 database is configured for this environment.");let{RDSClient:m}=await import("./chunk-2p85fnx5.js"),h=new m(l.region),I=ak(l.slug,t);w(`Scaling ${I} → ${r}–${a} ACUs`),await h.modifyDBCluster({DBClusterIdentifier:I,ServerlessV2ScalingConfiguration:{MinCapacity:r,MaxCapacity:a},ApplyImmediately:!0}),fn(`Scaling applied to ${I} (takes effect shortly).`)}class ip{client;region;constructor(e="us-east-1"){this.region=e,this.client=new n}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((m)=>({Name:m.Name,Priority:m.Priority,Action:m.Action?Object.keys(m.Action)[0]:m.OverrideAction?Object.keys(m.OverrideAction)[0]:"count"}))}}var ck=[{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"}],dk=[{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"}],lk=[{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"}],uk=/^(?:rpx-gateway|nginx|caddy|traefik|haproxy)$/;function Oe(e,t=""){let r=e==null?"":String(e).trim();return r&&r!=="-"&&r!=="—"?r:t}function pk(e){return Array.isArray(e)?e.length:0}function Un(e){let t=Oe(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 ur(e,t,r){if(r.has(t.source)&&r.has(t.target))e.push(t)}function vt(e,t={}){let r=[],a=[],l=[],m=e.server??{},h=Array.isArray(e.sites)?e.sites:[],I=Array.isArray(e.services)?e.services:[],R=Array.isArray(e.workers)?e.workers:[],S=e.security??{},C=!!e._serverReachable&&!e.metricsUnavailable,T="box";if(!C)l.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 j=[...new Set(h.map((de)=>Oe(de.domain)||Oe(de.route).split("/")[0]).filter((de)=>de&&de!=="internal"&&de!=="loopback"))],B=Array.isArray(S.tlsCertificates)?S.tlsCertificates:[],V=B.filter((de)=>Number(de?.daysRemaining??999)<21).length;r.push({id:"dns",label:j.length===1?j[0]:"Public domains",kind:"dns",layer:1,status:V?"warn":j.length?"ok":"unknown",sub:j.length>1?`${j.length} domains`:"DNS & certificates",facts:[{label:"Domains",value:j.length?j.slice(0,6).join(", "):"none resolved"},{label:"Certificates",value:B.length?`${B.length} issued`:"none reported"},...V?[{label:"Expiring",value:`${V} within 21 days`}]:[]],href:"/server/security",external:!0});let W=S.firewall??{},Y=Array.isArray(S.ports)?S.ports:[];r.push({id:"firewall",label:"Host firewall",kind:"firewall",layer:2,status:Un(W.status),sub:Oe(W.summary,"Inbound filtering"),facts:[{label:"State",value:Oe(W.status,"unknown")},{label:"Open ports",value:Y.length?Y.map((de)=>Oe(de.listen)).join(", "):"not reported"}],href:"/server/firewall",group:"box"});let te=I.find((de)=>uk.test(Oe(de.name)));r.push({id:"proxy",label:Oe(te?.name,"Reverse proxy"),kind:"proxy",layer:3,status:te?Un(te.status):"unknown",sub:"TLS termination & routing",facts:[{label:"Service",value:Oe(te?.name,"not detected")},{label:"State",value:Oe(te?.status,C?"not running":"not probed")},{label:"Routes",value:`${h.length} site${h.length===1?"":"s"}`}],href:"/server/services",group:"box"});for(let de of h){let Ne=`site:${Oe(de.name)}`;if(!Oe(de.name))continue;r.push({id:Ne,label:Oe(de.name),kind:"site",layer:4,status:Un(de.status),sub:Oe(de.runtime,"runtime"),facts:[{label:"Route",value:Oe(de.route,"internal")},{label:"Runtime",value:Oe(de.runtime,"unknown")},{label:"Delivery",value:Oe(de.deploy,"unknown")},{label:"TLS",value:Oe(de.tls,"unknown")},...de.responseMs!=null?[{label:"Response",value:`${Math.round(Number(de.responseMs))} ms`}]:[],...de.httpStatus!=null?[{label:"HTTP",value:String(de.httpStatus)}]:[]],href:"/server/sites",group:"box"})}for(let de of R){let Ne=`worker:${Oe(de.name)}`;if(!Oe(de.name))continue;r.push({id:Ne,label:Oe(de.name),kind:"worker",layer:5,status:Un(de.status),sub:`${Number(de.processes??1)} process${Number(de.processes??1)===1?"":"es"}`,facts:[{label:"Processes",value:String(de.processes??1)},{label:"State",value:Oe(de.status,"unknown")},...Oe(de.site)?[{label:"Site",value:Oe(de.site)}]:[]],href:"/operations/jobs",group:"box"})}let le=e.serverScheduler??{};if(le.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:5,status:"ok",sub:"Cron dispatch",facts:[{label:"Last run",value:Oe(le.lastRun,"unknown")}],href:"/operations/jobs",group:"box"});let X=I.map((de)=>{let Ne=Oe(de.name),ae=lk.find((je)=>je.match.test(Ne));return ae?{service:de,name:Ne,...ae}:null}).filter((de)=>!!de);for(let de of X)r.push({id:`data:${de.name}`,label:de.label,kind:de.kind,layer:6,status:Un(de.service.status),sub:de.name,facts:[{label:"Unit",value:de.name},{label:"State",value:Oe(de.service.status,"unknown")}],href:"/data/services",group:"box"});let ce=e.backup??{};if(ce.enabled)r.push({id:"backup",label:"Backups",kind:"backup",layer:7,status:"ok",sub:Oe(ce.destination,"destination"),facts:[{label:"Destination",value:Oe(ce.destination,"unknown")},{label:"Schedule",value:Oe(ce.schedule,"unknown")},{label:"Retention",value:`${ce.retention??0} copies`},{label:"Last run",value:Oe(ce.last,"unknown")}],href:"/data/backups"});let Ee=new Set(r.map((de)=>de.id));ur(a,{source:"internet",target:"dns",flow:"request",label:"https"},Ee),ur(a,{source:"dns",target:"firewall",flow:"request",label:"443/80"},Ee),ur(a,{source:"firewall",target:"proxy",flow:"request"},Ee);for(let de of h){let Ne=`site:${Oe(de.name)}`;ur(a,{source:"proxy",target:Ne,flow:"request",label:Oe(de.path)||void 0,status:Un(de.status)},Ee)}for(let de of R){let Ne=`worker:${Oe(de.name)}`,ae=`site:${Oe(de.site)}`;if(Ee.has(ae))ur(a,{source:ae,target:Ne,flow:"async",label:"queue"},Ee);else ur(a,{source:"proxy",target:Ne,flow:"async",label:"queue"},Ee)}for(let de of R)ur(a,{source:"scheduler",target:`worker:${Oe(de.name)}`,flow:"async",label:"dispatch"},Ee);let Re=[...h.map((de)=>`site:${Oe(de.name)}`),...R.map((de)=>`worker:${Oe(de.name)}`)];for(let de of X)for(let Ne of Re)ur(a,{source:Ne,target:`data:${de.name}`,flow:"data",label:"localhost"},Ee);if(X.length&&Re.length)l.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 de of X)ur(a,{source:`data:${de.name}`,target:"backup",flow:"backup",label:"snapshot"},Ee);for(let de of h)ur(a,{source:`site:${Oe(de.name)}`,target:"backup",flow:"backup"},Ee);return{mode:"server",project:Oe(t.project)||Oe(e.project?.name)||Oe(m.name,"project"),environment:Oe(t.environment)||Oe(e.environment,"production"),provider:Oe(m.provider,"unknown"),region:Oe(m.region,"unknown"),generatedAt:new Date().toISOString(),layers:ck,groups:[{id:"box",label:Oe(m.name,"App server"),sub:[Oe(m.provider),Oe(m.region),Oe(m.ip)].filter(Boolean).join(" · ")}],nodes:r,links:a,notes:l}}function es(e,t={}){let r=[],a=[],l=[],m=e.app??{},h=Array.isArray(e.functions)?e.functions:[],I=Array.isArray(e.queues)?e.queues:[],R=e.metrics??{};if(!h.length)l.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 S=Oe(m.url),C=S.replace(/^https?:\/\//,"").split("/")[0];r.push({id:"dns",label:C||"Application domain",kind:"dns",layer:1,status:C?"ok":"unknown",sub:"DNS & certificates",facts:[{label:"Endpoint",value:S||"not resolved"}],external:!0});let T=e.waf;if(T)r.push({id:"waf",label:"WAF",kind:"waf",layer:2,status:Un(T.status??"active"),sub:Oe(T.scope,"Managed rules"),facts:[{label:"Web ACL",value:Oe(T.name,"unnamed")},...T.blocked!=null?[{label:"Blocked (24h)",value:String(T.blocked)}]:[],{label:"Rules",value:String(pk(e.wafRules))}],href:"/serverless/firewall"});let j=e.assetsInfo;if(j)r.push({id:"cdn",label:"Asset CDN",kind:"cdn",layer:2,status:"ok",sub:Oe(j.cdn,"CloudFront"),facts:[{label:"Distribution",value:Oe(j.cdn,"unknown")},{label:"Custom domain",value:Oe(j.customDomain,"none")}],href:"/serverless/assets"}),r.push({id:"assets",label:"Asset bucket",kind:"storage",layer:6,status:"ok",sub:Oe(j.bucket,"S3"),facts:[{label:"Bucket",value:Oe(j.bucket,"unknown")},...j.files?[{label:"Objects",value:String(j.files)}]:[],...j.sizeMb?[{label:"Size",value:`${j.sizeMb} MB`}]:[]],href:"/serverless/assets"});let B=h.find((ae)=>Oe(ae.key).startsWith("http"));r.push({id:"gateway",label:"HTTP entry point",kind:"gateway",layer:3,status:B?"ok":"unknown",sub:"Function URL / API Gateway",facts:[{label:"Endpoint",value:S||"not resolved"},{label:"Invocations (24h)",value:String(R.invocations??0)},...R.errorRatePct!=null?[{label:"Error rate",value:`${R.errorRatePct}%`}]:[]],href:"/serverless/metrics"});for(let ae of h){let je=`fn:${Oe(ae.name)}`;if(!Oe(ae.name))continue;let Qe=Number(ae.errors??0),gt=Number(ae.invocations??0);r.push({id:je,label:Oe(ae.key,Oe(ae.name)),kind:"function",layer:4,status:Qe>0?gt&&Qe/gt>0.02?"bad":"warn":gt?"ok":"idle",sub:Oe(ae.runtime,"lambda"),facts:[{label:"Function",value:Oe(ae.name)},{label:"Memory",value:`${ae.memory??0} MB`},{label:"Timeout",value:`${ae.timeout??0}s`},{label:"Invocations (24h)",value:String(gt)},{label:"Errors (24h)",value:String(Qe)},{label:"p95",value:`${ae.p95??0} ms`},...ae.provisioned?[{label:"Provisioned",value:Oe(ae.provisioned)}]:[]],href:"/serverless/functions"})}for(let ae of I){let je=`queue:${Oe(ae.name)}`;if(!Oe(ae.name))continue;let Qe=Number(ae.dlq??0);r.push({id:je,label:Oe(ae.name),kind:"queue",layer:5,status:Qe>0?"bad":Number(ae.visible??0)>0?"warn":"ok",sub:"SQS",facts:[{label:"Visible",value:String(ae.visible??0)},{label:"In flight",value:String(ae.inFlight??0)},{label:"Processed (24h)",value:String(ae.processed??0)},{label:"Dead letter",value:String(Qe)}],href:"/serverless/queues"})}let V=e.aurora;if(V)r.push({id:"database",label:"Aurora Serverless",kind:"database",layer:6,status:Un(V.status),sub:Oe(V.engine,"aurora"),facts:[{label:"Cluster",value:Oe(V.id,"unknown")},{label:"Capacity",value:`${V.currentAcu??0} ACU (${V.minAcu??0}–${V.maxAcu??0})`},{label:"Connections",value:String(V.connections??0)}],href:"/serverless/data"});let W=e.proxy;if(W)r.push({id:"rds-proxy",label:"RDS Proxy",kind:"database",layer:5,status:Un(W.status),sub:"Connection pooling",facts:[{label:"Proxy",value:Oe(W.name,"unknown")},{label:"Endpoint",value:Oe(W.endpoint,"unknown")},{label:"Pooled",value:String(W.pooledConns??0)}],href:"/serverless/data"});let Y=e.redis;if(Y)r.push({id:"cache",label:"ElastiCache",kind:"cache",layer:6,status:Un(Y.status),sub:Oe(Y.node,"redis"),facts:[{label:"Group",value:Oe(Y.id,"unknown")},{label:"Hit rate",value:`${Y.hitRate??0}%`}],href:"/serverless/data"});let te=e.efs;if(te)r.push({id:"efs",label:"EFS",kind:"filesystem",layer:6,status:Un(te.status),sub:Oe(te.mount,"/mnt/local"),facts:[{label:"File system",value:Oe(te.id,"unknown")},{label:"Mount",value:Oe(te.mount,"unknown")},{label:"Size",value:`${te.sizeMb??0} MB`}],href:"/data/volumes"});let le=e.scheduler??{};if(le.enabled)r.push({id:"scheduler",label:"Scheduler",kind:"scheduler",layer:3,status:"ok",sub:Oe(le.expression,"rate(1 minute)"),facts:[{label:"Expression",value:Oe(le.expression,"unknown")},{label:"Last run",value:Oe(le.lastRun,"unknown")}],href:"/operations/jobs"});let X=new Set(r.map((ae)=>ae.id)),ce=X.has("waf")?"waf":"gateway";ur(a,{source:"internet",target:"dns",flow:"request",label:"https"},X),ur(a,{source:"dns",target:ce,flow:"request"},X),ur(a,{source:"dns",target:"cdn",flow:"request",label:"assets"},X),ur(a,{source:"waf",target:"gateway",flow:"request",label:"allowed"},X),ur(a,{source:"cdn",target:"assets",flow:"data",label:"origin"},X);let Ee=h.filter((ae)=>Oe(ae.key).startsWith("http")),Re=h.filter((ae)=>Oe(ae.key).startsWith("queue")),de=h.filter((ae)=>Oe(ae.key).startsWith("cli"));for(let ae of Ee)ur(a,{source:"gateway",target:`fn:${Oe(ae.name)}`,flow:"request",label:"invoke"},X);for(let ae of de)ur(a,{source:"scheduler",target:`fn:${Oe(ae.name)}`,flow:"async",label:"schedule"},X);for(let ae of I){for(let je of Ee)ur(a,{source:`fn:${Oe(je.name)}`,target:`queue:${Oe(ae.name)}`,flow:"async",label:"publish"},X);for(let je of Re)ur(a,{source:`queue:${Oe(ae.name)}`,target:`fn:${Oe(je.name)}`,flow:"async",label:"consume"},X)}let Ne=["rds-proxy","database","cache","efs","assets"];for(let ae of h){let je=`fn:${Oe(ae.name)}`;if(X.has("rds-proxy"))ur(a,{source:je,target:"rds-proxy",flow:"data",label:"pooled"},X);else ur(a,{source:je,target:"database",flow:"data",label:"sql"},X);for(let Qe of Ne.filter((gt)=>gt!=="rds-proxy"&&gt!=="database"))ur(a,{source:je,target:Qe,flow:"data"},X)}return ur(a,{source:"rds-proxy",target:"database",flow:"data",label:"sql"},X),{mode:"serverless",project:Oe(t.project)||Oe(m.name,"application"),environment:Oe(t.environment)||Oe(m.env,"production"),provider:"aws",region:Oe(m.region,"unknown"),generatedAt:new Date().toISOString(),layers:dk,groups:[],nodes:r,links:a,notes:l}}function Sh(e,t,r={}){return e==="serverless"?es(t,r):vt(t,r)}function yf(e){return String(e).padStart(2,"0")}function Cs(e){return`${e.getUTCFullYear()}-${yf(e.getUTCMonth()+1)}-${yf(e.getUTCDate())}`}function gk(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 a=Math.round(r/60);if(a<48)return`${a}h ago`;return`${Math.round(a/24)}d ago`}async function Ya(e,t,r,a,l,m){let h=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:r,Dimensions:[{Name:"FunctionName",Value:t}],StartTime:l,EndTime:m,Period:86400,Statistics:[a]}).catch(()=>[]);if(!h.length)return 0;if(a==="Sum")return h.reduce((I,R)=>I+(R.Sum??0),0);if(a==="Maximum")return Math.max(...h.map((I)=>I.Maximum??0));return h.reduce((I,R)=>I+(R.Average??0),0)/h.length}async function Za(e,t,r,a,l,m,h){let I=await e.getMetricStatistics({Namespace:t,MetricName:r,Dimensions:a,StartTime:m,EndTime:h,Period:86400,Statistics:[l]}).catch(()=>[]);if(!I.length)return 0;if(l==="Sum")return I.reduce((R,S)=>R+(S.Sum??0),0);if(l==="Maximum")return Math.max(...I.map((R)=>R.Maximum??0));return I.reduce((R,S)=>R+(S.Average??0),0)/I.length}async function op(e,t,r,a,l){let m=await e.getMetricStatistics({Namespace:"AWS/Lambda",MetricName:"Duration",Dimensions:[{Name:"FunctionName",Value:t}],StartTime:a,EndTime:l,Period:86400,ExtendedStatistics:[r]}).catch(()=>[]);return Math.round(m.reduce((h,I)=>h+(I.Percentiles?.[r]??0),0))}async function un(e,t){let r=await Pr(e,t),a=r.region,l=new oe(a),m=new b(a),h=new ye(a),I=new Date,R=new Date(I.getTime()-86400000),S=e.environments?.[t]?.app,C={};C.app={name:r.slug,env:t,region:a,runtime:S?.kind==="php"?`php-${S?.phpVersion??"8.3"} (fpm)`:S?.kind??"node",url:r.endpoint??"",build:r.lastRelease?.sha?.slice(0,7)??"—",deployedAt:r.lastRelease?.timestamp??"—"},C.maintenance={enabled:!1},C.scheduler={enabled:r.scheduler!=="off",expression:r.scheduler==="sub-minute"?"rate(1 minute) · sub-minute":"rate(1 minute)",lastRun:"—"};let T=0,j=0,B=0,V=[],W=[],Y=[];for(let ce of r.functions){let[Ee,Re,de,Ne,ae,je,Qe,gt,Kt]=await Promise.all([Ya(l,ce.name,"Invocations","Sum",R,I),Ya(l,ce.name,"Errors","Sum",R,I),Ya(l,ce.name,"Throttles","Sum",R,I),Ya(l,ce.name,"Duration","Average",R,I),m.getFunction(ce.name).catch(()=>null),op(l,ce.name,"p50",R,I),op(l,ce.name,"p95",R,I),op(l,ce.name,"p99",R,I),l.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:ce.name}],StartTime:new Date(I.getTime()-43200000),EndTime:I,Period:3600,Stat:"Sum"}).catch(()=>[])]);T+=Ee,j+=Re,B=Math.max(B,Ne);let ot=ae?.Configuration?.MemorySize??0,Pt=Object.keys(ae?.Configuration?.Environment?.Variables??{}),ir=[],lt=0;try{let{events:ue=[]}=await h.filterLogEvents({logGroupName:`/aws/lambda/${ce.name}`,startTime:R.getTime(),limit:120});for(let be of ue){let De=(be.message??"").trim(),mt=/Max Memory Used:\s*(\d+)\s*MB/.exec(De);if(mt)lt=Math.max(lt,Number(mt[1]));if(De&&!/^(?:START|END|REPORT|INIT_START)/.test(De))Y.push({source:ce.mode||ce.name,timestamp:new Date(be.timestamp??0).toISOString(),when:gk(be.timestamp??0),message:De.slice(0,400),level:/error|exception|fatal|panic|traceback/i.test(De)?"error":/warn|warning|timeout|retr(?:y|ies)|throttl/i.test(De)?"warn":"info"})}ir=ue.filter((be)=>!/^(?:START|END|REPORT|INIT_START)/.test((be.message??"").trim())).slice(-6).map((be)=>({ts:new Date(be.timestamp??0).toISOString().slice(11,19),msg:(be.message??"").trim().slice(0,120),err:/error|exception|fatal/i.test(be.message??"")}))}catch{}let G=Math.max(1,...Kt);V.push({key:ce.mode,name:ce.name,version:ce.version,memory:ot,timeout:ae?.Configuration?.Timeout??0,runtime:ae?.Configuration?.Runtime??"provided.al2023",invocations:Math.round(Ee),errors:Math.round(Re),p95:Qe||Math.round(Ne),status:"active",provisioned:ce.provisioned?`${ce.provisioned.allocated}/${ce.provisioned.requested}`:void 0}),W.push({key:ce.mode,name:ce.name,runtime:ae?.Configuration?.Runtime??"provided.al2023",arch:ae?.Configuration?.Architectures?.[0]??"x86_64",memory:ot,timeout:ae?.Configuration?.Timeout??0,ephemeral:ae?.Configuration?.EphemeralStorage?.Size??512,version:ce.version,concurrency:S?.concurrency??"—",invocations:Math.round(Ee),errors:Math.round(Re),throttles:Math.round(de),p50:je||Math.round(Ne),p95:Qe||Math.round(Ne),p99:gt||Math.round(Ne),maxMem:lt,spark:Kt.length?Kt.map((ue)=>Math.round(ue/G*100)):[0],env:Pt.length?Pt:["(none)"],recent:ir.length?ir:[{ts:"—",msg:"no recent events",err:!1}]})}C.functions=V,C.functionsDetail=W,C.serverlessLogs=Y.sort((ce,Ee)=>String(Ee.timestamp).localeCompare(String(ce.timestamp))).slice(0,600),C.serverlessLogsEmptyReason=Y.length?void 0:"No recent function logs were found in CloudWatch for this environment.";let te=T?Number((j/T*100).toFixed(2)):0,le=Math.round(await Ya(l,r.functions[0]?.name??"","ConcurrentExecutions","Maximum",R,I));C.metrics={invocations:Math.round(T),errorRatePct:te,p95Ms:Math.round(B),coldStartPct:void 0,concurrency:le,estCostUsd:void 0};try{let ce=new se(a),Ee=[],Re=[],de=0;try{let{QueueUrl:ae}=await ce.getQueueUrl(`${r.slug}-${t}-dlq`),{Attributes:je}=await ce.getQueueAttributes(ae);de=Number(je.ApproximateNumberOfMessages??0)}catch{}let Ne=S?Jt(S,r.slug,t):[];for(let ae of Ne){let je=ae.name.replace(`${r.slug}-${t}-`,""),Qe=0,gt=0;try{let{QueueUrl:ot}=await ce.getQueueUrl(ae.name),{Attributes:Pt}=await ce.getQueueAttributes(ot);Qe=Number(Pt.ApproximateNumberOfMessages??0),gt=Number(Pt.ApproximateNumberOfMessagesNotVisible??0)}catch{}let Kt=Math.round(await Za(l,"AWS/SQS","NumberOfMessagesDeleted",[{Name:"QueueName",Value:ae.name}],"Sum",R,I));Ee.push({name:je,visible:Qe,inFlight:gt,processed:Kt,dlq:de}),Re.push({name:ae.name,short:je,visible:Qe,inFlight:gt,delayed:0,processed:Kt,oldestSec:0,concurrency:ae.concurrency??S?.queueConcurrency??"—",tries:S?.queueTries??3,visTimeout:(S?.queueTimeout??120)*6,dlq:de})}if(Ee.length)C.queues=Ee;if(Re.length)C.queuesDetail=Re;C.dlqItems=[]}catch{}try{let ce=new f(a),{Stacks:Ee}=await ce.describeStacks({stackName:Gt(e,t)}),Re={};for(let de of Ee?.[0]?.Outputs??[])if(de.OutputKey)Re[de.OutputKey]=de.OutputValue??"";if(S?.database?.connection==="aurora-serverless"){let de=`${r.slug}-${t}-db`,Ne=[{Name:"DBClusterIdentifier",Value:de}],[ae,je]=await Promise.all([Za(l,"AWS/RDS","ServerlessDatabaseCapacity",Ne,"Average",R,I),Za(l,"AWS/RDS","DatabaseConnections",Ne,"Maximum",R,I)]);if(C.aurora={id:de,engine:"aurora-mysql",minAcu:S?.database?.minCapacity??0.5,maxAcu:S?.database?.maxCapacity??4,currentAcu:ae?Number(ae.toFixed(1)):S?.database?.minCapacity??0.5,database:"app",connections:Math.round(je),status:Re.DbEndpoint?"available":"creating"},S?.rdsProxy)C.proxy={name:`${r.slug}-${t}-proxy`,endpoint:Re.DbProxyEndpoint??"—",pooledConns:Math.round(je),status:"available"}}if(S?.cache?.driver==="elasticache"){let de=`${r.slug}-${t}-cache`,Ne=[{Name:"CacheClusterId",Value:`${de}-001`}],[ae,je]=await Promise.all([Za(l,"AWS/ElastiCache","CacheHits",Ne,"Sum",R,I),Za(l,"AWS/ElastiCache","CacheMisses",Ne,"Sum",R,I)]),Qe=ae+je>0?Number((ae/(ae+je)*100).toFixed(1)):0;C.redis={id:de,node:"cache.t4g.micro",engine:"redis",hitRate:Qe,status:Re.CacheEndpoint?"available":"creating"}}if(S?.efs){let de=0;try{if(Re.EfsFileSystemId){let Ne=new cr(a),{FileSystems:ae}=await Ne.describeFileSystems({FileSystemId:Re.EfsFileSystemId});de=Number(((ae?.[0]?.SizeInBytes?.Value??0)/1048576).toFixed(1))}}catch{}C.efs={id:Re.EfsFileSystemId??"efs",mount:"/mnt/local",sizeMb:de,status:"available"}}C.assetsInfo=Re.AssetsCdnDomain?{bucket:Re.AssetsBucketName??`${r.slug}-${t}-assets`,cdn:Re.AssetsCdnDomain,customDomain:S?.assetDomain??"—",assetUrl:r.assetUrl??"—",files:0,sizeMb:0,cacheHitPct:0,build:C.app.build}:void 0}catch{}if(C.assetsInfo)try{let Ee=await new o(a).list({bucket:C.assetsInfo.bucket,maxKeys:1000});C.assetsInfo.files=Ee.length,C.assetsInfo.sizeMb=Number((Ee.reduce((Re,de)=>Re+(de.Size??0),0)/1048576).toFixed(1)),C.assetsRecent=Ee.slice(0,8).map((Re)=>({path:`/${Re.Key}`,size:`${Math.max(1,Math.round((Re.Size??0)/1024))} KB`,type:Re.Key.split(".").pop()??""}))}catch{}try{if(S?.secrets){let ce=Array.isArray(S.secrets)?S.secrets.map((Ee)=>({key:Ee.split("/").pop().toUpperCase().replace(/[^A-Z0-9_]/g,"_"),source:Ee})):Object.entries(S.secrets).map(([Ee,Re])=>({key:Ee,source:String(Re)}));C.secretsList=ce.map((Ee)=>({...Ee,updated:"—"}))}}catch{}try{let ce=new o(a),Ee=`${r.slug}-${t}-deployments`,Re=await ce.getObjectJson(Ee,`deployments/${r.slug}/${t}/history.json`).catch(()=>null);if(Re?.records?.length)C.deploymentsDetail=Re.records.slice(-12).reverse().map((de)=>({sha:(de.sha??"").slice(0,7),status:de.status??"success",when:de.timestamp??"—",took:de.took??"—",by:de.by??"—",version:de.version??"—",hooks:de.hooks??[]}))}catch{}C.metricsTotals={invocations:C.metrics.invocations,errors:Math.round(j),errorRatePct:te,p95Ms:C.metrics.p95Ms,throttles:W.reduce((ce,Ee)=>ce+Ee.throttles,0),coldStartPct:void 0,estCostUsd:void 0,concurrency:le},C.metricsPerFn=W.map((ce)=>({key:ce.key,invocations:ce.invocations,errors:ce.errors,throttles:ce.throttles,avgMs:ce.p50,maxMs:ce.p99,costUsd:void 0}));try{C.invSpark=await l.getMetricSeries({Namespace:"AWS/Lambda",MetricName:"Invocations",Dimensions:[{Name:"FunctionName",Value:r.functions.find((ce)=>ce.mode==="http")?.name??""}],StartTime:new Date(I.getTime()-86400000),EndTime:I,Period:3600,Stat:"Sum"})}catch{}try{let ce=new gs,Ee=I,Re=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth(),1)),de=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth()-1,1)),[Ne,ae]=await Promise.all([ce.getCostByService({start:Cs(Re),end:Cs(Ee),granularity:"MONTHLY"}).catch(()=>[]),ce.getCostByService({start:Cs(de),end:Cs(Re),granularity:"MONTHLY"}).catch(()=>[])]);if(Ne.length){let je=Ne.reduce((lt,G)=>lt+G.amount,0),Qe=ae.reduce((lt,G)=>lt+G.amount,0),gt=Ee.getUTCDate(),Kt=new Date(Date.UTC(Ee.getUTCFullYear(),Ee.getUTCMonth()+1,0)).getUTCDate();C.costSummary={monthToDateUsd:Number(je.toFixed(2)),projectedUsd:Number((je/gt*Kt).toFixed(2)),lastMonthUsd:Number(Qe.toFixed(2)),dailyAvgUsd:Number((je/gt).toFixed(2))},C.costServices=Ne.filter((lt)=>lt.amount>0).sort((lt,G)=>G.amount-lt.amount).slice(0,12).map((lt)=>({name:lt.service,usd:Number(lt.amount.toFixed(2)),note:""})),C.metrics.estCostUsd=Number((je/gt).toFixed(2)),C.metricsTotals.estCostUsd=C.metrics.estCostUsd,C.costTrend=await ce.getDailyTotals({start:Cs(Re),end:Cs(Ee)}).catch(()=>[]);let ot=Ne.find((lt)=>/lambda/i.test(lt.service))?.amount??0,Pt=(lt)=>lt.invocations*(lt.p50/1000)*(lt.memory/1024),ir=W.reduce((lt,G)=>lt+Pt(G),0)||1;C.costPerFn=W.map((lt)=>({key:lt.key,requests:lt.invocations,gbSec:Math.round(Pt(lt)),usd:Number((ot*(Pt(lt)/ir)).toFixed(2))}))}}catch{}if(S?.firewall)try{let ce=await l.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"BlockedRequests",StartTime:R,EndTime:I,Period:86400,Statistics:["Sum"]}).catch(()=>[]),Ee=await l.getMetricStatistics({Namespace:"AWS/WAFV2",MetricName:"AllowedRequests",StartTime:R,EndTime:I,Period:86400,Statistics:["Sum"]}).catch(()=>[]);C.waf={enabled:!0,scope:"REGIONAL",acl:`${r.slug}-${t}-waf`,allowed24h:Math.round(Ee.reduce((Re,de)=>Re+(de.Sum??0),0)),blocked24h:Math.round(ce.reduce((Re,de)=>Re+(de.Sum??0),0))};try{let Re=new ip(a),de=await Re.listWebACLs("REGIONAL"),Ne=de.find((ae)=>ae.Name?.includes(`${r.slug}-${t}`))??de[0];if(Ne?.Name&&Ne.Id){C.waf.acl=Ne.Name;let ae=await Re.getWebACLRules(Ne.Name,Ne.Id,"REGIONAL");if(ae.length)C.wafRules=ae.map((je)=>({name:je.Name??"—",detail:`priority ${je.Priority??0}`,action:je.Action??"count",blocked24h:0}))}}catch{}}catch{}let X=[];if(C.aurora)X.push({name:"Aurora Serverless v2",detail:`${C.aurora.id} · ${C.aurora.minAcu}-${C.aurora.maxAcu} ACU`,status:C.aurora.status});if(C.proxy)X.push({name:"RDS Proxy",detail:C.proxy.name,status:C.proxy.status});if(C.redis)X.push({name:`ElastiCache (${C.redis.engine})`,detail:`${C.redis.node} · ${C.redis.hitRate}% hit rate`,status:C.redis.status});if(C.efs)X.push({name:"EFS",detail:`${C.efs.mount} · ${C.efs.sizeMb} MB`,status:C.efs.status});if(X.length)C.dataServices=X;if(r.scheduler!=="off"&&S?.kind==="php")try{let ce=await et(e,t,"schedule:list"),Ee=[];for(let Re of(ce||"").split(`
41
41
  `)){let de=/^\s*([\d*/,\-\s]+?)\s{2,}(.+?)(?:\s{2,}Next Due.*)?$/.exec(Re);if(de&&/[*\d]/.test(de[1])&&de[1].trim().split(/\s+/).length===5)Ee.push({command:de[2].trim().replace(/^php artisan /,""),cron:de[1].trim(),desc:"",lastRun:"—",lastStatus:"ok"})}if(Ee.length)C.schedulerTasks=Ee}catch{}return C.topology=es(C,{project:e.project.name,environment:t}),C}function Li(e){let t=Number(e);return Number.isFinite(t)&&t>=0?t:null}function mk(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 pu(e,t){if(!e||typeof e!=="object")return[];let r={source:t.name},a=[],l=t.now,m=(S,C,T,j=l)=>{if(C!==null)a.push({name:S,value:C,unit:T,timestamp:j,attributes:r})};m("storage.egress.month",Li(e.monthBytes),"bytes"),m("storage.egress.today",Li(e.todayBytes),"bytes"),m("storage.egress.projected_month",Li(e.projectedMonthBytes),"bytes");let h=Li(e.budgetBytes);if(h!==null&&h>0){m("storage.egress.budget",h,"bytes");let S=e.budgetUsedPercent,C=typeof S==="number"&&Number.isFinite(S)?S:Li(e.monthBytes)!==null?Math.round(Li(e.monthBytes)/h*1000)/10:null;m("storage.egress.budget_used_percent",C,"percent")}let I=t.maxReplayDays??45,R=Array.isArray(e.days)?e.days.slice(-I):[];for(let S of R){let C=mk(String(S?.date??"")),T=Li(S?.bytes);if(!C||T===null)continue;a.push({name:"storage.egress.day",value:T,unit:"bytes",timestamp:C,attributes:r});let j=Li(S?.downloads);if(j!==null)a.push({name:"storage.egress.day_downloads",value:j,unit:"count",timestamp:C,attributes:r})}return a}async function gu(e,t=process.env,r=fetch){let a=e.tokenEnv?t[e.tokenEnv]:void 0,l=await r(e.url,{headers:a?{Authorization:`Bearer ${a}`}:{},signal:AbortSignal.timeout(1e4)});if(!l.ok)throw Error(`HTTP ${l.status}`);return await l.json()}async function Ea(e,t){let r=[],a=[];if(!Array.isArray(e)||e.length===0)return{metrics:r,errors:a};let l=await Promise.all(e.map(async(m)=>{if(!m?.name||!m?.url)return{endpoint:m,error:"egress endpoint needs both a name and a url"};try{let h=await gu(m,t.env,t.fetchImpl);return{endpoint:m,report:h}}catch(h){return{endpoint:m,error:h instanceof Error?h.message:String(h)}}}));for(let m of l){let h=`egress:${m.endpoint?.name??"unnamed"}`;if("error"in m&&m.error){a.push({source:h,message:m.error});continue}r.push(...pu(m.report,{name:m.endpoint.name,now:t.now}))}return{metrics:r,errors:a}}import{createHash as x_}from"node:crypto";import{existsSync as Ii,mkdtempSync as wm,readdirSync as GS,rmSync as Ss,statSync as sw}from"node:fs";import{readFile as ii,writeFile as vs}from"node:fs/promises";import{tmpdir as Vu}from"node:os";import{dirname as D_,extname as Ec,join as Ut,normalize as O_,relative as $_,resolve as N_,sep as j_}from"node:path";import{fileURLToPath as B_}from"node:url";class Mo extends Error{status;code;requestId;constructor(e,t,r,a){super(r);this.status=e;this.code=t;this.requestId=a}}class gl{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}}),a=await r.json().catch(()=>({}));if(!r.ok)throw new Mo(r.status,a.error?.code??"api_error",a.error?.message??"API request failed.",a.error?.requestId??r.headers.get("x-request-id")??void 0);return a}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,a])=>[r,String(a)])))}`)}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,a])=>[r,String(a)]));return this.request(`/api/v1/queue?${t}`)}operationLogs(e,t={}){let r=new URLSearchParams(Object.entries(t).filter(([,a])=>a!==void 0).map(([a,l])=>[a,String(l)]));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,a]of Object.entries(e))if(a)t.set(r,String(a));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,a]of Object.entries(e))if(a)t.set(r,String(a));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 nI}from"node:crypto";import{lstatSync as fk,readdirSync as hk,readFileSync as yk}from"node:fs";import{relative as vk,resolve as vf,sep as bk}from"node:path";function Sk(e){return new Map(e.map((t)=>[t.path.replace(/^\.\//,"").replace(/\\/g,"/"),t]))}function Co(e,t,r){return{path:e,reason:t,weight:r}}function bf(e){try{return e?.content?JSON.parse(e.content):{}}catch{return{}}}function Ps(e,t,r,a,l,m){return{framework:e,strategy:t,confidence:r,evidence:a,defaults:{build:l,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:m}}function _s(e){let t=Sk(e.slice(0,1e4)),r=[];if(t.has("Dockerfile"))r.push(Ps("dockerfile","dockerfile",0.99,[Co("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 a=bf(t.get("composer.json"));if(t.has("artisan")&&a.require?.["laravel/framework"])r.push(Ps("laravel","server",0.98,[Co("artisan","Laravel Artisan entrypoint is present.",0.45),Co("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(Ps("php","server",0.82,[Co("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 l=bf(t.get("package.json"));if(t.has("package.json")){let m=t.has("bun.lock")||t.has("bun.lockb")||l.engines?.bun,h=m?"bun":"node",I=m?"bun":"node",R=[Co("package.json",`Defines ${l.scripts?.build?"build and ":""}${l.scripts?.start?"start ":""}scripts.`,0.55)];if(m)R.push(Co(t.has("bun.lock")?"bun.lock":t.has("bun.lockb")?"bun.lockb":"package.json","Pins the Bun package manager/runtime.",0.35));let S=!!(l.dependencies?.vite||l.devDependencies?.vite||l.dependencies?.["@stacksjs/bunpress"]||l.devDependencies?.["@stacksjs/bunpress"])&&!l.scripts?.start,C=S?{kind:"static",installCommand:`${h} install --frozen-lockfile`,buildCommand:`${h} run build`,publishDirectory:"dist"}:{kind:"server",runtime:h,installCommand:`${h} install --frozen-lockfile`,buildCommand:l.scripts?.build?`${h} run build`:void 0,startCommand:l.scripts?.start?`${h} run start`:h==="bun"?"bun run index.ts":"node index.js"};r.push(Ps(I,C.kind,Math.min(0.94,R.reduce((T,j)=>T+j.weight,0)),R,C,S?"Install dependencies, build static assets, and publish the output directory.":`Install dependencies, build if configured, and start the ${h} server.`))}if(!r.length&&(t.has("index.html")||t.has("public/index.html")))r.push(Ps("static","static",0.78,[Co(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(Ps("unknown","buildpack",0.2,[],{kind:"buildpack",runtime:"node"},"No supported framework signature was conclusive; choose commands and runtime manually."));return r.sort((m,h)=>h.confidence-m.confidence||m.framework.localeCompare(h.framework))}function sp(e,t={}){let r=vf(e),a=t.maxFiles??1e4,l=t.maxContentBytes??262144,m=[],h=new Set(["Dockerfile","package.json","composer.json","index.html","public/index.html","bun.lock","bun.lockb","artisan"]),I=new Set([".git",".ts-cloud",".cache",".next",".nuxt",".output",".turbo",".bun","node_modules","vendor","pantry","dist","build","coverage"]),R=(S)=>{for(let C of hk(S).sort()){if(I.has(C))continue;let T=vf(S,C),j=vk(r,T).split(bk).join("/");if(!j||j.startsWith("../"))throw Error("Detection path escaped the application root");let B=fk(T);if(B.isSymbolicLink())throw Error(`Detection refuses symbolic links: ${j}`);if(B.isDirectory())R(T);else if(B.isFile()){if(m.length>=a)throw Error("Application file-count limit exceeded");let V={path:j,size:B.size};if(h.has(j)&&B.size<=l)V.content=yk(T,"utf8");m.push(V)}}};return R(r),m}function cp(e){if(Array.isArray(e))return`[${e.map(cp).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)}:${cp(r)}`).join(",")}}`;return JSON.stringify(e)??"null"}function Xa(e){return!!e&&!e.startsWith("/")&&!e.split("/").includes("..")&&!/[\0\r\n]/.test(e)}function En(e,t,r,a){return{path:e,code:t,message:r,alternatives:a}}function ap(e){return JSON.parse(JSON.stringify(e))}function wk(e){let t=Object.fromEntries(Object.entries(e.environment??{}).map(([r,a])=>[r,typeof a==="string"?a:`\${${a.secretRef}}`]));if(e.build.kind==="prebuilt_image"||e.build.kind==="dockerfile")return ap({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 ap({serverless:{apps:{[e.slug]:{source:e.source,build:e.build,architecture:e.runtime.architecture,environment:t,domain:e.domain}}}});return ap({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 qn(e,t=[]){let r=[],a=(V)=>/(?:secret|token|password|passwd|private[_-]?key|api[_-]?key)/i.test(V),l=Object.fromEntries(Object.entries(e.environment??{}).map(([V,W])=>{if(typeof W==="string"&&a(V))return r.push(En(`environment.${V}`,"write_only_secret_required",`${V} must be supplied through the write-only secrets boundary.`)),[V,{secretRef:V}];return[V,W]})),m=e.build;if(e.build.kind==="dockerfile"&&e.build.buildArgs){let V=Object.fromEntries(Object.entries(e.build.buildArgs).map(([W,Y])=>{if(a(W))return r.push(En(`build.buildArgs.${W}`,"write_only_build_secret_required",`${W} must be declared in secretNames instead of buildArgs.`)),[W,"[REDACTED]"];return[W,Y]}));m={...e.build,buildArgs:V}}if(!/^[a-z0-9][a-z0-9-]{1,62}$/.test(e.slug))r.push(En("slug","invalid_slug","Slug must contain 2-63 lowercase letters, numbers, or hyphens."));if(!Xa((e.source.kind==="git"?e.source.monorepoRoot:e.source.kind==="local"?e.source.root:".")??"."))r.push(En("source","unsafe_source_root","Source root must stay inside the source tree."));if(e.source.kind==="git"&&e.source.sparsePaths?.some((V)=>!Xa(V)))r.push(En("source.sparsePaths","unsafe_sparse_path","Sparse checkout paths must stay inside the repository."));if(e.build.kind==="dockerfile"&&(!Xa(e.build.context)||!Xa(e.build.dockerfile)))r.push(En("build","unsafe_docker_path","Docker context and Dockerfile must stay inside the source tree."));if(e.build.kind==="static"&&!Xa(e.build.publishDirectory))r.push(En("build.publishDirectory","invalid_publish_directory","A safe static publish directory is required."));if(e.build.kind==="server"&&!e.build.startCommand.trim())r.push(En("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(En("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(En("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(En("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(En("runtime.port","invalid_port","Port must be an integer from 1 to 65535."));let h=e.runtime.healthCheck;if(h&&h.protocol!=="tcp"&&(!h.path||!h.path.startsWith("/")||/[\r\n]/.test(h.path)))r.push(En("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(En("domain.hostname","invalid_domain","Domain must be a valid DNS hostname."));let I=Object.values(l).flatMap((V)=>typeof V==="object"?[V.secretRef]:[]),R=[...new Set([...e.requiredSecretNames??[],...e.build.kind==="dockerfile"?e.build.secretNames??[]:[],...I])].sort(),S=new Set(t),C=R.filter((V)=>!S.has(V)),T={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:m,runtime:e.runtime,environment:l,domain:e.domain}},j=[...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(),B=[...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&&C.length===0,issues:r,missingSecrets:C,manifest:T,configPatch:wk({...e,build:m,environment:l}),capabilityRequirements:j,costDrivers:B,serializedManifest:`${cp(T)}
42
42
  `}}function Sf(e){let t=e.replace(/\\/g,"/");return!!t&&!t.startsWith("/")&&!/^[A-Za-z]:\//.test(t)&&!t.split("/").includes("..")&&!/[\0\r\n]/.test(t)}function wf(e,t,r={}){let a=r.maxBytes??104857600,l=r.maxEntries??1e4,m=r.maxExpandedBytes??524288000;if(e.byteLength>a)throw Error("Archive exceeds the compressed size limit");let h=new DataView(e.buffer,e.byteOffset,e.byteLength),I=[],R=0;if(t.toLowerCase().endsWith(".zip")||e[0]===80&&e[1]===75){let C=0;while(C+30<=e.length){let T=h.getUint32(C,!0);if(T===33639248||T===101010256)break;if(T!==67324752)throw Error("Malformed ZIP local header");let j=h.getUint16(C+6,!0),B=h.getUint32(C+18,!0),V=h.getUint32(C+22,!0),W=h.getUint16(C+26,!0),Y=h.getUint16(C+28,!0);if(j&8)throw Error("ZIP data descriptors are not accepted for uploaded artifacts");let te=new TextDecoder().decode(e.subarray(C+30,C+30+W));if(!Sf(te))throw Error(`Unsafe archive path: ${te}`);if(I.push(te),R+=V,I.length>l||R>m)throw Error("Archive expansion limit exceeded");C+=30+W+Y+B}return{format:"zip",entries:I.length,expandedBytes:R,paths:I}}if(!t.toLowerCase().match(/\.(?:tar|tar\.gz|tgz)$/))throw Error("Only ZIP and uncompressed TAR artifacts are supported");let S=0;while(S+512<=e.length){let C=e.subarray(S,S+512);if(C.every((W)=>W===0))break;let T=(W,Y)=>new TextDecoder().decode(C.subarray(W,W+Y)).replace(/\0.*$/,""),j=`${T(345,155)}${T(345,155)?"/":""}${T(0,100)}`,B=Number.parseInt(T(124,12).trim()||"0",8),V=String.fromCharCode(C[156]??0);if(!Sf(j))throw Error(`Unsafe archive path: ${j}`);if(V==="1"||V==="2")throw Error(`Archive links are not accepted: ${j}`);if(!Number.isFinite(B)||B<0)throw Error("Malformed TAR entry size");if(I.push(j),R+=B,I.length>l||R>m)throw Error("Archive expansion limit exceeded");S+=512+Math.ceil(B/512)*512}return{format:"tar",entries:I.length,expandedBytes:R,paths:I}}var kf=new Set(["source","build","runtime","environment","domain","review"]);function If(e,t){try{return typeof e==="string"?JSON.parse(e):t}catch{return t}}function Ef(e){return/(?:secret|token|password|passwd|private[_-]?key|api[_-]?key)/i.test(e)}function Rf(e){for(let[r,a]of Object.entries(e.environment??{}))if(typeof a==="string"&&Ef(r)&&a)throw Error(`${r} must be stored through the write-only secrets boundary`);if(e.build.kind==="dockerfile"){for(let[r,a]of Object.entries(e.build.buildArgs??{}))if(Ef(r)&&a)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 Af(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:If(e.input,{}),suppliedSecretNames:If(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 dp{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(Rf(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(),a=this.now(),l=e.step??"source";if(!kf.has(l))throw Error("Invalid draft step");let m=[...new Set(e.suppliedSecretNames??[])].sort(),h=qn(e.draft,m).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),l,JSON.stringify(e.draft),JSON.stringify(m),h,e.actorId??null,a,a]),this.controlPlane.appendEvent({organizationId:e.organizationId,projectId:e.projectId,actorId:e.actorId,type:"application.draft.created",payload:{draftId:r,step:l,status:h,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?Af(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(Af)}update(e,t,r){let a=this.get(e);if(!a||a.version!==t)throw Error(`Application draft ${e} changed since version ${t}`);if(!kf.has(r.step))throw Error("Invalid draft step");if(r.draft.projectId!==a.projectId)throw Error("Draft project cannot be changed");Rf(r.draft);let l=[...new Set(r.suppliedSecretNames??a.suppliedSecretNames)].sort(),m=qn(r.draft,l).valid?"ready":"draft",h=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(l),m,h,e,t]).changes!==1)throw Error(`Application draft ${e} changed since version ${t}`);return this.controlPlane.appendEvent({organizationId:a.organizationId,projectId:a.projectId,actorId:r.actorId,type:"application.draft.updated",payload:{draftId:e,fromVersion:t,toVersion:t+1,step:r.step,status:m}}),this.get(e)}markApplied(e,t,r){let a=this.get(e);if(!a||a.version!==t)throw Error(`Application draft ${e} changed since version ${t}`);let l=qn(a.input,a.suppliedSecretNames);if(!l.valid)throw Error(`Draft is not deployable: ${[...l.issues.map((h)=>h.message),...l.missingSecrets.map((h)=>`Missing secret ${h}`)].join("; ")}`);let m=this.now();return this.controlPlane.database.run("UPDATE application_drafts SET status='applied', step='review', version=version+1, updated_at=? WHERE id=? AND version=?",[m,e,t]),this.controlPlane.appendEvent({organizationId:a.organizationId,projectId:a.projectId,actorId:r,type:"application.draft.applied",payload:s({draftId:e,manifest:l.manifest})}),this.get(e)}}import{createCipheriv as kk,createDecipheriv as Ik,createHash as _f,randomBytes as Ek}from"node:crypto";function ec(e){return typeof e==="string"&&e?e:void 0}function lp(e){return _f("sha256").update(e).digest("hex").slice(0,16)}function Cf(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 Rk(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:ec(e.credential_fingerprint),credentialExpiresAt:ec(e.credential_expires_at),status:String(e.status),healthMessage:ec(e.health_message),lastTestedAt:ec(e.last_tested_at),version:Number(e.version),createdByActorId:ec(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}class up{controlPlane;key;nowFn;idFn;constructor(e,t){this.controlPlane=e;if(!t.encryptionKey)throw Error("Registry encryption key is required");this.key=_f("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=Ek(12),r=kk("aes-256-gcm",this.key,t),a=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${a.toString("base64url")}`}decrypt(e){let[t,r,a,l]=e.split(".");if(t!=="v1"||!r||!a||!l)throw Error("Registry credential envelope is invalid");let m=Ik("aes-256-gcm",this.key,Buffer.from(r,"base64url"));return m.setAuthTag(Buffer.from(a,"base64url")),Buffer.concat([m.update(Buffer.from(l,"base64url")),m.final()]).toString("utf8")}current(e){let t=Rk(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(),a=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),Cf(e.host),t?this.encrypt(t):null,t?lp(t):null,e.credentialExpiresAt??null,e.actorId??null,a,a]),this.controlPlane.appendEvent({organizationId:e.organizationId,actorId:e.actorId,type:"registry.connection.created",payload:{connectionId:r,provider:e.provider,host:Cf(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 a=this.get(e);if(!a||a.status==="disconnected")throw Error("Registry connection was not found");let l=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(l),lp(l),r.expiresAt??null,this.now(),e]),this.controlPlane.appendEvent({organizationId:a.organizationId,actorId:r.actorId,type:"registry.credential.rotated",payload:{connectionId:e,fingerprint:lp(l),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 a=this.credential(e),l=t.fetch??fetch,m=new AbortController,h=setTimeout(()=>m.abort(),t.timeoutMs??15000),I=a?.token?`Bearer ${a.token}`:a?.username||a?.password?`Basic ${Buffer.from(`${a.username??""}:${a.password??""}`).toString("base64")}`:void 0;try{let R=await l(`${r.host}/v2/`,{method:"GET",redirect:"error",signal:m.signal,headers:I?{Authorization:I}:void 0}),S=R.headers.get("www-authenticate")??"";if(R.status===401&&S.startsWith("Bearer ")&&a){let j=Object.fromEntries([...S.slice(7).matchAll(/(\w+)="([^"]+)"/g)].map((te)=>[te[1],te[2]])),B=new URL(j.realm??"");if(B.protocol!=="https:")throw Error("Registry authentication realm must use HTTPS");if(j.service)B.searchParams.set("service",j.service);if(t.image)B.searchParams.set("scope",`repository:${Tf(t.image).repository}:pull`);let V=await l(B,{signal:m.signal,redirect:"error",headers:I?{Authorization:I}:void 0});if(!V.ok)throw Error(`Registry authentication failed (${V.status})`);let W=await V.json(),Y=W.token??W.access_token;if(!Y)throw Error("Registry did not return an access token");R=t.image?await Pf(l,r.host,t.image,Y,m.signal):await l(`${r.host}/v2/`,{signal:m.signal,redirect:"error",headers:{Authorization:`Bearer ${Y}`}})}else if(R.ok&&t.image)R=await Pf(l,r.host,t.image,a?.token,m.signal,I);let C=R.ok?"healthy":"degraded",T=R.ok?t.image?"Registry image is readable.":"Registry connection is healthy.":`Registry request failed (${R.status})`;return this.controlPlane.database.run("UPDATE registry_connections SET status=?, health_message=?, last_tested_at=?, version=version+1, updated_at=? WHERE id=?",[C,T,this.now(),this.now(),e]),this.get(e)}catch(R){let S=m.signal.aborted?"Registry request timed out.":R instanceof Error?R.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=?",[S.slice(0,1000),this.now(),this.now(),e]),this.get(e)}finally{clearTimeout(h)}}}function Tf(e){let t=e.replace(/^https?:\/\//,""),r=t.indexOf("/");if(r<1)throw Error("Image must include registry/repository");let a=t.slice(r+1),l=a.lastIndexOf("@"),m=a.lastIndexOf(":"),h=l>=0?l:m>a.lastIndexOf("/")?m:-1,I=h>=0?a.slice(0,h):a,R=h>=0?a.slice(h+1):"latest";if(!/^[A-Za-z0-9_.\/-]+$/.test(I)||!/^[A-Za-z0-9_.:+-]+$/.test(R))throw Error("Image reference is invalid");return{repository:I,reference:R}}async function Pf(e,t,r,a,l,m){let h=Tf(r);return e(`${t}/v2/${h.repository}/manifests/${encodeURIComponent(h.reference)}`,{method:"HEAD",redirect:"error",signal:l,headers:{Accept:"application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json",...a?{Authorization:`Bearer ${a}`}:m?{Authorization:m}:{}}})}import{createHash as Ak}from"node:crypto";import{chmodSync as xf,existsSync as Df,mkdirSync as Ck,renameSync as Pk,unlinkSync as Of,writeFileSync as _k}from"node:fs";import{basename as Tk,join as xk}from"node:path";function pp(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 gp{controlPlane;root;idFn;nowFn;constructor(e,t){this.controlPlane=e;this.root=d(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=Tk(e.filename).slice(0,200);if(!r||r!==e.filename)throw Error("Artifact filename must not contain a path");let a=wf(e.bytes,r),l=Ak("sha256").update(e.bytes).digest("hex"),m=this.controlPlane.database.query("SELECT * FROM application_artifacts WHERE project_id=? AND sha256=?").get(e.projectId,l);if(m)return pp(m);let h=this.idFn();Ck(this.root,{recursive:!0,mode:448}),xf(this.root,448);let I=xk(this.root,`${h}.archive`),R=`${I}.partial`;try{_k(R,e.bytes,{mode:384,flag:"wx"}),Pk(R,I),xf(I,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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[h,e.organizationId,e.projectId,r,I,l,e.bytes.byteLength,a.format,a.entries,a.expandedBytes,e.actorId??null,this.nowFn().toISOString()])}catch(S){if(Df(R))Of(R);if(Df(I))Of(I);throw S}return this.controlPlane.appendEvent({organizationId:e.organizationId,projectId:e.projectId,actorId:e.actorId,type:"application.artifact.created",payload:{artifactId:h,filename:r,sha256:l,size:e.bytes.byteLength,entries:a.entries}}),this.get(h)}get(e){let t=this.controlPlane.database.query("SELECT * FROM application_artifacts WHERE id=?").get(e);return t?pp(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(pp)}}function Bc(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),a=r?e.controlPlane.listEnvironments(r.id).find((S)=>S.id===t.input.environmentId):void 0;if(!r||!a||a.projectId!==r.id||r.organizationId!==t.organizationId)throw Error("Draft deployment scope was not found");if(e.confirmEnvironment!==a.slug)throw Error(`Type ${a.slug} to confirm this deployment target`);let l=qn(t.input,t.suppliedSecretNames);if(!l.valid)throw Error(`Application plan is invalid: ${[...l.issues.map((S)=>S.message),...l.missingSecrets.map((S)=>`Missing secret ${S}`)].join("; ")}`);let m=e.controlPlane.listResources(r.id,a.id).find((S)=>S.kind==="application"&&S.slug===t.input.slug),h=JSON.parse(JSON.stringify({manifest:l.manifest,configPatch:l.configPatch})),I=m?e.controlPlane.updateResource(m.id,m.version,{name:t.input.name,desiredState:h}):e.controlPlane.createResource({projectId:r.id,environmentId:a.id,kind:"application",slug:t.input.slug,name:t.input.name,desiredState:h,metadata:{source:"application-onboarding",draftId:t.id}}),R=new c(e.controlPlane).enqueue({projectId:r.id,environmentId:a.id,resourceId:I.id,actorId:e.actorId,kind:"application.create",idempotencyKey:`application-draft:${t.id}:v${t.version}`,correlationId:`application-draft:${t.id}`,input:h,lockKey:`resource:${I.id}`,providerKey:I.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:I.id,operationId:R.id,actorId:e.actorId,type:"application.create.queued",payload:{draftId:t.id,environment:a.slug,strategy:t.input.build.kind,costDrivers:l.costDrivers}}),{plan:l,resource:I,operation:R}}function Xr(e){let t=["static","compute","serverless_zip","serverless_image"].includes(e.kind),r=["container","compose"].includes(e.kind)&&(e.replicas??1)>1,a=e.kind==="container"||e.kind==="serverless_zip"||e.kind==="serverless_image",l=(m,h)=>h&&(m==="atomic"?e.kind==="static"||e.hasHealthGate:e.hasHealthGate);return[{strategy:"atomic",supported:l("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:l("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:l("blue_green",a),explanation:a?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:l("canary",a),explanation:a?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 Qi(e,t){let r=Xr(e).find((a)=>a.strategy===t);if(!r.supported)throw Error(`${t} is unavailable: ${r.explanation}`);return r}import{createHash as Dk}from"node:crypto";var Ok=/^sha256:[a-f0-9]{64}$/,$k=/^[a-f0-9]{40,64}$/i;function Xn(e){return typeof e==="string"&&e?e:void 0}function Po(e,t){try{return JSON.parse(String(e))}catch{return t}}function $f(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:Po(e.provenance,{}),attestation:Po(e.attestation,{}),verifiedAt:String(e.verified_at),createdAt:String(e.created_at)}}function Nf(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:Xn(e.source_sha),configHash:String(e.config_hash),manifest:Po(e.manifest,{}),provenance:Po(e.provenance,{}),strategy:String(e.strategy),status:String(e.status),healthGate:e.health_gate==null?void 0:Po(e.health_gate,void 0),hooks:Po(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:Xn(e.previous_release_id),promotedFromReleaseId:Xn(e.promoted_from_release_id),actorId:Xn(e.actor_id),trigger:String(e.trigger),pinned:Number(e.pinned)===1,pinReason:Xn(e.pin_reason),activatedAt:Xn(e.activated_at),failedAt:Xn(e.failed_at),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Nk(e){return{sequence:Number(e.sequence),id:String(e.id),releaseId:String(e.release_id),fromStatus:Xn(e.from_status),toStatus:String(e.to_status),trafficPercent:e.traffic_percent==null?void 0:Number(e.traffic_percent),health:Po(e.health,{}),message:String(e.message),operationId:Xn(e.operation_id),createdAt:String(e.created_at)}}function jk(e,t){let r=[],a=(l,m,h)=>{if(JSON.stringify(m)===JSON.stringify(h))return;if(m&&h&&typeof m==="object"&&typeof h==="object"&&!Array.isArray(m)&&!Array.isArray(h)){for(let I of[...new Set([...Object.keys(m),...Object.keys(h)])].sort())a(l?`${l}.${I}`:I,m[I],h[I]);return}r.push({path:l,...m!==void 0?{before:m}:{},...h!==void 0?{after:h}:{}})};return a("",e,t),r}class Fo{controlPlane;now;id;constructor(e,t={}){this.controlPlane=e;this.now=t.now??(()=>new Date),this.id=t.id??(()=>crypto.randomUUID())}registerArtifact(e){if(!Ok.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 $f(t);let r=this.id(),a=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(s(e.provenance??{})),JSON.stringify(s(e.attestation??{})),a,a]),this.getArtifact(r)}getArtifact(e){let t=this.controlPlane.database.query("SELECT * FROM release_artifacts WHERE id=?").get(e);return t?$f(t):void 0}create(e){let t=this.getArtifact(e.artifactId),r=this.controlPlane.getResource(e.resourceId),a=this.controlPlane.listEnvironments(e.projectId).find((T)=>T.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||!a)throw Error("Release target scope does not match the resource");if(e.sourceSha&&!$k.test(e.sourceSha))throw Error("Release source must be an immutable commit SHA");Qi({kind:e.kind,provider:r.provider,hasHealthGate:!!e.healthGate,replicas:e.replicas},e.strategy);let l=s(e.config),m=Dk("sha256").update(JSON.stringify(l)).digest("hex"),h=this.active(e.resourceId),I=this.id(),R=this.now().toISOString(),S=e.approvalRequired?"awaiting_approval":"built",C=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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[I,e.organizationId,e.projectId,e.environmentId,e.resourceId,e.artifactId,e.kind,e.sourceSha??null,m,JSON.stringify(s(e.manifest)),JSON.stringify(s(e.provenance??{})),e.strategy,S,e.healthGate?JSON.stringify(e.healthGate):null,JSON.stringify(C),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,h?.id??null,e.promotedFromReleaseId??null,e.actorId??null,e.trigger??"manual",R,R]),this.recordTransition(I,void 0,S,{message:e.promotedFromReleaseId?"Immutable artifact promoted without rebuild.":"Immutable release record created."}),this.get(I)}get(e){let t=this.controlPlane.database.query("SELECT * FROM releases WHERE id=?").get(e);return t?Nf(t):void 0}list(e={}){return this.controlPlane.database.query("SELECT * FROM releases ORDER BY created_at DESC, rowid DESC").all().map(Nf).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(Nk)}recordTransition(e,t,r,a){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,a.trafficPercent??null,JSON.stringify(s(a.health??{})),a.message.slice(0,1000),a.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 a=this.get(e);if(!a)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"]}[a.status].includes(t))throw Error(`Invalid release transition ${a.status} → ${t}`);let m=this.now().toISOString();if(t==="active"){let h=this.active(a.resourceId);if(h&&h.id!==e)this.controlPlane.database.run("UPDATE releases SET status='superseded', updated_at=? WHERE id=?",[m,h.id]),this.recordTransition(h.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,m,t,m,m,e]),this.recordTransition(e,a.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 a=this.id(),l=this.now().toISOString();return this.controlPlane.database.run("INSERT INTO release_approvals (id, release_id, environment_id, decision, actor_id, comment, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[a,e,r.environmentId,t.decision,t.actorId,t.comment?.slice(0,1000)??null,l]),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:Xn(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),a=this.get(t);if(!r||!a)throw Error("Both releases are required for comparison");return{artifactChanged:r.artifactId!==a.artifactId,sourceChanged:r.sourceSha!==a.sourceSha,configChanged:r.configHash!==a.configHash,manifestChanges:jk(r.manifest,a.manifest),dataCaveat:a.hooks.migrations==="none"?"No database migration is recorded.":`Database hooks are ${a.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 a of this.list()){let l=r.get(a.resourceId)??[];l.push(a),r.set(a.resourceId,l)}return[...r.values()].flatMap((a)=>a.slice(t)).filter((a)=>new Date(a.createdAt)<e.before&&!a.pinned&&!["active","activating","awaiting_approval"].includes(a.status)&&!this.list().some((l)=>l.previousReleaseId===a.id&&["active","activating"].includes(l.status)))}}class yt{controlPlane;releases;queue;constructor(e){this.controlPlane=e;this.releases=new Fo(e),this.queue=new c(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 a=t.action??"activate",l=this.queue.enqueue({projectId:r.projectId,environmentId:r.environmentId,resourceId:r.resourceId,actorId:t.actorId,kind:`release.${a}`,idempotencyKey:`release:${r.id}:${a}:${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:`${a} queued.`,operationId:l.id,trafficPercent:0}),l}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 a=this.releases.transition(r.id,"failed",{message:t.message??"Health gate failed.",operationId:t.operationId,trafficPercent:0,health:t.health}),l=r.previousReleaseId?this.releases.get(r.previousReleaseId):void 0;if(!r.automaticRollback||r.rollbackAttempts>=1||!l)return{release:a};let m=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:l.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:a,rollbackOperation:m}}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 a=t.targetReleaseId?this.releases.get(t.targetReleaseId):r.previousReleaseId?this.releases.get(r.previousReleaseId):void 0;if(!a||a.resourceId!==r.resourceId||!["superseded","active"].includes(a.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:${a.id}`,correlationId:`release:${r.id}`,input:{releaseId:r.id,targetReleaseId:a.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 jm(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 ml(e,t){if(t.release.artifactId!==t.artifact.id)throw Error("Release activation artifact identity changed");Qi({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:jm(t.release)})}async function hl(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 zm=["release.activate","release.rollback"];function Bk(e){return e&&typeof e==="object"&&!Array.isArray(e)?e:{}}function fl(e){let t=new yt(e.store),r=async(a)=>{let l=Bk(a.operation.input),m=typeof l.releaseId==="string"?l.releaseId:"",h=t.releases.get(m);if(!h)throw Error(`Queued release ${m||"(missing)"} was not found`);if(h.projectId!==a.operation.projectId||h.environmentId!==a.operation.environmentId||h.resourceId!==a.operation.resourceId)throw Error("Queued release does not match the operation scope");let I=t.releases.getArtifact(h.artifactId);if(!I||I.digest!==t.releases.getArtifact(h.artifactId)?.digest)throw Error("Immutable release artifact is unavailable");let R=typeof l.targetReleaseId==="string"&&l.targetReleaseId?l.targetReleaseId:h.previousReleaseId,S=R?t.releases.get(R):void 0;if(S&&(S.resourceId!==h.resourceId||S.artifactId===h.artifactId&&S.id===h.id))throw Error("Rollback target does not match the release resource");let C=await e.resolveDriver(h);a.checkpoint("verify",`Verifying ${I.digest} and ${h.configHash} for ${C.name}.`),a.log(`Artifact ${I.digest}; source ${h.sourceSha??"not recorded"}; config ${h.configHash}.`,{stream:"system"}),a.throwIfCancellationRequested();let T;try{T=a.operation.kind==="release.rollback"?await hl(C,{release:h,artifact:I,previous:S}):await ml(C,{release:h,artifact:I,previous:S})}catch(j){if(a.operation.kind==="release.activate"&&t.releases.get(h.id)?.status==="activating")t.completeHealthGate(h.id,{healthy:!1,operationId:a.operation.id,message:j instanceof Error?j.message:String(j)});throw j}for(let j of T.transitions)t.releases.progress(h.id,{message:`${a.operation.kind==="release.rollback"?"Rollback":"Activation"} traffic at ${j.trafficPercent}%.`,trafficPercent:j.trafficPercent,health:j.observed,operationId:a.operation.id}),a.log(`Traffic ${j.trafficPercent}%: ${j.healthy?"healthy":"unhealthy"}.`,{stream:j.healthy?"step":"stderr",step:"health"});if(a.checkpoint("health","Evaluating the provider health result."),!T.activated||!T.healthy){if(a.operation.kind==="release.activate"&&t.releases.get(h.id)?.status==="activating")t.completeHealthGate(h.id,{healthy:!1,operationId:a.operation.id,health:{resourceVersions:T.resourceVersions},message:T.error??"Provider health gate failed."});throw Error(T.error??`${C.name} reported an unhealthy release`)}if(a.operation.kind==="release.activate"&&h.healthGate?.name){if(!e.resolveHealthGate)throw t.completeHealthGate(h.id,{healthy:!1,operationId:a.operation.id,message:`Named health gate ${h.healthGate.name} is not available to this worker.`}),Error(`Named health gate ${h.healthGate.name} is unavailable`);a.checkpoint("named-health-gate",`Waiting on ${h.healthGate.name}.`);let j=await e.resolveHealthGate(h.healthGate.name,h);if(a.log(`${h.healthGate.name}: ${j.healthy?"healthy":"unhealthy"}${j.message?` — ${j.message}`:""}.`,{stream:j.healthy?"step":"stderr",step:"health"}),!j.healthy)throw t.completeHealthGate(h.id,{healthy:!1,operationId:a.operation.id,health:j.evidence,message:j.message??`Named health gate ${h.healthGate.name} failed.`}),Error(j.message??`Named health gate ${h.healthGate.name} failed`)}if(a.operation.kind==="release.rollback"){let j=t.releases.get(h.id);if(j.status!=="rolled_back")t.releases.transition(j.id,"rolled_back",{message:`Traffic restored through ${C.name}.`,operationId:a.operation.id,trafficPercent:0,health:{resourceVersions:T.resourceVersions}});if(S&&S.status!=="active"){let B=S.status==="activating"?S:t.releases.transition(S.id,"activating",{message:"Rollback target restoring traffic.",operationId:a.operation.id,trafficPercent:0});t.releases.transition(B.id,"active",{message:"Previous immutable release restored.",operationId:a.operation.id,trafficPercent:100,health:{resourceVersions:T.resourceVersions}})}}else t.completeHealthGate(h.id,{healthy:!0,operationId:a.operation.id,health:{providerVersion:T.providerVersion??null,resourceVersions:T.resourceVersions},message:"Provider activation and health gates completed."});return a.checkpoint("finalize","Persisted the terminal release state."),{releaseId:h.id,artifactDigest:I.digest,provider:C.name,providerVersion:T.providerVersion??null,resourceVersions:T.resourceVersions,status:t.releases.get(h.id).status}};return Object.fromEntries(zm.map((a)=>[a,r]))}import{createCipheriv as Mk,createDecipheriv as Lk,createHash as Ff,randomBytes as mp}from"node:crypto";var zf={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 Vt(e){return typeof e==="string"&&e?e:void 0}function Do(e,t){try{return typeof e==="string"?JSON.parse(e):t}catch{return t}}function ei(e){return JSON.stringify(s(e))}function To(e){return Ff("sha256").update(e).digest("hex")}function jf(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 Bf(e){let t=e.trim();if(t.length<2||t.length>80)throw Error("Connection name must contain 2-80 characters");return t}function fp(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 Mf(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 Mc(e){return[...new Set((e??[]).map((t)=>t.trim()).filter(Boolean))].slice(0,100)}function Fk(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 zk(e){return{id:String(e.id),organizationId:String(e.organization_id),provider:String(e.provider),name:String(e.name),host:String(e.host),owner:Vt(e.owner),authKind:String(e.auth_kind),credentialConfigured:!!e.credential_ciphertext,credentialFingerprint:Vt(e.credential_fingerprint),grantedScopes:Do(e.granted_scopes,[]),capabilities:Do(e.capabilities,zf[String(e.provider)]),status:String(e.status),healthMessage:Vt(e.health_message),lastTestedAt:Vt(e.last_tested_at),lastSyncedAt:Vt(e.last_synced_at),credentialExpiresAt:Vt(e.credential_expires_at),version:Number(e.version),createdByActorId:Vt(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function hp(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:Do(e.metadata,{}),syncedAt:String(e.synced_at)}}function Lf(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:Vt(e.environment_id),resourceId:Vt(e.resource_id),connectionId:String(e.connection_id),repositoryId:Vt(e.repository_id),repositoryFullName:String(e.repository_full_name),defaultBranch:String(e.default_branch),branchRule:Vt(e.branch_rule),tagRule:Vt(e.tag_rule),monorepoRoot:String(e.monorepo_root),includePaths:Do(e.include_paths,[]),excludePaths:Do(e.exclude_paths,[]),submodules:Number(e.submodules)===1,cloneDepth:e.clone_depth==null?void 0:Number(e.clone_depth),deployKeyId:Vt(e.deploy_key_id),autoDeploy:Number(e.auto_deploy)===1,pullRequestPreviews:Number(e.pull_request_previews)===1,status:String(e.status),disabledReason:Vt(e.disabled_reason),version:Number(e.version),createdByActorId:Vt(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function yp(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:Vt(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function vp(e){return{id:String(e.id),connectionId:String(e.connection_id),repositoryId:Vt(e.repository_id),repositoryFullName:String(e.repository_full_name),providerWebhookId:Vt(e.provider_webhook_id),events:Do(e.events,[]),status:String(e.status),healthMessage:Vt(e.health_message),lastDeliveryAt:Vt(e.last_delivery_at),lastReconciledAt:Vt(e.last_reconciled_at),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function bp(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:Vt(e.action),commitSha:Vt(e.commit_sha),signatureStatus:String(e.signature_status),status:String(e.status),payloadSummary:Do(e.payload_summary,{}),operationId:Vt(e.operation_id),error:Vt(e.error),receivedAt:String(e.received_at),processedAt:Vt(e.processed_at)}}class Uo{controlPlane;key;nowFn;idFn;constructor(e,t={}){this.controlPlane=e;this.key=t.encryptionKey?Ff("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=mp(12),r=Mk("aes-256-gcm",this.key,t),a=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${a.toString("base64url")}`}decrypt(e){if(!this.key)throw Error("Source credential encryption key is not configured");let[t,r,a,l]=e.split(".");if(t!=="v1"||!r||!a||!l)throw Error("Encrypted source credential is unavailable");let m=Lk("aes-256-gcm",this.key,Buffer.from(r,"base64url"));return m.setAuthTag(Buffer.from(a,"base64url")),Buffer.concat([m.update(Buffer.from(l,"base64url")),m.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(),a=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)
43
43
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?)`,[r,e.organizationId,e.provider,Bf(e.name),jf(e.host),e.owner?.trim()||null,e.authKind??(a?"access_token":"none"),a?this.encrypt(a):null,a?To(a).slice(0,16):null,ei([...new Set(e.grantedScopes??[])].sort()),ei(zf[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:jf(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=zk(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 a=this.getConnection(e);if(!a||a.status==="disconnected")throw Error("Active source connection was not found");let l=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(l),To(l).slice(0,16),r.expiresAt??null,this.now(),e]),this.controlPlane.appendEvent({organizationId:a.organizationId,actorId:r.actorId,type:"source.credential.rotated",payload:{connectionId:e,fingerprint:To(l).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 a=this.now(),l=t.grantedScopes?[...new Set(t.grantedScopes.map((m)=>m.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,l?ei(l):null,t.tested?a:null,t.synced?a:null,a,e]),l&&JSON.stringify(l)!==JSON.stringify([...r.grantedScopes].sort()))this.controlPlane.appendEvent({organizationId:r.organizationId,type:"source.connection.scopes_updated",payload:{connectionId:e,grantedScopes:l}});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(),a=this.controlPlane.database.query("SELECT id FROM source_repositories WHERE connection_id = ? AND provider_repository_id = ?").get(e.connectionId,e.providerRepositoryId),l=a?String(a.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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
@@ -70,7 +70,7 @@ data: ${JSON.stringify(ut)}
70
70
  default_role = ?, enabled = ?, enforce_sso = ?, updated_at = ? WHERE id = ?`,[t,r,a,l,e.clientSecret?this.encrypt(e.clientSecret):null,JSON.stringify(m),JSON.stringify(h),e.defaultRole??I.defaultRole,e.enabled??I.enabled?1:0,e.enforceSso??I.enforceSso?1:0,R,I.id]),this.getOidcProvider(I.id)}if(!e.clientSecret)throw Error("OIDC client secret is required for a new provider");let S=e.id??this.idFn();return this.run(`INSERT INTO auth_oidc_providers (id, organization_id, slug, name, issuer, client_id,
71
71
  client_secret_ciphertext, scopes, allowed_domains, default_role, enabled, enforce_sso, created_at, updated_at)
72
72
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[S,e.organizationId,t,r,a,l,this.encrypt(e.clientSecret),JSON.stringify(m),JSON.stringify(h),e.defaultRole??"viewer",e.enabled===!1?0:1,e.enforceSso?1:0,R,R]),this.getOidcProvider(S)}getOidcProvider(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_providers WHERE id = ?").get(e);return t?Fc(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?Fc(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(Fc).filter((a)=>t.includeDisabled||a.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:Fc(t),clientSecret:this.decrypt(t.client_secret_ciphertext)}}beginOidcTransaction(e,t,r){if(!this.getOidcProvider(e)?.enabled)throw Error("OIDC provider is unavailable");let l=this.idFn(),m=ci(32).toString("base64url"),h=ci(32).toString("base64url"),I=ci(64).toString("base64url"),R=this.now(),S=new Date(this.nowFn().getTime()+cl).toISOString();return this.run(`INSERT INTO auth_oidc_transactions (id, provider_id, state_hash, nonce_ciphertext, verifier_ciphertext,
73
- redirect_uri, return_path, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[l,e,Vn(m),this.encrypt(h),this.encrypt(I),t,r,S,R]),{transaction:this.getOidcTransaction(l),state:m,nonce:h,verifier:I}}getOidcTransaction(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE id = ?").get(e);return t?Xf(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,Vn(t));if(!r)throw Error("OIDC transaction is invalid");let a=Xf(r,this.now());if(a.state!=="pending")throw Error(`OIDC transaction is ${a.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(),a.id,this.now()]).changes!==1)throw Error("OIDC transaction is no longer available");return{transaction:this.getOidcTransaction(a.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?fI(r):void 0}linkOidcSubject(e,t,r,a){let l=this.getOidcProvider(e),m=this.getIdentity(t);if(!l||!m)throw Error("OIDC provider or identity was not found");let h=kp(a);if(!r.trim()||r.length>512)throw Error("OIDC subject is invalid");let I=this.getOidcSubject(e,r);if(I&&I.identityId!==t)throw Error("OIDC subject is already linked to another identity");let R=this.now();if(I)return this.run("UPDATE auth_oidc_subjects SET email = ?, last_login_at = ? WHERE id = ?",[h,R,I.id]),this.getOidcSubject(e,r);let S=this.idFn();return this.run("INSERT INTO auth_oidc_subjects (id, provider_id, identity_id, subject, email, linked_at, last_login_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[S,e,t,r,h,R,R]),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 Jr(e,t){let r=e.notifications?.email?.from;if(!r)return!1;try{let{EmailClient:a}=await import("./chunk-7fbfmpyx.js");return await new a({region:e.project.region,defaultFrom:r}).send(t),!0}catch{return!1}}import{randomBytes as hI}from"node:crypto";import{chmodSync as yI,existsSync as vI,mkdirSync as bI,readFileSync as SI,writeFileSync as wI}from"node:fs";import{dirname as kI}from"node:path";function Vm(){return L("auth-encryption-key")}function Xe(e){let t=process.env.TS_CLOUD_AUTH_ENCRYPTION_KEY?.trim();if(t)return t;let r=d(e,"auth-encryption-key");try{if(vI(r)){let l=SI(r,"utf8").trim();if(l)return l}}catch{}let a=hI(32).toString("base64url");try{bI(kI(r),{recursive:!0,mode:448}),wI(r,`${a}
73
+ redirect_uri, return_path, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[l,e,Vn(m),this.encrypt(h),this.encrypt(I),t,r,S,R]),{transaction:this.getOidcTransaction(l),state:m,nonce:h,verifier:I}}getOidcTransaction(e){let t=this.controlPlane.database.query("SELECT * FROM auth_oidc_transactions WHERE id = ?").get(e);return t?Xf(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,Vn(t));if(!r)throw Error("OIDC transaction is invalid");let a=Xf(r,this.now());if(a.state!=="pending")throw Error(`OIDC transaction is ${a.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(),a.id,this.now()]).changes!==1)throw Error("OIDC transaction is no longer available");return{transaction:this.getOidcTransaction(a.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?fI(r):void 0}linkOidcSubject(e,t,r,a){let l=this.getOidcProvider(e),m=this.getIdentity(t);if(!l||!m)throw Error("OIDC provider or identity was not found");let h=kp(a);if(!r.trim()||r.length>512)throw Error("OIDC subject is invalid");let I=this.getOidcSubject(e,r);if(I&&I.identityId!==t)throw Error("OIDC subject is already linked to another identity");let R=this.now();if(I)return this.run("UPDATE auth_oidc_subjects SET email = ?, last_login_at = ? WHERE id = ?",[h,R,I.id]),this.getOidcSubject(e,r);let S=this.idFn();return this.run("INSERT INTO auth_oidc_subjects (id, provider_id, identity_id, subject, email, linked_at, last_login_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[S,e,t,r,h,R,R]),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 Jr(e,t){let r=e.notifications?.email?.from;if(!r)return!1;try{let{EmailClient:a}=await import("./chunk-mqscxx2z.js");return await new a({region:e.project.region,defaultFrom:r}).send(t),!0}catch{return!1}}import{randomBytes as hI}from"node:crypto";import{chmodSync as yI,existsSync as vI,mkdirSync as bI,readFileSync as SI,writeFileSync as wI}from"node:fs";import{dirname as kI}from"node:path";function Vm(){return L("auth-encryption-key")}function Xe(e){let t=process.env.TS_CLOUD_AUTH_ENCRYPTION_KEY?.trim();if(t)return t;let r=d(e,"auth-encryption-key");try{if(vI(r)){let l=SI(r,"utf8").trim();if(l)return l}}catch{}let a=hI(32).toString("base64url");try{bI(kI(r),{recursive:!0,mode:448}),wI(r,`${a}
74
74
  `,{mode:384}),yI(r,384)}catch{}return a}import{constants as II,createHash as Rp,createPublicKey as EI,createVerify as RI,timingSafeEqual as AI}from"node:crypto";var Rh=new Set(["RS256","PS256","ES256"]),kh=60;function Uc(e,t){let r=new URL(e),a=["127.0.0.1","::1","localhost"].includes(r.hostname);if(r.protocol!=="https:"&&!(r.protocol==="http:"&&a))throw Error(`${t} must use HTTPS`);if(r.username||r.password||r.hash)throw Error(`${t} contains unsupported URL components`);return r}function Ap(e,t){if(!e||typeof e!=="object"||Array.isArray(e))throw Error(`${t} is invalid`);return e}async function Cp(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 l=await e.text();if(l.length>1048576)throw Error(`${t} response is too large`);try{return Ap(JSON.parse(l),t)}catch(m){if(m instanceof Error&&m.message===`${t} is invalid`)throw m;throw Error(`${t} returned invalid JSON`)}}function CI(e,t){let r=Rp("sha256").update(e).digest(),a=Rp("sha256").update(t).digest();return AI(r,a)}function dl(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 Oo(e,t=fetch){let r=Uc(e.issuer,"OIDC issuer"),a=new URL(`${r.pathname.replace(/\/$/,"")}/.well-known/openid-configuration`,r.origin),l=await Cp(await t(a,{headers:{accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC discovery");if(l.issuer!==e.issuer)throw Error("OIDC discovery issuer does not match the configured issuer");for(let h of["authorization_endpoint","token_endpoint","jwks_uri"]){if(typeof l[h]!=="string")throw Error(`OIDC discovery is missing ${h}`);Uc(l[h],`OIDC ${h}`)}if(Array.isArray(l.response_types_supported)&&!l.response_types_supported.includes("code"))throw Error("OIDC provider does not support authorization code flow");if(Array.isArray(l.code_challenge_methods_supported)&&!l.code_challenge_methods_supported.includes("S256"))throw Error("OIDC provider does not support PKCE S256");let m=Array.isArray(l.id_token_signing_alg_values_supported)?l.id_token_signing_alg_values_supported.filter((h)=>typeof h==="string"):[];if(m.length>0&&!m.some((h)=>Rh.has(h)))throw Error("OIDC provider does not offer a supported ID-token signing algorithm");return l}async function Lo(e,t,r,a,l=fetch){let m=e.getOidcProviderBySlug(t);if(!m?.enabled)throw Error("OIDC provider is unavailable");let h=Uc(r,"Application origin").origin,I=await Oo(m,l),R=`${h}/auth/oidc/${encodeURIComponent(m.slug)}/callback`,S=e.beginOidcTransaction(m.id,R,dl(a)),C=new URL(I.authorization_endpoint);return C.searchParams.set("response_type","code"),C.searchParams.set("client_id",m.clientId),C.searchParams.set("redirect_uri",R),C.searchParams.set("scope",m.scopes.join(" ")),C.searchParams.set("state",S.state),C.searchParams.set("nonce",S.nonce),C.searchParams.set("code_challenge",Rp("sha256").update(S.verifier).digest("base64url")),C.searchParams.set("code_challenge_method","S256"),{authorizationUrl:C.href,expiresAt:S.transaction.expiresAt}}function PI(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:Ap(JSON.parse(Buffer.from(t[0],"base64url").toString("utf8")),"OIDC ID-token header"),claims:Ap(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 _I(e,t,r){let a=PI(e),l=typeof a.header.alg==="string"?a.header.alg:"",m=typeof a.header.kid==="string"?a.header.kid:"";if(!Rh.has(l)||!m)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(l))throw Error("OIDC ID-token algorithm was not advertised by the provider");let h=await Cp(await r(t.jwks_uri,{headers:{accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC signing-key request");if(!Array.isArray(h.keys))throw Error("OIDC signing-key response is invalid");let I=h.keys.find((T)=>{if(!T||typeof T!=="object"||Array.isArray(T))return!1;let j=T;return j.kid===m&&(!j.alg||j.alg===l)&&(!j.use||j.use==="sig")});if(!I)throw Error("OIDC ID-token signing key was not found");let R=EI({key:I,format:"jwk"}),S=RI("SHA256").update(a.signingInput).end();if(!(l==="PS256"?S.verify({key:R,padding:II.RSA_PKCS1_PSS_PADDING,saltLength:32},a.signature):l==="ES256"?S.verify({key:R,dsaEncoding:"ieee-p1363"},a.signature):S.verify(R,a.signature)))throw Error("OIDC ID-token signature is invalid");return a.claims}function TI(e,t,r,a){if(e.iss!==t.issuer)throw Error("OIDC ID-token issuer is invalid");let l=typeof e.aud==="string"?[e.aud]:Array.isArray(e.aud)?e.aud.filter((R)=>typeof R==="string"):[];if(!l.includes(t.clientId))throw Error("OIDC ID-token audience is invalid");if((l.length>1||e.azp!==void 0)&&e.azp!==t.clientId)throw Error("OIDC ID-token authorized party is invalid");let m=Math.floor(a.getTime()/1000);if(typeof e.exp!=="number"||e.exp<m-kh)throw Error("OIDC ID token is expired");if(typeof e.iat!=="number"||e.iat>m+kh)throw Error("OIDC ID-token issued-at time is invalid");if(typeof e.nonce!=="string"||!CI(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 h=e.email.trim().toLowerCase();if(h.length>254||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(h))throw Error("OIDC provider returned an invalid email address");let I=h.split("@")[1];if(!I||!t.allowedDomains.includes(I))throw Error("OIDC email domain is not allowed for this organization");return{provider:t,subject:e.sub,email:h,name:typeof e.name==="string"?e.name.slice(0,120):void 0,claims:e}}async function $o(e,t,r=fetch){let a=e.getOidcProviderBySlug(t.providerSlug);if(!a?.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 l=Uc(t.origin,"Application origin").origin,m=e.consumeOidcTransaction(a.id,t.state),h=`${l}/auth/oidc/${encodeURIComponent(a.slug)}/callback`;if(m.transaction.redirectUri!==h)throw Error("OIDC callback redirect URI does not match the original request");let{clientSecret:I}=e.getOidcProviderCredentials(a.id),R=await Oo(a,r),S=new URLSearchParams({grant_type:"authorization_code",code:t.code,redirect_uri:m.transaction.redirectUri,code_verifier:m.verifier}),C={accept:"application/json","content-type":"application/x-www-form-urlencoded"},T=R.token_endpoint_auth_methods_supported??["client_secret_basic"];if(T.includes("client_secret_basic")){let V=(Y)=>new URLSearchParams({value:Y}).toString().slice(6),W=`${V(a.clientId)}:${V(I)}`;C.authorization=`Basic ${Buffer.from(W).toString("base64")}`}else if(T.includes("client_secret_post"))S.set("client_id",a.clientId),S.set("client_secret",I);else throw Error("OIDC provider does not support a configured client authentication method");let j=await Cp(await r(R.token_endpoint,{method:"POST",headers:C,body:S,redirect:"error",signal:AbortSignal.timeout(1e4)}),"OIDC token exchange");if(typeof j.id_token!=="string")throw Error("OIDC token response did not include an ID token");let B=await _I(j.id_token,R,r);return{identity:TI(B,a,m.nonce,t.now??new Date),returnPath:m.transaction.returnPath}}import{createHash as xI,randomBytes as DI}from"node:crypto";var _h=new Set(pe),ll=7776000000,ul=31536000000,pl=86400000;function di(e){return typeof e==="string"?e:void 0}function Ph(e){return xI("sha256").update(e).digest("hex")}function OI(e){try{let t=JSON.parse(String(e));return Array.isArray(t)?t.filter((r)=>typeof r==="string"&&_h.has(r)):[]}catch{return[]}}function $I(e){let t=String(e.scope_type);return t==="organization"?{type:t}:{type:t,id:String(e.scope_id)}}function Pp(e){let t=di(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:di(e.description),createdByActorId:di(e.created_by_actor_id),disabledAt:t,createdAt:String(e.created_at),updatedAt:String(e.updated_at),state:t?"disabled":"active"}}function _p(e,t){let r=di(e.revoked_at),a=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:OI(e.capabilities),scope:$I(e),expiresAt:a,lastUsedAt:di(e.last_used_at),lastNetworkHint:di(e.last_network_hint),revokedAt:r,rotatedFromTokenId:di(e.rotated_from_token_id),createdByActorId:di(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at),state:r?"revoked":a<=t?"expired":"active"}}function NI(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:di(e.operation_id),responseStatus:Number(e.response_status),responseBody:t,expiresAt:String(e.expires_at),createdAt:String(e.created_at)}}class Ui{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 a=this.controlPlane.createActor({kind:"service_account",externalId:`service-account:${e.organizationId}:${t}`,displayName:r,metadata:{source:"api",serviceAccountSlug:t}}),l=this.idFn(),m=this.now();this.run(`INSERT INTO service_accounts (id, organization_id, actor_id, slug, name, description, created_by_actor_id, created_at, updated_at)
75
75
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[l,e.organizationId,a.id,t,r,e.description?.trim().slice(0,500)||null,e.createdByActorId??null,m,m]);let h=this.controlPlane.createMembership({organizationId:e.organizationId,actorId:a.id,roleTemplate:e.roleTemplate,scope:e.scope,source:"manual",performedByActorId:e.createdByActorId}),I=e.scope??{type:"organization"};return this.controlPlane.appendEvent({organizationId:e.organizationId,actorId:e.createdByActorId,type:"api.service_account.created",payload:{serviceAccountId:l,roleTemplate:e.roleTemplate,scope:{type:I.type,id:I.id??null}}}),{serviceAccount:this.getServiceAccount(l),membership:h}}getServiceAccount(e){let t=this.controlPlane.database.query("SELECT * FROM service_accounts WHERE id = ?").get(e);return t?Pp(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?Pp(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(Pp).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 a=this.now();return this.controlPlane.transaction(()=>{this.run("UPDATE service_accounts SET disabled_at = ?, updated_at = ? WHERE id = ?",[a,a,e]),this.run("UPDATE api_tokens SET revoked_at = ?, updated_at = ? WHERE service_account_id = ? AND revoked_at IS NULL",[a,a,e]);let l=this.controlPlane.getMembershipForActor(r.organizationId,r.actorId);if(l?.status==="active")this.controlPlane.revokeMembership(l.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 a=[...new Set(e.capabilities)];if(a.length===0||a.some((j)=>!_h.has(j)))throw Error("API token requires valid explicit capabilities");let l=e.scope??r.scope,m=this.controlPlane.resolveAuthorizationTarget(t.organizationId,l);if(!m)throw Error("API token scope was not found in this organization");for(let j of a)if(!D({membership:r,grants:this.controlPlane.listGrants(r.id),capability:j,target:m}).allowed)throw Error(`Service-account membership does not grant ${j} at the token scope`);let h=e.expiresAt?new Date(e.expiresAt):new Date(this.nowFn().getTime()+ll);if(!Number.isFinite(h.getTime())||h.getTime()<=this.nowFn().getTime()+60000||h.getTime()>this.nowFn().getTime()+ul)throw Error("API token expiry must be between one minute and one year from now");let I=this.idFn(),R=DI(32).toString("base64url"),S=`tsc_v1.${I}.${R}`,C=`tsc_v1.${I.slice(0,8)}`,T=this.now();return this.run(`INSERT INTO api_tokens (id, service_account_id, name, token_hash, token_prefix, capabilities, scope_type, scope_id,
76
76
  expires_at, rotated_from_token_id, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[I,t.id,e.name.trim().slice(0,100)||"API token",Ph(S),C,JSON.stringify(a.sort()),l.type,l.type==="organization"?null:l.id??null,h.toISOString(),e.rotatedFromTokenId??null,e.createdByActorId??null,T,T]),this.controlPlane.appendEvent({organizationId:t.organizationId,actorId:e.createdByActorId,type:"api.token.created",payload:{serviceAccountId:t.id,tokenId:I,prefix:C,capabilities:a,scope:{type:l.type,id:l.id??null},expiresAt:h.toISOString(),rotatedFromTokenId:e.rotatedFromTokenId??null}}),{token:this.getToken(I),secret:S}}getToken(e){let t=this.controlPlane.database.query("SELECT * FROM api_tokens WHERE id = ?").get(e);return t?_p(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)=>_p(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 a=this.controlPlane.database.query("SELECT * FROM api_tokens WHERE id = ? AND token_hash = ?").get(r[1],Ph(e));if(!a)return;let l=_p(a,this.now()),m=this.getServiceAccount(l.serviceAccountId);if(!m||m.state!=="active"||l.state!=="active")return;let h=this.controlPlane.getActor(m.actorId),I=this.controlPlane.getMembershipForActor(m.organizationId,m.actorId);if(!h||h.disabledAt||!I||I.status!=="active")return;let R=this.now(),S=!l.lastUsedAt||this.nowFn().getTime()-new Date(l.lastUsedAt).getTime()>=3600000;if(this.run("UPDATE api_tokens SET last_used_at = ?, last_network_hint = ?, updated_at = ? WHERE id = ?",[R,t?.slice(0,128)??null,R,l.id]),S)this.controlPlane.appendEvent({organizationId:m.organizationId,actorId:h.id,type:"api.token.used",payload:{serviceAccountId:m.id,tokenId:l.id,prefix:l.prefix}});return{serviceAccount:m,token:this.getToken(l.id),actor:h,membership:I}}rotateToken(e,t){let r=this.getToken(e);if(!r||r.state!=="active")throw Error("Active API token was not found");let a=this.createToken({serviceAccountId:r.serviceAccountId,name:`${r.name} (rotated)`,capabilities:r.capabilities,scope:r.scope,expiresAt:r.expiresAt,createdByActorId:t,rotatedFromTokenId:r.id}),l=this.getServiceAccount(r.serviceAccountId);return this.controlPlane.appendEvent({organizationId:l?.organizationId,actorId:t,type:"api.token.rotated",payload:{serviceAccountId:r.serviceAccountId,previousTokenId:r.id,tokenId:a.token.id}}),a}revokeToken(e,t){let r=this.getToken(e);if(!r)throw Error("API token was not found");if(r.state==="active"){let a=this.now();this.run("UPDATE api_tokens SET revoked_at = ?, updated_at = ? WHERE id = ?",[a,a,e]);let l=this.getServiceAccount(r.serviceAccountId);this.controlPlane.appendEvent({organizationId:l?.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?NI(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(),a=this.now(),l=new Date(this.nowFn().getTime()+pl).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)
@@ -673,7 +673,7 @@ data: ${JSON.stringify({cursor:m,at:new Date().toISOString()})}
673
673
  ${I}
674
674
  ${R}`);return null}return a}catch(l){if(a)Ss(a,{recursive:!0,force:!0});if(process.env.TSCLOUD_DASHBOARD_VERBOSE)console.warn(`ts-cloud dashboard: live UI build errored; serving the pre-built UI. ${l.message}`);return null}}function rs(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:vo(Ka(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,a])=>[r,{domain:a.domain,path:a.path,type:a.type,deploy:a.deploy,root:a.root,port:a.port,ssl:a.ssl}]))}}function gn(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 ns(e,t){return gn(t).find((r)=>r.id===e)}function ew(e){if(e.length<=QS)return e;return`${e.slice(0,QS)}
675
675
 
676
- [output truncated]`}async function tw(e,t,r){let a=e.getReader(),l=new TextDecoder,m="";while(!0){let{done:I,value:R}=await a.read();if(I)break;let S=l.decode(R,{stream:!0});if(m+=S,S)r?.(t,S)}let h=l.decode();if(h)m+=h,r?.(t,h);return m}async function Sm(e,t){let r=Bun.spawn([process.execPath,t.cliEntry,...e.command],{cwd:t.cwd,stdout:"pipe",stderr:"pipe",env:{...process.env,...t.env}}),a=()=>{try{r.kill()}catch{}};if(t.signal?.aborted)a();else t.signal?.addEventListener("abort",a,{once:!0});try{let[l,m,h]=await Promise.all([tw(r.stdout,"stdout",t.onOutput),tw(r.stderr,"stderr",t.onOutput),r.exited]);return{action:e.id,command:["cloud",...e.command].join(" "),exitCode:h,ok:h===0,stdout:ew(l),stderr:ew(m)}}finally{t.signal?.removeEventListener("abort",a)}}function sT(){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 aT=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 cT(e){let t=Ec(e);if(t&&t!==".html")return!1;let r=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(r==="/")return!1;return!aT.has(r)}var dT={"/":"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 rw(e,t){if(t.role==="admin")return!0;let r=Ec(e);if(r&&r!==".html")return!0;if(t.organizationSource==="legacy")return!cT(e);let a=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(a==="/access-denied")return!0;let l=dT[a];return!!l&&!!t.capabilities?.includes(l)}function lT(e,t){let r=decodeURIComponent(t).replace(/^\/+/,""),l=O_(r===""?"index.html":r);if(l.startsWith("..")||l.includes("/../"))return null;let m=Ut(e,l);if(Ii(m)&&!sw(m).isDirectory())return m;if(!Ec(m)&&Ii(`${m}.html`))return`${m}.html`;if(!Ec(m)&&Ii(Ut(m,"index.html")))return Ut(m,"index.html");return null}async function nw(e,t){let r=lT(e,t);if(!r){let m=Ut(e,"404.html");if(Ii(m))return new Response(await ii(m),{status:404,headers:{"content-type":"text/html; charset=utf-8"}});return Wu("Not found",404)}if(sw(r).isDirectory())return Wu("Not found",404);let a=await ii(r),l=U_[Ec(r)]??"application/octet-stream";return new Response(a,{headers:{"content-type":l}})}var qu=["observe","backup","restore","restart","resize","version","rotate","expose","delete","logs","slow_queries","users","databases"],iw=new WeakMap;async function ow(e){let t=iw.get(e);if(t)return t;let r=await import("./spend/index.js"),a=new r.SpendStore(e),l={store:a,service:new r.SpendService(a),gate:new r.SpendGate(e)};return iw.set(e,l),l}async function La(e={}){z_();let t=e.cwd??process.cwd(),r=e.host??M_,a=e.port??L_,l=e.cliEntry??process.argv[1];if(e.box)process.env.TS_CLOUD_DASHBOARD_BOX="1";await Q_(t);let m=e.config??await nl(),h=process.env.TS_CLOUD_DASHBOARD_DB_PASSWORD,I=p(m);if(h&&I&&!I.password)I.password=h;let R=m.infrastructure?.compute?.managedServices?.vitess;if(h&&R&&typeof R==="object"&&!R.password)R.password=h;let S=iu(t,m);if(S.reconciliation.failed>0)console.warn(` ts-cloud dashboard: marked ${S.reconciliation.failed} orphaned operation(s) as failed after restart.`);let C=Object.keys(m.environments??{}),T=J_(m,e.environment),j=Y_(t),B=await bs(m,T),V=new Map([[T,B]]),W=new Map([[T,Date.now()]]),Y=new Map([[T,Date.now()]]),te=new Map,le=Math.min(300000,Math.max(5000,Number(process.env.TS_CLOUD_DASHBOARD_REFRESH_MS)||30000)),X=Math.min(1800000,Math.max(60000,Number(process.env.TS_CLOUD_DASHBOARD_SITE_REFRESH_MS)||300000)),ce=M(m)!=="serverless",Ee=(N)=>{let Fe=V.get(N);if(Fe&&!YS(W.get(N),Date.now(),le))return Promise.resolve(Fe);let We=te.get(N);if(We)return We;let Me=!ce||YS(Y.get(N),Date.now(),X),rt=bs(m,N,{includeSiteHealth:Me}).then((Rt)=>{let q=V.get(N),Ur=Me?Rt:nT(q,Rt);if(V.set(N,Ur),W.set(N,Date.now()),Me)Y.set(N,Date.now());if(q?._serverReachable!==Ur._serverReachable||q?._metricsStatus!==Ur._metricsStatus||(q?.sitesDetail?.length??0)!==(Ur.sitesDetail?.length??0))ot();return Ur}).finally(()=>te.delete(N));return te.set(N,rt),rt},Re=Ot(t),de=process.env.TS_CLOUD_DASHBOARD_TELEMETRY?.trim();if(e.box&&de!=="0"&&(de==="1"||!m.cloud?.attachTo)){let N=!1,Fe=Date.now()+300000,We=async()=>{if(N)return;N=!0;try{let rt=Date.now(),Rt=rt>=Fe;if(Rt)Fe=rt+300000;let q=S.environments.get(T);await vm({controlPlane:S.store,projectId:S.project.id,environmentId:q?.id,config:m,environment:T,force:!0,lightweight:!0,includeSiteHealth:Rt})}catch(rt){if(e.verbose)console.warn(` ts-cloud dashboard: background telemetry collection failed: ${rt instanceof Error?rt.message:String(rt)}`)}finally{N=!1}};We(),setInterval(()=>void We(),60000).unref?.()}let ae=new Map,je=new Map,Qe=new Set,gt=0;function Kt(N,Fe){if(N.role==="admin"&&!S.store.getActorByExternalId("user",`dashboard:${N.username.toLowerCase()}`))return N;let We=S.store.getActorByExternalId("user",`dashboard:${N.username.toLowerCase()}`),Me=We?S.store.getMembershipForActor(S.organization.id,We.id):void 0;if(!Me||Me.status!=="active")return{...N,role:"member",sites:{},capabilities:[]};let rt=S.store.listGrants(Me.id),Rt=S.store.resolveAuthorizationTarget(S.organization.id,Me.scope)??S.store.resolveAuthorizationTarget(S.organization.id,{type:"project",id:S.project.id}),q=$t({membership:Me,grants:rt,target:Rt});if(Me.roleTemplate==="owner"||Me.roleTemplate==="admin")return{...N,role:"admin",sites:{},organizationRole:Me.roleTemplate,organizationSource:Me.source,capabilities:q};let Ur=S.environments.get(Fe),br={};for(let at of S.store.listResources(S.project.id,Ur?.id).filter((pt)=>pt.kind==="application")){let pt=S.store.resolveAuthorizationTarget(S.organization.id,{type:"resource",id:at.id});if(!pt||!D({membership:Me,grants:rt,capability:"project:read",target:pt}).allowed)continue;br[at.slug]=D({membership:Me,grants:rt,capability:"config:write",target:pt}).allowed?"owner":"collaborator"}return{...N,role:"member",sites:br,organizationRole:Me.roleTemplate,organizationSource:Me.source,capabilities:q}}function ot(){gt+=1,ae.clear();for(let N of Qe)Ss(N,{recursive:!0,force:!0});Qe.clear()}let Pt=(N,Fe)=>`${Fe}:${N.role==="admin"?"admin":`member:${Object.entries(N.sites).sort(([We],[Me])=>We.localeCompare(Me)).map(([We,Me])=>`${We}=${Me}`).join(",")}`}:${[...N.capabilities??[]].sort().join(",")}`;async function ir(N,Fe){let We=Kt(N,Fe),Me=Pt(We,Fe),rt=ae.get(Me);if(rt)return rt;let Rt=je.get(Me);if(Rt)return Rt;let q=gt,Ur=(async()=>{let br=V.get(Fe)??await bs(m,Fe);V.set(Fe,br);let at={...dm(br,{user:We,slug:m.project.slug}),viewer:{role:We.role,organizationRole:We.organizationRole,organizationSource:We.organizationSource,capabilities:We.capabilities??[]}},pt=await oT(t,at);if(pt&&q!==gt)return Ss(pt,{recursive:!0,force:!0}),Re?.uiRoot;if(pt)Qe.add(pt);let $r=pt??Re?.uiRoot;if($r)ae.set(Me,$r);return $r})();je.set(Me,Ur);try{return await Ur}finally{je.delete(Me)}}let lt=await ir({username:"",passwordHash:"",role:"admin",sites:{}},T);if(!lt)throw Error("ts-cloud dashboard UI not found. Run `bun run build` in ts-cloud or reinstall the package.");let G=new WeakMap,ue=process.env.TS_CLOUD_DASHBOARD_TERMINAL!=="0",be=process.env.TS_CLOUD_DASHBOARD_AUTH==="0";if(be&&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 De=!be,mt=Qb(t),Dt=De?eS(t,process.env.TS_CLOUD_UI_USERNAME?.trim()||"admin"):void 0,$e=new Fi(S.store,{encryptionKey:Xe(t)}),wt=new Ui(S.store),ut=new Zr(S.store),Ge=new Uo(S.store,{encryptionKey:Xe(t)}),zr=new dp(S.store),ws=new gp(S.store,{cwd:t}),Yn=new up(S.store,{encryptionKey:Xe(t)}),qt=new c(S.store,{workerId:`dashboard:${process.pid}`}),sr=new ea(S.store),oi=new da(S.store,Xe(t)),Ri=new ka(S.store),Rc=new Ki(sr,qt,oi),Pi=m.project?.region??"us-east-1",km=Xe(t),In=new Oa(Ri,{encryptionKey:km,backends:[new pn(S.store,km),new Ba(new z(Pi),Pi),new _a(new we(Pi),Pi),new xa]});await Su(In,S,m);let Hu=new K(Pi),cw={aws_rds:new ta(new oa(Hu)),aws_aurora:new ra(new aa(Hu)),aws_elasticache:new na(new ca(new nt(Pi))),server:new ia(new Zt),container:new sa(new Zt)},Im=(N)=>cw[N.provider],Sr=new ba(S.store),bo=new ts(Sr,qt),Em=new va(oi),dw={managed_database:new Ta(sr,Hu),logical_database:new Ra(sr,oi),volume:new Da,files:new wa(t),control_plane:new Pa(S.store,t),infrastructure:new Na(new nr(Pi))},lw=(N)=>dw[N.resourceKind],uw=(N)=>N.provider==="aws_backup"?void 0:Em,Ku=new Mt(S.store),Ju=[new _r,new js(d(t,"volumes"))],si=new Vs(Ku,Ju,qt),Ja=new la(S.store),Zn=new ua(Ja,[new sn("aws"),new sn("hetzner"),new sn("ssh")],qt),_i=new pa(S.store),Rm=new ga(_i,Ja),wo=new ma(S.store),Am=new ha(wo,qt),ai=new Aa(S.store),Gu=new ya(ai,qt),Cm=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((N)=>new Ia(N,S.store,S.project.id,S.organization.id)),Dr=new Xo(S.store),Pm=new Zo(Dr,{queue:qt}),yr=new Br(S.store),xi=new xr(S.store),Dn=new yt(S.store),st=new Ci(S.store,{encryptionKey:Xe(t)}),pw=()=>ow(S.store);for(let N of S.environments.values())Yo(Dr,m,{organization:S.organization,project:S.project,environment:N,resources:S.store.listResources(S.project.id,N.id)});let On=new Ei(st,{emailImpl:async(N)=>{let{email:Fe}=await import("./chunk-7fbfmpyx.js");return Fe.send(N)}}),_m=async(N)=>{let Fe=so(st,S.project.id,N),We=[];for(let Me of Fe.filter((rt)=>rt.notify&&rt.alert))We.push(...await On.deliverAll(On.enqueue(S.organization.id,Me.alert,Me.transition)));return We.push(...await On.deliverAll(On.enqueueRemindersAndEscalations(S.organization.id,st.listAlerts(S.project.id,{environmentId:N,states:["firing"]})))),We.push(...await On.retryDue()),{evaluations:Fe,deliveries:We}},Qu=!1,gw=async()=>{if(Qu)return;Qu=!0;try{for(let N of S.environments.values())for(let Fe of st.listHealthChecks(S.project.id,N.id).filter((We)=>We.enabled)){let We=st.listHealthResults(Fe.id,1)[0];if(We&&Date.now()-new Date(We.checkedAt).getTime()<Fe.intervalSeconds*1000)continue;let Me=await new Ve(st).runAndEvaluate(Fe);for(let rt of Me.evaluations.filter((Rt)=>Rt.notify&&Rt.alert))await On.deliverAll(On.enqueue(S.organization.id,rt.alert,rt.transition))}}finally{Qu=!1}},Tm=setInterval(()=>{for(let N of S.environments.values())_m(N.id).catch((Fe)=>console.error("ts-cloud alert evaluation failed:",Fe))},60000);Tm.unref?.();let xm=setInterval(()=>{gw().catch((N)=>console.error("ts-cloud health check evaluation failed:",N))},30000);xm.unref?.();let Dm=setInterval(()=>{try{Pm.tick()}catch(N){console.error("ts-cloud scheduled job evaluation failed:",N)}},30000);Dm.unref?.();let Om=setInterval(()=>{try{bo.enqueueDue(),bo.enqueueRetention()}catch(N){console.error("ts-cloud backup policy evaluation failed:",N)}},30000);Om.unref?.(),yr.cleanup();let $m=setInterval(()=>{try{yr.cleanup()}catch(N){console.error("ts-cloud preview cleanup failed:",N)}},3600000);$m.unref?.();let mw=e.queueWorker??!0,fw=sT(),hw=async(N,Fe)=>{let Me=(N.environmentId?S.store.listEnvironments(N.projectId).find((rt)=>rt.id===N.environmentId):void 0)?.slug??String(T);if(Fe.kind==="dashboard_operation"&&Fe.operationId){let rt=V.get(Me)??B,Rt=cm(Fe.operationId,m,rt);if(!Rt||Rt.danger||!["scheduler","backup","worker"].includes(Rt.group))return{ok:!1,stderr:"The allowlisted dashboard operation is no longer available."};let q=await Mu(m,Me,Rt);return{ok:q.ok,stdout:q.stdout,stderr:q.stderr??q.error,retryable:/temporar|unavailable|timeout|network/i.test(q.stderr??q.error??""),output:{command:q.command??null,operation:q.operation}}}if(Fe.kind==="serverless_scheduler"){let rt=await ym(m,Me,"run");return{ok:rt.ok,stdout:rt.stdout,stderr:rt.error,retryable:/temporar|unavailable|timeout|network/i.test(rt.error??""),output:{command:rt.command??null,operation:"serverless_scheduler"}}}return{ok:!1,stderr:`No safe executor is configured for ${Fe.kind}.`}},Ac=mw?new Gs(qt,{...jc({store:S.store,execute:async(N,Fe)=>{let We=Fe.operation.input&&typeof Fe.operation.input==="object"&&!Array.isArray(Fe.operation.input)?Fe.operation.input:{},Me=We.source&&typeof We.source==="object"?We.source:void 0,rt=t,Rt,q,Ur;try{if(Me?.bindingId&&Me?.connectionId&&Me?.commitSha){let at=Ge.getBinding(String(Me.bindingId)),pt=Ge.getConnection(String(Me.connectionId));if(!at||!pt||at.connectionId!==pt.id)throw Error("Queued source binding is no longer available");let Cr=(at.repositoryId?Ge.getRepository(at.repositoryId):Ge.listRepositories(pt.id).find((Es)=>Es.fullName.toLowerCase()===at.repositoryFullName.toLowerCase()))?.cloneUrl;if(!Cr&&pt.provider==="generic_ssh")Cr=`git@${new URL(pt.host).hostname}:${at.repositoryFullName}.git`;if(!Cr)Cr=new URL(`/${at.repositoryFullName}.git`,pt.host.endsWith("/")?pt.host:`${pt.host}/`).href;let Ce=at.deployKeyId?Ge.getDeployKey(at.deployKeyId):void 0,ar=Ce&&at.deployKeyId?{...Ce,privateKey:Ge.getDeployPrivateKey(at.deployKeyId)}:void 0;if(["github","gitlab","bitbucket","gitea"].includes(pt.provider)&&N.target.previewId){let Es=Ye(pt,Ge.getCredential(pt.id)),me=yr.previews.getInstance(N.target.previewId);Ur=async($n,xc)=>{try{await Es.setCommitStatus(at.repositoryFullName,String(Me.commitSha),{state:$n,url:me?.url,description:xc})}catch(Rs){Fe.log(`Could not publish source status: ${Rs instanceof Error?Rs.message:String(Rs)}`,{stream:"stderr"})}},await Ur("pending",`Preview deployment started for ${String(Me.commitSha).slice(0,12)}`)}Rt=wm(Ut(Vu(),"ts-cloud-queued-source-")),Fe.log(`Checking out immutable source commit ${Me.commitSha}.`,{stream:"system"}),rt=(await Ho({remote:Cr,binding:at,destination:Ut(Rt,"checkout"),ref:String(Me.branch??at.defaultBranch),commitSha:String(Me.commitSha)},{credential:Ge.getCredential(pt.id),deployKey:ar})).directory}if(Fe.operation.kind!=="preview.destroy"){let at=N.target.previewId?yr.previews.getInstance(N.target.previewId):void 0,pt=at?yr.previews.getDefinition(at.definitionId):void 0,$r=Fe.operation.resourceId?S.store.getResource(Fe.operation.resourceId):void 0;if(q=await In.resolve({projectId:S.project.id,environmentId:Fe.operation.environmentId,resourceId:Fe.operation.resourceId,functionId:$r?.kind==="function"?$r.id:void 0,previewId:at?.id,trustedPreview:!!at&&!at.fork,allowedPreviewSecrets:pt?.inheritedSecrets}),q.warnings.some((Cr)=>Cr.code==="missing_required"))throw Error(`Required deployment configuration is unavailable: ${q.warnings.filter((Cr)=>Cr.code==="missing_required").map((Cr)=>Cr.key).join(", ")}`);if(Fe.operation.resourceId)for(let Cr of Object.values(q.entries))Ri.setDependency({entryId:Cr.id,resourceId:Fe.operation.resourceId,injectionTarget:"environment",required:Cr.required,requiresRedeploy:!0});Fe.log(`Resolved configuration ${q.configurationHash.slice(0,18)} for ${Object.keys(q.values).length} keys.`,{stream:"system"})}let br=await Sm(N,{cwd:rt,cliEntry:l,signal:Fe.signal,env:q?.values,onOutput:(at,pt)=>Fe.log(pt,{stream:at,step:"execute",secrets:[...fw,...Object.entries(q?.entries??{}).filter(([,$r])=>$r.kind==="secret").map(([$r])=>q.values[$r]).filter(Boolean)]})});if(br.ok&&Fe.operation.resourceId&&q)for(let at of Object.values(q.entries))Ri.setDependency({entryId:at.id,resourceId:Fe.operation.resourceId,injectionTarget:"environment",required:at.required,requiresRedeploy:!1,lastDeployedVersion:at.version});return await Ur?.(br.ok?"success":"failure",br.ok?`Preview is ready at ${String(Me?.commitSha).slice(0,12)}`:`Preview deployment failed at ${String(Me?.commitSha).slice(0,12)}`),br}catch(br){throw await Ur?.("error",`Preview deployment could not complete at ${String(Me?.commitSha).slice(0,12)}`),br}finally{if(Rt)Ss(Rt,{recursive:!0,force:!0})}}}),...Ml({store:Dr,executor:hw}),...Ul({store:sr,secrets:oi,resolveAdapter:Im}),...Gl(Ja,Zn.drivers),...Vl(wo,[new fa("aws","AWS regional execution requires an injected AwsRegionalTransport; topology and plans were preserved without provider mutation.")]),...Jl({store:ai,cleanup:Cm}),...zc(Ku,Ju),...hu({store:Sr,queue:qt,resolveSource:lw,resolveDestination:uw,validateHealth:async(N,Fe)=>{if(!N.healthCheckId)return{healthy:!0,mode:"adapter"};let We=st.getHealthCheck(N.healthCheckId);if(!We||We.projectId!==N.projectId)return{healthy:!1,error:"Configured restore health check was not found."};let Me=await new Ve(st).runAndEvaluate(We);return{healthy:Me.result.status==="healthy",healthCheckId:We.id,healthResultId:Me.result.id,target:Fe}}}),...fl({store:S.store,resolveDriver:e.releaseDriver??((N)=>({name:`${S.store.getResource(N.resourceId)?.provider??"provider"} release driver`,capability:()=>({strategy:N.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(N,Fe)=>{let We=st.listHealthChecks(Fe.projectId,Fe.environmentId).find((rt)=>rt.enabled&&rt.name===N&&(!rt.resourceId||rt.resourceId===Fe.resourceId));if(!We)return{healthy:!1,message:`Named health gate ${N} was not found for this release.`};let Me=await new Ve(st).runAndEvaluate(We);return{healthy:Me.result.status==="healthy",evidence:{healthCheckId:We.id,healthResultId:Me.result.id,status:Me.result.status,timings:Me.result.timings},message:Me.result.message}}})},{parallelism:e.queueParallelism??(Number(process.env.TS_CLOUD_QUEUE_PARALLELISM)||8),onError:(N)=>console.error("ts-cloud deployment queue worker failed:",N)}):void 0;if(Pl(S),Vi(ut,ne(S,String(T)),B),Dt)Yi(S,Dt.users),nS($e,S,Dt.users);let lr=tS({cwd:t,enabled:De,secret:mt,authentication:$e,authorization:{store:S.store,organizationId:S.organization.id,projectId:S.project.id,defaultEnvironment:String(T)}}),wr=new Jo,Nm=setInterval(()=>wr.sweep(),60000);Nm.unref?.();let Cc=new Sc,Yu=new Sc(3,900000,900000),Pc=new Sc(8,900000,900000),Bm=setInterval(()=>Cc.prune(),300000),Mm=setInterval(()=>Yu.prune(),300000),Lm=setInterval(()=>Pc.prune(),300000);if(Bm.unref?.(),Mm.unref?.(),Lm.unref?.(),De){if(Dt?.generated)console.warn(`
676
+ [output truncated]`}async function tw(e,t,r){let a=e.getReader(),l=new TextDecoder,m="";while(!0){let{done:I,value:R}=await a.read();if(I)break;let S=l.decode(R,{stream:!0});if(m+=S,S)r?.(t,S)}let h=l.decode();if(h)m+=h,r?.(t,h);return m}async function Sm(e,t){let r=Bun.spawn([process.execPath,t.cliEntry,...e.command],{cwd:t.cwd,stdout:"pipe",stderr:"pipe",env:{...process.env,...t.env}}),a=()=>{try{r.kill()}catch{}};if(t.signal?.aborted)a();else t.signal?.addEventListener("abort",a,{once:!0});try{let[l,m,h]=await Promise.all([tw(r.stdout,"stdout",t.onOutput),tw(r.stderr,"stderr",t.onOutput),r.exited]);return{action:e.id,command:["cloud",...e.command].join(" "),exitCode:h,ok:h===0,stdout:ew(l),stderr:ew(m)}}finally{t.signal?.removeEventListener("abort",a)}}function sT(){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 aT=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 cT(e){let t=Ec(e);if(t&&t!==".html")return!1;let r=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(r==="/")return!1;return!aT.has(r)}var dT={"/":"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 rw(e,t){if(t.role==="admin")return!0;let r=Ec(e);if(r&&r!==".html")return!0;if(t.organizationSource==="legacy")return!cT(e);let a=e.replace(/\.html$/,"").replace(/\/+$/,"")||"/";if(a==="/access-denied")return!0;let l=dT[a];return!!l&&!!t.capabilities?.includes(l)}function lT(e,t){let r=decodeURIComponent(t).replace(/^\/+/,""),l=O_(r===""?"index.html":r);if(l.startsWith("..")||l.includes("/../"))return null;let m=Ut(e,l);if(Ii(m)&&!sw(m).isDirectory())return m;if(!Ec(m)&&Ii(`${m}.html`))return`${m}.html`;if(!Ec(m)&&Ii(Ut(m,"index.html")))return Ut(m,"index.html");return null}async function nw(e,t){let r=lT(e,t);if(!r){let m=Ut(e,"404.html");if(Ii(m))return new Response(await ii(m),{status:404,headers:{"content-type":"text/html; charset=utf-8"}});return Wu("Not found",404)}if(sw(r).isDirectory())return Wu("Not found",404);let a=await ii(r),l=U_[Ec(r)]??"application/octet-stream";return new Response(a,{headers:{"content-type":l}})}var qu=["observe","backup","restore","restart","resize","version","rotate","expose","delete","logs","slow_queries","users","databases"],iw=new WeakMap;async function ow(e){let t=iw.get(e);if(t)return t;let r=await import("./spend/index.js"),a=new r.SpendStore(e),l={store:a,service:new r.SpendService(a),gate:new r.SpendGate(e)};return iw.set(e,l),l}async function La(e={}){z_();let t=e.cwd??process.cwd(),r=e.host??M_,a=e.port??L_,l=e.cliEntry??process.argv[1];if(e.box)process.env.TS_CLOUD_DASHBOARD_BOX="1";await Q_(t);let m=e.config??await nl(),h=process.env.TS_CLOUD_DASHBOARD_DB_PASSWORD,I=p(m);if(h&&I&&!I.password)I.password=h;let R=m.infrastructure?.compute?.managedServices?.vitess;if(h&&R&&typeof R==="object"&&!R.password)R.password=h;let S=iu(t,m);if(S.reconciliation.failed>0)console.warn(` ts-cloud dashboard: marked ${S.reconciliation.failed} orphaned operation(s) as failed after restart.`);let C=Object.keys(m.environments??{}),T=J_(m,e.environment),j=Y_(t),B=await bs(m,T),V=new Map([[T,B]]),W=new Map([[T,Date.now()]]),Y=new Map([[T,Date.now()]]),te=new Map,le=Math.min(300000,Math.max(5000,Number(process.env.TS_CLOUD_DASHBOARD_REFRESH_MS)||30000)),X=Math.min(1800000,Math.max(60000,Number(process.env.TS_CLOUD_DASHBOARD_SITE_REFRESH_MS)||300000)),ce=M(m)!=="serverless",Ee=(N)=>{let Fe=V.get(N);if(Fe&&!YS(W.get(N),Date.now(),le))return Promise.resolve(Fe);let We=te.get(N);if(We)return We;let Me=!ce||YS(Y.get(N),Date.now(),X),rt=bs(m,N,{includeSiteHealth:Me}).then((Rt)=>{let q=V.get(N),Ur=Me?Rt:nT(q,Rt);if(V.set(N,Ur),W.set(N,Date.now()),Me)Y.set(N,Date.now());if(q?._serverReachable!==Ur._serverReachable||q?._metricsStatus!==Ur._metricsStatus||(q?.sitesDetail?.length??0)!==(Ur.sitesDetail?.length??0))ot();return Ur}).finally(()=>te.delete(N));return te.set(N,rt),rt},Re=Ot(t),de=process.env.TS_CLOUD_DASHBOARD_TELEMETRY?.trim();if(e.box&&de!=="0"&&(de==="1"||!m.cloud?.attachTo)){let N=!1,Fe=Date.now()+300000,We=async()=>{if(N)return;N=!0;try{let rt=Date.now(),Rt=rt>=Fe;if(Rt)Fe=rt+300000;let q=S.environments.get(T);await vm({controlPlane:S.store,projectId:S.project.id,environmentId:q?.id,config:m,environment:T,force:!0,lightweight:!0,includeSiteHealth:Rt})}catch(rt){if(e.verbose)console.warn(` ts-cloud dashboard: background telemetry collection failed: ${rt instanceof Error?rt.message:String(rt)}`)}finally{N=!1}};We(),setInterval(()=>void We(),60000).unref?.()}let ae=new Map,je=new Map,Qe=new Set,gt=0;function Kt(N,Fe){if(N.role==="admin"&&!S.store.getActorByExternalId("user",`dashboard:${N.username.toLowerCase()}`))return N;let We=S.store.getActorByExternalId("user",`dashboard:${N.username.toLowerCase()}`),Me=We?S.store.getMembershipForActor(S.organization.id,We.id):void 0;if(!Me||Me.status!=="active")return{...N,role:"member",sites:{},capabilities:[]};let rt=S.store.listGrants(Me.id),Rt=S.store.resolveAuthorizationTarget(S.organization.id,Me.scope)??S.store.resolveAuthorizationTarget(S.organization.id,{type:"project",id:S.project.id}),q=$t({membership:Me,grants:rt,target:Rt});if(Me.roleTemplate==="owner"||Me.roleTemplate==="admin")return{...N,role:"admin",sites:{},organizationRole:Me.roleTemplate,organizationSource:Me.source,capabilities:q};let Ur=S.environments.get(Fe),br={};for(let at of S.store.listResources(S.project.id,Ur?.id).filter((pt)=>pt.kind==="application")){let pt=S.store.resolveAuthorizationTarget(S.organization.id,{type:"resource",id:at.id});if(!pt||!D({membership:Me,grants:rt,capability:"project:read",target:pt}).allowed)continue;br[at.slug]=D({membership:Me,grants:rt,capability:"config:write",target:pt}).allowed?"owner":"collaborator"}return{...N,role:"member",sites:br,organizationRole:Me.roleTemplate,organizationSource:Me.source,capabilities:q}}function ot(){gt+=1,ae.clear();for(let N of Qe)Ss(N,{recursive:!0,force:!0});Qe.clear()}let Pt=(N,Fe)=>`${Fe}:${N.role==="admin"?"admin":`member:${Object.entries(N.sites).sort(([We],[Me])=>We.localeCompare(Me)).map(([We,Me])=>`${We}=${Me}`).join(",")}`}:${[...N.capabilities??[]].sort().join(",")}`;async function ir(N,Fe){let We=Kt(N,Fe),Me=Pt(We,Fe),rt=ae.get(Me);if(rt)return rt;let Rt=je.get(Me);if(Rt)return Rt;let q=gt,Ur=(async()=>{let br=V.get(Fe)??await bs(m,Fe);V.set(Fe,br);let at={...dm(br,{user:We,slug:m.project.slug}),viewer:{role:We.role,organizationRole:We.organizationRole,organizationSource:We.organizationSource,capabilities:We.capabilities??[]}},pt=await oT(t,at);if(pt&&q!==gt)return Ss(pt,{recursive:!0,force:!0}),Re?.uiRoot;if(pt)Qe.add(pt);let $r=pt??Re?.uiRoot;if($r)ae.set(Me,$r);return $r})();je.set(Me,Ur);try{return await Ur}finally{je.delete(Me)}}let lt=await ir({username:"",passwordHash:"",role:"admin",sites:{}},T);if(!lt)throw Error("ts-cloud dashboard UI not found. Run `bun run build` in ts-cloud or reinstall the package.");let G=new WeakMap,ue=process.env.TS_CLOUD_DASHBOARD_TERMINAL!=="0",be=process.env.TS_CLOUD_DASHBOARD_AUTH==="0";if(be&&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 De=!be,mt=Qb(t),Dt=De?eS(t,process.env.TS_CLOUD_UI_USERNAME?.trim()||"admin"):void 0,$e=new Fi(S.store,{encryptionKey:Xe(t)}),wt=new Ui(S.store),ut=new Zr(S.store),Ge=new Uo(S.store,{encryptionKey:Xe(t)}),zr=new dp(S.store),ws=new gp(S.store,{cwd:t}),Yn=new up(S.store,{encryptionKey:Xe(t)}),qt=new c(S.store,{workerId:`dashboard:${process.pid}`}),sr=new ea(S.store),oi=new da(S.store,Xe(t)),Ri=new ka(S.store),Rc=new Ki(sr,qt,oi),Pi=m.project?.region??"us-east-1",km=Xe(t),In=new Oa(Ri,{encryptionKey:km,backends:[new pn(S.store,km),new Ba(new z(Pi),Pi),new _a(new we(Pi),Pi),new xa]});await Su(In,S,m);let Hu=new K(Pi),cw={aws_rds:new ta(new oa(Hu)),aws_aurora:new ra(new aa(Hu)),aws_elasticache:new na(new ca(new nt(Pi))),server:new ia(new Zt),container:new sa(new Zt)},Im=(N)=>cw[N.provider],Sr=new ba(S.store),bo=new ts(Sr,qt),Em=new va(oi),dw={managed_database:new Ta(sr,Hu),logical_database:new Ra(sr,oi),volume:new Da,files:new wa(t),control_plane:new Pa(S.store,t),infrastructure:new Na(new nr(Pi))},lw=(N)=>dw[N.resourceKind],uw=(N)=>N.provider==="aws_backup"?void 0:Em,Ku=new Mt(S.store),Ju=[new _r,new js(d(t,"volumes"))],si=new Vs(Ku,Ju,qt),Ja=new la(S.store),Zn=new ua(Ja,[new sn("aws"),new sn("hetzner"),new sn("ssh")],qt),_i=new pa(S.store),Rm=new ga(_i,Ja),wo=new ma(S.store),Am=new ha(wo,qt),ai=new Aa(S.store),Gu=new ya(ai,qt),Cm=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((N)=>new Ia(N,S.store,S.project.id,S.organization.id)),Dr=new Xo(S.store),Pm=new Zo(Dr,{queue:qt}),yr=new Br(S.store),xi=new xr(S.store),Dn=new yt(S.store),st=new Ci(S.store,{encryptionKey:Xe(t)}),pw=()=>ow(S.store);for(let N of S.environments.values())Yo(Dr,m,{organization:S.organization,project:S.project,environment:N,resources:S.store.listResources(S.project.id,N.id)});let On=new Ei(st,{emailImpl:async(N)=>{let{email:Fe}=await import("./chunk-mqscxx2z.js");return Fe.send(N)}}),_m=async(N)=>{let Fe=so(st,S.project.id,N),We=[];for(let Me of Fe.filter((rt)=>rt.notify&&rt.alert))We.push(...await On.deliverAll(On.enqueue(S.organization.id,Me.alert,Me.transition)));return We.push(...await On.deliverAll(On.enqueueRemindersAndEscalations(S.organization.id,st.listAlerts(S.project.id,{environmentId:N,states:["firing"]})))),We.push(...await On.retryDue()),{evaluations:Fe,deliveries:We}},Qu=!1,gw=async()=>{if(Qu)return;Qu=!0;try{for(let N of S.environments.values())for(let Fe of st.listHealthChecks(S.project.id,N.id).filter((We)=>We.enabled)){let We=st.listHealthResults(Fe.id,1)[0];if(We&&Date.now()-new Date(We.checkedAt).getTime()<Fe.intervalSeconds*1000)continue;let Me=await new Ve(st).runAndEvaluate(Fe);for(let rt of Me.evaluations.filter((Rt)=>Rt.notify&&Rt.alert))await On.deliverAll(On.enqueue(S.organization.id,rt.alert,rt.transition))}}finally{Qu=!1}},Tm=setInterval(()=>{for(let N of S.environments.values())_m(N.id).catch((Fe)=>console.error("ts-cloud alert evaluation failed:",Fe))},60000);Tm.unref?.();let xm=setInterval(()=>{gw().catch((N)=>console.error("ts-cloud health check evaluation failed:",N))},30000);xm.unref?.();let Dm=setInterval(()=>{try{Pm.tick()}catch(N){console.error("ts-cloud scheduled job evaluation failed:",N)}},30000);Dm.unref?.();let Om=setInterval(()=>{try{bo.enqueueDue(),bo.enqueueRetention()}catch(N){console.error("ts-cloud backup policy evaluation failed:",N)}},30000);Om.unref?.(),yr.cleanup();let $m=setInterval(()=>{try{yr.cleanup()}catch(N){console.error("ts-cloud preview cleanup failed:",N)}},3600000);$m.unref?.();let mw=e.queueWorker??!0,fw=sT(),hw=async(N,Fe)=>{let Me=(N.environmentId?S.store.listEnvironments(N.projectId).find((rt)=>rt.id===N.environmentId):void 0)?.slug??String(T);if(Fe.kind==="dashboard_operation"&&Fe.operationId){let rt=V.get(Me)??B,Rt=cm(Fe.operationId,m,rt);if(!Rt||Rt.danger||!["scheduler","backup","worker"].includes(Rt.group))return{ok:!1,stderr:"The allowlisted dashboard operation is no longer available."};let q=await Mu(m,Me,Rt);return{ok:q.ok,stdout:q.stdout,stderr:q.stderr??q.error,retryable:/temporar|unavailable|timeout|network/i.test(q.stderr??q.error??""),output:{command:q.command??null,operation:q.operation}}}if(Fe.kind==="serverless_scheduler"){let rt=await ym(m,Me,"run");return{ok:rt.ok,stdout:rt.stdout,stderr:rt.error,retryable:/temporar|unavailable|timeout|network/i.test(rt.error??""),output:{command:rt.command??null,operation:"serverless_scheduler"}}}return{ok:!1,stderr:`No safe executor is configured for ${Fe.kind}.`}},Ac=mw?new Gs(qt,{...jc({store:S.store,execute:async(N,Fe)=>{let We=Fe.operation.input&&typeof Fe.operation.input==="object"&&!Array.isArray(Fe.operation.input)?Fe.operation.input:{},Me=We.source&&typeof We.source==="object"?We.source:void 0,rt=t,Rt,q,Ur;try{if(Me?.bindingId&&Me?.connectionId&&Me?.commitSha){let at=Ge.getBinding(String(Me.bindingId)),pt=Ge.getConnection(String(Me.connectionId));if(!at||!pt||at.connectionId!==pt.id)throw Error("Queued source binding is no longer available");let Cr=(at.repositoryId?Ge.getRepository(at.repositoryId):Ge.listRepositories(pt.id).find((Es)=>Es.fullName.toLowerCase()===at.repositoryFullName.toLowerCase()))?.cloneUrl;if(!Cr&&pt.provider==="generic_ssh")Cr=`git@${new URL(pt.host).hostname}:${at.repositoryFullName}.git`;if(!Cr)Cr=new URL(`/${at.repositoryFullName}.git`,pt.host.endsWith("/")?pt.host:`${pt.host}/`).href;let Ce=at.deployKeyId?Ge.getDeployKey(at.deployKeyId):void 0,ar=Ce&&at.deployKeyId?{...Ce,privateKey:Ge.getDeployPrivateKey(at.deployKeyId)}:void 0;if(["github","gitlab","bitbucket","gitea"].includes(pt.provider)&&N.target.previewId){let Es=Ye(pt,Ge.getCredential(pt.id)),me=yr.previews.getInstance(N.target.previewId);Ur=async($n,xc)=>{try{await Es.setCommitStatus(at.repositoryFullName,String(Me.commitSha),{state:$n,url:me?.url,description:xc})}catch(Rs){Fe.log(`Could not publish source status: ${Rs instanceof Error?Rs.message:String(Rs)}`,{stream:"stderr"})}},await Ur("pending",`Preview deployment started for ${String(Me.commitSha).slice(0,12)}`)}Rt=wm(Ut(Vu(),"ts-cloud-queued-source-")),Fe.log(`Checking out immutable source commit ${Me.commitSha}.`,{stream:"system"}),rt=(await Ho({remote:Cr,binding:at,destination:Ut(Rt,"checkout"),ref:String(Me.branch??at.defaultBranch),commitSha:String(Me.commitSha)},{credential:Ge.getCredential(pt.id),deployKey:ar})).directory}if(Fe.operation.kind!=="preview.destroy"){let at=N.target.previewId?yr.previews.getInstance(N.target.previewId):void 0,pt=at?yr.previews.getDefinition(at.definitionId):void 0,$r=Fe.operation.resourceId?S.store.getResource(Fe.operation.resourceId):void 0;if(q=await In.resolve({projectId:S.project.id,environmentId:Fe.operation.environmentId,resourceId:Fe.operation.resourceId,functionId:$r?.kind==="function"?$r.id:void 0,previewId:at?.id,trustedPreview:!!at&&!at.fork,allowedPreviewSecrets:pt?.inheritedSecrets}),q.warnings.some((Cr)=>Cr.code==="missing_required"))throw Error(`Required deployment configuration is unavailable: ${q.warnings.filter((Cr)=>Cr.code==="missing_required").map((Cr)=>Cr.key).join(", ")}`);if(Fe.operation.resourceId)for(let Cr of Object.values(q.entries))Ri.setDependency({entryId:Cr.id,resourceId:Fe.operation.resourceId,injectionTarget:"environment",required:Cr.required,requiresRedeploy:!0});Fe.log(`Resolved configuration ${q.configurationHash.slice(0,18)} for ${Object.keys(q.values).length} keys.`,{stream:"system"})}let br=await Sm(N,{cwd:rt,cliEntry:l,signal:Fe.signal,env:q?.values,onOutput:(at,pt)=>Fe.log(pt,{stream:at,step:"execute",secrets:[...fw,...Object.entries(q?.entries??{}).filter(([,$r])=>$r.kind==="secret").map(([$r])=>q.values[$r]).filter(Boolean)]})});if(br.ok&&Fe.operation.resourceId&&q)for(let at of Object.values(q.entries))Ri.setDependency({entryId:at.id,resourceId:Fe.operation.resourceId,injectionTarget:"environment",required:at.required,requiresRedeploy:!1,lastDeployedVersion:at.version});return await Ur?.(br.ok?"success":"failure",br.ok?`Preview is ready at ${String(Me?.commitSha).slice(0,12)}`:`Preview deployment failed at ${String(Me?.commitSha).slice(0,12)}`),br}catch(br){throw await Ur?.("error",`Preview deployment could not complete at ${String(Me?.commitSha).slice(0,12)}`),br}finally{if(Rt)Ss(Rt,{recursive:!0,force:!0})}}}),...Ml({store:Dr,executor:hw}),...Ul({store:sr,secrets:oi,resolveAdapter:Im}),...Gl(Ja,Zn.drivers),...Vl(wo,[new fa("aws","AWS regional execution requires an injected AwsRegionalTransport; topology and plans were preserved without provider mutation.")]),...Jl({store:ai,cleanup:Cm}),...zc(Ku,Ju),...hu({store:Sr,queue:qt,resolveSource:lw,resolveDestination:uw,validateHealth:async(N,Fe)=>{if(!N.healthCheckId)return{healthy:!0,mode:"adapter"};let We=st.getHealthCheck(N.healthCheckId);if(!We||We.projectId!==N.projectId)return{healthy:!1,error:"Configured restore health check was not found."};let Me=await new Ve(st).runAndEvaluate(We);return{healthy:Me.result.status==="healthy",healthCheckId:We.id,healthResultId:Me.result.id,target:Fe}}}),...fl({store:S.store,resolveDriver:e.releaseDriver??((N)=>({name:`${S.store.getResource(N.resourceId)?.provider??"provider"} release driver`,capability:()=>({strategy:N.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(N,Fe)=>{let We=st.listHealthChecks(Fe.projectId,Fe.environmentId).find((rt)=>rt.enabled&&rt.name===N&&(!rt.resourceId||rt.resourceId===Fe.resourceId));if(!We)return{healthy:!1,message:`Named health gate ${N} was not found for this release.`};let Me=await new Ve(st).runAndEvaluate(We);return{healthy:Me.result.status==="healthy",evidence:{healthCheckId:We.id,healthResultId:Me.result.id,status:Me.result.status,timings:Me.result.timings},message:Me.result.message}}})},{parallelism:e.queueParallelism??(Number(process.env.TS_CLOUD_QUEUE_PARALLELISM)||8),onError:(N)=>console.error("ts-cloud deployment queue worker failed:",N)}):void 0;if(Pl(S),Vi(ut,ne(S,String(T)),B),Dt)Yi(S,Dt.users),nS($e,S,Dt.users);let lr=tS({cwd:t,enabled:De,secret:mt,authentication:$e,authorization:{store:S.store,organizationId:S.organization.id,projectId:S.project.id,defaultEnvironment:String(T)}}),wr=new Jo,Nm=setInterval(()=>wr.sweep(),60000);Nm.unref?.();let Cc=new Sc,Yu=new Sc(3,900000,900000),Pc=new Sc(8,900000,900000),Bm=setInterval(()=>Cc.prune(),300000),Mm=setInterval(()=>Yu.prune(),300000),Lm=setInterval(()=>Pc.prune(),300000);if(Bm.unref?.(),Mm.unref?.(),Lm.unref?.(),De){if(Dt?.generated)console.warn(`
677
677
  ts-cloud dashboard: created the first admin.
678
678
  username: ${Dt.generated.username}
679
679
  password: ${Dt.generated.password}