@stacksjs/ts-cloud 0.16.36 → 0.16.37
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.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-c8439azc.js → chunk-017cjgwt.js} +2 -2
- package/dist/bin/{chunk-kcsjaam6.js → chunk-0ffqbgbs.js} +3 -3
- package/dist/bin/{chunk-4f5hhqh9.js → chunk-1fjhc7w7.js} +4 -4
- package/dist/bin/{chunk-2ax1rm70.js → chunk-2bkxxset.js} +2 -2
- package/dist/bin/chunk-2gygs4xw.js +1 -0
- package/dist/bin/chunk-3gc8y0ta.js +1 -0
- package/dist/bin/{chunk-twmeg17s.js → chunk-4zxwtvvf.js} +1 -1
- package/dist/bin/{chunk-cnwncp50.js → chunk-5keq8y15.js} +4 -4
- package/dist/bin/{chunk-8p2v1gat.js → chunk-6dm7x6g2.js} +12 -12
- package/dist/bin/{chunk-71jh460j.js → chunk-6r35j09y.js} +2 -2
- package/dist/bin/{chunk-vkdw6sxn.js → chunk-6sdffc79.js} +1 -1
- package/dist/bin/{chunk-exc2mqcc.js → chunk-71z22p71.js} +7 -7
- package/dist/bin/{chunk-9n3wmdd6.js → chunk-7xj986z7.js} +2 -2
- package/dist/bin/{chunk-bfzdbe4g.js → chunk-8gay06gq.js} +6 -6
- package/dist/bin/chunk-cdzas02w.js +1 -0
- package/dist/bin/{chunk-0870bs4x.js → chunk-dvyd4bxh.js} +12 -12
- package/dist/bin/chunk-excjyrfx.js +1 -0
- package/dist/bin/chunk-fawjv4dc.js +1 -0
- package/dist/bin/{chunk-v3prk467.js → chunk-fxyr2wkt.js} +3 -3
- package/dist/bin/{chunk-r8e263ne.js → chunk-gd94501z.js} +5 -5
- package/dist/bin/chunk-gewxhd5z.js +1 -0
- package/dist/bin/chunk-gjadvs6y.js +1 -0
- package/dist/bin/{chunk-qbagghsb.js → chunk-hsek7hvh.js} +93 -116
- package/dist/bin/{chunk-svrgx20b.js → chunk-kj4gm2hk.js} +3 -3
- package/dist/bin/chunk-n84pv5ns.js +1 -0
- package/dist/bin/{chunk-5yv95sqs.js → chunk-na2j5twe.js} +1 -1
- package/dist/bin/{chunk-h42xsxhm.js → chunk-nhz2az7v.js} +2 -2
- package/dist/bin/chunk-r263q1aa.js +1 -0
- package/dist/bin/chunk-rbjj0bcn.js +1 -0
- package/dist/bin/chunk-sp78dh4p.js +1 -0
- package/dist/bin/chunk-t844fst8.js +1 -0
- package/dist/bin/chunk-tkz95bkg.js +1 -0
- package/dist/bin/{chunk-bpw8m7rw.js → chunk-vg9et0kb.js} +2 -2
- package/dist/bin/{chunk-ar6bxdv4.js → chunk-w663zt0w.js} +3 -3
- package/dist/bin/chunk-xpzkwgb4.js +1 -0
- package/dist/bin/chunk-zswkrc34.js +1 -0
- package/dist/bin/cli.js +29 -29
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-mhv7dbr1.js → chunk-0fhz75e0.js} +3 -3
- package/dist/{chunk-tez0qfv9.js → chunk-1kfagk30.js} +1 -1
- package/dist/chunk-1mrqpf8e.js +1 -0
- package/dist/chunk-2bbm2q0s.js +1 -0
- package/dist/{chunk-kcj92xx7.js → chunk-2bvmp0br.js} +2 -2
- package/dist/{chunk-n4z75mk8.js → chunk-3bsf7585.js} +1 -1
- package/dist/chunk-46jnzd0d.js +1 -0
- package/dist/{chunk-7gvnrx46.js → chunk-5np6w0g7.js} +2 -2
- package/dist/{chunk-pdjap529.js → chunk-78r4k21k.js} +1 -1
- package/dist/{chunk-0kddm2mt.js → chunk-98xzqtnw.js} +1 -1
- package/dist/{chunk-k3mazfb2.js → chunk-a74kqzne.js} +12 -12
- package/dist/{chunk-hvwqct5q.js → chunk-aqxp4s43.js} +1 -1
- package/dist/{chunk-ajn6xp8v.js → chunk-azt6sm0r.js} +1 -1
- package/dist/{chunk-q9rdxpmg.js → chunk-fsdd2cj8.js} +2 -2
- package/dist/chunk-j5v7fgxz.js +1 -0
- package/dist/chunk-jfqm2c9q.js +1 -0
- package/dist/{chunk-mxw5gkd8.js → chunk-k92sywmh.js} +1 -1
- package/dist/{chunk-2x636sgn.js → chunk-mbs6pr03.js} +6 -6
- package/dist/{chunk-fszn9rnn.js → chunk-mce0cpgf.js} +10 -10
- package/dist/{chunk-yzns0k2b.js → chunk-n0vz557v.js} +1 -1
- package/dist/{chunk-3nqtbyfp.js → chunk-n3p8vr8s.js} +3 -3
- package/dist/{chunk-p0ksat08.js → chunk-pjhag27y.js} +1 -1
- package/dist/chunk-ppr0bkgd.js +1 -0
- package/dist/{chunk-nr6z3e1p.js → chunk-rkjnr9fp.js} +3 -3
- package/dist/{chunk-ncsb3sdn.js → chunk-svzmsd7g.js} +1 -1
- package/dist/{chunk-ctkzxq0d.js → chunk-t0azf37g.js} +2 -2
- package/dist/{chunk-9aaj9a0s.js → chunk-vmhfc7nk.js} +91 -114
- package/dist/{chunk-78shfb0z.js → chunk-x7pnt65y.js} +55 -55
- package/dist/{chunk-my6yn5sd.js → chunk-ybdxrf42.js} +1 -1
- package/dist/{chunk-sekw1nyx.js → chunk-zg589zg1.js} +10 -10
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/generators/infrastructure.d.ts +7 -0
- package/dist/index.js +17 -17
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +1 -1
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +5 -5
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +5 -5
- package/dist/ui/operations/jobs.html +5 -5
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +5 -5
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +1 -1
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +5 -5
- package/dist/ui/serverless/metrics.html +1 -1
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +5 -5
- package/dist/ui/serverless.html +6 -6
- package/package.json +3 -3
- package/dist/bin/chunk-3gg55dkc.js +0 -1
- package/dist/bin/chunk-691k55nw.js +0 -1
- package/dist/bin/chunk-7n84q4np.js +0 -1
- package/dist/bin/chunk-7s3wtq40.js +0 -1
- package/dist/bin/chunk-8bb6kyhm.js +0 -1
- package/dist/bin/chunk-9pvkb6br.js +0 -1
- package/dist/bin/chunk-e9mkg5dn.js +0 -1
- package/dist/bin/chunk-h5darb19.js +0 -1
- package/dist/bin/chunk-h6n5v6rf.js +0 -1
- package/dist/bin/chunk-hfswzdzj.js +0 -1
- package/dist/bin/chunk-w68hker6.js +0 -1
- package/dist/bin/chunk-x8wvsf1k.js +0 -1
- package/dist/bin/chunk-y1qk3df2.js +0 -1
- package/dist/bin/chunk-y4pfvx0x.js +0 -1
- package/dist/bin/chunk-zjw9sdr5.js +0 -1
- package/dist/chunk-0my5jwq8.js +0 -1
- package/dist/chunk-fxk29btr.js +0 -1
- package/dist/chunk-fz62nas4.js +0 -1
- package/dist/chunk-gyp7jcgw.js +0 -1
- package/dist/chunk-wxtr8sv8.js +0 -1
- package/dist/chunk-yhjagaff.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{re,h}from"./chunk-twmeg17s.js";import{us}from"./chunk-bfzdbe4g.js";var Lp=["edge.requests","edge.egress_gb","function.invocations","function.gb_seconds","build.minutes","compute.instance_hours","storage.gb_hours","object.egress_gb","object.requests","database.gb_hours","database.io_requests","telemetry.ingest_gb","image.transformations"],nn={"edge.requests":{key:"edge.requests",unit:"requests",label:"Edge requests",precision:0},"edge.egress_gb":{key:"edge.egress_gb",unit:"gb",label:"Edge egress",precision:3},"function.invocations":{key:"function.invocations",unit:"invocations",label:"Function invocations",precision:0},"function.gb_seconds":{key:"function.gb_seconds",unit:"gb_seconds",label:"Function compute",precision:2},"build.minutes":{key:"build.minutes",unit:"minutes",label:"Build minutes",precision:2},"compute.instance_hours":{key:"compute.instance_hours",unit:"hours",label:"Instance hours",precision:2},"storage.gb_hours":{key:"storage.gb_hours",unit:"gb_hours",label:"Block storage",precision:2},"object.egress_gb":{key:"object.egress_gb",unit:"gb",label:"Object storage egress",precision:3},"object.requests":{key:"object.requests",unit:"requests",label:"Object storage requests",precision:0},"database.gb_hours":{key:"database.gb_hours",unit:"gb_hours",label:"Database storage",precision:2},"database.io_requests":{key:"database.io_requests",unit:"requests",label:"Database I/O",precision:0},"telemetry.ingest_gb":{key:"telemetry.ingest_gb",unit:"gb",label:"Telemetry ingest",precision:3},"image.transformations":{key:"image.transformations",unit:"count",label:"Image transformations",precision:0}},rs=["notify","block_builds","block_deployments","throttle_requests","suspend_functions","serve_static","suspend_project"],oe={notify:0,block_builds:1,block_deployments:2,throttle_requests:3,suspend_functions:4,serve_static:5,suspend_project:6};var Mp=1e6;function tr(e){if(e.tiers&&e.tiers.length>0)return e.tiers;return[{upToQuantity:null,microCentsPerUnit:e.microCentsPerUnit??0}]}function bc(e,t){if(!(e>0))return 0;let r=[...t].sort((s,a)=>{if(s.upToQuantity===null)return 1;if(a.upToQuantity===null)return-1;return s.upToQuantity-a.upToQuantity}),n=e,o=0,i=0;for(let s of r){if(n<=0)break;let d=(s.upToQuantity===null?1/0:s.upToQuantity)-o;if(d<=0)continue;let c=Math.min(n,d);i+=c*s.microCentsPerUnit,n-=c,o+=c}if(n>0){let s=r.reduce((a,d)=>Math.max(a,d.microCentsPerUnit),0);i+=n*s}return i}function Cd(e,t,r,n){let o=e.entries.filter((a)=>a.meter===t);if(o.length===0)return;let i=o.filter((a)=>a.provider===r),s=i.length>0?i:o.filter((a)=>a.provider==="*");return s.find((a)=>a.region===n)??s.find((a)=>a.region==null)}function po(e,t,r=0){let n=Cd(e,t.meter,t.provider,t.region),o=Math.max(0,t.quantity);if(!n)return{meter:t.meter,provider:t.provider??"unknown",region:t.region,quantity:o,includedQuantity:0,billableQuantity:o,costCents:0,unpriced:!0};let i=Math.max(0,n.includedQuantity??0),s=Math.max(0,r-i),a=Math.max(0,i-Math.max(0,r)),d=Math.min(o,a),c=o-d,u=tr(n),p=bc(s+c,u)-bc(s,u);return{meter:t.meter,provider:n.provider,region:n.region??t.region,quantity:o,includedQuantity:d,billableQuantity:c,costCents:p/1e6,unpriced:!1}}function Up(e,t){let r=new Map,n=[];for(let o of t){let i=`${o.meter}\x00${o.provider??""}\x00${o.region??""}`,s=r.get(i)??0,a=po(e,o,s);r.set(i,s+a.quantity),n.push(a)}return{currency:e.currency,totalCents:n.reduce((o,i)=>o+i.costCents,0),lines:n,unpricedMeters:[...new Set(n.filter((o)=>o.unpriced).map((o)=>String(o.meter)))]}}function Fp(e){return Math.round(e*100)/100}function Bp(e,...t){let r=new Map,n=(i)=>`${i.meter}\x00${i.provider}\x00${i.region??""}`;for(let i of e.entries)r.set(n(i),i);let o=e.currency;for(let i of t){o=i.currency||o;for(let s of i.entries)r.set(n(s),s)}return{currency:o,entries:[...r.values()]}}var V=(e)=>Math.round(e*1e6),N=(e)=>Math.round(e*1e6),Sc={currency:"USD",entries:[{meter:"edge.requests",provider:"aws",microCentsPerUnit:N(0.00075)},{meter:"edge.egress_gb",provider:"aws",includedQuantity:100,tiers:[{upToQuantity:10240,microCentsPerUnit:V(8.5)},{upToQuantity:51200,microCentsPerUnit:V(8)},{upToQuantity:null,microCentsPerUnit:V(6)}]},{meter:"function.invocations",provider:"aws",includedQuantity:1e6,microCentsPerUnit:N(0.002)},{meter:"function.gb_seconds",provider:"aws",includedQuantity:400000,microCentsPerUnit:N(0.00166667)},{meter:"storage.gb_hours",provider:"aws",microCentsPerUnit:N(0.010958904109589041)},{meter:"object.egress_gb",provider:"aws",includedQuantity:100,microCentsPerUnit:V(9)},{meter:"object.requests",provider:"aws",microCentsPerUnit:N(0.000039999999999999996)},{meter:"database.gb_hours",provider:"aws",microCentsPerUnit:N(0.015753424657534248)},{meter:"compute.instance_hours",provider:"aws",microCentsPerUnit:N(4.16)},{meter:"edge.egress_gb",provider:"hetzner",includedQuantity:20480,microCentsPerUnit:V(0.108)},{meter:"object.egress_gb",provider:"hetzner",includedQuantity:1024,microCentsPerUnit:V(0.108)},{meter:"compute.instance_hours",provider:"hetzner",microCentsPerUnit:N(0.95)},{meter:"storage.gb_hours",provider:"hetzner",microCentsPerUnit:N(0.006027397260273972)},{meter:"edge.requests",provider:"hetzner",microCentsPerUnit:0},{meter:"edge.requests",provider:"local",microCentsPerUnit:0},{meter:"edge.egress_gb",provider:"local",microCentsPerUnit:0},{meter:"function.invocations",provider:"local",microCentsPerUnit:0},{meter:"function.gb_seconds",provider:"local",microCentsPerUnit:0},{meter:"build.minutes",provider:"*",includedQuantity:6000,microCentsPerUnit:N(0.8)},{meter:"telemetry.ingest_gb",provider:"*",includedQuantity:5,microCentsPerUnit:V(50)},{meter:"image.transformations",provider:"*",includedQuantity:5000,microCentsPerUnit:N(0.05)}]};var tt=new Map;function rt(e){let t=tt.get(e);if(!t)t=new Intl.DateTimeFormat("en-US",{timeZone:e,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",weekday:"short",hourCycle:"h23"}),tt.set(e,t);return t}var rr={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};function ns(e){try{return rt(e),!0}catch{return!1}}function mo(e,t){let r=rt(t).formatToParts(e),n=(o)=>r.find((i)=>i.type===o)?.value??"0";return{year:Number(n("year")),month:Number(n("month")),day:Number(n("day")),hour:Number(n("hour")),minute:Number(n("minute")),second:Number(n("second")),weekday:rr[n("weekday")]??0}}function vc(e,t){let r=mo(e,t);return Date.UTC(r.year,r.month-1,r.day,r.hour,r.minute,r.second)-Math.floor(e.getTime()/1000)*1000}function sn(e,t,r,n,o=0){let i=Date.UTC(t,r-1,n,o),s=new Date(i-vc(new Date(i),e));return new Date(i-vc(s,e))}function nr(e,t){return new Date(Date.UTC(e,t-1,1)).toLocaleString("en-US",{month:"long",year:"numeric",timeZone:"UTC"})}function br(e,t,r=new Date){let n=ns(t)?t:"UTC",o=mo(r,n),i,s,a;if(e==="daily")i=sn(n,o.year,o.month,o.day),s=sn(n,o.year,o.month,o.day+1),a=`${o.year}-${String(o.month).padStart(2,"0")}-${String(o.day).padStart(2,"0")}`;else if(e==="weekly"){let u=(o.weekday+6)%7;i=sn(n,o.year,o.month,o.day-u),s=sn(n,o.year,o.month,o.day-u+7);let p=mo(i,n);a=`week of ${p.year}-${String(p.month).padStart(2,"0")}-${String(p.day).padStart(2,"0")}`}else i=sn(n,o.year,o.month,1),s=sn(n,o.year,o.month+1,1),a=nr(o.year,o.month);let d=s.getTime()-i.getTime(),c=Math.max(0,Math.min(d,r.getTime()-i.getTime()));return{start:i.toISOString(),end:s.toISOString(),elapsedMs:c,totalMs:d,label:a}}function jp(e,t,r=new Date){let n=br(e,t,r),o=new Date(new Date(n.start).getTime()-1),i=br(e,t,o);return{...i,elapsedMs:i.totalMs}}function gi(e){let r=(typeof e==="string"?new Date(e):e).getTime();if(!Number.isFinite(r))throw Error("hourBucket requires a valid date");return new Date(Math.floor(r/3600000)*3600000).toISOString()}function Vp(e,t,r=9600){let n=Math.floor(new Date(e).getTime()/3600000)*3600000,o=new Date(t).getTime();if(!Number.isFinite(n)||!Number.isFinite(o))throw Error("hourBucketsBetween requires valid dates");let i=[];for(let s=n;s<o&&i.length<r;s+=3600000)i.push(new Date(s).toISOString());return i}import{createHash as or}from"node:crypto";var le=1073741824,Cc=[{match:"request.count",meter:"edge.requests"},{match:"traffic.requests",meter:"edge.requests"},{match:"http.request",meter:"edge.requests",field:"count"},{match:"traffic.bytes_out",meter:"edge.egress_gb",scale:1/le},{match:"storage.egress.day",meter:"object.egress_gb",scale:1/le},{match:"storage.egress.month",meter:"object.egress_gb",scale:1/le,cumulative:!0},{match:"storage.egress.day_downloads",meter:"object.requests"},{match:"function.invocation",meter:"function.invocations",field:"count"},{match:"function.duration_ms",meter:"function.gb_seconds",scale:0.001},{match:"build.duration_ms",meter:"build.minutes",scale:0.000016666666666666667},{match:"telemetry.ingest_bytes",meter:"telemetry.ingest_gb",scale:1/le},{match:"image.transform",meter:"image.transformations",field:"count"}];function ir(e,t){return e.match.endsWith("*")?t.startsWith(e.match.slice(0,-1)):e.match===t}function Td(e,t=Cc){return t.find((r)=>!r.match.endsWith("*")&&r.match===e)??t.find((r)=>ir(r,e))}function sr(e,t){let r=t.field??"value",n=r==="count"?1:r==="bytesOut"?e.bytesOut:r==="bytesIn"?e.bytesIn:r==="durationMs"?e.durationMs:e.value;if(n==null||!Number.isFinite(n))return;return n*(t.scale??1)}function Ed(e,t){return or("sha256").update([t,e.meter,e.organizationId,e.projectId??"",e.environmentId??"",e.resourceId??"",e.timestamp].join("\x00")).digest("hex").slice(0,32)}class go{resetToleranceRatio;last=new Map;constructor(e=0.999){this.resetToleranceRatio=e}delta(e,t,r=new Date){if(!Number.isFinite(t)||t<0)return;let n=new Date(r).getTime(),o=this.last.get(e);if(!o)return this.last.set(e,{value:t,at:n}),t>0?t:void 0;if(n<o.at)return;if(t<o.value&&t>=o.value*this.resetToleranceRatio)return;if(this.last.set(e,{value:t,at:n}),t>=o.value){let i=t-o.value;return i>0?i:void 0}return t>0?t:void 0}prune(e){let t=e.getTime(),r=0;for(let[n,o]of this.last)if(o.at<t)this.last.delete(n),r++;return r}get size(){return this.last.size}}function nt(e,t){let r=e[t];return typeof r==="string"&&r.length>0?r:void 0}function Tc(e,t,r={}){let n=r.mappings??Cc,o=r.counters,i=[];for(let s of t){let a=Td(s.name,n);if(!a)continue;let d=sr(s,a);if(d==null)continue;if(a.cumulative){if(!o)continue;let u=[s.projectId,s.environmentId??"",s.resourceId??"",s.name,s.source].join("\x00"),p=o.delta(u,d,s.timestamp);if(p==null)continue;d=p}if(!(d>0))continue;let c={organizationId:e,projectId:s.projectId,environmentId:s.environmentId,resourceId:s.resourceId,provider:nt(s.attributes,"provider")??r.defaultProvider,region:s.region??nt(s.attributes,"region"),meter:a.meter,quantity:d,timestamp:s.timestamp,attributes:{source:s.source,signal:s.name}};i.push({...c,key:Ed(c,s.id)})}return i}function Ec(e){let t=new Map;for(let r of e){let n=new Date(Math.floor(new Date(r.timestamp).getTime()/3600000)*3600000).toISOString(),o=[r.organizationId,r.projectId??"",r.environmentId??"",r.resourceId??"",r.provider??"",r.region??"",r.meter,n].join("\x00"),i=t.get(o);if(i)i.quantity+=r.quantity;else t.set(o,{...r,timestamp:n})}return[...t.values()]}import{createHash as ar}from"node:crypto";var K=(e)=>{if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}},j=(e)=>typeof e==="string"&&e!==""?e:void 0,ue=(e)=>Number(e)===1,ot=(e)=>e==null?void 0:Number(e);function it(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),name:String(e.name),period:String(e.period),timezone:String(e.timezone),currency:String(e.currency),softLimitCents:ot(e.soft_limit_cents),hardLimitCents:ot(e.hard_limit_cents),thresholds:K(e.thresholds),meters:K(e.meters),graceSeconds:Number(e.grace_seconds),hysteresisPercent:Number(e.hysteresis_percent),dryRun:ue(e.dry_run),enabled:ue(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Ae(e){return{id:String(e.id),budgetId:String(e.budget_id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),action:String(e.action),state:String(e.state),reason:String(e.reason),restore:K(e.restore),triggeredAtPercent:Number(e.triggered_at_percent),simulated:ue(e.simulated),appliedAt:j(e.applied_at),releasedAt:j(e.released_at),error:j(e.error),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function st(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),signal:String(e.signal),direction:String(e.direction),observed:Number(e.observed),expected:Number(e.expected),score:Number(e.score),deltaPercent:Number(e.delta_percent),severity:String(e.severity),bucketStart:String(e.bucket_start),evidence:K(e.evidence),acknowledgedAt:j(e.acknowledged_at),createdAt:String(e.created_at)}}function dr(e){return{organizationId:String(e.organization_id),projectId:String(e.project_id),environmentId:String(e.environment_id),resourceId:String(e.resource_id),provider:String(e.provider),region:String(e.region),meter:String(e.meter),bucketStart:String(e.bucket_start),quantity:Number(e.quantity),costCents:Number(e.cost_cents),sampleCount:Number(e.sample_count),updatedAt:String(e.updated_at)}}function Sr(e,t,r){return[e,t??"",r??""].join("/")}var is=[{atPercent:50,actions:["notify"]},{atPercent:80,actions:["notify"]},{atPercent:100,actions:["notify"],onProjection:!0},{atPercent:100,actions:["notify","block_builds","block_deployments"]},{atPercent:115,actions:["notify","block_builds","block_deployments","throttle_requests"]}];class vr{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}now(){return(this.options.now?.()??new Date).toISOString()}get priceBook(){return this.options.priceBook??Sc}query(e,t=[]){return this.controlPlane.database.query(e).all(...t)}createBudget(e){let t=e.name.trim();if(!t)throw Error("Budgets require a name.");if(e.softLimitCents==null&&e.hardLimitCents==null)throw Error("A budget needs a soft limit, a hard limit, or both.");if(e.softLimitCents!=null&&e.hardLimitCents!=null&&e.softLimitCents>e.hardLimitCents)throw Error("The soft limit must not exceed the hard limit.");let r=e.timezone??"UTC";if(!ns(r))throw Error(`Unknown timezone: ${r}`);let n=(e.thresholds??[...is]).filter((s)=>Number.isFinite(s.atPercent)&&s.atPercent>=0);if(e.environmentId&&!e.projectId)throw Error("An environment-scoped budget must also name its project.");let o=crypto.randomUUID(),i=this.now();return this.controlPlane.database.run("INSERT INTO spend_budgets (id,organization_id,project_id,environment_id,name,period,timezone,currency,soft_limit_cents,hard_limit_cents,thresholds,meters,grace_seconds,hysteresis_percent,dry_run,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,?,?)",[o,e.organizationId,e.projectId??null,e.environmentId??null,t,e.period,r,e.currency??"USD",e.softLimitCents??null,e.hardLimitCents??null,JSON.stringify(n),JSON.stringify(e.meters??[]),Math.max(0,Math.floor(e.graceSeconds??0)),Math.max(0,e.hysteresisPercent??5),e.dryRun?1:0,e.enabled===!1?0:1,i,i]),this.getBudget(o)}getBudget(e){let t=this.query("SELECT * FROM spend_budgets WHERE id = ?",[e])[0];return t?it(t):void 0}listBudgets(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);if(e.enabledOnly)t.push("enabled = 1");return this.query(`SELECT * FROM spend_budgets WHERE ${t.join(" AND ")} ORDER BY created_at`,r).map(it)}budgetsForScope(e,t,r){return this.listBudgets({organizationId:e,enabledOnly:!0}).filter((n)=>{if(n.projectId&&n.projectId!==t)return!1;if(n.environmentId&&n.environmentId!==r)return!1;return!0}).sort((n,o)=>Number(!!n.projectId)-Number(!!o.projectId)||Number(!!n.environmentId)-Number(!!o.environmentId))}updateBudget(e,t,r){let n=this.getBudget(e);if(!n)throw Error("Budget was not found.");if(r!=null&&r!==n.version)throw Error(`Budget was modified concurrently (expected version ${r}, found ${n.version}).`);let o={...n,...t};if(o.softLimitCents==null&&o.hardLimitCents==null)throw Error("A budget needs a soft limit, a hard limit, or both.");if(o.softLimitCents!=null&&o.hardLimitCents!=null&&o.softLimitCents>o.hardLimitCents)throw Error("The soft limit must not exceed the hard limit.");if(t.timezone&&!ns(t.timezone))throw Error(`Unknown timezone: ${t.timezone}`);return this.controlPlane.database.run("UPDATE spend_budgets SET name=?,period=?,timezone=?,currency=?,soft_limit_cents=?,hard_limit_cents=?,thresholds=?,meters=?,grace_seconds=?,hysteresis_percent=?,dry_run=?,enabled=?,version=version+1,updated_at=? WHERE id=?",[o.name,o.period,o.timezone,o.currency??"USD",o.softLimitCents??null,o.hardLimitCents??null,JSON.stringify(o.thresholds??[]),JSON.stringify(o.meters??[]),Math.max(0,Math.floor(o.graceSeconds??0)),Math.max(0,o.hysteresisPercent??5),o.dryRun?1:0,o.enabled===!1?0:1,this.now(),e]),this.getBudget(e)}deleteBudget(e){return this.controlPlane.database.run("DELETE FROM spend_budgets WHERE id = ?",[e]).changes>0}ingestUsage(e){let t={applied:0,duplicates:0,costCents:0,unpricedMeters:[]},r=new Set,n=this.now();return this.controlPlane.database.transaction((i)=>{for(let s of i){if(!(s.quantity>0)||!Number.isFinite(s.quantity))continue;let a=s.key??this.deltaFallbackKey(s);if(this.controlPlane.database.run("INSERT OR IGNORE INTO spend_usage_receipts (key,organization_id,bucket_start,created_at) VALUES (?,?,?,?)",[a,s.organizationId,gi(s.timestamp),n]).changes===0){t.duplicates++;continue}let c={projectId:s.projectId??"",environmentId:s.environmentId??"",resourceId:s.resourceId??"",provider:s.provider??"",region:s.region??""},u=this.periodQuantity(s),p=po(this.priceBook,{meter:s.meter,quantity:s.quantity,provider:s.provider,region:s.region},u);if(p.unpriced)r.add(String(s.meter));this.controlPlane.database.run(`INSERT INTO spend_usage (organization_id,project_id,environment_id,resource_id,provider,region,meter,bucket_start,quantity,cost_cents,sample_count,updated_at)
|
|
1
|
+
import{re,h}from"./chunk-4zxwtvvf.js";import{us}from"./chunk-8gay06gq.js";var Fp=["edge.requests","edge.egress_gb","function.invocations","function.gb_seconds","build.minutes","compute.instance_hours","storage.gb_hours","object.egress_gb","object.requests","database.gb_hours","database.io_requests","telemetry.ingest_gb","image.transformations"],nn={"edge.requests":{key:"edge.requests",unit:"requests",label:"Edge requests",precision:0},"edge.egress_gb":{key:"edge.egress_gb",unit:"gb",label:"Edge egress",precision:3},"function.invocations":{key:"function.invocations",unit:"invocations",label:"Function invocations",precision:0},"function.gb_seconds":{key:"function.gb_seconds",unit:"gb_seconds",label:"Function compute",precision:2},"build.minutes":{key:"build.minutes",unit:"minutes",label:"Build minutes",precision:2},"compute.instance_hours":{key:"compute.instance_hours",unit:"hours",label:"Instance hours",precision:2},"storage.gb_hours":{key:"storage.gb_hours",unit:"gb_hours",label:"Block storage",precision:2},"object.egress_gb":{key:"object.egress_gb",unit:"gb",label:"Object storage egress",precision:3},"object.requests":{key:"object.requests",unit:"requests",label:"Object storage requests",precision:0},"database.gb_hours":{key:"database.gb_hours",unit:"gb_hours",label:"Database storage",precision:2},"database.io_requests":{key:"database.io_requests",unit:"requests",label:"Database I/O",precision:0},"telemetry.ingest_gb":{key:"telemetry.ingest_gb",unit:"gb",label:"Telemetry ingest",precision:3},"image.transformations":{key:"image.transformations",unit:"count",label:"Image transformations",precision:0}},rs=["notify","block_builds","block_deployments","throttle_requests","suspend_functions","serve_static","suspend_project"],oe={notify:0,block_builds:1,block_deployments:2,throttle_requests:3,suspend_functions:4,serve_static:5,suspend_project:6};var Bp=1e6;function tr(e){if(e.tiers&&e.tiers.length>0)return e.tiers;return[{upToQuantity:null,microCentsPerUnit:e.microCentsPerUnit??0}]}function bc(e,t){if(!(e>0))return 0;let r=[...t].sort((s,a)=>{if(s.upToQuantity===null)return 1;if(a.upToQuantity===null)return-1;return s.upToQuantity-a.upToQuantity}),n=e,o=0,i=0;for(let s of r){if(n<=0)break;let d=(s.upToQuantity===null?1/0:s.upToQuantity)-o;if(d<=0)continue;let c=Math.min(n,d);i+=c*s.microCentsPerUnit,n-=c,o+=c}if(n>0){let s=r.reduce((a,d)=>Math.max(a,d.microCentsPerUnit),0);i+=n*s}return i}function Td(e,t,r,n){let o=e.entries.filter((a)=>a.meter===t);if(o.length===0)return;let i=o.filter((a)=>a.provider===r),s=i.length>0?i:o.filter((a)=>a.provider==="*");return s.find((a)=>a.region===n)??s.find((a)=>a.region==null)}function po(e,t,r=0){let n=Td(e,t.meter,t.provider,t.region),o=Math.max(0,t.quantity);if(!n)return{meter:t.meter,provider:t.provider??"unknown",region:t.region,quantity:o,includedQuantity:0,billableQuantity:o,costCents:0,unpriced:!0};let i=Math.max(0,n.includedQuantity??0),s=Math.max(0,r-i),a=Math.max(0,i-Math.max(0,r)),d=Math.min(o,a),c=o-d,u=tr(n),p=bc(s+c,u)-bc(s,u);return{meter:t.meter,provider:n.provider,region:n.region??t.region,quantity:o,includedQuantity:d,billableQuantity:c,costCents:p/1e6,unpriced:!1}}function jp(e,t){let r=new Map,n=[];for(let o of t){let i=`${o.meter}\x00${o.provider??""}\x00${o.region??""}`,s=r.get(i)??0,a=po(e,o,s);r.set(i,s+a.quantity),n.push(a)}return{currency:e.currency,totalCents:n.reduce((o,i)=>o+i.costCents,0),lines:n,unpricedMeters:[...new Set(n.filter((o)=>o.unpriced).map((o)=>String(o.meter)))]}}function Vp(e){return Math.round(e*100)/100}function zp(e,...t){let r=new Map,n=(i)=>`${i.meter}\x00${i.provider}\x00${i.region??""}`;for(let i of e.entries)r.set(n(i),i);let o=e.currency;for(let i of t){o=i.currency||o;for(let s of i.entries)r.set(n(s),s)}return{currency:o,entries:[...r.values()]}}var V=(e)=>Math.round(e*1e6),N=(e)=>Math.round(e*1e6),Sc={currency:"USD",entries:[{meter:"edge.requests",provider:"aws",microCentsPerUnit:N(0.00075)},{meter:"edge.egress_gb",provider:"aws",includedQuantity:100,tiers:[{upToQuantity:10240,microCentsPerUnit:V(8.5)},{upToQuantity:51200,microCentsPerUnit:V(8)},{upToQuantity:null,microCentsPerUnit:V(6)}]},{meter:"function.invocations",provider:"aws",includedQuantity:1e6,microCentsPerUnit:N(0.002)},{meter:"function.gb_seconds",provider:"aws",includedQuantity:400000,microCentsPerUnit:N(0.00166667)},{meter:"storage.gb_hours",provider:"aws",microCentsPerUnit:N(0.010958904109589041)},{meter:"object.egress_gb",provider:"aws",includedQuantity:100,microCentsPerUnit:V(9)},{meter:"object.requests",provider:"aws",microCentsPerUnit:N(0.000039999999999999996)},{meter:"database.gb_hours",provider:"aws",microCentsPerUnit:N(0.015753424657534248)},{meter:"compute.instance_hours",provider:"aws",microCentsPerUnit:N(4.16)},{meter:"edge.egress_gb",provider:"hetzner",includedQuantity:20480,microCentsPerUnit:V(0.108)},{meter:"object.egress_gb",provider:"hetzner",includedQuantity:1024,microCentsPerUnit:V(0.108)},{meter:"compute.instance_hours",provider:"hetzner",microCentsPerUnit:N(0.95)},{meter:"storage.gb_hours",provider:"hetzner",microCentsPerUnit:N(0.006027397260273972)},{meter:"edge.requests",provider:"hetzner",microCentsPerUnit:0},{meter:"edge.requests",provider:"local",microCentsPerUnit:0},{meter:"edge.egress_gb",provider:"local",microCentsPerUnit:0},{meter:"function.invocations",provider:"local",microCentsPerUnit:0},{meter:"function.gb_seconds",provider:"local",microCentsPerUnit:0},{meter:"build.minutes",provider:"*",includedQuantity:6000,microCentsPerUnit:N(0.8)},{meter:"telemetry.ingest_gb",provider:"*",includedQuantity:5,microCentsPerUnit:V(50)},{meter:"image.transformations",provider:"*",includedQuantity:5000,microCentsPerUnit:N(0.05)}]};var tt=new Map;function rt(e){let t=tt.get(e);if(!t)t=new Intl.DateTimeFormat("en-US",{timeZone:e,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",weekday:"short",hourCycle:"h23"}),tt.set(e,t);return t}var rr={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};function ns(e){try{return rt(e),!0}catch{return!1}}function mo(e,t){let r=rt(t).formatToParts(e),n=(o)=>r.find((i)=>i.type===o)?.value??"0";return{year:Number(n("year")),month:Number(n("month")),day:Number(n("day")),hour:Number(n("hour")),minute:Number(n("minute")),second:Number(n("second")),weekday:rr[n("weekday")]??0}}function vc(e,t){let r=mo(e,t);return Date.UTC(r.year,r.month-1,r.day,r.hour,r.minute,r.second)-Math.floor(e.getTime()/1000)*1000}function sn(e,t,r,n,o=0){let i=Date.UTC(t,r-1,n,o),s=new Date(i-vc(new Date(i),e));return new Date(i-vc(s,e))}function nr(e,t){return new Date(Date.UTC(e,t-1,1)).toLocaleString("en-US",{month:"long",year:"numeric",timeZone:"UTC"})}function br(e,t,r=new Date){let n=ns(t)?t:"UTC",o=mo(r,n),i,s,a;if(e==="daily")i=sn(n,o.year,o.month,o.day),s=sn(n,o.year,o.month,o.day+1),a=`${o.year}-${String(o.month).padStart(2,"0")}-${String(o.day).padStart(2,"0")}`;else if(e==="weekly"){let u=(o.weekday+6)%7;i=sn(n,o.year,o.month,o.day-u),s=sn(n,o.year,o.month,o.day-u+7);let p=mo(i,n);a=`week of ${p.year}-${String(p.month).padStart(2,"0")}-${String(p.day).padStart(2,"0")}`}else i=sn(n,o.year,o.month,1),s=sn(n,o.year,o.month+1,1),a=nr(o.year,o.month);let d=s.getTime()-i.getTime(),c=Math.max(0,Math.min(d,r.getTime()-i.getTime()));return{start:i.toISOString(),end:s.toISOString(),elapsedMs:c,totalMs:d,label:a}}function Hp(e,t,r=new Date){let n=br(e,t,r),o=new Date(new Date(n.start).getTime()-1),i=br(e,t,o);return{...i,elapsedMs:i.totalMs}}function gi(e){let r=(typeof e==="string"?new Date(e):e).getTime();if(!Number.isFinite(r))throw Error("hourBucket requires a valid date");return new Date(Math.floor(r/3600000)*3600000).toISOString()}function qp(e,t,r=9600){let n=Math.floor(new Date(e).getTime()/3600000)*3600000,o=new Date(t).getTime();if(!Number.isFinite(n)||!Number.isFinite(o))throw Error("hourBucketsBetween requires valid dates");let i=[];for(let s=n;s<o&&i.length<r;s+=3600000)i.push(new Date(s).toISOString());return i}import{createHash as or}from"node:crypto";var le=1073741824,Cc=[{match:"request.count",meter:"edge.requests"},{match:"traffic.requests",meter:"edge.requests"},{match:"http.request",meter:"edge.requests",field:"count"},{match:"traffic.bytes_out",meter:"edge.egress_gb",scale:1/le},{match:"storage.egress.day",meter:"object.egress_gb",scale:1/le},{match:"storage.egress.month",meter:"object.egress_gb",scale:1/le,cumulative:!0},{match:"storage.egress.day_downloads",meter:"object.requests"},{match:"function.invocation",meter:"function.invocations",field:"count"},{match:"function.duration_ms",meter:"function.gb_seconds",scale:0.001},{match:"build.duration_ms",meter:"build.minutes",scale:0.000016666666666666667},{match:"telemetry.ingest_bytes",meter:"telemetry.ingest_gb",scale:1/le},{match:"image.transform",meter:"image.transformations",field:"count"}];function ir(e,t){return e.match.endsWith("*")?t.startsWith(e.match.slice(0,-1)):e.match===t}function Ed(e,t=Cc){return t.find((r)=>!r.match.endsWith("*")&&r.match===e)??t.find((r)=>ir(r,e))}function sr(e,t){let r=t.field??"value",n=r==="count"?1:r==="bytesOut"?e.bytesOut:r==="bytesIn"?e.bytesIn:r==="durationMs"?e.durationMs:e.value;if(n==null||!Number.isFinite(n))return;return n*(t.scale??1)}function wd(e,t){return or("sha256").update([t,e.meter,e.organizationId,e.projectId??"",e.environmentId??"",e.resourceId??"",e.timestamp].join("\x00")).digest("hex").slice(0,32)}class go{resetToleranceRatio;last=new Map;constructor(e=0.999){this.resetToleranceRatio=e}delta(e,t,r=new Date){if(!Number.isFinite(t)||t<0)return;let n=new Date(r).getTime(),o=this.last.get(e);if(!o)return this.last.set(e,{value:t,at:n}),t>0?t:void 0;if(n<o.at)return;if(t<o.value&&t>=o.value*this.resetToleranceRatio)return;if(this.last.set(e,{value:t,at:n}),t>=o.value){let i=t-o.value;return i>0?i:void 0}return t>0?t:void 0}prune(e){let t=e.getTime(),r=0;for(let[n,o]of this.last)if(o.at<t)this.last.delete(n),r++;return r}get size(){return this.last.size}}function nt(e,t){let r=e[t];return typeof r==="string"&&r.length>0?r:void 0}function Tc(e,t,r={}){let n=r.mappings??Cc,o=r.counters,i=[];for(let s of t){let a=Ed(s.name,n);if(!a)continue;let d=sr(s,a);if(d==null)continue;if(a.cumulative){if(!o)continue;let u=[s.projectId,s.environmentId??"",s.resourceId??"",s.name,s.source].join("\x00"),p=o.delta(u,d,s.timestamp);if(p==null)continue;d=p}if(!(d>0))continue;let c={organizationId:e,projectId:s.projectId,environmentId:s.environmentId,resourceId:s.resourceId,provider:nt(s.attributes,"provider")??r.defaultProvider,region:s.region??nt(s.attributes,"region"),meter:a.meter,quantity:d,timestamp:s.timestamp,attributes:{source:s.source,signal:s.name}};i.push({...c,key:wd(c,s.id)})}return i}function Ec(e){let t=new Map;for(let r of e){let n=new Date(Math.floor(new Date(r.timestamp).getTime()/3600000)*3600000).toISOString(),o=[r.organizationId,r.projectId??"",r.environmentId??"",r.resourceId??"",r.provider??"",r.region??"",r.meter,n].join("\x00"),i=t.get(o);if(i)i.quantity+=r.quantity;else t.set(o,{...r,timestamp:n})}return[...t.values()]}import{createHash as ar}from"node:crypto";var K=(e)=>{if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}},j=(e)=>typeof e==="string"&&e!==""?e:void 0,ue=(e)=>Number(e)===1,ot=(e)=>e==null?void 0:Number(e);function it(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),name:String(e.name),period:String(e.period),timezone:String(e.timezone),currency:String(e.currency),softLimitCents:ot(e.soft_limit_cents),hardLimitCents:ot(e.hard_limit_cents),thresholds:K(e.thresholds),meters:K(e.meters),graceSeconds:Number(e.grace_seconds),hysteresisPercent:Number(e.hysteresis_percent),dryRun:ue(e.dry_run),enabled:ue(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Ae(e){return{id:String(e.id),budgetId:String(e.budget_id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),action:String(e.action),state:String(e.state),reason:String(e.reason),restore:K(e.restore),triggeredAtPercent:Number(e.triggered_at_percent),simulated:ue(e.simulated),appliedAt:j(e.applied_at),releasedAt:j(e.released_at),error:j(e.error),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function st(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:j(e.project_id),environmentId:j(e.environment_id),signal:String(e.signal),direction:String(e.direction),observed:Number(e.observed),expected:Number(e.expected),score:Number(e.score),deltaPercent:Number(e.delta_percent),severity:String(e.severity),bucketStart:String(e.bucket_start),evidence:K(e.evidence),acknowledgedAt:j(e.acknowledged_at),createdAt:String(e.created_at)}}function dr(e){return{organizationId:String(e.organization_id),projectId:String(e.project_id),environmentId:String(e.environment_id),resourceId:String(e.resource_id),provider:String(e.provider),region:String(e.region),meter:String(e.meter),bucketStart:String(e.bucket_start),quantity:Number(e.quantity),costCents:Number(e.cost_cents),sampleCount:Number(e.sample_count),updatedAt:String(e.updated_at)}}function Sr(e,t,r){return[e,t??"",r??""].join("/")}var is=[{atPercent:50,actions:["notify"]},{atPercent:80,actions:["notify"]},{atPercent:100,actions:["notify"],onProjection:!0},{atPercent:100,actions:["notify","block_builds","block_deployments"]},{atPercent:115,actions:["notify","block_builds","block_deployments","throttle_requests"]}];class vr{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}now(){return(this.options.now?.()??new Date).toISOString()}get priceBook(){return this.options.priceBook??Sc}query(e,t=[]){return this.controlPlane.database.query(e).all(...t)}createBudget(e){let t=e.name.trim();if(!t)throw Error("Budgets require a name.");if(e.softLimitCents==null&&e.hardLimitCents==null)throw Error("A budget needs a soft limit, a hard limit, or both.");if(e.softLimitCents!=null&&e.hardLimitCents!=null&&e.softLimitCents>e.hardLimitCents)throw Error("The soft limit must not exceed the hard limit.");let r=e.timezone??"UTC";if(!ns(r))throw Error(`Unknown timezone: ${r}`);let n=(e.thresholds??[...is]).filter((s)=>Number.isFinite(s.atPercent)&&s.atPercent>=0);if(e.environmentId&&!e.projectId)throw Error("An environment-scoped budget must also name its project.");let o=crypto.randomUUID(),i=this.now();return this.controlPlane.database.run("INSERT INTO spend_budgets (id,organization_id,project_id,environment_id,name,period,timezone,currency,soft_limit_cents,hard_limit_cents,thresholds,meters,grace_seconds,hysteresis_percent,dry_run,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,?,?)",[o,e.organizationId,e.projectId??null,e.environmentId??null,t,e.period,r,e.currency??"USD",e.softLimitCents??null,e.hardLimitCents??null,JSON.stringify(n),JSON.stringify(e.meters??[]),Math.max(0,Math.floor(e.graceSeconds??0)),Math.max(0,e.hysteresisPercent??5),e.dryRun?1:0,e.enabled===!1?0:1,i,i]),this.getBudget(o)}getBudget(e){let t=this.query("SELECT * FROM spend_budgets WHERE id = ?",[e])[0];return t?it(t):void 0}listBudgets(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);if(e.enabledOnly)t.push("enabled = 1");return this.query(`SELECT * FROM spend_budgets WHERE ${t.join(" AND ")} ORDER BY created_at`,r).map(it)}budgetsForScope(e,t,r){return this.listBudgets({organizationId:e,enabledOnly:!0}).filter((n)=>{if(n.projectId&&n.projectId!==t)return!1;if(n.environmentId&&n.environmentId!==r)return!1;return!0}).sort((n,o)=>Number(!!n.projectId)-Number(!!o.projectId)||Number(!!n.environmentId)-Number(!!o.environmentId))}updateBudget(e,t,r){let n=this.getBudget(e);if(!n)throw Error("Budget was not found.");if(r!=null&&r!==n.version)throw Error(`Budget was modified concurrently (expected version ${r}, found ${n.version}).`);let o={...n,...t};if(o.softLimitCents==null&&o.hardLimitCents==null)throw Error("A budget needs a soft limit, a hard limit, or both.");if(o.softLimitCents!=null&&o.hardLimitCents!=null&&o.softLimitCents>o.hardLimitCents)throw Error("The soft limit must not exceed the hard limit.");if(t.timezone&&!ns(t.timezone))throw Error(`Unknown timezone: ${t.timezone}`);return this.controlPlane.database.run("UPDATE spend_budgets SET name=?,period=?,timezone=?,currency=?,soft_limit_cents=?,hard_limit_cents=?,thresholds=?,meters=?,grace_seconds=?,hysteresis_percent=?,dry_run=?,enabled=?,version=version+1,updated_at=? WHERE id=?",[o.name,o.period,o.timezone,o.currency??"USD",o.softLimitCents??null,o.hardLimitCents??null,JSON.stringify(o.thresholds??[]),JSON.stringify(o.meters??[]),Math.max(0,Math.floor(o.graceSeconds??0)),Math.max(0,o.hysteresisPercent??5),o.dryRun?1:0,o.enabled===!1?0:1,this.now(),e]),this.getBudget(e)}deleteBudget(e){return this.controlPlane.database.run("DELETE FROM spend_budgets WHERE id = ?",[e]).changes>0}ingestUsage(e){let t={applied:0,duplicates:0,costCents:0,unpricedMeters:[]},r=new Set,n=this.now();return this.controlPlane.database.transaction((i)=>{for(let s of i){if(!(s.quantity>0)||!Number.isFinite(s.quantity))continue;let a=s.key??this.deltaFallbackKey(s);if(this.controlPlane.database.run("INSERT OR IGNORE INTO spend_usage_receipts (key,organization_id,bucket_start,created_at) VALUES (?,?,?,?)",[a,s.organizationId,gi(s.timestamp),n]).changes===0){t.duplicates++;continue}let c={projectId:s.projectId??"",environmentId:s.environmentId??"",resourceId:s.resourceId??"",provider:s.provider??"",region:s.region??""},u=this.periodQuantity(s),p=po(this.priceBook,{meter:s.meter,quantity:s.quantity,provider:s.provider,region:s.region},u);if(p.unpriced)r.add(String(s.meter));this.controlPlane.database.run(`INSERT INTO spend_usage (organization_id,project_id,environment_id,resource_id,provider,region,meter,bucket_start,quantity,cost_cents,sample_count,updated_at)
|
|
2
2
|
VALUES (?,?,?,?,?,?,?,?,?,?,1,?)
|
|
3
3
|
ON CONFLICT(organization_id,project_id,environment_id,resource_id,provider,region,meter,bucket_start) DO UPDATE SET
|
|
4
4
|
quantity = quantity + excluded.quantity,
|
|
@@ -6,7 +6,7 @@ import{re,h}from"./chunk-twmeg17s.js";import{us}from"./chunk-bfzdbe4g.js";var Lp
|
|
|
6
6
|
sample_count = sample_count + 1,
|
|
7
7
|
updated_at = excluded.updated_at`,[s.organizationId,c.projectId,c.environmentId,c.resourceId,c.provider,c.region,s.meter,gi(s.timestamp),s.quantity,p.costCents,n]),t.applied++,t.costCents+=p.costCents}})(e),t.unpricedMeters=[...r],t}deltaFallbackKey(e){return ar("sha256").update([e.organizationId,e.projectId??"",e.environmentId??"",e.resourceId??"",e.provider??"",e.region??"",e.meter,e.timestamp,String(e.quantity)].join("\x00")).digest("hex").slice(0,32)}periodQuantity(e){let t=br("monthly","UTC",new Date(e.timestamp)),r=this.query("SELECT COALESCE(SUM(quantity), 0) AS total FROM spend_usage WHERE organization_id = ? AND meter = ? AND provider = ? AND region = ? AND bucket_start >= ? AND bucket_start < ?",[e.organizationId,e.meter,e.provider??"",e.region??"",t.start,t.end])[0];return Number(r?.total??0)}usageClauses(e){let t=["organization_id = ?","bucket_start >= ?","bucket_start < ?"],r=[e.organizationId,e.from,e.to];if(e.projectId)t.push("project_id = ?"),r.push(e.projectId);if(e.environmentId)t.push("environment_id = ?"),r.push(e.environmentId);if(e.resourceId)t.push("resource_id = ?"),r.push(e.resourceId);if(e.meters?.length)t.push(`meter IN (${e.meters.map(()=>"?").join(",")})`),r.push(...e.meters.map(String));if(e.providers?.length)t.push(`provider IN (${e.providers.map(()=>"?").join(",")})`),r.push(...e.providers);return{where:t.join(" AND "),bindings:r}}summarizeUsage(e){let{where:t,bindings:r}=this.usageClauses(e),n=this.query(`SELECT meter, provider, SUM(quantity) AS quantity, SUM(cost_cents) AS cost_cents, SUM(sample_count) AS sample_count
|
|
8
8
|
FROM spend_usage WHERE ${t} GROUP BY meter, provider ORDER BY SUM(cost_cents) DESC, meter`,r).map((i)=>({meter:String(i.meter),provider:String(i.provider),quantity:Number(i.quantity),costCents:Number(i.cost_cents),sampleCount:Number(i.sample_count)})),o=this.query(`SELECT bucket_start, SUM(cost_cents) AS cost_cents, SUM(quantity) AS quantity
|
|
9
|
-
FROM spend_usage WHERE ${t} GROUP BY bucket_start ORDER BY bucket_start`,r).map((i)=>({bucketStart:String(i.bucket_start),costCents:Number(i.cost_cents),quantity:Number(i.quantity)}));return{from:e.from,to:e.to,totalCents:n.reduce((i,s)=>i+s.costCents,0),byMeter:n,series:o}}listRollups(e,t=1000){let{where:r,bindings:n}=this.usageClauses(e);return this.query(`SELECT * FROM spend_usage WHERE ${r} ORDER BY bucket_start DESC LIMIT ?`,[...n,Math.max(1,Math.min(1e4,t))]).map(dr)}budgetSpendCents(e,t=new Date){let r=br(e.period,e.timezone,t),n=this.summarizeUsage({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,meters:e.meters.length>0?e.meters:void 0,from:r.start,to:r.end});return{window:r,summary:n}}pruneUsage(e,t=new Date){let r=new Date(t.getTime()-Math.max(1,e)*86400000).toISOString(),n=this.controlPlane.database.run("DELETE FROM spend_usage WHERE bucket_start < ?",[r]).changes,o=new Date(t.getTime()-604800000).toISOString(),i=this.controlPlane.database.run("DELETE FROM spend_usage_receipts WHERE created_at < ?",[o]).changes;return{rollups:n,receipts:i}}recordDecision(e){this.controlPlane.database.run("INSERT INTO spend_decisions (id,budget_id,level,window_start,window_end,used_percent,projected_percent,actual_cents,projected_cents,actions,simulated,reason,evaluated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[crypto.randomUUID(),e.budgetId,e.level,e.window.start,e.window.end,e.usedPercent,e.projectedPercent,e.projection.actualCents,e.projection.projectedCents,JSON.stringify(e.actions),e.simulated?1:0,e.reason,e.evaluatedAt])}listDecisions(e,t=50){return this.query("SELECT * FROM spend_decisions WHERE budget_id = ? ORDER BY evaluated_at DESC LIMIT ?",[e,Math.max(1,Math.min(500,t))]).map((r)=>({id:r.id,budgetId:r.budget_id,level:r.level,window:{start:r.window_start,end:r.window_end},usedPercent:Number(r.used_percent),projectedPercent:Number(r.projected_percent),actualCents:Number(r.actual_cents),projectedCents:Number(r.projected_cents),actions:K(r.actions),simulated:ue(r.simulated),reason:r.reason,evaluatedAt:r.evaluated_at}))}openEnforcement(e){let t=this.activeEnforcement(e.budget.id,e.action);if(t)return t;let r=crypto.randomUUID(),n=this.now();return this.controlPlane.database.run("INSERT INTO spend_enforcements (id,budget_id,organization_id,project_id,environment_id,action,state,reason,restore,triggered_at_percent,simulated,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[r,e.budget.id,e.budget.organizationId,e.budget.projectId??null,e.budget.environmentId??null,e.action,"pending",e.reason,JSON.stringify(h(e.restore??{})),e.triggeredAtPercent,e.simulated?1:0,n,n]),this.getEnforcement(r)}getEnforcement(e){let t=this.query("SELECT * FROM spend_enforcements WHERE id = ?",[e])[0];return t?Ae(t):void 0}activeEnforcement(e,t){let r=this.query("SELECT * FROM spend_enforcements WHERE budget_id = ? AND action = ? AND state IN ('pending','active','releasing')",[e,t])[0];return r?Ae(r):void 0}listEnforcements(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.budgetId)t.push("budget_id = ?"),r.push(e.budgetId);if(e.activeOnly)t.push("state IN ('pending','active','releasing')");return this.query(`SELECT * FROM spend_enforcements WHERE ${t.join(" AND ")} ORDER BY created_at DESC`,r).map(Ae)}transitionEnforcement(e,t,r={}){let n=this.getEnforcement(e);if(!n)throw Error("Enforcement was not found.");let o=this.now();return this.controlPlane.database.run("UPDATE spend_enforcements SET state=?, error=?, restore=?, applied_at=?, released_at=?, updated_at=? WHERE id=?",[t,r.error??null,JSON.stringify(h(r.restore??n.restore)),t==="active"?n.appliedAt??o:n.appliedAt??null,t==="released"?o:n.releasedAt??null,o,e]),this.getEnforcement(e)}recordAnomaly(e){let t=crypto.randomUUID();return this.controlPlane.database.run("INSERT OR IGNORE INTO spend_anomalies (id,organization_id,project_id,environment_id,scope_key,signal,direction,observed,expected,score,delta_percent,severity,bucket_start,evidence,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.projectId??null,e.environmentId??null,Sr(e.organizationId,e.projectId,e.environmentId),e.signal,e.direction,e.observed,e.expected,e.score,e.deltaPercent,e.severity,e.bucketStart,JSON.stringify(h(e.evidence??{})),this.now()]).changes>0?this.getAnomaly(t):void 0}getAnomaly(e){let t=this.query("SELECT * FROM spend_anomalies WHERE id = ?",[e])[0];return t?st(t):void 0}listAnomalies(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("project_id = ?"),r.push(e.projectId);if(e.since)t.push("bucket_start >= ?"),r.push(e.since);if(e.unacknowledgedOnly)t.push("acknowledged_at IS NULL");return this.query(`SELECT * FROM spend_anomalies WHERE ${t.join(" AND ")} ORDER BY bucket_start DESC LIMIT ?`,[...r,Math.max(1,Math.min(1000,e.limit??100))]).map(st)}acknowledgeAnomaly(e){return this.controlPlane.database.run("UPDATE spend_anomalies SET acknowledged_at = ? WHERE id = ? AND acknowledged_at IS NULL",[this.now(),e]).changes>0}}function at(e){if(!(e.totalMs>0))return 1;return Math.min(1,Math.max(0,e.elapsedMs/e.totalMs))}function cr(e){let t=e.window,r=Math.max(1,t.elapsedMs),n=e.actualCents/r,o=e.series??[],i=Math.min(1,Math.max(0,e.recencyWeight??0.6));if(o.length<2||i===0)return n;let s=0.3,a=o[0].costCents;for(let c=1;c<o.length;c++)a=s*o[c].costCents+(1-s)*a;let d=a/3600000;return n*(1-i)+d*i}function lr(e,t){let r=at(e),n=1-Math.exp(-3*r),o=Math.min(1,t/6);return Math.round(n*o*100)/100}function wc(e){let t=e.window,r=at(t),n=Math.max(0,e.actualCents),o=cr(e),i=Math.max(0,t.totalMs-t.elapsedMs),s=n+o*i,a=(e.series??[]).filter((c)=>c.costCents>0).length,d={actualCents:n,burnRateCentsPerMs:o,projectedCents:s,elapsedFraction:r,confidence:lr(t,a)};if(e.limitCents!=null&&e.limitCents>0&&o>0){let c=e.limitCents-n;if(c<=0)d.timeToExhaustionMs=0,d.exhaustionAt=new Date(new Date(t.start).getTime()+t.elapsedMs).toISOString();else{let u=c/o;if(u<=i)d.timeToExhaustionMs=u,d.exhaustionAt=new Date(new Date(t.start).getTime()+t.elapsedMs+u).toISOString()}}return d}function fo(e,t){if(t==null)return 0;if(t<=0)return e>0?1/0:0;return e/t*100}function fi(e){if(e==null)return"";if(e<=0)return"now";let t=Math.floor(e/3600000),r=Math.floor(t/24);if(r>0)return`${r}d ${t%24}h`;if(t>0)return`${t}h ${Math.floor(e%3600000/60000)}m`;return`${Math.max(1,Math.floor(e/60000))}m`}var wd=0.35;function ss(e){return e.hardLimitCents??e.softLimitCents}function ur(e,t,r){if(r.some((s)=>s!=="notify"))return"hard_capped";let o=ss(e),i=e.softLimitCents;if(i!=null&&o!=null&&o>0&&t>=i/o*100)return"soft_capped";if(t>=50)return"warning";return"ok"}function me(e){return[...new Set(e)].sort((t,r)=>oe[t]-oe[r])}function mr(e,t,r,n,o){if(o.length===0)return`Spend is at ${r.toFixed(1)}% of the ${t.period} budget.`;let i=o[o.length-1];if(i.projected)return`Projected spend for this ${t.period} window reaches ${i.observedPercent.toFixed(1)}% of the budget (${n.confidence.toFixed(2)} confidence), crossing the ${i.atPercent}% threshold.`;return`Spend reached ${r.toFixed(1)}% of the ${t.period} budget, crossing the ${i.atPercent}% threshold${e==="hard_capped"?" and triggering enforcement":""}.`}function Ac(e){let{budget:t,window:r}=e,n=e.now??new Date,o=ss(t),i=wc({window:r,actualCents:e.actualCents,series:e.series,limitCents:o}),s=fo(e.actualCents,o),a=fo(i.projectedCents,o),d=t.graceSeconds*1000,c=d===0||e.breachingSince!=null&&n.getTime()-new Date(e.breachingSince).getTime()>=d,u=i.confidence>=wd,p=[],l=new Set;for(let b of[...t.thresholds].sort((I,_)=>I.atPercent-_.atPercent)){let I=b.onProjection===!0,_=I?a:s;if(!(_>=b.atPercent))continue;let w=b.actions.filter((C)=>C!=="notify");if(I&&!u&&w.length>0)continue;p.push({atPercent:b.atPercent,actions:b.actions,projected:I,observedPercent:_});for(let C of b.actions){if(C!=="notify"&&!c)continue;l.add(C)}}let f=me(l),g=100-t.hysteresisPercent,y=me((e.activeActions??[]).filter((b)=>{if(l.has(b))return!1;let I=t.thresholds.filter((w)=>w.actions.includes(b)).reduce((w,C)=>w==null?C.atPercent:Math.min(w,C.atPercent),void 0);if(I==null)return!0;return Math.max(s,u?a:0)<=I*(g/100)})),v=ur(t,s,f);return{budgetId:t.id,level:v,window:r,projection:i,usedPercent:s,projectedPercent:a,breaches:p,actions:t.dryRun?f.filter((b)=>b==="notify"):f,releases:y,simulated:t.dryRun,reason:mr(v,t,s,i,p),evaluatedAt:n.toISOString()}}function Rc(e){let t=new Set;for(let i of e)for(let s of i.actions)t.add(s);let r=new Set;for(let i of e)for(let s of i.releases)if(!t.has(s))r.add(s);let n={ok:0,warning:1,soft_capped:2,hard_capped:3},o=e.reduce((i,s)=>n[s.level]>n[i]?s.level:i,"ok");return{actions:me(t),releases:me(r),level:o}}var os={notify:"Send the configured spend notifications.",block_builds:"Refuse new builds. Running builds finish.",block_deployments:"Refuse new deployments. The running release keeps serving.",throttle_requests:"Rate-limit inbound requests at the edge to cap egress and compute.",suspend_functions:"Stop invoking serverless functions; static and cached responses still serve.",serve_static:"Serve the last built static output only; dynamic rendering is off.",suspend_project:"Park all inbound traffic behind a 503. No data is removed."},Ad=["throttle_requests","suspend_functions","serve_static","suspend_project"],pr=["production"];function dt(e,t,r){let n=Ad.includes(e),o=r.approvalRequiredFor??pr,i=r.environmentKind!=null&&o.includes(r.environmentKind),s=r.maxAutomaticAction!=null&&oe[e]>oe[r.maxAutomaticAction];return{action:e,description:os[e],userVisible:n,requiresApproval:s||n&&i,reason:t}}function Ic(e,t={}){let r=e.actions.map((o)=>dt(o,e.reason,t)),n=[...e.releases].sort((o,i)=>oe[i]-oe[o]).map((o)=>dt(o,"Spend fell back below the threshold that armed this action.",t));return{budgetId:e.budgetId,simulated:e.simulated,apply:r.filter((o)=>!o.requiresApproval),release:n.map((o)=>({...o,requiresApproval:!1})),withheld:r.filter((o)=>o.requiresApproval)}}async function Pc(e,t,r,n,o){let i={applied:[],released:[],failed:[],withheld:n.withheld,simulated:n.simulated};for(let s of n.apply){let a=e.openEnforcement({budget:t,action:s.action,reason:s.reason,triggeredAtPercent:r.usedPercent,simulated:n.simulated});if(a.state==="active")continue;if(n.simulated){i.applied.push(e.transitionEnforcement(a.id,"active",{restore:{simulated:!0}}));continue}try{let d=await o.apply(s.action,{budget:t,decision:r,record:a});i.applied.push(e.transitionEnforcement(a.id,"active",{restore:d}))}catch(d){let c=d instanceof Error?d.message:String(d);e.transitionEnforcement(a.id,"failed",{error:c}),i.failed.push({action:s.action,error:c})}}for(let s of n.release){let a=e.activeEnforcement(t.id,s.action);if(!a)continue;if(n.simulated||a.simulated){i.released.push(e.transitionEnforcement(a.id,"released"));continue}e.transitionEnforcement(a.id,"releasing");try{await o.release(s.action,{budget:t,record:a,restore:a.restore}),i.released.push(e.transitionEnforcement(a.id,"released"))}catch(d){let c=d instanceof Error?d.message:String(d);e.transitionEnforcement(a.id,"releasing",{error:c}),i.failed.push({action:s.action,error:c})}}return i}function Dc(e){return e.filter((t)=>t.state==="active").map((t)=>t.action).sort((t,r)=>oe[r]-oe[t])[0]}function Nc(e,t){let r=new Set(t.filter((o)=>o.state==="active"&&!o.simulated).map((o)=>o.action)),n={build:["block_builds","suspend_project"],deploy:["block_deployments","suspend_project"],function_invoke:["suspend_functions","serve_static","suspend_project"],request:["suspend_project"]};for(let o of n[e]??[])if(r.has(o))return{allowed:!1,blockedBy:o,reason:os[o]};return{allowed:!0}}function ho(e){if(e.length===0)return 0;let t=[...e].sort((n,o)=>n-o),r=t.length>>1;return t.length%2===0?(t[r-1]+t[r])/2:t[r]}function Rd(e,t){if(e.length===0)return 0;let r=t??ho(e);return 1.4826*ho(e.map((n)=>Math.abs(n-r)))}function Id(e,t){let r=ho(t),n=Rd(t,r);if(n===0)n=Math.max(Math.abs(r)*0.1,Number.EPSILON);return{score:(e-r)/n,center:r,deviation:n}}function zp(e,t=0.3){let r=[],n=e[0]??0;for(let o of e)n=t*o+(1-t)*n,r.push(n);return r}function gr(e,t,r){let n=[];for(let o=t-r;o>=0;o-=r)if(Number.isFinite(e[o]))n.push(e[o]);return n}function Pd(e,t={}){let r=Math.max(1,Math.floor(t.seasonLength??24)),n=t.threshold??3.5,o=t.criticalThreshold??n*2,i=Math.max(2,Math.floor(t.minHistory??3)),s=Math.max(0,t.minAbsoluteDelta??0),a=e.map((u)=>u.value),d=[],c=0;for(let u=0;u<e.length;u++){let p=gr(a,u,r);if(p.length<i)continue;let l=a[u];if(!Number.isFinite(l))continue;c++;let{score:f,center:g,deviation:y}=Id(l,p),v=f>=0?"spike":"drop";if(v==="drop"&&t.detectDrops!==!0)continue;if(Math.abs(f)<n)continue;if(Math.abs(l-g)<s)continue;d.push({bucketStart:e[u].bucketStart,observed:l,expected:g,score:f,direction:v,deltaPercent:g===0?l===0?0:1/0:(l-g)/g*100,severity:Math.abs(f)>=o?"critical":"warning",historySize:p.length,deviation:y})}return{anomalies:d,warmingUp:c===0,evaluated:c}}function kc(e,t={}){if(e.length===0)return;let r=Pd(e,t),n=e[e.length-1].bucketStart;return r.anomalies.find((o)=>o.bucketStart===n)}function as(e){if(e==="cost")return{seasonLength:24,threshold:3.5,minHistory:3,minAbsoluteDelta:25};if(e.startsWith("edge.")||e.startsWith("function."))return{seasonLength:168,threshold:4,minHistory:3,minAbsoluteDelta:1000};return{seasonLength:24,threshold:3.5,minHistory:3}}var Dd={low:6,medium:3.5,high:2.5},B=(e)=>typeof e==="string"&&e!==""?e:void 0;function Re(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:B(e.project_id),environmentId:B(e.environment_id),signal:String(e.signal),enabled:Number(e.enabled)===1,sensitivity:String(e.sensitivity),seasonLength:Number(e.season_length),minAbsoluteDelta:Number(e.min_absolute_delta),detectDrops:Number(e.detect_drops)===1,severity:String(e.severity),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function fr(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:B(e.project_id),signal:B(e.signal),routePattern:B(e.route_pattern),statusCode:e.status_code==null?void 0:Number(e.status_code),reason:String(e.reason),actorId:B(e.actor_id),expiresAt:B(e.expires_at),createdAt:String(e.created_at)}}function Nd(e,t){if(e==="*"||e==="**")return!0;let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"\x01").replace(/\*/g,"[^/]*").replace(/\u0001/g,".*");return new RegExp(`^${r}$`).test(t)}class yo{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}now(){return(this.options.now?.()??new Date).toISOString()}query(e,t=[]){return this.controlPlane.database.query(e).all(...t)}upsert(e){let t=e.signal.trim();if(!t)throw Error("An anomaly config needs a signal.");if(e.seasonLength!=null&&(!Number.isInteger(e.seasonLength)||e.seasonLength<1))throw Error("seasonLength must be a positive integer.");let r=Sr(e.organizationId,e.projectId,e.environmentId),n=this.now(),o=this.query("SELECT * FROM anomaly_configs WHERE scope_key = ? AND signal = ?",[r,t])[0],i=as(t);if(o)return this.controlPlane.database.run("UPDATE anomaly_configs SET enabled=?,sensitivity=?,season_length=?,min_absolute_delta=?,detect_drops=?,severity=?,version=version+1,updated_at=? WHERE id=?",[e.enabled===!1?0:1,e.sensitivity??String(o.sensitivity),e.seasonLength??Number(o.season_length),e.minAbsoluteDelta??Number(o.min_absolute_delta),e.detectDrops==null?Number(o.detect_drops):e.detectDrops?1:0,e.severity??String(o.severity),n,String(o.id)]),this.get(String(o.id));let s=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO anomaly_configs (id,organization_id,project_id,environment_id,scope_key,signal,enabled,sensitivity,season_length,min_absolute_delta,detect_drops,severity,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,1,?,?)",[s,e.organizationId,e.projectId??null,e.environmentId??null,r,t,e.enabled===!1?0:1,e.sensitivity??"medium",e.seasonLength??i.seasonLength??24,e.minAbsoluteDelta??i.minAbsoluteDelta??0,e.detectDrops?1:0,e.severity??"warning",n,n]),this.get(s)}get(e){let t=this.query("SELECT * FROM anomaly_configs WHERE id = ?",[e])[0];return t?Re(t):void 0}list(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);return this.query(`SELECT * FROM anomaly_configs WHERE ${t.join(" AND ")} ORDER BY signal`,r).map(Re)}delete(e){return this.controlPlane.database.run("DELETE FROM anomaly_configs WHERE id = ?",[e]).changes>0}optionsFor(e,t){let r=[Sr(e.organizationId,e.projectId,e.environmentId),Sr(e.organizationId,e.projectId),Sr(e.organizationId)];for(let n of r){let o=this.query("SELECT * FROM anomaly_configs WHERE scope_key = ? AND signal = ?",[n,t])[0];if(!o)continue;let i=Re(o);return{config:i,enabled:i.enabled,options:{...as(t),threshold:Dd[i.sensitivity],seasonLength:i.seasonLength,minAbsoluteDelta:i.minAbsoluteDelta,detectDrops:i.detectDrops}}}return{options:as(t),enabled:!0}}silence(e){let t=e.reason.trim();if(!t)throw Error("A silence needs a reason: someone will ask why this stopped alerting.");if(!e.signal&&!e.routePattern&&e.statusCode==null)throw Error("A silence needs at least one of signal, routePattern, or statusCode.");let r=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO anomaly_silences (id,organization_id,project_id,scope_key,signal,route_pattern,status_code,reason,actor_id,expires_at,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)",[r,e.organizationId,e.projectId??null,Sr(e.organizationId,e.projectId),e.signal??null,e.routePattern??null,e.statusCode??null,t,e.actorId??null,e.expiresAt??null,this.now()]),this.listSilences({organizationId:e.organizationId}).find((n)=>n.id===r)}listSilences(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);if(!e.includeExpired)t.push("(expires_at IS NULL OR expires_at > ?)"),r.push(this.now());return this.query(`SELECT * FROM anomaly_silences WHERE ${t.join(" AND ")} ORDER BY created_at DESC`,r).map(fr)}removeSilence(e){return this.controlPlane.database.run("DELETE FROM anomaly_silences WHERE id = ?",[e]).changes>0}isSilenced(e,t){return this.listSilences(e).find((r)=>{if(r.signal&&r.signal!==t.signal)return!1;if(r.statusCode!=null&&r.statusCode!==t.statusCode)return!1;if(r.routePattern){if(!t.route)return!1;if(!Nd(r.routePattern,t.route))return!1}return!0})}}var Lt=[{key:"cost",routeAware:!1,label:"Cost",source:"usage",gapPolicy:"zero",minSamples:0,unit:"cents"},{key:"edge.requests",routeAware:!1,label:"Edge requests",source:"usage",gapPolicy:"zero",minSamples:0,unit:"requests"},{key:"edge.egress_gb",routeAware:!1,label:"Edge egress",source:"usage",gapPolicy:"zero",minSamples:0,unit:"GB"},{key:"function.invocations",routeAware:!1,label:"Function invocations",source:"usage",gapPolicy:"zero",minSamples:0,unit:"invocations"},{key:"http.requests",routeAware:!0,label:"HTTP requests",source:"telemetry",gapPolicy:"zero",minSamples:0,unit:"requests"},{key:"http.errors",routeAware:!0,label:"HTTP 5xx",source:"telemetry",gapPolicy:"zero",minSamples:0,unit:"responses"},{key:"http.error_rate",routeAware:!0,label:"HTTP error rate",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ratio",ratio:!0},{key:"http.client_error_rate",routeAware:!0,label:"HTTP 4xx rate",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ratio",ratio:!0},{key:"http.latency_p95",routeAware:!0,label:"Latency p95",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ms"}];function bo(e){return Lt.find((t)=>t.key===e)}var G=3600000;function Ir(e,t=960){let r=Math.floor(new Date(e.from).getTime()/G)*G,n=new Date(e.to).getTime(),o=[];for(let i=r;i<n&&o.length<t;i+=G)o.push(i);return o}function Pe(e,t,r){let n=[],o=0,i=0;for(let s of Ir(t)){let a=r.get(s),d=new Date(s).toISOString();if(!a){n.push({bucketStart:d,value:e.gapPolicy==="zero"?0:Number.NaN});continue}if(a.samples<e.minSamples){n.push({bucketStart:d,value:Number.NaN}),i++;continue}n.push({bucketStart:d,value:a.value}),o++}return{signal:e.key,points:n,populated:o,suppressed:i,unit:e.unit}}class So{controlPlane;spend;counterCache=new Map;constructor(e,t){this.controlPlane=e;this.spend=t}query(e,t){return this.controlPlane.database.query(e).all(...t)}usageSeries(e,t,r){let n=this.spend.summarizeUsage({organizationId:t.organizationId,projectId:t.projectId,environmentId:t.environmentId,meters:e.key==="cost"?void 0:[e.key],from:r.from,to:r.to}),o=new Map;for(let i of n.series)o.set(new Date(i.bucketStart).getTime(),{value:e.key==="cost"?i.costCents:i.quantity,samples:1});return Pe(e,r,o)}requestFilter(e,t){let r=["project_id = ?","kind = 'request'","timestamp >= ?","timestamp < ?"],n=[e.projectId,t.from,t.to];if(e.environmentId)r.push("environment_id = ?"),n.push(e.environmentId);if(e.route)r.push("path_template = ?"),n.push(e.route);return{clauses:r,bindings:n}}counters(e,t){let r=[e.projectId,e.environmentId??"",e.route??"",t.from,t.to].join("\x00"),n=this.counterCache.get(r);if(n)return n;let{clauses:o,bindings:i}=this.requestFilter(e,t),s=this.query(`SELECT
|
|
9
|
+
FROM spend_usage WHERE ${t} GROUP BY bucket_start ORDER BY bucket_start`,r).map((i)=>({bucketStart:String(i.bucket_start),costCents:Number(i.cost_cents),quantity:Number(i.quantity)}));return{from:e.from,to:e.to,totalCents:n.reduce((i,s)=>i+s.costCents,0),byMeter:n,series:o}}listRollups(e,t=1000){let{where:r,bindings:n}=this.usageClauses(e);return this.query(`SELECT * FROM spend_usage WHERE ${r} ORDER BY bucket_start DESC LIMIT ?`,[...n,Math.max(1,Math.min(1e4,t))]).map(dr)}budgetSpendCents(e,t=new Date){let r=br(e.period,e.timezone,t),n=this.summarizeUsage({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,meters:e.meters.length>0?e.meters:void 0,from:r.start,to:r.end});return{window:r,summary:n}}pruneUsage(e,t=new Date){let r=new Date(t.getTime()-Math.max(1,e)*86400000).toISOString(),n=this.controlPlane.database.run("DELETE FROM spend_usage WHERE bucket_start < ?",[r]).changes,o=new Date(t.getTime()-604800000).toISOString(),i=this.controlPlane.database.run("DELETE FROM spend_usage_receipts WHERE created_at < ?",[o]).changes;return{rollups:n,receipts:i}}recordDecision(e){this.controlPlane.database.run("INSERT INTO spend_decisions (id,budget_id,level,window_start,window_end,used_percent,projected_percent,actual_cents,projected_cents,actions,simulated,reason,evaluated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[crypto.randomUUID(),e.budgetId,e.level,e.window.start,e.window.end,e.usedPercent,e.projectedPercent,e.projection.actualCents,e.projection.projectedCents,JSON.stringify(e.actions),e.simulated?1:0,e.reason,e.evaluatedAt])}listDecisions(e,t=50){return this.query("SELECT * FROM spend_decisions WHERE budget_id = ? ORDER BY evaluated_at DESC LIMIT ?",[e,Math.max(1,Math.min(500,t))]).map((r)=>({id:r.id,budgetId:r.budget_id,level:r.level,window:{start:r.window_start,end:r.window_end},usedPercent:Number(r.used_percent),projectedPercent:Number(r.projected_percent),actualCents:Number(r.actual_cents),projectedCents:Number(r.projected_cents),actions:K(r.actions),simulated:ue(r.simulated),reason:r.reason,evaluatedAt:r.evaluated_at}))}openEnforcement(e){let t=this.activeEnforcement(e.budget.id,e.action);if(t)return t;let r=crypto.randomUUID(),n=this.now();return this.controlPlane.database.run("INSERT INTO spend_enforcements (id,budget_id,organization_id,project_id,environment_id,action,state,reason,restore,triggered_at_percent,simulated,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[r,e.budget.id,e.budget.organizationId,e.budget.projectId??null,e.budget.environmentId??null,e.action,"pending",e.reason,JSON.stringify(h(e.restore??{})),e.triggeredAtPercent,e.simulated?1:0,n,n]),this.getEnforcement(r)}getEnforcement(e){let t=this.query("SELECT * FROM spend_enforcements WHERE id = ?",[e])[0];return t?Ae(t):void 0}activeEnforcement(e,t){let r=this.query("SELECT * FROM spend_enforcements WHERE budget_id = ? AND action = ? AND state IN ('pending','active','releasing')",[e,t])[0];return r?Ae(r):void 0}listEnforcements(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.budgetId)t.push("budget_id = ?"),r.push(e.budgetId);if(e.activeOnly)t.push("state IN ('pending','active','releasing')");return this.query(`SELECT * FROM spend_enforcements WHERE ${t.join(" AND ")} ORDER BY created_at DESC`,r).map(Ae)}transitionEnforcement(e,t,r={}){let n=this.getEnforcement(e);if(!n)throw Error("Enforcement was not found.");let o=this.now();return this.controlPlane.database.run("UPDATE spend_enforcements SET state=?, error=?, restore=?, applied_at=?, released_at=?, updated_at=? WHERE id=?",[t,r.error??null,JSON.stringify(h(r.restore??n.restore)),t==="active"?n.appliedAt??o:n.appliedAt??null,t==="released"?o:n.releasedAt??null,o,e]),this.getEnforcement(e)}recordAnomaly(e){let t=crypto.randomUUID();return this.controlPlane.database.run("INSERT OR IGNORE INTO spend_anomalies (id,organization_id,project_id,environment_id,scope_key,signal,direction,observed,expected,score,delta_percent,severity,bucket_start,evidence,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.projectId??null,e.environmentId??null,Sr(e.organizationId,e.projectId,e.environmentId),e.signal,e.direction,e.observed,e.expected,e.score,e.deltaPercent,e.severity,e.bucketStart,JSON.stringify(h(e.evidence??{})),this.now()]).changes>0?this.getAnomaly(t):void 0}getAnomaly(e){let t=this.query("SELECT * FROM spend_anomalies WHERE id = ?",[e])[0];return t?st(t):void 0}listAnomalies(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("project_id = ?"),r.push(e.projectId);if(e.since)t.push("bucket_start >= ?"),r.push(e.since);if(e.unacknowledgedOnly)t.push("acknowledged_at IS NULL");return this.query(`SELECT * FROM spend_anomalies WHERE ${t.join(" AND ")} ORDER BY bucket_start DESC LIMIT ?`,[...r,Math.max(1,Math.min(1000,e.limit??100))]).map(st)}acknowledgeAnomaly(e){return this.controlPlane.database.run("UPDATE spend_anomalies SET acknowledged_at = ? WHERE id = ? AND acknowledged_at IS NULL",[this.now(),e]).changes>0}}function at(e){if(!(e.totalMs>0))return 1;return Math.min(1,Math.max(0,e.elapsedMs/e.totalMs))}function cr(e){let t=e.window,r=Math.max(1,t.elapsedMs),n=e.actualCents/r,o=e.series??[],i=Math.min(1,Math.max(0,e.recencyWeight??0.6));if(o.length<2||i===0)return n;let s=0.3,a=o[0].costCents;for(let c=1;c<o.length;c++)a=s*o[c].costCents+(1-s)*a;let d=a/3600000;return n*(1-i)+d*i}function lr(e,t){let r=at(e),n=1-Math.exp(-3*r),o=Math.min(1,t/6);return Math.round(n*o*100)/100}function wc(e){let t=e.window,r=at(t),n=Math.max(0,e.actualCents),o=cr(e),i=Math.max(0,t.totalMs-t.elapsedMs),s=n+o*i,a=(e.series??[]).filter((c)=>c.costCents>0).length,d={actualCents:n,burnRateCentsPerMs:o,projectedCents:s,elapsedFraction:r,confidence:lr(t,a)};if(e.limitCents!=null&&e.limitCents>0&&o>0){let c=e.limitCents-n;if(c<=0)d.timeToExhaustionMs=0,d.exhaustionAt=new Date(new Date(t.start).getTime()+t.elapsedMs).toISOString();else{let u=c/o;if(u<=i)d.timeToExhaustionMs=u,d.exhaustionAt=new Date(new Date(t.start).getTime()+t.elapsedMs+u).toISOString()}}return d}function fo(e,t){if(t==null)return 0;if(t<=0)return e>0?1/0:0;return e/t*100}function fi(e){if(e==null)return"";if(e<=0)return"now";let t=Math.floor(e/3600000),r=Math.floor(t/24);if(r>0)return`${r}d ${t%24}h`;if(t>0)return`${t}h ${Math.floor(e%3600000/60000)}m`;return`${Math.max(1,Math.floor(e/60000))}m`}var Ad=0.35;function ss(e){return e.hardLimitCents??e.softLimitCents}function ur(e,t,r){if(r.some((s)=>s!=="notify"))return"hard_capped";let o=ss(e),i=e.softLimitCents;if(i!=null&&o!=null&&o>0&&t>=i/o*100)return"soft_capped";if(t>=50)return"warning";return"ok"}function me(e){return[...new Set(e)].sort((t,r)=>oe[t]-oe[r])}function mr(e,t,r,n,o){if(o.length===0)return`Spend is at ${r.toFixed(1)}% of the ${t.period} budget.`;let i=o[o.length-1];if(i.projected)return`Projected spend for this ${t.period} window reaches ${i.observedPercent.toFixed(1)}% of the budget (${n.confidence.toFixed(2)} confidence), crossing the ${i.atPercent}% threshold.`;return`Spend reached ${r.toFixed(1)}% of the ${t.period} budget, crossing the ${i.atPercent}% threshold${e==="hard_capped"?" and triggering enforcement":""}.`}function Ac(e){let{budget:t,window:r}=e,n=e.now??new Date,o=ss(t),i=wc({window:r,actualCents:e.actualCents,series:e.series,limitCents:o}),s=fo(e.actualCents,o),a=fo(i.projectedCents,o),d=t.graceSeconds*1000,c=d===0||e.breachingSince!=null&&n.getTime()-new Date(e.breachingSince).getTime()>=d,u=i.confidence>=Ad,p=[],l=new Set;for(let b of[...t.thresholds].sort((I,_)=>I.atPercent-_.atPercent)){let I=b.onProjection===!0,_=I?a:s;if(!(_>=b.atPercent))continue;let w=b.actions.filter((C)=>C!=="notify");if(I&&!u&&w.length>0)continue;p.push({atPercent:b.atPercent,actions:b.actions,projected:I,observedPercent:_});for(let C of b.actions){if(C!=="notify"&&!c)continue;l.add(C)}}let f=me(l),g=100-t.hysteresisPercent,y=me((e.activeActions??[]).filter((b)=>{if(l.has(b))return!1;let I=t.thresholds.filter((w)=>w.actions.includes(b)).reduce((w,C)=>w==null?C.atPercent:Math.min(w,C.atPercent),void 0);if(I==null)return!0;return Math.max(s,u?a:0)<=I*(g/100)})),v=ur(t,s,f);return{budgetId:t.id,level:v,window:r,projection:i,usedPercent:s,projectedPercent:a,breaches:p,actions:t.dryRun?f.filter((b)=>b==="notify"):f,releases:y,simulated:t.dryRun,reason:mr(v,t,s,i,p),evaluatedAt:n.toISOString()}}function Rc(e){let t=new Set;for(let i of e)for(let s of i.actions)t.add(s);let r=new Set;for(let i of e)for(let s of i.releases)if(!t.has(s))r.add(s);let n={ok:0,warning:1,soft_capped:2,hard_capped:3},o=e.reduce((i,s)=>n[s.level]>n[i]?s.level:i,"ok");return{actions:me(t),releases:me(r),level:o}}var os={notify:"Send the configured spend notifications.",block_builds:"Refuse new builds. Running builds finish.",block_deployments:"Refuse new deployments. The running release keeps serving.",throttle_requests:"Rate-limit inbound requests at the edge to cap egress and compute.",suspend_functions:"Stop invoking serverless functions; static and cached responses still serve.",serve_static:"Serve the last built static output only; dynamic rendering is off.",suspend_project:"Park all inbound traffic behind a 503. No data is removed."},Rd=["throttle_requests","suspend_functions","serve_static","suspend_project"],pr=["production"];function dt(e,t,r){let n=Rd.includes(e),o=r.approvalRequiredFor??pr,i=r.environmentKind!=null&&o.includes(r.environmentKind),s=r.maxAutomaticAction!=null&&oe[e]>oe[r.maxAutomaticAction];return{action:e,description:os[e],userVisible:n,requiresApproval:s||n&&i,reason:t}}function Ic(e,t={}){let r=e.actions.map((o)=>dt(o,e.reason,t)),n=[...e.releases].sort((o,i)=>oe[i]-oe[o]).map((o)=>dt(o,"Spend fell back below the threshold that armed this action.",t));return{budgetId:e.budgetId,simulated:e.simulated,apply:r.filter((o)=>!o.requiresApproval),release:n.map((o)=>({...o,requiresApproval:!1})),withheld:r.filter((o)=>o.requiresApproval)}}async function Pc(e,t,r,n,o){let i={applied:[],released:[],failed:[],withheld:n.withheld,simulated:n.simulated};for(let s of n.apply){let a=e.openEnforcement({budget:t,action:s.action,reason:s.reason,triggeredAtPercent:r.usedPercent,simulated:n.simulated});if(a.state==="active")continue;if(n.simulated){i.applied.push(e.transitionEnforcement(a.id,"active",{restore:{simulated:!0}}));continue}try{let d=await o.apply(s.action,{budget:t,decision:r,record:a});i.applied.push(e.transitionEnforcement(a.id,"active",{restore:d}))}catch(d){let c=d instanceof Error?d.message:String(d);e.transitionEnforcement(a.id,"failed",{error:c}),i.failed.push({action:s.action,error:c})}}for(let s of n.release){let a=e.activeEnforcement(t.id,s.action);if(!a)continue;if(n.simulated||a.simulated){i.released.push(e.transitionEnforcement(a.id,"released"));continue}e.transitionEnforcement(a.id,"releasing");try{await o.release(s.action,{budget:t,record:a,restore:a.restore}),i.released.push(e.transitionEnforcement(a.id,"released"))}catch(d){let c=d instanceof Error?d.message:String(d);e.transitionEnforcement(a.id,"releasing",{error:c}),i.failed.push({action:s.action,error:c})}}return i}function Dc(e){return e.filter((t)=>t.state==="active").map((t)=>t.action).sort((t,r)=>oe[r]-oe[t])[0]}function Nc(e,t){let r=new Set(t.filter((o)=>o.state==="active"&&!o.simulated).map((o)=>o.action)),n={build:["block_builds","suspend_project"],deploy:["block_deployments","suspend_project"],function_invoke:["suspend_functions","serve_static","suspend_project"],request:["suspend_project"]};for(let o of n[e]??[])if(r.has(o))return{allowed:!1,blockedBy:o,reason:os[o]};return{allowed:!0}}function ho(e){if(e.length===0)return 0;let t=[...e].sort((n,o)=>n-o),r=t.length>>1;return t.length%2===0?(t[r-1]+t[r])/2:t[r]}function Id(e,t){if(e.length===0)return 0;let r=t??ho(e);return 1.4826*ho(e.map((n)=>Math.abs(n-r)))}function Pd(e,t){let r=ho(t),n=Id(t,r);if(n===0)n=Math.max(Math.abs(r)*0.1,Number.EPSILON);return{score:(e-r)/n,center:r,deviation:n}}function Gp(e,t=0.3){let r=[],n=e[0]??0;for(let o of e)n=t*o+(1-t)*n,r.push(n);return r}function gr(e,t,r){let n=[];for(let o=t-r;o>=0;o-=r)if(Number.isFinite(e[o]))n.push(e[o]);return n}function Dd(e,t={}){let r=Math.max(1,Math.floor(t.seasonLength??24)),n=t.threshold??3.5,o=t.criticalThreshold??n*2,i=Math.max(2,Math.floor(t.minHistory??3)),s=Math.max(0,t.minAbsoluteDelta??0),a=e.map((u)=>u.value),d=[],c=0;for(let u=0;u<e.length;u++){let p=gr(a,u,r);if(p.length<i)continue;let l=a[u];if(!Number.isFinite(l))continue;c++;let{score:f,center:g,deviation:y}=Pd(l,p),v=f>=0?"spike":"drop";if(v==="drop"&&t.detectDrops!==!0)continue;if(Math.abs(f)<n)continue;if(Math.abs(l-g)<s)continue;d.push({bucketStart:e[u].bucketStart,observed:l,expected:g,score:f,direction:v,deltaPercent:g===0?l===0?0:1/0:(l-g)/g*100,severity:Math.abs(f)>=o?"critical":"warning",historySize:p.length,deviation:y})}return{anomalies:d,warmingUp:c===0,evaluated:c}}function kc(e,t={}){if(e.length===0)return;let r=Dd(e,t),n=e[e.length-1].bucketStart;return r.anomalies.find((o)=>o.bucketStart===n)}function as(e){if(e==="cost")return{seasonLength:24,threshold:3.5,minHistory:3,minAbsoluteDelta:25};if(e.startsWith("edge.")||e.startsWith("function."))return{seasonLength:168,threshold:4,minHistory:3,minAbsoluteDelta:1000};return{seasonLength:24,threshold:3.5,minHistory:3}}var Nd={low:6,medium:3.5,high:2.5},B=(e)=>typeof e==="string"&&e!==""?e:void 0;function Re(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:B(e.project_id),environmentId:B(e.environment_id),signal:String(e.signal),enabled:Number(e.enabled)===1,sensitivity:String(e.sensitivity),seasonLength:Number(e.season_length),minAbsoluteDelta:Number(e.min_absolute_delta),detectDrops:Number(e.detect_drops)===1,severity:String(e.severity),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function fr(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:B(e.project_id),signal:B(e.signal),routePattern:B(e.route_pattern),statusCode:e.status_code==null?void 0:Number(e.status_code),reason:String(e.reason),actorId:B(e.actor_id),expiresAt:B(e.expires_at),createdAt:String(e.created_at)}}function kd(e,t){if(e==="*"||e==="**")return!0;let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"\x01").replace(/\*/g,"[^/]*").replace(/\u0001/g,".*");return new RegExp(`^${r}$`).test(t)}class yo{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}now(){return(this.options.now?.()??new Date).toISOString()}query(e,t=[]){return this.controlPlane.database.query(e).all(...t)}upsert(e){let t=e.signal.trim();if(!t)throw Error("An anomaly config needs a signal.");if(e.seasonLength!=null&&(!Number.isInteger(e.seasonLength)||e.seasonLength<1))throw Error("seasonLength must be a positive integer.");let r=Sr(e.organizationId,e.projectId,e.environmentId),n=this.now(),o=this.query("SELECT * FROM anomaly_configs WHERE scope_key = ? AND signal = ?",[r,t])[0],i=as(t);if(o)return this.controlPlane.database.run("UPDATE anomaly_configs SET enabled=?,sensitivity=?,season_length=?,min_absolute_delta=?,detect_drops=?,severity=?,version=version+1,updated_at=? WHERE id=?",[e.enabled===!1?0:1,e.sensitivity??String(o.sensitivity),e.seasonLength??Number(o.season_length),e.minAbsoluteDelta??Number(o.min_absolute_delta),e.detectDrops==null?Number(o.detect_drops):e.detectDrops?1:0,e.severity??String(o.severity),n,String(o.id)]),this.get(String(o.id));let s=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO anomaly_configs (id,organization_id,project_id,environment_id,scope_key,signal,enabled,sensitivity,season_length,min_absolute_delta,detect_drops,severity,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,1,?,?)",[s,e.organizationId,e.projectId??null,e.environmentId??null,r,t,e.enabled===!1?0:1,e.sensitivity??"medium",e.seasonLength??i.seasonLength??24,e.minAbsoluteDelta??i.minAbsoluteDelta??0,e.detectDrops?1:0,e.severity??"warning",n,n]),this.get(s)}get(e){let t=this.query("SELECT * FROM anomaly_configs WHERE id = ?",[e])[0];return t?Re(t):void 0}list(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);return this.query(`SELECT * FROM anomaly_configs WHERE ${t.join(" AND ")} ORDER BY signal`,r).map(Re)}delete(e){return this.controlPlane.database.run("DELETE FROM anomaly_configs WHERE id = ?",[e]).changes>0}optionsFor(e,t){let r=[Sr(e.organizationId,e.projectId,e.environmentId),Sr(e.organizationId,e.projectId),Sr(e.organizationId)];for(let n of r){let o=this.query("SELECT * FROM anomaly_configs WHERE scope_key = ? AND signal = ?",[n,t])[0];if(!o)continue;let i=Re(o);return{config:i,enabled:i.enabled,options:{...as(t),threshold:Nd[i.sensitivity],seasonLength:i.seasonLength,minAbsoluteDelta:i.minAbsoluteDelta,detectDrops:i.detectDrops}}}return{options:as(t),enabled:!0}}silence(e){let t=e.reason.trim();if(!t)throw Error("A silence needs a reason: someone will ask why this stopped alerting.");if(!e.signal&&!e.routePattern&&e.statusCode==null)throw Error("A silence needs at least one of signal, routePattern, or statusCode.");let r=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO anomaly_silences (id,organization_id,project_id,scope_key,signal,route_pattern,status_code,reason,actor_id,expires_at,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)",[r,e.organizationId,e.projectId??null,Sr(e.organizationId,e.projectId),e.signal??null,e.routePattern??null,e.statusCode??null,t,e.actorId??null,e.expiresAt??null,this.now()]),this.listSilences({organizationId:e.organizationId}).find((n)=>n.id===r)}listSilences(e){let t=["organization_id = ?"],r=[e.organizationId];if(e.projectId)t.push("(project_id IS NULL OR project_id = ?)"),r.push(e.projectId);if(!e.includeExpired)t.push("(expires_at IS NULL OR expires_at > ?)"),r.push(this.now());return this.query(`SELECT * FROM anomaly_silences WHERE ${t.join(" AND ")} ORDER BY created_at DESC`,r).map(fr)}removeSilence(e){return this.controlPlane.database.run("DELETE FROM anomaly_silences WHERE id = ?",[e]).changes>0}isSilenced(e,t){return this.listSilences(e).find((r)=>{if(r.signal&&r.signal!==t.signal)return!1;if(r.statusCode!=null&&r.statusCode!==t.statusCode)return!1;if(r.routePattern){if(!t.route)return!1;if(!kd(r.routePattern,t.route))return!1}return!0})}}var Lt=[{key:"cost",routeAware:!1,label:"Cost",source:"usage",gapPolicy:"zero",minSamples:0,unit:"cents"},{key:"edge.requests",routeAware:!1,label:"Edge requests",source:"usage",gapPolicy:"zero",minSamples:0,unit:"requests"},{key:"edge.egress_gb",routeAware:!1,label:"Edge egress",source:"usage",gapPolicy:"zero",minSamples:0,unit:"GB"},{key:"function.invocations",routeAware:!1,label:"Function invocations",source:"usage",gapPolicy:"zero",minSamples:0,unit:"invocations"},{key:"http.requests",routeAware:!0,label:"HTTP requests",source:"telemetry",gapPolicy:"zero",minSamples:0,unit:"requests"},{key:"http.errors",routeAware:!0,label:"HTTP 5xx",source:"telemetry",gapPolicy:"zero",minSamples:0,unit:"responses"},{key:"http.error_rate",routeAware:!0,label:"HTTP error rate",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ratio",ratio:!0},{key:"http.client_error_rate",routeAware:!0,label:"HTTP 4xx rate",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ratio",ratio:!0},{key:"http.latency_p95",routeAware:!0,label:"Latency p95",source:"telemetry",gapPolicy:"gap",minSamples:20,unit:"ms"}];function bo(e){return Lt.find((t)=>t.key===e)}var G=3600000;function Ir(e,t=960){let r=Math.floor(new Date(e.from).getTime()/G)*G,n=new Date(e.to).getTime(),o=[];for(let i=r;i<n&&o.length<t;i+=G)o.push(i);return o}function Pe(e,t,r){let n=[],o=0,i=0;for(let s of Ir(t)){let a=r.get(s),d=new Date(s).toISOString();if(!a){n.push({bucketStart:d,value:e.gapPolicy==="zero"?0:Number.NaN});continue}if(a.samples<e.minSamples){n.push({bucketStart:d,value:Number.NaN}),i++;continue}n.push({bucketStart:d,value:a.value}),o++}return{signal:e.key,points:n,populated:o,suppressed:i,unit:e.unit}}class So{controlPlane;spend;counterCache=new Map;constructor(e,t){this.controlPlane=e;this.spend=t}query(e,t){return this.controlPlane.database.query(e).all(...t)}usageSeries(e,t,r){let n=this.spend.summarizeUsage({organizationId:t.organizationId,projectId:t.projectId,environmentId:t.environmentId,meters:e.key==="cost"?void 0:[e.key],from:r.from,to:r.to}),o=new Map;for(let i of n.series)o.set(new Date(i.bucketStart).getTime(),{value:e.key==="cost"?i.costCents:i.quantity,samples:1});return Pe(e,r,o)}requestFilter(e,t){let r=["project_id = ?","kind = 'request'","timestamp >= ?","timestamp < ?"],n=[e.projectId,t.from,t.to];if(e.environmentId)r.push("environment_id = ?"),n.push(e.environmentId);if(e.route)r.push("path_template = ?"),n.push(e.route);return{clauses:r,bindings:n}}counters(e,t){let r=[e.projectId,e.environmentId??"",e.route??"",t.from,t.to].join("\x00"),n=this.counterCache.get(r);if(n)return n;let{clauses:o,bindings:i}=this.requestFilter(e,t),s=this.query(`SELECT
|
|
10
10
|
CAST(strftime('%s', timestamp) AS INTEGER) / 3600 AS bucket,
|
|
11
11
|
COUNT(*) AS total,
|
|
12
12
|
SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) AS server_errors,
|
|
@@ -29,9 +29,9 @@ import{re,h}from"./chunk-twmeg17s.js";import{us}from"./chunk-bfzdbe4g.js";var Lp
|
|
|
29
29
|
GROUP BY bucket
|
|
30
30
|
ORDER BY bucket`,o),s=new Map;for(let a of i)s.set(Number(a.bucket)*G,{value:Number(a.value),samples:Number(a.samples)});return Pe(e,r,s)}series(e,t,r){let n=bo(e);if(!n)return{signal:e,points:[],populated:0,suppressed:0,unit:""};return n.source==="usage"?this.usageSeries(n,t,r):this.telemetrySeries(n,t,r)}busiestRoutes(e,t,r=10,n=500){if(!e.projectId)return[];let o=["kind = 'request'","project_id = ?","timestamp >= ?","timestamp < ?","path_template IS NOT NULL"],i=[e.projectId,t.from,t.to];if(e.environmentId)o.push("environment_id = ?"),i.push(e.environmentId);return this.query(`SELECT path_template, COUNT(*) AS total FROM telemetry_records
|
|
31
31
|
WHERE ${o.join(" AND ")}
|
|
32
|
-
GROUP BY path_template HAVING total >= ? ORDER BY total DESC LIMIT ?`,[...i,n,Math.max(1,Math.min(50,r))]).map((s)=>String(s.path_template))}}function vo(e){let t={seasonLength:24,threshold:3.5,minHistory:3,minAbsoluteDelta:0,detectDrops:!1};if(e==="cost")return{...t,minAbsoluteDelta:25};if(e==="edge.requests"||e==="http.requests")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:1000,detectDrops:!0};if(e==="edge.egress_gb")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:5};if(e==="function.invocations")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:1000};if(e==="http.errors")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:25};if(e==="http.error_rate"||e==="http.client_error_rate")return{...t,seasonLength:168,threshold:3.5,minAbsoluteDelta:0.02};if(e==="http.latency_p95")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:100};return t}function xc(e){let t=vo(e),r=t.seasonLength*(t.minHistory+1);return Math.min(960,Math.max(336,r))}var
|
|
32
|
+
GROUP BY path_template HAVING total >= ? ORDER BY total DESC LIMIT ?`,[...i,n,Math.max(1,Math.min(50,r))]).map((s)=>String(s.path_template))}}function vo(e){let t={seasonLength:24,threshold:3.5,minHistory:3,minAbsoluteDelta:0,detectDrops:!1};if(e==="cost")return{...t,minAbsoluteDelta:25};if(e==="edge.requests"||e==="http.requests")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:1000,detectDrops:!0};if(e==="edge.egress_gb")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:5};if(e==="function.invocations")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:1000};if(e==="http.errors")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:25};if(e==="http.error_rate"||e==="http.client_error_rate")return{...t,seasonLength:168,threshold:3.5,minAbsoluteDelta:0.02};if(e==="http.latency_p95")return{...t,seasonLength:168,threshold:4,minAbsoluteDelta:100};return t}function xc(e){let t=vo(e),r=t.seasonLength*(t.minHistory+1);return Math.min(960,Math.max(336,r))}var xd="1.3";function _r(e){if(e.startsWith("edge.")||e.startsWith("object.egress"))return"Networking";if(e.startsWith("function.")||e.startsWith("compute.")||e.startsWith("build."))return"Compute";if(e.startsWith("storage.")||e.startsWith("object."))return"Storage";if(e.startsWith("database."))return"Databases";if(e.startsWith("telemetry."))return"Management and Governance";return"Other"}function ct(e){return nn[e]?.label??e}function lt(e){let t=nn[e]?.unit;if(t==="gb")return"GB";if(t==="gb_hours")return"GB-Hours";if(t==="gb_seconds")return"GB-Seconds";if(t==="hours")return"Hours";if(t==="minutes")return"Minutes";if(t==="requests")return"Requests";if(t==="invocations")return"Invocations";return"Count"}function Er(e){return`${e.slice(0,10)}T00:00:00.000Z`}function wr(e){return new Date(new Date(e).getTime()+86400000).toISOString()}function Ar(e){return new Date(new Date(e).getTime()+3600000).toISOString()}function _c(e,t){let r=t.currency??"USD",n=(t.granularity??"daily")==="daily",o=new Map;for(let i of e){let s=n?Er(i.bucketStart):i.bucketStart,a=[s,i.meter,i.provider,i.region,i.projectId,i.resourceId].join("\x00"),d=o.get(a);if(d)d.quantity+=i.quantity,d.costCents+=i.costCents;else o.set(a,{rollup:i,quantity:i.quantity,costCents:i.costCents,start:s})}return[...o.values()].sort((i,s)=>i.start.localeCompare(s.start)||String(i.rollup.meter).localeCompare(String(s.rollup.meter))).map(({rollup:i,quantity:s,costCents:a,start:d})=>{let c=Math.round(a)/100,u=i.provider||"ts-cloud";return{FocusVersion:xd,ChargePeriodStart:d,ChargePeriodEnd:n?wr(d):Ar(d),BillingPeriodStart:t.billingPeriodStart,BillingPeriodEnd:t.billingPeriodEnd,BillingCurrency:r,BilledCost:c,EffectiveCost:c,ListCost:c,ChargeCategory:"Usage",ChargeDescription:`${ct(i.meter)} on ${u}`,ProviderName:u,PublisherName:u,InvoiceIssuerName:u,ServiceName:ct(i.meter),ServiceCategory:_r(String(i.meter)),SkuId:String(i.meter),PricingUnit:lt(String(i.meter)),PricingQuantity:s,ConsumedQuantity:s,ConsumedUnit:lt(String(i.meter)),RegionId:i.region||void 0,ResourceId:i.resourceId||void 0,SubAccountId:i.projectId||void 0,SubAccountName:i.projectId?t.projectNames?.[i.projectId]??i.projectId:void 0,Tags:{...i.environmentId?{environment:i.environmentId}:{},...i.projectId?{project:i.projectId}:{}}}})}function Co(e){return e.map((t)=>JSON.stringify(t)).join(`
|
|
33
33
|
`)+(e.length>0?`
|
|
34
|
-
`:"")}function*Hp(e,t=500){for(let r=0;r<e.length;r+=t)yield Co(e.slice(r,r+t))}class ht{store;counters=new go;breaching=new Map;anomalyConfigs;signals;constructor(e){this.store=e;this.anomalyConfigs=new yo(e.controlPlane),this.signals=new So(e.controlPlane,e)}ingestTelemetry(e,t,r){let n=Tc(e,t,{counters:this.counters,defaultProvider:r});return this.store.ingestUsage(n)}ingestUsage(e,t=!0){return this.store.ingestUsage(t?Ec(e):[...e])}status(e,t=new Date){let{window:r,summary:n}=this.store.budgetSpendCents(e,t),i=this.store.listEnforcements({organizationId:e.organizationId,budgetId:e.id,activeOnly:!0}).filter((a)=>a.state==="active").map((a)=>a.action),s=Ac({budget:e,window:r,actualCents:n.totalCents,series:n.series,activeActions:i,breachingSince:this.breaching.get(e.id),now:t});return{budget:e,decision:s,summary:n,activeActions:i,timeToCap:fi(s.projection.timeToExhaustionMs)}}async runCycle(e){let t=e.now??new Date,r=this.store.budgetsForScope(e.organizationId,e.projectId,e.environmentId),n=[],o=[];for(let s of r){let a=this.status(s,t);this.trackBreach(s,a.decision,t),this.store.recordDecision(a.decision),n.push(a)}let i=Rc(n.map((s)=>s.decision));if(e.handlers){let s={environmentKind:e.environmentKind,...e.policy};for(let a of n){let d=Ic(a.decision,s);if(d.apply.length===0&&d.release.length===0&&d.withheld.length===0)continue;o.push(await Pc(this.store,a.budget,a.decision,d,e.handlers))}}return{organizationId:e.organizationId,statuses:n,level:i.level,actions:i.actions,releases:i.releases,enforcement:o,anomalies:this.detectAnomalies(e,t),evaluatedAt:t.toISOString()}}trackBreach(e,t,r){if(!t.breaches.some((o)=>o.actions.some((i)=>i!=="notify"))){this.breaching.delete(e.id);return}if(!this.breaching.has(e.id))this.breaching.set(e.id,r.toISOString())}detectAnomalies(e,t=new Date,r={}){let n=new Date(Math.floor(t.getTime()/3600000)*3600000).toISOString(),o={organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId},i=e.signals??Lt.map((d)=>d.key),s=[],a;for(let d of i){let c=r.seasonLength?Math.max(336,r.seasonLength*((r.minHistory??3)+1)):xc(d),u={from:new Date(new Date(n).getTime()-c*3600000).toISOString(),to:n};if(s.push(...this.detectSignal(d,o,u,r)),!e.routes)continue;if(!bo(d)?.routeAware)continue;a??=this.signals.busiestRoutes(o,u);for(let p of a){if(this.anomalyConfigs.isSilenced(o,{signal:d,route:p}))continue;s.push(...this.detectSignal(d,{...o,route:p},u,r,p))}}return this.signals.resetCache(),s}detectSignal(e,t,r,n,o){let i=this.anomalyConfigs.optionsFor(t,e);if(!i.enabled)return[];if(!o&&this.anomalyConfigs.isSilenced(t,{signal:e}))return[];let s=this.signals.series(e,t,r);if(s.points.length===0)return[];let a=kc(s.points,{...vo(e),...i.options,...n});if(!a)return[];let d=this.store.recordAnomaly({organizationId:t.organizationId,projectId:t.projectId,environmentId:t.environmentId,signal:o?`${e}@${o}`:e,direction:a.direction,observed:a.observed,expected:a.expected,score:a.score,deltaPercent:Number.isFinite(a.deltaPercent)?a.deltaPercent:0,severity:i.config?.severity??a.severity,bucketStart:a.bucketStart,evidence:{historySize:a.historySize,deviation:a.deviation,unit:s.unit,populatedBuckets:s.populated,suppressedBuckets:s.suppressed,route:o??null,lookbackFrom:r.from,lookbackTo:r.to}});return d?[d]:[]}usageReport(e){let t=e.now??new Date,r=br(e.period??"monthly",e.timezone??"UTC",t),n=this.store.summarizeUsage({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,from:r.start,to:r.end}),o=this.store.budgetsForScope(e.organizationId,e.projectId,e.environmentId).map((s)=>{let a=this.status(s,t),d=ss(s);return{id:s.id,name:s.name,period:s.period,limitCents:d,softLimitCents:s.softLimitCents,hardLimitCents:s.hardLimitCents,spentCents:a.decision.projection.actualCents,remainingCents:d==null?null:Math.max(0,d-a.decision.projection.actualCents),usedPercent:a.decision.usedPercent,projectedCents:a.decision.projection.projectedCents,projectedPercent:a.decision.projectedPercent,projectionConfidence:a.decision.projection.confidence,level:a.decision.level,timeToCap:a.timeToCap,activeActions:a.activeActions,dryRun:s.dryRun}}),i=this.store.listEnforcements({organizationId:e.organizationId,activeOnly:!0});return{organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,window:{start:r.start,end:r.end,label:r.label},currency:this.store.priceBook.currency,totalCents:n.totalCents,byMeter:n.byMeter,series:n.series,budgets:o,enforcement:{strongestAction:Dc(i)??null,active:i.map((s)=>({id:s.id,budgetId:s.budgetId,action:s.action,state:s.state,reason:s.reason,simulated:s.simulated,appliedAt:s.appliedAt}))},generatedAt:t.toISOString(),currentBucket:gi(t)}}}function Gp(e,t,r,n=1440){let o=new Map(e.map((d)=>[d.bucketStart,d.value])),i=Math.floor(new Date(t).getTime()/3600000)*3600000,s=new Date(r).getTime(),a=[];for(let d=i;d<s&&a.length<n;d+=3600000){let c=new Date(d).toISOString();a.push({bucketStart:c,value:o.get(c)??0})}return a}var Oc="spend.gates",Rr={build:["block_builds","suspend_project"],deploy:["block_deployments","suspend_project"],function_invoke:["suspend_functions","serve_static","suspend_project"],request:["suspend_project"]};function pe(e){return`${e.budgetId}:${e.action}`}function Pr(e,t){if(e.organizationId!==t.organizationId)return!1;if(e.projectId&&e.projectId!==t.projectId)return!1;if(e.environmentId&&e.environmentId!==t.environmentId)return!1;return!0}function Cr(e,t){if(e.organizationId!==t.organizationId)return!1;if(t.projectId&&e.projectId!==t.projectId)return!1;if(t.environmentId&&e.environmentId!==t.environmentId)return!1;return!0}function kr(e){let t={...e};for(let r of["projectId","environmentId"])if(t[r]==null)delete t[r];return t}class Mt{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}read(){let e=this.controlPlane.getSetting(Oc);return Array.isArray(e)?e:[]}write(e){this.controlPlane.setSetting(Oc,e)}list(e){return this.read().filter((t)=>!e||Pr(t,e)).sort((t,r)=>oe[r.action]-oe[t.action])}listUnder(e){return this.read().filter((t)=>Cr(t,e)).sort((t,r)=>oe[r.action]-oe[t.action])}open(e){let t=e.appliedAt??(this.options.now?.()??new Date).toISOString(),r=kr({...e,appliedAt:t}),n=this.read().filter((o)=>pe(o)!==pe(r));return n.push(r),this.write(n),r}close(e,t){let r=this.read(),n=r.filter((o)=>pe(o)!==pe({budgetId:e,action:t}));if(n.length===r.length)return!1;return this.write(n),!0}closeBudget(e){let t=this.read(),r=t.filter((n)=>n.budgetId!==e);return this.write(r),t.length-r.length}check(e,t){let r=Rr[e]??[];for(let n of this.list(t)){if(n.simulated)continue;if(!r.includes(n.action))continue;return{allowed:!1,action:n.action,budgetId:n.budgetId,reason:`${n.reason} ${os[n.action]}`}}return{allowed:!0}}strongest(e){return this.list(e).find((t)=>!t.simulated)?.action}}class $c extends Error{operation;verdict;code="spend_cap_exceeded";status=402;constructor(e,t){super(t.reason??`A spend cap is blocking this ${e}.`);this.operation=e;this.verdict=t}}function qp(e,t,r){let n=e.check(t,r);if(!n.allowed)throw new $c(t,n)}var ut=["notify","block_builds","block_deployments"];function Lc(e){let t=e.throttleFactor??0.5;return{apply:async(o,i)=>{let{budget:s,record:a,decision:d}=i;e.gate.open({budgetId:s.id,action:o,organizationId:s.organizationId,projectId:s.projectId,environmentId:s.environmentId,reason:d.reason,simulated:a.simulated});let c={gated:!0};if(!a.simulated&&!ut.includes(o)){let u={projectId:s.projectId,environmentId:s.environmentId},p=e.transport;if(o==="throttle_requests"&&p?.throttleRequests)c={...await p.throttleRequests({...u,factor:t}),gated:!0};else if(o==="suspend_functions"&&p?.suspendFunctions)c={...await p.suspendFunctions(u),gated:!0};else if(o==="serve_static"&&p?.serveStatic)c={...await p.serveStatic(u),gated:!0};else if(o==="suspend_project"&&p?.suspendProject)c={...await p.suspendProject(u),gated:!0};else c={gated:!0,unsupported:!0}}return await e.notify?.({action:o,budgetId:s.id,reason:d.reason,simulated:a.simulated,released:!1}),c},release:async(o,i)=>{let{budget:s,record:a,restore:d}=i,c=e.transport;if(!a.simulated&&!ut.includes(o)&&d.unsupported!==!0){if(o==="throttle_requests"&&c?.restoreRequests)await c.restoreRequests(d);else if(o==="suspend_functions"&&c?.resumeFunctions)await c.resumeFunctions(d);else if(o==="serve_static"&&c?.restoreDynamic)await c.restoreDynamic(d);else if(o==="suspend_project"&&c?.resumeProject)await c.resumeProject(d)}e.gate.close(s.id,o),await e.notify?.({action:o,budgetId:s.id,reason:a.reason,simulated:a.simulated,released:!0})}}}class xd{calls=[];record(e,t){return this.calls.push({method:e,input:t}),{recorded:e}}throttleRequests(e){return this.record("throttleRequests",e)}restoreRequests(e){this.record("restoreRequests",e)}suspendFunctions(e){return this.record("suspendFunctions",e)}resumeFunctions(e){this.record("resumeFunctions",e)}serveStatic(e){return this.record("serveStatic",e)}restoreDynamic(e){this.record("restoreDynamic",e)}suspendProject(e){return this.record("suspendProject",e)}resumeProject(e){this.record("resumeProject",e)}}import{createCipheriv as Tr,createDecipheriv as Dr,createHash as _t,randomBytes as Or}from"node:crypto";var O=(e)=>{if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}},E=(e)=>typeof e==="string"?e:void 0,Te=(e)=>Number(e)===1,M=(e,t,r,n)=>{let o=Number(e);return Number.isFinite(o)?Math.min(n,Math.max(r,Math.floor(o))):t},pt=(e)=>_t("sha256").update(e).digest("hex").slice(0,16);function yt(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),name:String(e.name),kind:String(e.kind),target:String(e.target),config:O(e.config),intervalSeconds:Number(e.interval_seconds),timeoutSeconds:Number(e.timeout_seconds),failureThreshold:Number(e.failure_threshold),recoveryThreshold:Number(e.recovery_threshold),regions:O(e.regions),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function vt(e){return{id:String(e.id),checkId:String(e.check_id),status:String(e.status),agent:String(e.agent),region:E(e.region),statusCode:e.status_code==null?void 0:Number(e.status_code),message:E(e.message),timings:O(e.timings),checkedAt:String(e.checked_at)}}function bt(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),healthCheckId:E(e.health_check_id),name:String(e.name),signal:String(e.signal),operator:String(e.operator),threshold:e.threshold==null?void 0:Number(e.threshold),recoveryThreshold:e.recovery_threshold==null?void 0:Number(e.recovery_threshold),windowMs:Number(e.window_ms),consecutive:Number(e.consecutive),recoveryConsecutive:Number(e.recovery_consecutive),noDataPolicy:String(e.no_data_policy),severity:String(e.severity),groupBy:O(e.group_by),labels:O(e.labels),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Ce(e){return{id:String(e.id),ruleId:String(e.rule_id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),dedupKey:String(e.dedup_key),groupKey:String(e.group_key),state:String(e.state),severity:String(e.severity),title:String(e.title),evidence:O(e.evidence),failureCount:Number(e.failure_count),recoveryCount:Number(e.recovery_count),occurrenceCount:Number(e.occurrence_count),ownerActorId:E(e.owner_actor_id),acknowledgedByActorId:E(e.acknowledged_by_actor_id),acknowledgedAt:E(e.acknowledged_at),firstSeenAt:String(e.first_seen_at),lastSeenAt:String(e.last_seen_at),firingAt:E(e.firing_at),resolvedAt:E(e.resolved_at),silencedUntil:E(e.silenced_until),updatedAt:String(e.updated_at)}}function St(e){return{id:String(e.id),organizationId:String(e.organization_id),name:String(e.name),kind:String(e.kind),config:O(e.config),credentialFingerprint:E(e.credential_fingerprint),hasCredential:!!e.credential_ciphertext,status:String(e.status),version:Number(e.version),lastTestedAt:E(e.last_tested_at),lastError:E(e.last_error),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function It(e){return{id:String(e.id),organizationId:String(e.organization_id),name:String(e.name),priority:Number(e.priority),matcher:O(e.matcher),channelIds:O(e.channel_ids),quietHours:e.quiet_hours?O(e.quiet_hours):void 0,groupWaitSeconds:Number(e.group_wait_seconds),reminderSeconds:e.reminder_seconds==null?void 0:Number(e.reminder_seconds),escalation:O(e.escalation),template:E(e.template),rateLimitPerMinute:Number(e.rate_limit_per_minute),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function ke(e){return{id:String(e.id),alertId:E(e.alert_id),channelId:String(e.channel_id),routeId:E(e.route_id),eventType:String(e.event_type),idempotencyKey:String(e.idempotency_key),state:String(e.state),attempt:Number(e.attempt),maxAttempts:Number(e.max_attempts),nextAttemptAt:E(e.next_attempt_at),responseStatus:e.response_status==null?void 0:Number(e.response_status),error:E(e.error),payload:O(e.payload),createdAt:String(e.created_at),updatedAt:String(e.updated_at),deliveredAt:E(e.delivered_at)}}class ft{controlPlane;options;key;constructor(e,t){this.controlPlane=e;this.options=t;this.key=_t("sha256").update(t.encryptionKey).digest()}now(){return(this.options.now?.()??new Date).toISOString()}encrypt(e){let t=Or(12),r=Tr("aes-256-gcm",this.key,t),n=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${n.toString("base64url")}`}decrypt(e){let[,t,r,n]=e.split("."),o=Dr("aes-256-gcm",this.key,Buffer.from(t,"base64url"));return o.setAuthTag(Buffer.from(r,"base64url")),Buffer.concat([o.update(Buffer.from(n,"base64url")),o.final()]).toString("utf8")}createHealthCheck(e){if(!e.name.trim())throw Error("Health checks require a name.");if(!["http","tcp","command"].includes(e.kind))throw Error("Unsupported health check kind.");if(e.kind==="http"&&!/^https?:\/\//.test(e.target)||e.kind==="tcp"&&!/^[a-zA-Z0-9.-]+$/.test(e.target)||e.kind==="command"&&!e.config.command?.length)throw Error("Health check target is invalid.");let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO health_checks (id,project_id,environment_id,resource_id,name,kind,target,config,interval_seconds,timeout_seconds,failure_threshold,recovery_threshold,regions,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.projectId,e.environmentId??null,e.resourceId??null,e.name.trim().slice(0,100),e.kind,e.target,JSON.stringify(e.config),M(e.intervalSeconds,60,10,86400),M(e.timeoutSeconds,10,1,300),M(e.failureThreshold,3,1,100),M(e.recoveryThreshold,2,1,100),JSON.stringify(e.regions.slice(0,20)),e.enabled?1:0,1,r,r]),this.getHealthCheck(t)}getHealthCheck(e){let t=this.controlPlane.database.query("SELECT * FROM health_checks WHERE id=?").get(e);return t?yt(t):void 0}listHealthChecks(e,t){return this.controlPlane.database.query(`SELECT * FROM health_checks WHERE project_id=?${t?" AND environment_id=?":""} ORDER BY updated_at DESC`).all(e,...t?[t]:[]).map(yt)}setHealthCheckEnabled(e,t){this.controlPlane.database.run("UPDATE health_checks SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getHealthCheck(e);if(!r)throw Error("Health check was not found.");return r}appendHealthResult(e){let t=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO health_results (id,check_id,status,agent,region,status_code,message,timings,checked_at) VALUES (?,?,?,?,?,?,?,?,?)",[t,e.checkId,e.status,e.agent.slice(0,100),e.region??null,e.statusCode??null,e.message?.slice(0,1000)??null,JSON.stringify(e.timings),e.checkedAt]),vt(this.controlPlane.database.query("SELECT * FROM health_results WHERE id=?").get(t))}listHealthResults(e,t=100){return this.controlPlane.database.query("SELECT * FROM health_results WHERE check_id=? ORDER BY checked_at DESC LIMIT ?").all(e,Math.min(1000,Math.max(1,t))).map(vt)}createRule(e){if(!e.name.trim())throw Error("Alert rules require a name.");if(e.operator!=="unhealthy"&&e.threshold==null)throw Error("Metric alert rules require a threshold.");let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO alert_rules (id,project_id,environment_id,resource_id,health_check_id,name,signal,operator,threshold,recovery_threshold,window_ms,consecutive,recovery_consecutive,no_data_policy,severity,group_by,labels,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.projectId,e.environmentId??null,e.resourceId??null,e.healthCheckId??null,e.name.trim().slice(0,120),e.signal,e.operator,e.threshold??null,e.recoveryThreshold??null,M(e.windowMs,300000,1e4,2678400000),M(e.consecutive,3,1,100),M(e.recoveryConsecutive,2,1,100),e.noDataPolicy,e.severity,JSON.stringify(e.groupBy.slice(0,20)),JSON.stringify(e.labels),e.enabled?1:0,1,r,r]),this.getRule(t)}getRule(e){let t=this.controlPlane.database.query("SELECT * FROM alert_rules WHERE id=?").get(e);return t?bt(t):void 0}listRules(e,t){return this.controlPlane.database.query(`SELECT * FROM alert_rules WHERE project_id=?${t?" AND environment_id=?":""} ORDER BY updated_at DESC`).all(e,...t?[t]:[]).map(bt)}setRuleEnabled(e,t){this.controlPlane.database.run("UPDATE alert_rules SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getRule(e);if(!r)throw Error("Alert rule was not found.");return r}getAlertByDedup(e){let t=this.controlPlane.database.query("SELECT * FROM alerts WHERE dedup_key=?").get(e);return t?Ce(t):void 0}getAlert(e){let t=this.controlPlane.database.query("SELECT * FROM alerts WHERE id=?").get(e);return t?Ce(t):void 0}listAlerts(e,t={}){let r=["project_id=?"],n=[e];if(t.environmentId)r.push("environment_id=?"),n.push(t.environmentId);if(t.states?.length)r.push(`state IN (${t.states.map(()=>"?").join(",")})`),n.push(...t.states);return this.controlPlane.database.query(`SELECT * FROM alerts WHERE ${r.join(" AND ")} ORDER BY updated_at DESC LIMIT ?`).all(...n,Math.min(1000,t.limit??200)).map(Ce)}saveAlert(e,t,r){return this.controlPlane.database.run("INSERT INTO alerts (id,rule_id,project_id,environment_id,resource_id,dedup_key,group_key,state,severity,title,evidence,failure_count,recovery_count,occurrence_count,owner_actor_id,acknowledged_by_actor_id,acknowledged_at,first_seen_at,last_seen_at,firing_at,resolved_at,silenced_until,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,severity=excluded.severity,title=excluded.title,evidence=excluded.evidence,failure_count=excluded.failure_count,recovery_count=excluded.recovery_count,occurrence_count=excluded.occurrence_count,owner_actor_id=excluded.owner_actor_id,acknowledged_by_actor_id=excluded.acknowledged_by_actor_id,acknowledged_at=excluded.acknowledged_at,last_seen_at=excluded.last_seen_at,firing_at=excluded.firing_at,resolved_at=excluded.resolved_at,silenced_until=excluded.silenced_until,updated_at=excluded.updated_at",[e.id,e.ruleId,e.projectId,e.environmentId??null,e.resourceId??null,e.dedupKey,e.groupKey,e.state,e.severity,e.title,JSON.stringify(e.evidence),e.failureCount,e.recoveryCount,e.occurrenceCount,e.ownerActorId??null,e.acknowledgedByActorId??null,e.acknowledgedAt??null,e.firstSeenAt,e.lastSeenAt,e.firingAt??null,e.resolvedAt??null,e.silencedUntil??null,e.updatedAt]),this.controlPlane.database.run("INSERT INTO alert_events (id,alert_id,type,actor_id,payload,created_at) VALUES (?,?,?,?,?,?)",[crypto.randomUUID(),e.id,t,r??null,JSON.stringify({state:e.state,severity:e.severity,evidence:e.evidence}),e.updatedAt]),this.getAlert(e.id)}acknowledge(e,t){let r=this.getAlert(e);if(!r)throw Error("Alert was not found.");let n=this.now();return this.saveAlert({...r,acknowledgedByActorId:t,acknowledgedAt:n,updatedAt:n},"acknowledged",t)}assign(e,t,r){let n=this.getAlert(e);if(!n)throw Error("Alert was not found.");let o=this.now();return this.saveAlert({...n,ownerActorId:t,updatedAt:o},"assigned",r)}silenceAlert(e,t,r){let n=this.getAlert(e);if(!n)throw Error("Alert was not found.");let o=new Date(t);if(!Number.isFinite(o.getTime())||o<=new Date)throw Error("Silence end must be in the future.");let i=this.now();return this.saveAlert({...n,state:"silenced",silencedUntil:o.toISOString(),updatedAt:i},"silenced",r)}createSilence(e){let t=new Date(e.startsAt),r=new Date(e.endsAt);if(!Number.isFinite(t.getTime())||!Number.isFinite(r.getTime())||t>=r)throw Error("Silence window is invalid.");try{new Intl.DateTimeFormat("en",{timeZone:e.timezone}).format(t)}catch{throw Error("Silence timezone is invalid.")}let n=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO alert_silences (id,project_id,environment_id,resource_id,matcher,reason,starts_at,ends_at,timezone,created_by_actor_id,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)",[n,e.projectId,e.environmentId??null,e.resourceId??null,JSON.stringify(e.matcher??{}),e.reason.slice(0,500),t.toISOString(),r.toISOString(),e.timezone,e.actorId??null,this.now()]),n}isSilenced(e,t,r){return this.controlPlane.database.query("SELECT * FROM alert_silences WHERE project_id=? AND starts_at<=? AND ends_at>?").all(e.projectId,r,r).some((o)=>{if(o.environment_id&&o.environment_id!==e.environmentId)return!1;if(o.resource_id&&o.resource_id!==e.resourceId)return!1;let i=O(o.matcher);return Object.entries(i).every(([s,a])=>t[s]===a)})}createChannel(e){if(!e.name.trim())throw Error("Notification channels require a name.");let t=crypto.randomUUID(),r=this.now(),n=e.credential?.trim();return this.controlPlane.database.run("INSERT INTO notification_channels (id,organization_id,name,kind,config,credential_ciphertext,credential_fingerprint,status,version,created_by_actor_id,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.name.trim().slice(0,100),e.kind,JSON.stringify(e.config??{}),n?this.encrypt(n):null,n?pt(n):null,"active",1,e.actorId??null,r,r]),this.getChannel(t)}getChannel(e){let t=this.controlPlane.database.query("SELECT * FROM notification_channels WHERE id=?").get(e);return t?St(t):void 0}channelCredential(e){let t=this.controlPlane.database.query("SELECT credential_ciphertext FROM notification_channels WHERE id=?").get(e);return t?.credential_ciphertext?this.decrypt(String(t.credential_ciphertext)):void 0}listChannels(e){return this.controlPlane.database.query("SELECT * FROM notification_channels WHERE organization_id=? ORDER BY updated_at DESC").all(e).map(St)}rotateChannel(e,t){let r=this.now();this.controlPlane.database.run("UPDATE notification_channels SET credential_ciphertext=?,credential_fingerprint=?,status='active',last_error=NULL,version=version+1,updated_at=? WHERE id=?",[this.encrypt(t),pt(t),r,e]);let n=this.getChannel(e);if(!n)throw Error("Notification channel was not found.");return n}setChannelStatus(e,t,r){this.controlPlane.database.run("UPDATE notification_channels SET status=?,last_error=?,updated_at=? WHERE id=?",[t,r?.slice(0,1000)??null,this.now(),e]);let n=this.getChannel(e);if(!n)throw Error("Notification channel was not found.");return n}markChannelTest(e,t,r){let n=this.now();return this.controlPlane.database.run("UPDATE notification_channels SET status=?,last_tested_at=?,last_error=?,updated_at=? WHERE id=?",[t?"active":"failing",n,r?.slice(0,1000)??null,n,e]),this.getChannel(e)}createRoute(e){let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO notification_routes (id,organization_id,name,priority,matcher,channel_ids,quiet_hours,group_wait_seconds,reminder_seconds,escalation,template,rate_limit_per_minute,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.name.trim().slice(0,100),e.priority,JSON.stringify(e.matcher),JSON.stringify(e.channelIds),e.quietHours?JSON.stringify(e.quietHours):null,M(e.groupWaitSeconds,30,0,86400),e.reminderSeconds??null,JSON.stringify(e.escalation),e.template?.trim().slice(0,2000)??null,M(e.rateLimitPerMinute,60,1,1e4),e.enabled?1:0,1,r,r]),this.getRoute(t)}getRoute(e){let t=this.controlPlane.database.query("SELECT * FROM notification_routes WHERE id=?").get(e);return t?It(t):void 0}listRoutes(e){return this.controlPlane.database.query("SELECT * FROM notification_routes WHERE organization_id=? ORDER BY priority DESC,created_at ASC").all(e).map(It)}countRouteDeliveries(e,t){return Number(this.controlPlane.database.query("SELECT COUNT(*) count FROM notification_deliveries WHERE route_id=? AND created_at>=?").get(e,t)?.count??0)}setRouteEnabled(e,t){this.controlPlane.database.run("UPDATE notification_routes SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getRoute(e);if(!r)throw Error("Notification route was not found.");return r}createDelivery(e){let t=this.controlPlane.database.query("SELECT * FROM notification_deliveries WHERE idempotency_key=?").get(e.idempotencyKey);if(t)return ke(t);let r=crypto.randomUUID(),n=this.now();return this.controlPlane.database.run("INSERT INTO notification_deliveries (id,alert_id,channel_id,route_id,event_type,idempotency_key,state,attempt,max_attempts,next_attempt_at,payload,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[r,e.alertId??null,e.channelId,e.routeId??null,e.eventType,e.idempotencyKey,"pending",0,M(e.maxAttempts,3,1,10),e.nextAttemptAt??null,JSON.stringify(e.payload),n,n]),this.getDelivery(r)}getDelivery(e){let t=this.controlPlane.database.query("SELECT * FROM notification_deliveries WHERE id=?").get(e);return t?ke(t):void 0}listDeliveries(e={}){let t=[],r=[];if(e.alertId)t.push("alert_id=?"),r.push(e.alertId);if(e.states?.length)t.push(`state IN (${e.states.map(()=>"?").join(",")})`),r.push(...e.states);return this.controlPlane.database.query(`SELECT * FROM notification_deliveries${t.length?" WHERE "+t.join(" AND "):""} ORDER BY updated_at DESC LIMIT ?`).all(...r,Math.min(1000,e.limit??200)).map(ke)}updateDelivery(e,t){return this.controlPlane.database.run("UPDATE notification_deliveries SET state=?,attempt=?,next_attempt_at=?,response_status=?,error=?,delivered_at=?,updated_at=? WHERE id=?",[t.state,t.attempt,t.nextAttemptAt??null,t.responseStatus??null,t.error?.slice(0,1000)??null,t.deliveredAt??null,this.now(),e]),this.getDelivery(e)}}import{createHash as xr}from"node:crypto";function Nr(e,t,r){if(e==="gt")return t>r;if(e==="gte")return t>=r;if(e==="lt")return t<r;if(e==="lte")return t<=r;return t===r}function jr(e,t,r){if(t.status==="no_data"||t.status==null&&t.value==null)return;if(e.operator==="unhealthy")return t.status==="unhealthy";if(t.value==null||e.threshold==null)return;return Nr(e.operator,t.value,r&&e.recoveryThreshold!=null?e.recoveryThreshold:e.threshold)}function Mr(e,t){let r=Object.fromEntries(e.groupBy.flatMap((o)=>t.group?.[o]==null?[]:[[o,String(t.group[o])]]));return{key:Object.entries(r).sort(([o],[i])=>o.localeCompare(i)).map(([o,i])=>`${o}=${i}`).join(",")||"default",values:r}}function Lr(e,t){return xr("sha256").update(`${e}\x00${t}`).digest("hex")}class Y{store;constructor(e){this.store=e}evaluate(e,t){if(!e.enabled)return{transition:"ignored",notify:!1};let r=Mr(e,t),n=Lr(e.id,r.key),o=this.store.getAlertByDedup(n),i=o?.state==="firing"||o?.state==="silenced",s=jr(e,t,i);if(s==null&&e.noDataPolicy==="ignore")return{alert:o,transition:"ignored",notify:!1};let a=s??e.noDataPolicy==="firing",d=s==null&&e.noDataPolicy==="pending",c=new Date(t.timestamp).toISOString(),u=h({...t.evidence??{},...t.value==null?{}:{value:t.value},...t.status?{healthStatus:t.status}:{},group:r.values}),p;if(!o){let y=a||d?1:0,v=a&&y>=e.consecutive?"firing":"pending";p={id:crypto.randomUUID(),ruleId:e.id,projectId:e.projectId,environmentId:e.environmentId,resourceId:e.resourceId,dedupKey:n,groupKey:r.key,state:v,severity:e.severity,title:e.name,evidence:u,failureCount:y,recoveryCount:0,occurrenceCount:1,firstSeenAt:c,lastSeenAt:c,firingAt:v==="firing"?c:void 0,updatedAt:c}}else if(a||d){let y=o.state==="resolved",v=(y?0:o.failureCount)+1,b=o.silencedUntil&&new Date(o.silencedUntil)>new Date(c),I=d?"pending":v>=e.consecutive?"firing":"pending";if((b||this.store.isSilenced(e,r.values,c))&&I==="firing")I="silenced";p={...o,state:I,severity:e.severity,title:e.name,evidence:u,failureCount:v,recoveryCount:0,occurrenceCount:o.occurrenceCount+1,firstSeenAt:y?c:o.firstSeenAt,lastSeenAt:c,firingAt:I==="firing"||I==="silenced"?o.firingAt??c:void 0,resolvedAt:void 0,updatedAt:c}}else{let y=o.recoveryCount+1,v=y>=e.recoveryConsecutive;p={...o,state:v?"resolved":o.state,evidence:u,failureCount:v?0:o.failureCount,recoveryCount:y,lastSeenAt:c,resolvedAt:v?c:o.resolvedAt,silencedUntil:v?void 0:o.silencedUntil,updatedAt:c}}let l=o?.state!==p.state,f=p.state==="pending"?"pending":p.state==="firing"?l?"firing":"updated":p.state==="silenced"?"silenced":l?"resolved":"updated";return{alert:this.store.saveAlert(p,l||!o?f:"observed"),transition:f,notify:f==="firing"||f==="resolved"}}}import{createHmac as qr}from"node:crypto";function $r(e,t){let r=Object.fromEntries(new Intl.DateTimeFormat("en-US",{timeZone:t,weekday:"short",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}).formatToParts(e).map((o)=>[o.type,o.value])),n=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return{minute:Number(r.hour)*60+Number(r.minute),weekday:n.indexOf(r.weekday)}}function Et(e){let t=/^(\d{2}):(\d{2})$/.exec(e);if(!t)throw Error("Quiet hours require HH:MM times.");let r=Number(t[1])*60+Number(t[2]);if(Number(t[1])>23||Number(t[2])>59)throw Error("Quiet hours require valid HH:MM times.");return r}function Oe(e,t){if(!e.quietHours)return!1;let r=$r(t,e.quietHours.timezone),n=Et(e.quietHours.start),o=Et(e.quietHours.end);if(e.quietHours.weekdays?.length&&!e.quietHours.weekdays.includes(r.weekday))return!1;return n<=o?r.minute>=n&&r.minute<o:r.minute>=n||r.minute<o}function Vr(e,t,r){let n=e.matcher;return(!n.projectIds?.length||n.projectIds.includes(t.projectId))&&(!n.environmentIds?.length||!!t.environmentId&&n.environmentIds.includes(t.environmentId))&&(!n.resourceIds?.length||!!t.resourceId&&n.resourceIds.includes(t.resourceId))&&(!n.severities?.length||n.severities.includes(t.severity))&&(!n.eventTypes?.length||n.eventTypes.includes(r))}function Br(e){if(!e)return{};try{let t=JSON.parse(e);return t&&typeof t==="object"?t:{value:e}}catch{return{value:e}}}function zr(e,t,r){let n={severity:e.severity.toUpperCase(),title:e.title,state:e.state,event:t,projectId:e.projectId,environmentId:e.environmentId??"",resourceId:e.resourceId??"",groupKey:e.groupKey};return(r?.trim()||"[{{severity}}] {{title}} · {{state}}").replace(/\{\{(severity|title|state|event|projectId|environmentId|resourceId|groupKey)\}\}/g,(o,i)=>n[i]).slice(0,2000)}function De(e,t,r){return{schemaVersion:1,event:t,notificationText:zr(e,t,r),alert:{id:e.id,state:e.state,severity:e.severity,title:e.title,projectId:e.projectId,environmentId:e.environmentId??null,resourceId:e.resourceId??null,groupKey:e.groupKey,firstSeenAt:e.firstSeenAt,lastSeenAt:e.lastSeenAt,firingAt:e.firingAt??null,resolvedAt:e.resolvedAt??null,evidence:e.evidence}}}class yr{store;options;fetchImpl;constructor(e,t={}){this.store=e;this.options=t;this.fetchImpl=t.fetchImpl??globalThis.fetch}now(){return this.options.now?.()??new Date}preview(e,t,r){let n=[];for(let o of this.store.listRoutes(e)){if(!o.enabled||!Vr(o,t,r))continue;let i=[];for(let s of o.channelIds){let a=this.store.getChannel(s);if(a?.status==="active")i.push(a)}n.push({route:o,channels:i,quiet:Oe(o,this.now())})}return n}enqueue(e,t,r){let n=r==="resolved"?t.resolvedAt:r==="firing"?t.firingAt:t.updatedAt,o=[];for(let i of this.preview(e,t,r)){if(i.quiet&&r!=="resolved")continue;let s=r==="resolved"||i.route.groupWaitSeconds===0?void 0:new Date(this.now().getTime()+i.route.groupWaitSeconds*1000).toISOString(),a=r==="resolved"?Number.POSITIVE_INFINITY:Math.max(0,i.route.rateLimitPerMinute-this.store.countRouteDeliveries(i.route.id,new Date(this.now().getTime()-60000).toISOString()));for(let d of i.channels){if(a<=0)break;o.push(this.store.createDelivery({alertId:t.id,channelId:d.id,routeId:i.route.id,eventType:r,idempotencyKey:`${t.id}:${r}:${n}:${d.id}`,payload:De(t,r,i.route.template),nextAttemptAt:s})),a--}}return o}enqueueRemindersAndEscalations(e,t){let r=this.now(),n=[];for(let o of t.filter((i)=>i.state==="firing"&&!i.acknowledgedAt&&i.firingAt)){let i=Math.max(0,(r.getTime()-new Date(o.firingAt).getTime())/1000);for(let s of this.preview(e,o,"reminder")){if(s.quiet)continue;if(s.route.reminderSeconds&&i>=s.route.reminderSeconds){let a=Math.floor(i/s.route.reminderSeconds);for(let d of s.channels)n.push(this.store.createDelivery({alertId:o.id,channelId:d.id,routeId:s.route.id,eventType:"reminder",idempotencyKey:`${o.id}:reminder:${s.route.id}:${a}:${d.id}`,payload:De(o,"reminder")}))}for(let[a,d]of s.route.escalation.entries())if(i>=d.afterSeconds){for(let c of d.channelIds)if(this.store.getChannel(c)?.status==="active")n.push(this.store.createDelivery({alertId:o.id,channelId:c,routeId:s.route.id,eventType:"escalation",idempotencyKey:`${o.id}:escalation:${s.route.id}:${a}:${c}`,payload:De(o,"escalation")}))}}}return n}async send(e,t){let r=Br(this.store.channelCredential(e.id)),n=typeof t.notificationText==="string"?t.notificationText:`[${String(t.alert?.severity??"info").toUpperCase()}] ${String(t.alert?.title??"ts-cloud alert")} · ${String(t.alert?.state??t.event)}`;try{if(e.kind==="email"){if(!this.options.emailImpl)return{ok:!1,error:"Email adapter is not configured."};return await this.options.emailImpl({to:e.config.to,from:e.config.from,subject:`[ts-cloud] ${String(t.alert?.title??t.event)}`,text:`${n}
|
|
34
|
+
`:"")}function*Wp(e,t=500){for(let r=0;r<e.length;r+=t)yield Co(e.slice(r,r+t))}class ht{store;counters=new go;breaching=new Map;anomalyConfigs;signals;constructor(e){this.store=e;this.anomalyConfigs=new yo(e.controlPlane),this.signals=new So(e.controlPlane,e)}ingestTelemetry(e,t,r){let n=Tc(e,t,{counters:this.counters,defaultProvider:r});return this.store.ingestUsage(n)}ingestUsage(e,t=!0){return this.store.ingestUsage(t?Ec(e):[...e])}status(e,t=new Date){let{window:r,summary:n}=this.store.budgetSpendCents(e,t),i=this.store.listEnforcements({organizationId:e.organizationId,budgetId:e.id,activeOnly:!0}).filter((a)=>a.state==="active").map((a)=>a.action),s=Ac({budget:e,window:r,actualCents:n.totalCents,series:n.series,activeActions:i,breachingSince:this.breaching.get(e.id),now:t});return{budget:e,decision:s,summary:n,activeActions:i,timeToCap:fi(s.projection.timeToExhaustionMs)}}async runCycle(e){let t=e.now??new Date,r=this.store.budgetsForScope(e.organizationId,e.projectId,e.environmentId),n=[],o=[];for(let s of r){let a=this.status(s,t);this.trackBreach(s,a.decision,t),this.store.recordDecision(a.decision),n.push(a)}let i=Rc(n.map((s)=>s.decision));if(e.handlers){let s={environmentKind:e.environmentKind,...e.policy};for(let a of n){let d=Ic(a.decision,s);if(d.apply.length===0&&d.release.length===0&&d.withheld.length===0)continue;o.push(await Pc(this.store,a.budget,a.decision,d,e.handlers))}}return{organizationId:e.organizationId,statuses:n,level:i.level,actions:i.actions,releases:i.releases,enforcement:o,anomalies:this.detectAnomalies(e,t),evaluatedAt:t.toISOString()}}trackBreach(e,t,r){if(!t.breaches.some((o)=>o.actions.some((i)=>i!=="notify"))){this.breaching.delete(e.id);return}if(!this.breaching.has(e.id))this.breaching.set(e.id,r.toISOString())}detectAnomalies(e,t=new Date,r={}){let n=new Date(Math.floor(t.getTime()/3600000)*3600000).toISOString(),o={organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId},i=e.signals??Lt.map((d)=>d.key),s=[],a;for(let d of i){let c=r.seasonLength?Math.max(336,r.seasonLength*((r.minHistory??3)+1)):xc(d),u={from:new Date(new Date(n).getTime()-c*3600000).toISOString(),to:n};if(s.push(...this.detectSignal(d,o,u,r)),!e.routes)continue;if(!bo(d)?.routeAware)continue;a??=this.signals.busiestRoutes(o,u);for(let p of a){if(this.anomalyConfigs.isSilenced(o,{signal:d,route:p}))continue;s.push(...this.detectSignal(d,{...o,route:p},u,r,p))}}return this.signals.resetCache(),s}detectSignal(e,t,r,n,o){let i=this.anomalyConfigs.optionsFor(t,e);if(!i.enabled)return[];if(!o&&this.anomalyConfigs.isSilenced(t,{signal:e}))return[];let s=this.signals.series(e,t,r);if(s.points.length===0)return[];let a=kc(s.points,{...vo(e),...i.options,...n});if(!a)return[];let d=this.store.recordAnomaly({organizationId:t.organizationId,projectId:t.projectId,environmentId:t.environmentId,signal:o?`${e}@${o}`:e,direction:a.direction,observed:a.observed,expected:a.expected,score:a.score,deltaPercent:Number.isFinite(a.deltaPercent)?a.deltaPercent:0,severity:i.config?.severity??a.severity,bucketStart:a.bucketStart,evidence:{historySize:a.historySize,deviation:a.deviation,unit:s.unit,populatedBuckets:s.populated,suppressedBuckets:s.suppressed,route:o??null,lookbackFrom:r.from,lookbackTo:r.to}});return d?[d]:[]}usageReport(e){let t=e.now??new Date,r=br(e.period??"monthly",e.timezone??"UTC",t),n=this.store.summarizeUsage({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,from:r.start,to:r.end}),o=this.store.budgetsForScope(e.organizationId,e.projectId,e.environmentId).map((s)=>{let a=this.status(s,t),d=ss(s);return{id:s.id,name:s.name,period:s.period,limitCents:d,softLimitCents:s.softLimitCents,hardLimitCents:s.hardLimitCents,spentCents:a.decision.projection.actualCents,remainingCents:d==null?null:Math.max(0,d-a.decision.projection.actualCents),usedPercent:a.decision.usedPercent,projectedCents:a.decision.projection.projectedCents,projectedPercent:a.decision.projectedPercent,projectionConfidence:a.decision.projection.confidence,level:a.decision.level,timeToCap:a.timeToCap,activeActions:a.activeActions,dryRun:s.dryRun}}),i=this.store.listEnforcements({organizationId:e.organizationId,activeOnly:!0});return{organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,window:{start:r.start,end:r.end,label:r.label},currency:this.store.priceBook.currency,totalCents:n.totalCents,byMeter:n.byMeter,series:n.series,budgets:o,enforcement:{strongestAction:Dc(i)??null,active:i.map((s)=>({id:s.id,budgetId:s.budgetId,action:s.action,state:s.state,reason:s.reason,simulated:s.simulated,appliedAt:s.appliedAt}))},generatedAt:t.toISOString(),currentBucket:gi(t)}}}function Kp(e,t,r,n=1440){let o=new Map(e.map((d)=>[d.bucketStart,d.value])),i=Math.floor(new Date(t).getTime()/3600000)*3600000,s=new Date(r).getTime(),a=[];for(let d=i;d<s&&a.length<n;d+=3600000){let c=new Date(d).toISOString();a.push({bucketStart:c,value:o.get(c)??0})}return a}var Oc="spend.gates",Rr={build:["block_builds","suspend_project"],deploy:["block_deployments","suspend_project"],function_invoke:["suspend_functions","serve_static","suspend_project"],request:["suspend_project"]};function pe(e){return`${e.budgetId}:${e.action}`}function Pr(e,t){if(e.organizationId!==t.organizationId)return!1;if(e.projectId&&e.projectId!==t.projectId)return!1;if(e.environmentId&&e.environmentId!==t.environmentId)return!1;return!0}function Cr(e,t){if(e.organizationId!==t.organizationId)return!1;if(t.projectId&&e.projectId!==t.projectId)return!1;if(t.environmentId&&e.environmentId!==t.environmentId)return!1;return!0}function kr(e){let t={...e};for(let r of["projectId","environmentId"])if(t[r]==null)delete t[r];return t}class Mt{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}read(){let e=this.controlPlane.getSetting(Oc);return Array.isArray(e)?e:[]}write(e){this.controlPlane.setSetting(Oc,e)}list(e){return this.read().filter((t)=>!e||Pr(t,e)).sort((t,r)=>oe[r.action]-oe[t.action])}listUnder(e){return this.read().filter((t)=>Cr(t,e)).sort((t,r)=>oe[r.action]-oe[t.action])}open(e){let t=e.appliedAt??(this.options.now?.()??new Date).toISOString(),r=kr({...e,appliedAt:t}),n=this.read().filter((o)=>pe(o)!==pe(r));return n.push(r),this.write(n),r}close(e,t){let r=this.read(),n=r.filter((o)=>pe(o)!==pe({budgetId:e,action:t}));if(n.length===r.length)return!1;return this.write(n),!0}closeBudget(e){let t=this.read(),r=t.filter((n)=>n.budgetId!==e);return this.write(r),t.length-r.length}check(e,t){let r=Rr[e]??[];for(let n of this.list(t)){if(n.simulated)continue;if(!r.includes(n.action))continue;return{allowed:!1,action:n.action,budgetId:n.budgetId,reason:`${n.reason} ${os[n.action]}`}}return{allowed:!0}}strongest(e){return this.list(e).find((t)=>!t.simulated)?.action}}class $c extends Error{operation;verdict;code="spend_cap_exceeded";status=402;constructor(e,t){super(t.reason??`A spend cap is blocking this ${e}.`);this.operation=e;this.verdict=t}}function Jp(e,t,r){let n=e.check(t,r);if(!n.allowed)throw new $c(t,n)}var ut=["notify","block_builds","block_deployments"];function Lc(e){let t=e.throttleFactor??0.5;return{apply:async(o,i)=>{let{budget:s,record:a,decision:d}=i;e.gate.open({budgetId:s.id,action:o,organizationId:s.organizationId,projectId:s.projectId,environmentId:s.environmentId,reason:d.reason,simulated:a.simulated});let c={gated:!0};if(!a.simulated&&!ut.includes(o)){let u={projectId:s.projectId,environmentId:s.environmentId},p=e.transport;if(o==="throttle_requests"&&p?.throttleRequests)c={...await p.throttleRequests({...u,factor:t}),gated:!0};else if(o==="suspend_functions"&&p?.suspendFunctions)c={...await p.suspendFunctions(u),gated:!0};else if(o==="serve_static"&&p?.serveStatic)c={...await p.serveStatic(u),gated:!0};else if(o==="suspend_project"&&p?.suspendProject)c={...await p.suspendProject(u),gated:!0};else c={gated:!0,unsupported:!0}}return await e.notify?.({action:o,budgetId:s.id,reason:d.reason,simulated:a.simulated,released:!1}),c},release:async(o,i)=>{let{budget:s,record:a,restore:d}=i,c=e.transport;if(!a.simulated&&!ut.includes(o)&&d.unsupported!==!0){if(o==="throttle_requests"&&c?.restoreRequests)await c.restoreRequests(d);else if(o==="suspend_functions"&&c?.resumeFunctions)await c.resumeFunctions(d);else if(o==="serve_static"&&c?.restoreDynamic)await c.restoreDynamic(d);else if(o==="suspend_project"&&c?.resumeProject)await c.resumeProject(d)}e.gate.close(s.id,o),await e.notify?.({action:o,budgetId:s.id,reason:a.reason,simulated:a.simulated,released:!0})}}}class _d{calls=[];record(e,t){return this.calls.push({method:e,input:t}),{recorded:e}}throttleRequests(e){return this.record("throttleRequests",e)}restoreRequests(e){this.record("restoreRequests",e)}suspendFunctions(e){return this.record("suspendFunctions",e)}resumeFunctions(e){this.record("resumeFunctions",e)}serveStatic(e){return this.record("serveStatic",e)}restoreDynamic(e){this.record("restoreDynamic",e)}suspendProject(e){return this.record("suspendProject",e)}resumeProject(e){this.record("resumeProject",e)}}import{createCipheriv as Tr,createDecipheriv as Dr,createHash as _t,randomBytes as Or}from"node:crypto";var O=(e)=>{if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}},E=(e)=>typeof e==="string"?e:void 0,Te=(e)=>Number(e)===1,M=(e,t,r,n)=>{let o=Number(e);return Number.isFinite(o)?Math.min(n,Math.max(r,Math.floor(o))):t},pt=(e)=>_t("sha256").update(e).digest("hex").slice(0,16);function yt(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),name:String(e.name),kind:String(e.kind),target:String(e.target),config:O(e.config),intervalSeconds:Number(e.interval_seconds),timeoutSeconds:Number(e.timeout_seconds),failureThreshold:Number(e.failure_threshold),recoveryThreshold:Number(e.recovery_threshold),regions:O(e.regions),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function vt(e){return{id:String(e.id),checkId:String(e.check_id),status:String(e.status),agent:String(e.agent),region:E(e.region),statusCode:e.status_code==null?void 0:Number(e.status_code),message:E(e.message),timings:O(e.timings),checkedAt:String(e.checked_at)}}function bt(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),healthCheckId:E(e.health_check_id),name:String(e.name),signal:String(e.signal),operator:String(e.operator),threshold:e.threshold==null?void 0:Number(e.threshold),recoveryThreshold:e.recovery_threshold==null?void 0:Number(e.recovery_threshold),windowMs:Number(e.window_ms),consecutive:Number(e.consecutive),recoveryConsecutive:Number(e.recovery_consecutive),noDataPolicy:String(e.no_data_policy),severity:String(e.severity),groupBy:O(e.group_by),labels:O(e.labels),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Ce(e){return{id:String(e.id),ruleId:String(e.rule_id),projectId:String(e.project_id),environmentId:E(e.environment_id),resourceId:E(e.resource_id),dedupKey:String(e.dedup_key),groupKey:String(e.group_key),state:String(e.state),severity:String(e.severity),title:String(e.title),evidence:O(e.evidence),failureCount:Number(e.failure_count),recoveryCount:Number(e.recovery_count),occurrenceCount:Number(e.occurrence_count),ownerActorId:E(e.owner_actor_id),acknowledgedByActorId:E(e.acknowledged_by_actor_id),acknowledgedAt:E(e.acknowledged_at),firstSeenAt:String(e.first_seen_at),lastSeenAt:String(e.last_seen_at),firingAt:E(e.firing_at),resolvedAt:E(e.resolved_at),silencedUntil:E(e.silenced_until),updatedAt:String(e.updated_at)}}function St(e){return{id:String(e.id),organizationId:String(e.organization_id),name:String(e.name),kind:String(e.kind),config:O(e.config),credentialFingerprint:E(e.credential_fingerprint),hasCredential:!!e.credential_ciphertext,status:String(e.status),version:Number(e.version),lastTestedAt:E(e.last_tested_at),lastError:E(e.last_error),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function It(e){return{id:String(e.id),organizationId:String(e.organization_id),name:String(e.name),priority:Number(e.priority),matcher:O(e.matcher),channelIds:O(e.channel_ids),quietHours:e.quiet_hours?O(e.quiet_hours):void 0,groupWaitSeconds:Number(e.group_wait_seconds),reminderSeconds:e.reminder_seconds==null?void 0:Number(e.reminder_seconds),escalation:O(e.escalation),template:E(e.template),rateLimitPerMinute:Number(e.rate_limit_per_minute),enabled:Te(e.enabled),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function ke(e){return{id:String(e.id),alertId:E(e.alert_id),channelId:String(e.channel_id),routeId:E(e.route_id),eventType:String(e.event_type),idempotencyKey:String(e.idempotency_key),state:String(e.state),attempt:Number(e.attempt),maxAttempts:Number(e.max_attempts),nextAttemptAt:E(e.next_attempt_at),responseStatus:e.response_status==null?void 0:Number(e.response_status),error:E(e.error),payload:O(e.payload),createdAt:String(e.created_at),updatedAt:String(e.updated_at),deliveredAt:E(e.delivered_at)}}class ft{controlPlane;options;key;constructor(e,t){this.controlPlane=e;this.options=t;this.key=_t("sha256").update(t.encryptionKey).digest()}now(){return(this.options.now?.()??new Date).toISOString()}encrypt(e){let t=Or(12),r=Tr("aes-256-gcm",this.key,t),n=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${n.toString("base64url")}`}decrypt(e){let[,t,r,n]=e.split("."),o=Dr("aes-256-gcm",this.key,Buffer.from(t,"base64url"));return o.setAuthTag(Buffer.from(r,"base64url")),Buffer.concat([o.update(Buffer.from(n,"base64url")),o.final()]).toString("utf8")}createHealthCheck(e){if(!e.name.trim())throw Error("Health checks require a name.");if(!["http","tcp","command"].includes(e.kind))throw Error("Unsupported health check kind.");if(e.kind==="http"&&!/^https?:\/\//.test(e.target)||e.kind==="tcp"&&!/^[a-zA-Z0-9.-]+$/.test(e.target)||e.kind==="command"&&!e.config.command?.length)throw Error("Health check target is invalid.");let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO health_checks (id,project_id,environment_id,resource_id,name,kind,target,config,interval_seconds,timeout_seconds,failure_threshold,recovery_threshold,regions,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.projectId,e.environmentId??null,e.resourceId??null,e.name.trim().slice(0,100),e.kind,e.target,JSON.stringify(e.config),M(e.intervalSeconds,60,10,86400),M(e.timeoutSeconds,10,1,300),M(e.failureThreshold,3,1,100),M(e.recoveryThreshold,2,1,100),JSON.stringify(e.regions.slice(0,20)),e.enabled?1:0,1,r,r]),this.getHealthCheck(t)}getHealthCheck(e){let t=this.controlPlane.database.query("SELECT * FROM health_checks WHERE id=?").get(e);return t?yt(t):void 0}listHealthChecks(e,t){return this.controlPlane.database.query(`SELECT * FROM health_checks WHERE project_id=?${t?" AND environment_id=?":""} ORDER BY updated_at DESC`).all(e,...t?[t]:[]).map(yt)}setHealthCheckEnabled(e,t){this.controlPlane.database.run("UPDATE health_checks SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getHealthCheck(e);if(!r)throw Error("Health check was not found.");return r}appendHealthResult(e){let t=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO health_results (id,check_id,status,agent,region,status_code,message,timings,checked_at) VALUES (?,?,?,?,?,?,?,?,?)",[t,e.checkId,e.status,e.agent.slice(0,100),e.region??null,e.statusCode??null,e.message?.slice(0,1000)??null,JSON.stringify(e.timings),e.checkedAt]),vt(this.controlPlane.database.query("SELECT * FROM health_results WHERE id=?").get(t))}listHealthResults(e,t=100){return this.controlPlane.database.query("SELECT * FROM health_results WHERE check_id=? ORDER BY checked_at DESC LIMIT ?").all(e,Math.min(1000,Math.max(1,t))).map(vt)}createRule(e){if(!e.name.trim())throw Error("Alert rules require a name.");if(e.operator!=="unhealthy"&&e.threshold==null)throw Error("Metric alert rules require a threshold.");let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO alert_rules (id,project_id,environment_id,resource_id,health_check_id,name,signal,operator,threshold,recovery_threshold,window_ms,consecutive,recovery_consecutive,no_data_policy,severity,group_by,labels,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.projectId,e.environmentId??null,e.resourceId??null,e.healthCheckId??null,e.name.trim().slice(0,120),e.signal,e.operator,e.threshold??null,e.recoveryThreshold??null,M(e.windowMs,300000,1e4,2678400000),M(e.consecutive,3,1,100),M(e.recoveryConsecutive,2,1,100),e.noDataPolicy,e.severity,JSON.stringify(e.groupBy.slice(0,20)),JSON.stringify(e.labels),e.enabled?1:0,1,r,r]),this.getRule(t)}getRule(e){let t=this.controlPlane.database.query("SELECT * FROM alert_rules WHERE id=?").get(e);return t?bt(t):void 0}listRules(e,t){return this.controlPlane.database.query(`SELECT * FROM alert_rules WHERE project_id=?${t?" AND environment_id=?":""} ORDER BY updated_at DESC`).all(e,...t?[t]:[]).map(bt)}setRuleEnabled(e,t){this.controlPlane.database.run("UPDATE alert_rules SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getRule(e);if(!r)throw Error("Alert rule was not found.");return r}getAlertByDedup(e){let t=this.controlPlane.database.query("SELECT * FROM alerts WHERE dedup_key=?").get(e);return t?Ce(t):void 0}getAlert(e){let t=this.controlPlane.database.query("SELECT * FROM alerts WHERE id=?").get(e);return t?Ce(t):void 0}listAlerts(e,t={}){let r=["project_id=?"],n=[e];if(t.environmentId)r.push("environment_id=?"),n.push(t.environmentId);if(t.states?.length)r.push(`state IN (${t.states.map(()=>"?").join(",")})`),n.push(...t.states);return this.controlPlane.database.query(`SELECT * FROM alerts WHERE ${r.join(" AND ")} ORDER BY updated_at DESC LIMIT ?`).all(...n,Math.min(1000,t.limit??200)).map(Ce)}saveAlert(e,t,r){return this.controlPlane.database.run("INSERT INTO alerts (id,rule_id,project_id,environment_id,resource_id,dedup_key,group_key,state,severity,title,evidence,failure_count,recovery_count,occurrence_count,owner_actor_id,acknowledged_by_actor_id,acknowledged_at,first_seen_at,last_seen_at,firing_at,resolved_at,silenced_until,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,severity=excluded.severity,title=excluded.title,evidence=excluded.evidence,failure_count=excluded.failure_count,recovery_count=excluded.recovery_count,occurrence_count=excluded.occurrence_count,owner_actor_id=excluded.owner_actor_id,acknowledged_by_actor_id=excluded.acknowledged_by_actor_id,acknowledged_at=excluded.acknowledged_at,last_seen_at=excluded.last_seen_at,firing_at=excluded.firing_at,resolved_at=excluded.resolved_at,silenced_until=excluded.silenced_until,updated_at=excluded.updated_at",[e.id,e.ruleId,e.projectId,e.environmentId??null,e.resourceId??null,e.dedupKey,e.groupKey,e.state,e.severity,e.title,JSON.stringify(e.evidence),e.failureCount,e.recoveryCount,e.occurrenceCount,e.ownerActorId??null,e.acknowledgedByActorId??null,e.acknowledgedAt??null,e.firstSeenAt,e.lastSeenAt,e.firingAt??null,e.resolvedAt??null,e.silencedUntil??null,e.updatedAt]),this.controlPlane.database.run("INSERT INTO alert_events (id,alert_id,type,actor_id,payload,created_at) VALUES (?,?,?,?,?,?)",[crypto.randomUUID(),e.id,t,r??null,JSON.stringify({state:e.state,severity:e.severity,evidence:e.evidence}),e.updatedAt]),this.getAlert(e.id)}acknowledge(e,t){let r=this.getAlert(e);if(!r)throw Error("Alert was not found.");let n=this.now();return this.saveAlert({...r,acknowledgedByActorId:t,acknowledgedAt:n,updatedAt:n},"acknowledged",t)}assign(e,t,r){let n=this.getAlert(e);if(!n)throw Error("Alert was not found.");let o=this.now();return this.saveAlert({...n,ownerActorId:t,updatedAt:o},"assigned",r)}silenceAlert(e,t,r){let n=this.getAlert(e);if(!n)throw Error("Alert was not found.");let o=new Date(t);if(!Number.isFinite(o.getTime())||o<=new Date)throw Error("Silence end must be in the future.");let i=this.now();return this.saveAlert({...n,state:"silenced",silencedUntil:o.toISOString(),updatedAt:i},"silenced",r)}createSilence(e){let t=new Date(e.startsAt),r=new Date(e.endsAt);if(!Number.isFinite(t.getTime())||!Number.isFinite(r.getTime())||t>=r)throw Error("Silence window is invalid.");try{new Intl.DateTimeFormat("en",{timeZone:e.timezone}).format(t)}catch{throw Error("Silence timezone is invalid.")}let n=crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO alert_silences (id,project_id,environment_id,resource_id,matcher,reason,starts_at,ends_at,timezone,created_by_actor_id,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)",[n,e.projectId,e.environmentId??null,e.resourceId??null,JSON.stringify(e.matcher??{}),e.reason.slice(0,500),t.toISOString(),r.toISOString(),e.timezone,e.actorId??null,this.now()]),n}isSilenced(e,t,r){return this.controlPlane.database.query("SELECT * FROM alert_silences WHERE project_id=? AND starts_at<=? AND ends_at>?").all(e.projectId,r,r).some((o)=>{if(o.environment_id&&o.environment_id!==e.environmentId)return!1;if(o.resource_id&&o.resource_id!==e.resourceId)return!1;let i=O(o.matcher);return Object.entries(i).every(([s,a])=>t[s]===a)})}createChannel(e){if(!e.name.trim())throw Error("Notification channels require a name.");let t=crypto.randomUUID(),r=this.now(),n=e.credential?.trim();return this.controlPlane.database.run("INSERT INTO notification_channels (id,organization_id,name,kind,config,credential_ciphertext,credential_fingerprint,status,version,created_by_actor_id,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.name.trim().slice(0,100),e.kind,JSON.stringify(e.config??{}),n?this.encrypt(n):null,n?pt(n):null,"active",1,e.actorId??null,r,r]),this.getChannel(t)}getChannel(e){let t=this.controlPlane.database.query("SELECT * FROM notification_channels WHERE id=?").get(e);return t?St(t):void 0}channelCredential(e){let t=this.controlPlane.database.query("SELECT credential_ciphertext FROM notification_channels WHERE id=?").get(e);return t?.credential_ciphertext?this.decrypt(String(t.credential_ciphertext)):void 0}listChannels(e){return this.controlPlane.database.query("SELECT * FROM notification_channels WHERE organization_id=? ORDER BY updated_at DESC").all(e).map(St)}rotateChannel(e,t){let r=this.now();this.controlPlane.database.run("UPDATE notification_channels SET credential_ciphertext=?,credential_fingerprint=?,status='active',last_error=NULL,version=version+1,updated_at=? WHERE id=?",[this.encrypt(t),pt(t),r,e]);let n=this.getChannel(e);if(!n)throw Error("Notification channel was not found.");return n}setChannelStatus(e,t,r){this.controlPlane.database.run("UPDATE notification_channels SET status=?,last_error=?,updated_at=? WHERE id=?",[t,r?.slice(0,1000)??null,this.now(),e]);let n=this.getChannel(e);if(!n)throw Error("Notification channel was not found.");return n}markChannelTest(e,t,r){let n=this.now();return this.controlPlane.database.run("UPDATE notification_channels SET status=?,last_tested_at=?,last_error=?,updated_at=? WHERE id=?",[t?"active":"failing",n,r?.slice(0,1000)??null,n,e]),this.getChannel(e)}createRoute(e){let t=crypto.randomUUID(),r=this.now();return this.controlPlane.database.run("INSERT INTO notification_routes (id,organization_id,name,priority,matcher,channel_ids,quiet_hours,group_wait_seconds,reminder_seconds,escalation,template,rate_limit_per_minute,enabled,version,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.organizationId,e.name.trim().slice(0,100),e.priority,JSON.stringify(e.matcher),JSON.stringify(e.channelIds),e.quietHours?JSON.stringify(e.quietHours):null,M(e.groupWaitSeconds,30,0,86400),e.reminderSeconds??null,JSON.stringify(e.escalation),e.template?.trim().slice(0,2000)??null,M(e.rateLimitPerMinute,60,1,1e4),e.enabled?1:0,1,r,r]),this.getRoute(t)}getRoute(e){let t=this.controlPlane.database.query("SELECT * FROM notification_routes WHERE id=?").get(e);return t?It(t):void 0}listRoutes(e){return this.controlPlane.database.query("SELECT * FROM notification_routes WHERE organization_id=? ORDER BY priority DESC,created_at ASC").all(e).map(It)}countRouteDeliveries(e,t){return Number(this.controlPlane.database.query("SELECT COUNT(*) count FROM notification_deliveries WHERE route_id=? AND created_at>=?").get(e,t)?.count??0)}setRouteEnabled(e,t){this.controlPlane.database.run("UPDATE notification_routes SET enabled=?,version=version+1,updated_at=? WHERE id=?",[t?1:0,this.now(),e]);let r=this.getRoute(e);if(!r)throw Error("Notification route was not found.");return r}createDelivery(e){let t=this.controlPlane.database.query("SELECT * FROM notification_deliveries WHERE idempotency_key=?").get(e.idempotencyKey);if(t)return ke(t);let r=crypto.randomUUID(),n=this.now();return this.controlPlane.database.run("INSERT INTO notification_deliveries (id,alert_id,channel_id,route_id,event_type,idempotency_key,state,attempt,max_attempts,next_attempt_at,payload,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[r,e.alertId??null,e.channelId,e.routeId??null,e.eventType,e.idempotencyKey,"pending",0,M(e.maxAttempts,3,1,10),e.nextAttemptAt??null,JSON.stringify(e.payload),n,n]),this.getDelivery(r)}getDelivery(e){let t=this.controlPlane.database.query("SELECT * FROM notification_deliveries WHERE id=?").get(e);return t?ke(t):void 0}listDeliveries(e={}){let t=[],r=[];if(e.alertId)t.push("alert_id=?"),r.push(e.alertId);if(e.states?.length)t.push(`state IN (${e.states.map(()=>"?").join(",")})`),r.push(...e.states);return this.controlPlane.database.query(`SELECT * FROM notification_deliveries${t.length?" WHERE "+t.join(" AND "):""} ORDER BY updated_at DESC LIMIT ?`).all(...r,Math.min(1000,e.limit??200)).map(ke)}updateDelivery(e,t){return this.controlPlane.database.run("UPDATE notification_deliveries SET state=?,attempt=?,next_attempt_at=?,response_status=?,error=?,delivered_at=?,updated_at=? WHERE id=?",[t.state,t.attempt,t.nextAttemptAt??null,t.responseStatus??null,t.error?.slice(0,1000)??null,t.deliveredAt??null,this.now(),e]),this.getDelivery(e)}}import{createHash as xr}from"node:crypto";function Nr(e,t,r){if(e==="gt")return t>r;if(e==="gte")return t>=r;if(e==="lt")return t<r;if(e==="lte")return t<=r;return t===r}function jr(e,t,r){if(t.status==="no_data"||t.status==null&&t.value==null)return;if(e.operator==="unhealthy")return t.status==="unhealthy";if(t.value==null||e.threshold==null)return;return Nr(e.operator,t.value,r&&e.recoveryThreshold!=null?e.recoveryThreshold:e.threshold)}function Mr(e,t){let r=Object.fromEntries(e.groupBy.flatMap((o)=>t.group?.[o]==null?[]:[[o,String(t.group[o])]]));return{key:Object.entries(r).sort(([o],[i])=>o.localeCompare(i)).map(([o,i])=>`${o}=${i}`).join(",")||"default",values:r}}function Lr(e,t){return xr("sha256").update(`${e}\x00${t}`).digest("hex")}class Y{store;constructor(e){this.store=e}evaluate(e,t){if(!e.enabled)return{transition:"ignored",notify:!1};let r=Mr(e,t),n=Lr(e.id,r.key),o=this.store.getAlertByDedup(n),i=o?.state==="firing"||o?.state==="silenced",s=jr(e,t,i);if(s==null&&e.noDataPolicy==="ignore")return{alert:o,transition:"ignored",notify:!1};let a=s??e.noDataPolicy==="firing",d=s==null&&e.noDataPolicy==="pending",c=new Date(t.timestamp).toISOString(),u=h({...t.evidence??{},...t.value==null?{}:{value:t.value},...t.status?{healthStatus:t.status}:{},group:r.values}),p;if(!o){let y=a||d?1:0,v=a&&y>=e.consecutive?"firing":"pending";p={id:crypto.randomUUID(),ruleId:e.id,projectId:e.projectId,environmentId:e.environmentId,resourceId:e.resourceId,dedupKey:n,groupKey:r.key,state:v,severity:e.severity,title:e.name,evidence:u,failureCount:y,recoveryCount:0,occurrenceCount:1,firstSeenAt:c,lastSeenAt:c,firingAt:v==="firing"?c:void 0,updatedAt:c}}else if(a||d){let y=o.state==="resolved",v=(y?0:o.failureCount)+1,b=o.silencedUntil&&new Date(o.silencedUntil)>new Date(c),I=d?"pending":v>=e.consecutive?"firing":"pending";if((b||this.store.isSilenced(e,r.values,c))&&I==="firing")I="silenced";p={...o,state:I,severity:e.severity,title:e.name,evidence:u,failureCount:v,recoveryCount:0,occurrenceCount:o.occurrenceCount+1,firstSeenAt:y?c:o.firstSeenAt,lastSeenAt:c,firingAt:I==="firing"||I==="silenced"?o.firingAt??c:void 0,resolvedAt:void 0,updatedAt:c}}else{let y=o.recoveryCount+1,v=y>=e.recoveryConsecutive;p={...o,state:v?"resolved":o.state,evidence:u,failureCount:v?0:o.failureCount,recoveryCount:y,lastSeenAt:c,resolvedAt:v?c:o.resolvedAt,silencedUntil:v?void 0:o.silencedUntil,updatedAt:c}}let l=o?.state!==p.state,f=p.state==="pending"?"pending":p.state==="firing"?l?"firing":"updated":p.state==="silenced"?"silenced":l?"resolved":"updated";return{alert:this.store.saveAlert(p,l||!o?f:"observed"),transition:f,notify:f==="firing"||f==="resolved"}}}import{createHmac as qr}from"node:crypto";function $r(e,t){let r=Object.fromEntries(new Intl.DateTimeFormat("en-US",{timeZone:t,weekday:"short",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}).formatToParts(e).map((o)=>[o.type,o.value])),n=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return{minute:Number(r.hour)*60+Number(r.minute),weekday:n.indexOf(r.weekday)}}function Et(e){let t=/^(\d{2}):(\d{2})$/.exec(e);if(!t)throw Error("Quiet hours require HH:MM times.");let r=Number(t[1])*60+Number(t[2]);if(Number(t[1])>23||Number(t[2])>59)throw Error("Quiet hours require valid HH:MM times.");return r}function Oe(e,t){if(!e.quietHours)return!1;let r=$r(t,e.quietHours.timezone),n=Et(e.quietHours.start),o=Et(e.quietHours.end);if(e.quietHours.weekdays?.length&&!e.quietHours.weekdays.includes(r.weekday))return!1;return n<=o?r.minute>=n&&r.minute<o:r.minute>=n||r.minute<o}function Vr(e,t,r){let n=e.matcher;return(!n.projectIds?.length||n.projectIds.includes(t.projectId))&&(!n.environmentIds?.length||!!t.environmentId&&n.environmentIds.includes(t.environmentId))&&(!n.resourceIds?.length||!!t.resourceId&&n.resourceIds.includes(t.resourceId))&&(!n.severities?.length||n.severities.includes(t.severity))&&(!n.eventTypes?.length||n.eventTypes.includes(r))}function Br(e){if(!e)return{};try{let t=JSON.parse(e);return t&&typeof t==="object"?t:{value:e}}catch{return{value:e}}}function zr(e,t,r){let n={severity:e.severity.toUpperCase(),title:e.title,state:e.state,event:t,projectId:e.projectId,environmentId:e.environmentId??"",resourceId:e.resourceId??"",groupKey:e.groupKey};return(r?.trim()||"[{{severity}}] {{title}} · {{state}}").replace(/\{\{(severity|title|state|event|projectId|environmentId|resourceId|groupKey)\}\}/g,(o,i)=>n[i]).slice(0,2000)}function De(e,t,r){return{schemaVersion:1,event:t,notificationText:zr(e,t,r),alert:{id:e.id,state:e.state,severity:e.severity,title:e.title,projectId:e.projectId,environmentId:e.environmentId??null,resourceId:e.resourceId??null,groupKey:e.groupKey,firstSeenAt:e.firstSeenAt,lastSeenAt:e.lastSeenAt,firingAt:e.firingAt??null,resolvedAt:e.resolvedAt??null,evidence:e.evidence}}}class yr{store;options;fetchImpl;constructor(e,t={}){this.store=e;this.options=t;this.fetchImpl=t.fetchImpl??globalThis.fetch}now(){return this.options.now?.()??new Date}preview(e,t,r){let n=[];for(let o of this.store.listRoutes(e)){if(!o.enabled||!Vr(o,t,r))continue;let i=[];for(let s of o.channelIds){let a=this.store.getChannel(s);if(a?.status==="active")i.push(a)}n.push({route:o,channels:i,quiet:Oe(o,this.now())})}return n}enqueue(e,t,r){let n=r==="resolved"?t.resolvedAt:r==="firing"?t.firingAt:t.updatedAt,o=[];for(let i of this.preview(e,t,r)){if(i.quiet&&r!=="resolved")continue;let s=r==="resolved"||i.route.groupWaitSeconds===0?void 0:new Date(this.now().getTime()+i.route.groupWaitSeconds*1000).toISOString(),a=r==="resolved"?Number.POSITIVE_INFINITY:Math.max(0,i.route.rateLimitPerMinute-this.store.countRouteDeliveries(i.route.id,new Date(this.now().getTime()-60000).toISOString()));for(let d of i.channels){if(a<=0)break;o.push(this.store.createDelivery({alertId:t.id,channelId:d.id,routeId:i.route.id,eventType:r,idempotencyKey:`${t.id}:${r}:${n}:${d.id}`,payload:De(t,r,i.route.template),nextAttemptAt:s})),a--}}return o}enqueueRemindersAndEscalations(e,t){let r=this.now(),n=[];for(let o of t.filter((i)=>i.state==="firing"&&!i.acknowledgedAt&&i.firingAt)){let i=Math.max(0,(r.getTime()-new Date(o.firingAt).getTime())/1000);for(let s of this.preview(e,o,"reminder")){if(s.quiet)continue;if(s.route.reminderSeconds&&i>=s.route.reminderSeconds){let a=Math.floor(i/s.route.reminderSeconds);for(let d of s.channels)n.push(this.store.createDelivery({alertId:o.id,channelId:d.id,routeId:s.route.id,eventType:"reminder",idempotencyKey:`${o.id}:reminder:${s.route.id}:${a}:${d.id}`,payload:De(o,"reminder")}))}for(let[a,d]of s.route.escalation.entries())if(i>=d.afterSeconds){for(let c of d.channelIds)if(this.store.getChannel(c)?.status==="active")n.push(this.store.createDelivery({alertId:o.id,channelId:c,routeId:s.route.id,eventType:"escalation",idempotencyKey:`${o.id}:escalation:${s.route.id}:${a}:${c}`,payload:De(o,"escalation")}))}}}return n}async send(e,t){let r=Br(this.store.channelCredential(e.id)),n=typeof t.notificationText==="string"?t.notificationText:`[${String(t.alert?.severity??"info").toUpperCase()}] ${String(t.alert?.title??"ts-cloud alert")} · ${String(t.alert?.state??t.event)}`;try{if(e.kind==="email"){if(!this.options.emailImpl)return{ok:!1,error:"Email adapter is not configured."};return await this.options.emailImpl({to:e.config.to,from:e.config.from,subject:`[ts-cloud] ${String(t.alert?.title??t.event)}`,text:`${n}
|
|
35
35
|
|
|
36
36
|
${JSON.stringify(t,null,2)}`}),{ok:!0,status:202}}if(e.kind==="sms"){if(!this.options.smsImpl)return{ok:!1,error:"SMS adapter is not configured."};let u=e.config.to;if(typeof u!=="string"||!u.trim())return{ok:!1,error:"SMS channels need a `to` number."};return await this.options.smsImpl({to:u,from:e.config.from,text:n.slice(0,300)}),{ok:!0,status:202}}let o=r.url??r.value,i=t,s={"content-type":"application/json"};if(e.kind==="slack")i={text:n};if(e.kind==="discord")i={content:n};if(e.kind==="teams")i={text:n};if(e.kind==="telegram")o=`https://api.telegram.org/bot${r.botToken??r.value}/sendMessage`,i={chat_id:e.config.chatId,text:n};if(!o||!/^https:\/\//.test(o))return{ok:!1,error:"Channel endpoint is unavailable or not HTTPS."};let a=JSON.stringify(i);if(e.kind==="webhook"&&r.signingSecret){let u=Math.floor(this.now().getTime()/1000).toString();s["x-ts-cloud-timestamp"]=u,s["x-ts-cloud-signature"]=`v1=${qr("sha256",r.signingSecret).update(`${u}.${a}`).digest("hex")}`}let d=new AbortController,c=setTimeout(()=>d.abort(),1e4);try{let u=await this.fetchImpl(o,{method:"POST",headers:s,body:a,signal:d.signal});return u.ok?{ok:!0,status:u.status}:{ok:!1,status:u.status,error:`Channel returned HTTP ${u.status}.`}}finally{clearTimeout(c)}}catch(o){return{ok:!1,error:o instanceof Error?o.message:String(o)}}}async deliver(e){let t=this.store.getDelivery(e);if(!t)throw Error("Notification delivery was not found.");if(t.state==="delivered"||t.state==="dead"||t.nextAttemptAt&&t.nextAttemptAt>this.now().toISOString())return t;let r=this.store.getChannel(t.channelId);if(!r||r.status==="disabled"||r.status==="paused")return this.store.updateDelivery(e,{state:"failed",attempt:t.attempt+1,error:"Notification channel is unavailable."});let n=t.attempt+1,o=await this.send(r,t.payload);if(o.ok)return this.store.setChannelStatus(r.id,"active"),this.store.updateDelivery(e,{state:"delivered",attempt:n,responseStatus:o.status,deliveredAt:this.now().toISOString()});let s=!(!o.status||o.status===429||o.status>=500)||n>=t.maxAttempts,a=s?void 0:new Date(this.now().getTime()+Math.min(3600000,30000*2**(n-1))).toISOString();return this.store.setChannelStatus(r.id,"failing",o.error),this.store.updateDelivery(e,{state:s?"dead":"retrying",attempt:n,nextAttemptAt:a,responseStatus:o.status,error:o.error})}async deliverAll(e){return Promise.all(e.map((t)=>this.deliver(t.id)))}async retryDue(){let e=this.now().toISOString(),t=this.store.listDeliveries({states:["pending","retrying"]}).filter((r)=>!r.nextAttemptAt||r.nextAttemptAt<=e);return this.deliverAll(t)}async testChannel(e){let t=this.store.getChannel(e);if(!t)throw Error("Notification channel was not found.");let r=await this.send(t,{schemaVersion:1,event:"test",message:"ts-cloud notification channel test. No incident was created."});return this.store.markChannelTest(e,r.ok,r.error),r}}import{lookup as Ur}from"node:dns/promises";import{connect as Fr}from"node:net";async function Hr(e,t){let r=Bun.spawn(e,{stdout:"pipe",stderr:"pipe"}),n=setTimeout(()=>r.kill(),t);try{return{exitCode:await r.exited,stdout:await new Response(r.stdout).text(),stderr:await new Response(r.stderr).text()}}finally{clearTimeout(n)}}class Me{store;options;constructor(e,t={}){this.store=e;this.options=t}now(){return this.options.now?.()??new Date}async probe(e){let t=performance.now(),r=this.now().toISOString(),n=this.options.agent??"local";try{if(e.kind==="http"){let s=new URL(e.target),a=performance.now();await(this.options.lookupImpl??Ur)(s.hostname);let d=performance.now()-a,c=new AbortController,u=setTimeout(()=>c.abort(),e.timeoutSeconds*1000);try{let p=performance.now(),l=await(this.options.fetchImpl??fetch)(s.toString(),{method:e.config.method??"GET",headers:e.config.headers,signal:c.signal,redirect:"manual"}),f=performance.now()-p,g=e.config.expectedBody?await l.text():"",y=e.config.expectedStatuses??[200,201,202,204],v=y.includes(l.status)&&(!e.config.expectedBody||g.includes(e.config.expectedBody));return{checkId:e.id,status:v?"healthy":"unhealthy",agent:n,region:this.options.region,statusCode:l.status,message:v?void 0:`Expected ${y.join("/")} and configured body match.`,timings:{dnsMs:d,ttfbMs:f,totalMs:performance.now()-t},checkedAt:r}}finally{clearTimeout(u)}}if(e.kind==="tcp"){let s=Number(e.config.port);if(!Number.isInteger(s)||s<1||s>65535)throw Error("TCP health check requires a valid port.");let a=performance.now();return await new Promise((d,c)=>{let u=Fr({host:e.target,port:s}),p=setTimeout(()=>{u.destroy(),c(Error("TCP health check timed out."))},e.timeoutSeconds*1000);u.once("connect",()=>{clearTimeout(p),u.destroy(),d()}),u.once("error",(l)=>{clearTimeout(p),c(l)})}),{checkId:e.id,status:"healthy",agent:n,region:this.options.region,timings:{connectMs:performance.now()-a,totalMs:performance.now()-t},checkedAt:r}}let o=e.config.command??[];if(!o.length)throw Error("Command health check is not configured.");let i=await(this.options.commandImpl??Hr)(o,e.timeoutSeconds*1000);return{checkId:e.id,status:i.exitCode===0?"healthy":"unhealthy",agent:n,region:this.options.region,message:i.exitCode===0?void 0:(i.stderr||i.stdout||`Command exited ${i.exitCode}`).slice(0,1000),timings:{totalMs:performance.now()-t},checkedAt:r}}catch(o){return{checkId:e.id,status:"unhealthy",agent:n,region:this.options.region,message:(o instanceof Error?o.message:String(o)).slice(0,1000),timings:{totalMs:performance.now()-t},checkedAt:r}}}async run(e){return this.store.appendHealthResult(await this.probe(e))}async runAndEvaluate(e){let t=await this.run(e),r=new Y(this.store),n=this.store.listRules(e.projectId,e.environmentId).filter((o)=>o.healthCheckId===e.id);return{result:t,evaluations:n.map((o)=>r.evaluate(o,{status:t.status,timestamp:t.checkedAt,group:{agent:t.agent,region:t.region??""},evidence:{healthResultId:t.id,statusCode:t.statusCode??null,message:t.message??null,timings:t.timings}}))}}}var Qr=Object.freeze({rawDays:30,downsampleAfterDays:7,downsampleBucketMs:3600000,maxRecords:1e6,samplingRate:1,collectLogs:!0,collectTraces:!0,collectRequestAnalytics:!0,estimatedStorageUsdPerGbMonth:0});function ge(e,t,r,n){let o=Number(e);return Number.isFinite(o)?Math.min(n,Math.max(r,Math.floor(o))):t}function wt(e,t,r,n){let o=Number(e);return Number.isFinite(o)?Math.min(n,Math.max(r,o)):t}function xe(e,t){return typeof e==="boolean"?e:t}function At(e,t={...Qr}){let r=e&&typeof e==="object"&&!Array.isArray(e)?e:{},n=ge(r.rawDays,t.rawDays,1,3650),o=ge(r.downsampleAfterDays,t.downsampleAfterDays,1,n);return{rawDays:n,downsampleAfterDays:o,downsampleBucketMs:ge(r.downsampleBucketMs,t.downsampleBucketMs,60000,86400000),maxRecords:ge(r.maxRecords,t.maxRecords,1000,1e8),samplingRate:wt(r.samplingRate,t.samplingRate,0.01,1),collectLogs:xe(r.collectLogs,t.collectLogs),collectTraces:xe(r.collectTraces,t.collectTraces),collectRequestAnalytics:xe(r.collectRequestAnalytics,t.collectRequestAnalytics),estimatedStorageUsdPerGbMonth:wt(r.estimatedStorageUsdPerGbMonth,t.estimatedStorageUsdPerGbMonth,0,1e4)}}function Rt(e){return`telemetry.policy:${e}`}function Xe(e,t){return At(e.getSetting(Rt(t)))}function pi(e,t,r){let n=At(r,Xe(e,t));return e.setSetting(Rt(t),n),n}function mi(e,t){return Number((Math.max(0,e)/1073741824*t.estimatedStorageUsdPerGbMonth).toFixed(4))}var Jr=/(?:authorization|cookie|password|passwd|secret|token|api[_-]?key|private[_-]?key|access[_-]?key|session)/i,Wr=/\b(?:authorization|cookie|password|passwd|secret|token|api[_-]?key|private[_-]?key|access[_-]?key)\s*[=:]\s*[^\s,;&\[]+/gi,Kr=/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,Gr=/\b(?:\d{1,3}\.){3}\d{1,3}\b/g;function Ne(e,t={}){let r=e.replace(/([?&][^=&#\s]+)=([^&#\s]*)/g,"$1=[REDACTED]").replace(Wr,"[REDACTED]");if(t.redactEmail!==!1)r=r.replace(Kr,"[EMAIL]");if(t.redactIp)r=r.replace(Gr,"[IP]");for(let n of t.patterns??[])r=r.replace(n,"[REDACTED]");return r}function Z(e,t={},r){if(r&&Jr.test(r))return"[REDACTED]";if(e===null||typeof e==="boolean"||typeof e==="number")return e;if(typeof e==="string")return Ne(e,t);if(Array.isArray(e))return e.map((n)=>Z(n,t));if(e&&typeof e==="object"){let n={};for(let[o,i]of Object.entries(e))n[o]=Z(i,t,o);return n}return String(e??"")}function es(e){if(!e)return;return e.split("?",1)[0].replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/gi,":id").replace(/\/(?:(?:\d{4,})|(?:[0-9a-f]{16,}))(?:\/|$)/gi,(r)=>r.endsWith("/")?"/:id/":"/:id").slice(0,512)}var Pt=65536,Yr=2678400000,Zr=new Set(["metric","log","trace","request","event"]);function k(e){return typeof e==="string"?e:void 0}function X(e){return e==null?void 0:Number(e)}function Xr(e){if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}}function he(e){return{id:String(e.id),projectId:String(e.project_id),environmentId:k(e.environment_id),resourceId:k(e.resource_id),kind:String(e.kind),source:String(e.source),name:String(e.name),timestamp:String(e.timestamp),observedAt:String(e.observed_at),value:X(e.value),unit:k(e.unit),level:k(e.level),message:k(e.message),durationMs:X(e.duration_ms),statusCode:X(e.status_code),method:k(e.method),host:k(e.host),pathTemplate:k(e.path_template),bytesIn:X(e.bytes_in),bytesOut:X(e.bytes_out),region:k(e.region),cacheResult:k(e.cache_result),upstream:k(e.upstream),traceId:k(e.trace_id),requestId:k(e.request_id),deploymentId:k(e.deployment_id),releaseId:k(e.release_id),workloadId:k(e.workload_id),sampled:Number(e.sampled)===1,attributes:Xr(e.attributes),ingestedBytes:Number(e.ingested_bytes)}}function U(e,t){let r=new Date(e);if(!e||!Number.isFinite(r.getTime()))throw Error(`${t} must be a valid ISO-8601 instant.`);return r}function fe(e){let t=U(e.from,"from"),r=U(e.to,"to");if(t>=r)throw Error("Telemetry from must be earlier than to.");if(r.getTime()-t.getTime()>Yr)throw Error("Telemetry queries are limited to 31 days.");return{from:t,to:r}}function Ct(e){if(!e)return;try{let t=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));if(typeof t?.timestamp!=="string"||typeof t?.id!=="string")throw Error();return t}catch{throw Error("Telemetry cursor is invalid.")}}function ts(e){return e?Buffer.from(JSON.stringify({timestamp:e.timestamp,id:e.id})).toString("base64url"):void 0}function on(e,t){if(!e.length)return;let r=[...e].sort((o,i)=>o-i),n=Math.max(0,Math.min(r.length-1,Math.ceil(t/100*r.length)-1));return r[n]}function te(e,t){if(t==="count")return e.length;if(!e.length)return;if(t==="sum")return e.reduce((r,n)=>r+n,0);if(t==="avg")return e.reduce((r,n)=>r+n,0)/e.length;if(t==="min")return Math.min(...e);if(t==="max")return Math.max(...e);return on(e,Number(t.slice(1)))}function an(e,t="UTC"){try{return new Intl.DateTimeFormat("en-US",{timeZone:t,month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZoneName:"short"}).format(e)}catch{throw Error(`Unknown telemetry timezone: ${t}`)}}class Qe{controlPlane;options;constructor(e,t={}){this.controlPlane=e;this.options=t}now(){return this.options.now?.()??new Date}append(e){if(!Zr.has(e.kind))throw Error(`Unsupported telemetry kind: ${e.kind}`);let t=U(e.timestamp,"timestamp").toISOString(),r=e.observedAt?U(e.observedAt,"observedAt").toISOString():this.now().toISOString(),n=Z(e.attributes??{},this.options.redaction),o=e.message?Ne(e.message,this.options.redaction).slice(0,32768):void 0,i=es(e.pathTemplate),s=e.id??crypto.randomUUID(),a=JSON.stringify({...e,id:s,timestamp:t,observedAt:r,attributes:n,message:o,pathTemplate:i}),d=Buffer.byteLength(a);if(d>Pt)throw Error(`Telemetry records are limited to ${Pt} bytes.`);return this.controlPlane.database.run("INSERT OR IGNORE INTO telemetry_records (id, project_id, environment_id, resource_id, kind, source, name, timestamp, observed_at, value, unit, level, message, duration_ms, status_code, method, host, path_template, bytes_in, bytes_out, region, cache_result, upstream, trace_id, request_id, deployment_id, release_id, workload_id, sampled, attributes, ingested_bytes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[s,e.projectId,e.environmentId??null,e.resourceId??null,e.kind,e.source.slice(0,128),e.name.slice(0,256),t,r,e.value??null,e.unit??null,e.level??null,o??null,e.durationMs??null,e.statusCode??null,e.method?.slice(0,16)??null,e.host?.slice(0,256)??null,i??null,e.bytesIn??null,e.bytesOut??null,e.region?.slice(0,64)??null,e.cacheResult?.slice(0,64)??null,e.upstream?.slice(0,256)??null,e.traceId?.slice(0,256)??null,e.requestId?.slice(0,256)??null,e.deploymentId?.slice(0,256)??null,e.releaseId?.slice(0,256)??null,e.workloadId?.slice(0,512)??null,e.sampled===!1?0:1,JSON.stringify(n),d]),this.get(s)}appendMany(e){if(e.length>1e4)throw Error("Telemetry batches are limited to 10,000 records.");return this.controlPlane.database.transaction((r)=>r.map((n)=>this.append(n)))(e)}get(e){let t=this.controlPlane.database.query("SELECT * FROM telemetry_records WHERE id=?").get(e);return t?he(t):void 0}query(e){let{from:t,to:r}=fe(e),n=Math.min(5000,Math.max(1,Math.floor(e.limit??500))),o=["project_id=?","timestamp>=?","timestamp<?"],i=[e.projectId,t.toISOString(),r.toISOString()],s=(b,I)=>{if(I)o.push(`${b}=?`),i.push(I)},a=(b,I)=>{let _=[...new Set(I??[])].slice(0,100);if(_.length)o.push(`${b} IN (${_.map(()=>"?").join(",")})`),i.push(..._)};if(s("environment_id",e.environmentId),a("resource_id",e.resourceIds),a("kind",e.kinds),a("name",e.names),a("source",e.sources),a("level",e.levels),s("trace_id",e.traceId),s("request_id",e.requestId),s("deployment_id",e.deploymentId),s("release_id",e.releaseId),s("workload_id",e.workloadId),e.text)o.push("(message LIKE ? OR name LIKE ?)"),i.push(`%${e.text.slice(0,256)}%`,`%${e.text.slice(0,256)}%`);let d=Ct(e.cursor);if(d)o.push("(timestamp<? OR (timestamp=? AND id<?))"),i.push(d.timestamp,d.timestamp,d.id);let c=this.controlPlane.database.query(`SELECT * FROM telemetry_records WHERE ${o.join(" AND ")} ORDER BY timestamp DESC, id DESC LIMIT ?`).all(...i,n+1),u=c.slice(0,n).map(he),p=c.length>n,l=new Map;for(let b of u)l.set(b.source,[...l.get(b.source)??[],b]);let f=this.now().getTime(),g=[...l].map(([b,I])=>{let _=I.reduce((C,A)=>A.observedAt>C?A.observedAt:C,I[0].observedAt),w=f-new Date(_).getTime();return{source:b,latestAt:_,freshness:w<=120000?"live":w<=600000?"stale":"unavailable",count:I.length}}),y=Math.max(60000,(r.getTime()-t.getTime())/100),v=[...l].flatMap(([b,I])=>{let _=[...new Set(I.map((w)=>new Date(w.timestamp).getTime()))].sort((w,C)=>w-C);return _.slice(1).flatMap((w,C)=>w-_[C]>y?[{from:new Date(_[C]).toISOString(),to:new Date(w).toISOString(),source:b}]:[])});return{records:u,nextCursor:p?ts(u.at(-1)):void 0,truncated:p,scannedRange:{from:t.toISOString(),to:r.toISOString()},sources:g,gaps:v}}tail(e,t){let{from:r,to:n}=fe(e),o=Math.min(1000,Math.max(1,Math.floor(e.limit??200))),i=["project_id=?","timestamp>=?","timestamp<?"],s=[e.projectId,r.toISOString(),n.toISOString()],a=(l,f)=>{if(f)i.push(`${l}=?`),s.push(f)},d=(l,f)=>{let g=[...new Set(f??[])].slice(0,100);if(g.length)i.push(`${l} IN (${g.map(()=>"?").join(",")})`),s.push(...g)};if(a("environment_id",e.environmentId),d("resource_id",e.resourceIds),d("kind",e.kinds),d("name",e.names),d("source",e.sources),d("level",e.levels),a("trace_id",e.traceId),a("request_id",e.requestId),a("deployment_id",e.deploymentId),a("release_id",e.releaseId),a("workload_id",e.workloadId),e.text)i.push("(message LIKE ? OR name LIKE ?)"),s.push(`%${e.text.slice(0,256)}%`,`%${e.text.slice(0,256)}%`);let c=Ct(t);if(c)i.push("(timestamp>? OR (timestamp=? AND id>?))"),s.push(c.timestamp,c.timestamp,c.id);let u=this.controlPlane.database.query(`SELECT * FROM telemetry_records WHERE ${i.join(" AND ")} ORDER BY timestamp ASC, id ASC LIMIT ?`).all(...s,o+1),p=u.slice(0,o).map(he);return{records:p,cursor:ts(p.at(-1))??t,truncated:u.length>o}}series(e){let{from:t,to:r}=fe(e),n=Math.min(86400000,Math.max(1000,Math.floor(e.bucketMs)));if((r.getTime()-t.getTime())/n>2000)throw Error("Telemetry series are limited to 2,000 buckets.");let o=this.query({...e,kinds:["metric"],limit:5000,cursor:void 0}),i=new Map;for(let a of o.records)i.set(`${a.source}\x00${a.name}`,[...i.get(`${a.source}\x00${a.name}`)??[],a]);let s=(a,d,c)=>{let u=new Map;for(let l of a){let f=d.getTime()+Math.floor((new Date(l.timestamp).getTime()-d.getTime())/n)*n;if(f>=d.getTime()&&f<c.getTime()&&l.value!=null)u.set(f,[...u.get(f)??[],l.value])}let p=[];for(let l=d.getTime();l<c.getTime();l+=n){let f=u.get(l)??[],g=te(f,e.aggregation);p.push({timestamp:new Date(l).toISOString(),label:an(new Date(l),e.timezone),value:g,count:f.length,gap:g==null})}return p};return[...i].map(([a,d])=>{let[c,u]=a.split("\x00"),p={name:u,source:c,unit:d.find((l)=>l.unit)?.unit,aggregation:e.aggregation,bucketMs:n,points:s(d,t,r)};if(e.compareFrom&&e.compareTo){let l=this.query({...e,from:e.compareFrom,to:e.compareTo,kinds:["metric"],limit:5000,cursor:void 0}).records.filter((f)=>f.source===c&&f.name===u);p.comparison=s(l,U(e.compareFrom,"compareFrom"),U(e.compareTo,"compareTo"))}return p})}status(e,t,r=30,n=1,o){let i=[e],s=t?" AND environment_id=?":"";if(t)i.push(t);let a=[...new Set(o??[])].slice(0,100);if(o&&a.length===0)return[];let d=o?` AND resource_id IN (${a.map(()=>"?").join(",")||"''"})`:"";i.push(...a);let c=this.controlPlane.database.query(`SELECT source, MAX(latest_observed_at) latest, SUM(ingested_bytes) bytes, SUM(record_count) count, MIN(first_observed_at) first FROM telemetry_source_rollups WHERE project_id=?${s}${d} GROUP BY source`).all(...i),u=this.now().getTime();return c.map((p)=>{let l=String(p.latest),f=Math.max(0,Math.floor((u-new Date(l).getTime())/1000)),g=Math.max(1,(new Date(l).getTime()-new Date(String(p.first)).getTime())/86400000);return{source:String(p.source),freshness:f<=120?"live":f<=600?"stale":"unavailable",lastObservedAt:l,lagSeconds:f,samplingRate:n,retentionDays:r,estimatedDailyBytes:Math.round(Number(p.bytes)/g)}})}saveQuery(e,t,r,n){let o=r.trim().slice(0,80);if(!o)throw Error("Saved telemetry queries require a name.");if(fe(n),n.projectId!==e)throw Error("Saved telemetry queries cannot cross project scope.");let i=this.now().toISOString(),s=JSON.stringify(Z(n,this.options.redaction));if(Buffer.byteLength(s)>16384)throw Error("Saved telemetry queries are limited to 16 KB.");let a=this.controlPlane.database.query("SELECT * FROM telemetry_saved_queries WHERE project_id=? AND actor_id IS ? AND name=?").get(e,t??null,o),d=a?String(a.id):crypto.randomUUID();return this.controlPlane.database.run("INSERT INTO telemetry_saved_queries (id, project_id, actor_id, name, query, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(project_id, actor_id, name) DO UPDATE SET query=excluded.query, updated_at=excluded.updated_at",[d,e,t??null,o,s,a?String(a.created_at):i,i]),{id:d,projectId:e,actorId:t,name:o,query:JSON.parse(s),createdAt:a?String(a.created_at):i,updatedAt:i}}listSavedQueries(e,t){return this.controlPlane.database.query("SELECT * FROM telemetry_saved_queries WHERE project_id=? AND actor_id IS ? ORDER BY updated_at DESC").all(e,t??null).map((r)=>({id:String(r.id),projectId:String(r.project_id),actorId:k(r.actor_id),name:String(r.name),query:JSON.parse(String(r.query)),createdAt:String(r.created_at),updatedAt:String(r.updated_at)}))}deleteSavedQuery(e,t,r){return this.controlPlane.database.run("DELETE FROM telemetry_saved_queries WHERE id=? AND project_id=? AND actor_id IS ?",[r,e,t??null]).changes>0}downsample(e,t){let r=Math.min(86400000,Math.max(60000,Math.floor(e.downsampleBucketMs))),n=new Date(this.now().getTime()-Math.max(1,e.downsampleAfterDays)*86400000).toISOString(),o=new Date(this.now().getTime()-Math.max(1,e.rawDays)*86400000).toISOString(),i=this.controlPlane.database.query(`SELECT * FROM telemetry_records WHERE kind='metric' AND source NOT LIKE '%:rollup' AND timestamp>=? AND timestamp<?${t?" AND project_id=?":""} ORDER BY timestamp ASC LIMIT 50001`).all(o,n,...t?[t]:[]);if(i.length>50000)throw Error("Telemetry downsampling is limited to 50,000 raw points per pass; run compaction more frequently.");let s=i.map(he),a=new Map;for(let c of s){let u=Math.floor(new Date(c.timestamp).getTime()/r)*r,p=JSON.stringify([c.projectId,c.environmentId??"",c.resourceId??"",c.source,c.name,c.unit??"",u]);a.set(p,[...a.get(p)??[],c])}return this.controlPlane.database.transaction(()=>{for(let c=0;c<s.length;c+=500){let u=s.slice(c,c+500).map((p)=>p.id);if(u.length)this.controlPlane.database.run(`DELETE FROM telemetry_records WHERE id IN (${u.map(()=>"?").join(",")})`,u)}for(let[c,u]of a){let[p,l,f,g,y,v,b]=JSON.parse(c),I=u.flatMap((_)=>_.value==null?[]:[_.value]);this.append({projectId:p,environmentId:l||void 0,resourceId:f||void 0,kind:"metric",source:`${g}:rollup`,name:y,unit:v||void 0,timestamp:new Date(b).toISOString(),value:te(I,"avg"),attributes:{downsampled:!0,count:I.length,min:te(I,"min"),max:te(I,"max"),p95:te(I,"p95"),bucketMs:r}})}})(),{compacted:s.length,rollups:a.size}}enforceRetention(e,t){let r=this.downsample(e,t),n=Math.min(3650,Math.max(1,Math.floor(e.rawDays))),o=new Date(this.now().getTime()-n*86400000).toISOString(),i=t?" AND project_id=?":"",s=this.controlPlane.database.run(`DELETE FROM telemetry_records WHERE timestamp<?${i}`,t?[o,t]:[o]).changes,a=Number(this.controlPlane.database.query(`SELECT MAX(0, COUNT(*)-?) excess FROM telemetry_records${t?" WHERE project_id=?":""}`).get(e.maxRecords,...t?[t]:[])?.excess??0);if(a>0)this.controlPlane.database.run(`DELETE FROM telemetry_records WHERE id IN (SELECT id FROM telemetry_records${t?" WHERE project_id=?":""} ORDER BY timestamp ASC LIMIT ?)`,t?[t,a]:[a]);return this.rebuildStatusRollups(t),{deleted:s+a,...r}}rebuildStatusRollups(e){let t=e?" WHERE project_id=?":"",r=e?[e]:[];this.controlPlane.database.transaction(()=>{this.controlPlane.database.run(`DELETE FROM telemetry_source_rollups${t}`,r),this.controlPlane.database.run(`INSERT INTO telemetry_source_rollups (
|
|
37
37
|
project_id, environment_id, resource_id, source,
|
|
@@ -41,12 +41,12 @@ ${JSON.stringify(t,null,2)}`}),{ok:!0,status:202}}if(e.kind==="sms"){if(!this.op
|
|
|
41
41
|
project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source,
|
|
42
42
|
MIN(observed_at), MAX(observed_at), SUM(ingested_bytes), COUNT(*)
|
|
43
43
|
FROM telemetry_records${t}
|
|
44
|
-
GROUP BY project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source`,r)})()}}function rn(e,t,r,n=new Date){let o=new Qe(e.controlPlane,{now:()=>n}),i=new Y(e);return e.listRules(t,r).filter((s)=>s.enabled&&!s.healthCheckId).map((s)=>{let a=new Date(n.getTime()-s.windowMs).toISOString(),d=o.query({projectId:t,environmentId:r,resourceIds:s.resourceId?[s.resourceId]:void 0,kinds:["metric"],names:[s.signal],from:a,to:new Date(n.getTime()+1).toISOString(),limit:5000}),c=d.records.flatMap((p)=>p.value==null?[]:[p.value]),u=c.length?s.operator==="gt"||s.operator==="gte"?Math.max(...c):s.operator==="lt"||s.operator==="lte"?Math.min(...c):c.at(0):void 0;return i.evaluate(s,{value:u,status:u==null?"no_data":void 0,timestamp:n.toISOString(),group:{resourceId:s.resourceId??"",source:d.records[0]?.source??""},evidence:{signal:s.signal,windowMs:s.windowMs,sampleCount:c.length,source:d.records[0]?.source??null}})})}var Wp=["spend.enforced"];function dn(e){if(e.level==="hard_capped")return"critical";if(e.level==="soft_capped")return"warning";return"info"}function ee(e,t="USD"){let r=e/100;try{return new Intl.NumberFormat("en-US",{style:"currency",currency:t}).format(r)}catch{return`${r.toFixed(2)} ${t}`}}function _d(e,t,r){let n=ee(t.projection.actualCents,e.currency),o=e.hardLimitCents??e.softLimitCents,i=o==null?"":` of ${ee(o,e.currency)}`,s=t.simulated?" [dry run]":"";if(r==="spend.released")return`[RESOLVED] ${e.name}: spend fell back to ${n}${i}.${s}`;if(r==="spend.enforced"){let c=t.actions.filter((u)=>u!=="notify").join(", ");return`[CAP] ${e.name}: ${n}${i} (${t.usedPercent.toFixed(0)}%). Enforcing ${c||"notifications only"}.${s}`}let a=fi(t.projection.timeToExhaustionMs),d=a?` Projected to reach the limit in ${a}.`:` Projected ${ee(t.projection.projectedCents,e.currency)} by period end.`;return`[SPEND] ${e.name}: ${n}${i} (${t.usedPercent.toFixed(0)}%).${d}${s}`}function kt(e,t,r){return{schemaVersion:1,event:r,notificationText:_d(e,t,r),spend:{budgetId:e.id,budgetName:e.name,organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,period:e.period,currency:e.currency,level:t.level,simulated:t.simulated,usedPercent:Math.round(t.usedPercent*10)/10,projectedPercent:Math.round(t.projectedPercent*10)/10,actualCents:Math.round(t.projection.actualCents),projectedCents:Math.round(t.projection.projectedCents),projectionConfidence:t.projection.confidence,softLimitCents:e.softLimitCents??null,hardLimitCents:e.hardLimitCents??null,timeToCap:fi(t.projection.timeToExhaustionMs),actions:t.actions,window:{start:t.window.start,end:t.window.end,label:t.window.label},reason:t.reason}}}function cn(e,t){return{schemaVersion:1,event:"spend.anomaly",notificationText:`[ANOMALY] Hourly spend ${Number.isFinite(e.deltaPercent)?`${e.deltaPercent>0?"+":""}${e.deltaPercent.toFixed(0)}%`:"new"} vs the usual ${ee(e.expected,t)} for this hour (observed ${ee(e.observed,t)}).`,spend:{anomalyId:e.id,organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,signal:e.signal,direction:e.direction,severity:e.severity,observedCents:Math.round(e.observed),expectedCents:Math.round(e.expected),score:Math.round(e.score*10)/10,bucketStart:e.bucketStart}}}function ln(e,t,r,n){let o=e.matcher;if(o.projectIds?.length&&(!t.projectId||!o.projectIds.includes(t.projectId)))return!1;if(o.environmentIds?.length&&(!t.environmentId||!o.environmentIds.includes(t.environmentId)))return!1;if(o.severities?.length&&!o.severities.includes(r))return!1;if(o.eventTypes?.length&&!o.eventTypes.includes(n))return!1;return!0}class To{store;options;constructor(e,t={}){this.store=e;this.options=t}now(){return this.options.now?.()??new Date}channelsFor(e,t,r,n){let o=[];for(let i of this.store.listRoutes(e)){if(!i.enabled||!ln(i,t,r,n))continue;let s=i.channelIds.map((a)=>this.store.getChannel(a)).filter((a)=>a?.status==="active");o.push({route:i,channels:s,quiet:Oe(i,this.now())})}return o}dispatch(e,t,r,n,o,i){let s=[],a=[];for(let d of this.channelsFor(e,t,r,n)){if(d.quiet&&n!=="spend.released"){a.push(d.route.id);continue}let c=this.store.countRouteDeliveries(d.route.id,new Date(this.now().getTime()-60000).toISOString()),u=Math.max(0,d.route.rateLimitPerMinute-c);for(let p of d.channels){if(u<=0)break;s.push(this.store.createDelivery({channelId:p.id,routeId:d.route.id,eventType:n,idempotencyKey:`spend:${n}:${i}:${p.id}`,payload:o,nextAttemptAt:d.route.groupWaitSeconds===0?void 0:new Date(this.now().getTime()+d.route.groupWaitSeconds*1000).toISOString()})),u--}}return{deliveries:s,suppressed:a}}notifyDecision(e,t){if(t.breaches.length===0)return{deliveries:[],suppressed:[]};let n=t.actions.some((i)=>i!=="notify")?"spend.enforced":"spend.threshold",o=t.breaches[t.breaches.length-1].atPercent;return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},dn(t),n,kt(e,t,n),`${e.id}:${t.window.start}:${o}`)}notifyRelease(e,t,r){if(r.length===0)return{deliveries:[],suppressed:[]};return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},"info","spend.released",{...kt(e,t,"spend.released"),released:[...r]},`${e.id}:${t.window.start}:${[...r].sort().join("+")}`)}notifyAnomaly(e,t="USD"){return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},e.severity,"spend.anomaly",cn(e,t),e.id)}}var Kp="spend.loop.lease";function un(){return`${typeof process>"u"?"unknown":String(process.pid)}:${crypto.randomUUID().slice(0,8)}`}class cs{controlPlane;owner;ttlMs;constructor(e,t={}){this.controlPlane=e;this.owner=t.owner??un(),this.ttlMs=Math.max(5000,(t.ttlSeconds??120)*1000),this.nowFn=t.now??(()=>new Date)}nowFn;read(){let e=this.controlPlane.getSetting("spend.loop.lease");if(!e||typeof e!=="object"||Array.isArray(e))return;let t=e;if(typeof t.owner!=="string"||typeof t.expiresAt!=="string")return;return t}current(){let e=this.read();if(!e)return;return new Date(e.expiresAt).getTime()>this.nowFn().getTime()?e:void 0}acquire(){let e=this.nowFn();return this.controlPlane.database.transaction(()=>{let r=this.read(),n=r&&new Date(r.expiresAt).getTime()>e.getTime();if(n&&r.owner!==this.owner)return!1;let o={owner:this.owner,acquiredAt:n?r.acquiredAt:e.toISOString(),expiresAt:new Date(e.getTime()+this.ttlMs).toISOString()};return this.controlPlane.setSetting("spend.loop.lease",o),!0})()}release(){return this.controlPlane.database.transaction(()=>{let t=this.read();if(!t||t.owner!==this.owner)return!1;return this.controlPlane.setSetting("spend.loop.lease",null),!0})()}held(){return this.current()?.owner===this.owner}}var Tt={applied:0,duplicates:0,costCents:0,unpricedMeters:[]};class hi{options;gate;service;notifications;constructor(e){this.options=e;this.gate=new Mt(e.controlPlane,{now:e.now}),this.service=new ht(e.store),this.notifications=e.alerts?new To(e.alerts,{now:e.now}):void 0}now(){return this.options.now?.()??new Date}ingest(e,t,r){if(t.length===0)return{...Tt};return this.service.ingestTelemetry(e,t,r)}async run(e,t=[]){let r=this.now(),n=[],o={scope:e,ingested:{...Tt},decisions:[],applied:[],released:[],failed:[],withheld:[],anomalies:[],notificationsSent:0,ranAt:r.toISOString(),durationMs:0,warnings:n};try{if(o.ingested=this.ingest(e.organizationId,t),o.ingested.unpricedMeters.length>0)n.push(`No price entry for ${o.ingested.unpricedMeters.join(", ")}; that usage is metered but counts as zero against every budget.`)}catch(a){n.push(`Usage ingest failed: ${ne(a)}`)}let i=Lc({gate:this.gate,transport:this.options.transport}),s;try{s=await this.service.runCycle({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,environmentKind:e.environmentKind,policy:this.options.policy,now:r,handlers:i})}catch(a){return n.push(`Spend evaluation failed: ${ne(a)}`),o.durationMs=this.now().getTime()-r.getTime(),o}o.decisions=s.statuses.map((a)=>a.decision),o.anomalies=s.anomalies;for(let a of s.enforcement)o.applied.push(...a.applied.map((d)=>d.action)),o.released.push(...a.released.map((d)=>d.action)),o.failed.push(...a.failed),o.withheld.push(...a.withheld.map((d)=>d.action));for(let a of o.failed)n.push(`Enforcement for ${a.action} did not complete: ${a.error}`);if(o.withheld.length>0)n.push(`${o.withheld.join(", ")} require approval on this environment and were not applied automatically.`);try{o.released.push(...this.reconcileGate(e))}catch(a){n.push(`Gate reconciliation failed: ${ne(a)}`)}if(this.notifications)try{for(let a of s.statuses)if(o.notificationsSent+=this.notifications.notifyDecision(a.budget,a.decision).deliveries.length,a.decision.releases.length>0)o.notificationsSent+=this.notifications.notifyRelease(a.budget,a.decision,a.decision.releases).deliveries.length;for(let a of s.anomalies)o.notificationsSent+=this.notifications.notifyAnomaly(a,this.options.store.priceBook.currency).deliveries.length}catch(a){n.push(`Spend notifications failed: ${ne(a)}`)}try{this.options.store.pruneUsage(this.options.retentionDays??400,r)}catch(a){n.push(`Usage pruning failed: ${ne(a)}`)}return o.durationMs=this.now().getTime()-r.getTime(),o}reconcileGate(e){let t=new Map(this.options.store.listBudgets({organizationId:e.organizationId}).filter((n)=>n.enabled).map((n)=>[n.id,n])),r=[];for(let n of this.gate.listUnder({organizationId:e.organizationId})){if(t.has(n.budgetId))continue;this.gate.close(n.budgetId,n.action),r.push(n.action)}return r}async runAll(e=[]){let t=[];for(let r of this.options.controlPlane.listOrganizations()){t.push(await this.run({organizationId:r.id},e));for(let n of this.options.controlPlane.listProjects().filter((o)=>o.organizationId===r.id))for(let o of this.options.controlPlane.listEnvironments(n.id))t.push(await this.run({organizationId:r.id,projectId:n.id,environmentId:o.id,environmentKind:o.kind}))}return t}}function ne(e){return e instanceof Error?e.message:String(e)}var yi=60;function Eo(e,t={}){let r=Math.max(10,t.intervalSeconds??yi)*1000,n=!1,o=!1,i=async()=>{if(n||o)return;if(t.lease&&!t.lease.acquire()){t.onSkip?.(t.lease.current()?.owner??"another process");return}n=!0;try{let a=await e.runAll();t.onResult?.(a)}catch(a){t.onError?.(a)}finally{n=!1}},s=setInterval(()=>void i(),r);if(s.unref?.(),t.immediate)i();return()=>{o=!0,clearInterval(s),t.lease?.release()}}function ie(e,t){if(t.code!==0)throw Error(`${e} failed (exit ${t.code}): ${t.stderr.trim().slice(0,400)}`)}class Od{options;constructor(e){this.options=e}async targets(e){let t=await this.options.functions(e);if(t.length===0)throw Error("No Lambda functions were resolved for this scope.");return t}async suspendFunctions(e){let t=await this.targets(e),r={};for(let n of t)r[n]=await this.options.lambda.getFunctionConcurrency(n),await this.options.lambda.putFunctionConcurrency(n,0);return{kind:"lambda_reserved_concurrency",previous:r}}async resumeFunctions(e){let t=e.previous??{};for(let[r,n]of Object.entries(t))if(typeof n==="number")await this.options.lambda.putFunctionConcurrency(r,n);else await this.options.lambda.deleteFunctionConcurrency(r)}async serveStatic(e){return{...await this.suspendFunctions(e),via:"serve_static"}}async restoreDynamic(e){await this.resumeFunctions(e)}async suspendProject(e){let t=await this.targets(e),r={};for(let n of t){let i={...(await this.options.lambda.getFunction(n)).Configuration?.Environment?.Variables??{}};r[n]=i.MAINTENANCE_MODE??null,await this.options.lambda.updateFunctionConfiguration({FunctionName:n,Environment:{Variables:{...i,MAINTENANCE_MODE:"1"}}}),await this.options.republish?.(n)}return{kind:"lambda_maintenance_mode",previous:r}}async resumeProject(e){let t=e.previous??{};for(let r of Object.keys(t)){let o={...(await this.options.lambda.getFunction(r)).Configuration?.Environment?.Variables??{}};o.MAINTENANCE_MODE=typeof t[r]==="string"?t[r]:"0",await this.options.lambda.updateFunctionConfiguration({FunctionName:r,Environment:{Variables:o}}),await this.options.republish?.(r)}}}class $d{options;constructor(e){this.options=e}async unitsFor(e){let t=await this.options.units(e);if(t.length===0)throw Error("No systemd units were resolved for this scope.");for(let r of t)if(!/^[A-Za-z0-9@._-]+$/.test(r))throw Error(`Refusing to act on an unsafe unit name: ${r}`);return t}async stopUnits(e,t){let r=await this.unitsFor(e),n=[];for(let o of r){let i=await this.options.exec(this.options.host,`systemctl list-units --plain --no-legend --state=active --type=service '${o}@*.service' '${o}.service' 2>/dev/null | awk '{print $1}'`);ie(`listing units for ${o}`,i);let s=i.stdout.split(`
|
|
44
|
+
GROUP BY project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source`,r)})()}}function rn(e,t,r,n=new Date){let o=new Qe(e.controlPlane,{now:()=>n}),i=new Y(e);return e.listRules(t,r).filter((s)=>s.enabled&&!s.healthCheckId).map((s)=>{let a=new Date(n.getTime()-s.windowMs).toISOString(),d=o.query({projectId:t,environmentId:r,resourceIds:s.resourceId?[s.resourceId]:void 0,kinds:["metric"],names:[s.signal],from:a,to:new Date(n.getTime()+1).toISOString(),limit:5000}),c=d.records.flatMap((p)=>p.value==null?[]:[p.value]),u=c.length?s.operator==="gt"||s.operator==="gte"?Math.max(...c):s.operator==="lt"||s.operator==="lte"?Math.min(...c):c.at(0):void 0;return i.evaluate(s,{value:u,status:u==null?"no_data":void 0,timestamp:n.toISOString(),group:{resourceId:s.resourceId??"",source:d.records[0]?.source??""},evidence:{signal:s.signal,windowMs:s.windowMs,sampleCount:c.length,source:d.records[0]?.source??null}})})}var Xp=["spend.enforced"];function dn(e){if(e.level==="hard_capped")return"critical";if(e.level==="soft_capped")return"warning";return"info"}function ee(e,t="USD"){let r=e/100;try{return new Intl.NumberFormat("en-US",{style:"currency",currency:t}).format(r)}catch{return`${r.toFixed(2)} ${t}`}}function Od(e,t,r){let n=ee(t.projection.actualCents,e.currency),o=e.hardLimitCents??e.softLimitCents,i=o==null?"":` of ${ee(o,e.currency)}`,s=t.simulated?" [dry run]":"";if(r==="spend.released")return`[RESOLVED] ${e.name}: spend fell back to ${n}${i}.${s}`;if(r==="spend.enforced"){let c=t.actions.filter((u)=>u!=="notify").join(", ");return`[CAP] ${e.name}: ${n}${i} (${t.usedPercent.toFixed(0)}%). Enforcing ${c||"notifications only"}.${s}`}let a=fi(t.projection.timeToExhaustionMs),d=a?` Projected to reach the limit in ${a}.`:` Projected ${ee(t.projection.projectedCents,e.currency)} by period end.`;return`[SPEND] ${e.name}: ${n}${i} (${t.usedPercent.toFixed(0)}%).${d}${s}`}function kt(e,t,r){return{schemaVersion:1,event:r,notificationText:Od(e,t,r),spend:{budgetId:e.id,budgetName:e.name,organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,period:e.period,currency:e.currency,level:t.level,simulated:t.simulated,usedPercent:Math.round(t.usedPercent*10)/10,projectedPercent:Math.round(t.projectedPercent*10)/10,actualCents:Math.round(t.projection.actualCents),projectedCents:Math.round(t.projection.projectedCents),projectionConfidence:t.projection.confidence,softLimitCents:e.softLimitCents??null,hardLimitCents:e.hardLimitCents??null,timeToCap:fi(t.projection.timeToExhaustionMs),actions:t.actions,window:{start:t.window.start,end:t.window.end,label:t.window.label},reason:t.reason}}}function cn(e,t){return{schemaVersion:1,event:"spend.anomaly",notificationText:`[ANOMALY] Hourly spend ${Number.isFinite(e.deltaPercent)?`${e.deltaPercent>0?"+":""}${e.deltaPercent.toFixed(0)}%`:"new"} vs the usual ${ee(e.expected,t)} for this hour (observed ${ee(e.observed,t)}).`,spend:{anomalyId:e.id,organizationId:e.organizationId,projectId:e.projectId??null,environmentId:e.environmentId??null,signal:e.signal,direction:e.direction,severity:e.severity,observedCents:Math.round(e.observed),expectedCents:Math.round(e.expected),score:Math.round(e.score*10)/10,bucketStart:e.bucketStart}}}function ln(e,t,r,n){let o=e.matcher;if(o.projectIds?.length&&(!t.projectId||!o.projectIds.includes(t.projectId)))return!1;if(o.environmentIds?.length&&(!t.environmentId||!o.environmentIds.includes(t.environmentId)))return!1;if(o.severities?.length&&!o.severities.includes(r))return!1;if(o.eventTypes?.length&&!o.eventTypes.includes(n))return!1;return!0}class To{store;options;constructor(e,t={}){this.store=e;this.options=t}now(){return this.options.now?.()??new Date}channelsFor(e,t,r,n){let o=[];for(let i of this.store.listRoutes(e)){if(!i.enabled||!ln(i,t,r,n))continue;let s=i.channelIds.map((a)=>this.store.getChannel(a)).filter((a)=>a?.status==="active");o.push({route:i,channels:s,quiet:Oe(i,this.now())})}return o}dispatch(e,t,r,n,o,i){let s=[],a=[];for(let d of this.channelsFor(e,t,r,n)){if(d.quiet&&n!=="spend.released"){a.push(d.route.id);continue}let c=this.store.countRouteDeliveries(d.route.id,new Date(this.now().getTime()-60000).toISOString()),u=Math.max(0,d.route.rateLimitPerMinute-c);for(let p of d.channels){if(u<=0)break;s.push(this.store.createDelivery({channelId:p.id,routeId:d.route.id,eventType:n,idempotencyKey:`spend:${n}:${i}:${p.id}`,payload:o,nextAttemptAt:d.route.groupWaitSeconds===0?void 0:new Date(this.now().getTime()+d.route.groupWaitSeconds*1000).toISOString()})),u--}}return{deliveries:s,suppressed:a}}notifyDecision(e,t){if(t.breaches.length===0)return{deliveries:[],suppressed:[]};let n=t.actions.some((i)=>i!=="notify")?"spend.enforced":"spend.threshold",o=t.breaches[t.breaches.length-1].atPercent;return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},dn(t),n,kt(e,t,n),`${e.id}:${t.window.start}:${o}`)}notifyRelease(e,t,r){if(r.length===0)return{deliveries:[],suppressed:[]};return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},"info","spend.released",{...kt(e,t,"spend.released"),released:[...r]},`${e.id}:${t.window.start}:${[...r].sort().join("+")}`)}notifyAnomaly(e,t="USD"){return this.dispatch(e.organizationId,{projectId:e.projectId,environmentId:e.environmentId},e.severity,"spend.anomaly",cn(e,t),e.id)}}var Qp="spend.loop.lease";function un(){return`${typeof process>"u"?"unknown":String(process.pid)}:${crypto.randomUUID().slice(0,8)}`}class cs{controlPlane;owner;ttlMs;constructor(e,t={}){this.controlPlane=e;this.owner=t.owner??un(),this.ttlMs=Math.max(5000,(t.ttlSeconds??120)*1000),this.nowFn=t.now??(()=>new Date)}nowFn;read(){let e=this.controlPlane.getSetting("spend.loop.lease");if(!e||typeof e!=="object"||Array.isArray(e))return;let t=e;if(typeof t.owner!=="string"||typeof t.expiresAt!=="string")return;return t}current(){let e=this.read();if(!e)return;return new Date(e.expiresAt).getTime()>this.nowFn().getTime()?e:void 0}acquire(){let e=this.nowFn();return this.controlPlane.database.transaction(()=>{let r=this.read(),n=r&&new Date(r.expiresAt).getTime()>e.getTime();if(n&&r.owner!==this.owner)return!1;let o={owner:this.owner,acquiredAt:n?r.acquiredAt:e.toISOString(),expiresAt:new Date(e.getTime()+this.ttlMs).toISOString()};return this.controlPlane.setSetting("spend.loop.lease",o),!0})()}release(){return this.controlPlane.database.transaction(()=>{let t=this.read();if(!t||t.owner!==this.owner)return!1;return this.controlPlane.setSetting("spend.loop.lease",null),!0})()}held(){return this.current()?.owner===this.owner}}var Tt={applied:0,duplicates:0,costCents:0,unpricedMeters:[]};class hi{options;gate;service;notifications;constructor(e){this.options=e;this.gate=new Mt(e.controlPlane,{now:e.now}),this.service=new ht(e.store),this.notifications=e.alerts?new To(e.alerts,{now:e.now}):void 0}now(){return this.options.now?.()??new Date}ingest(e,t,r){if(t.length===0)return{...Tt};return this.service.ingestTelemetry(e,t,r)}async run(e,t=[]){let r=this.now(),n=[],o={scope:e,ingested:{...Tt},decisions:[],applied:[],released:[],failed:[],withheld:[],anomalies:[],notificationsSent:0,ranAt:r.toISOString(),durationMs:0,warnings:n};try{if(o.ingested=this.ingest(e.organizationId,t),o.ingested.unpricedMeters.length>0)n.push(`No price entry for ${o.ingested.unpricedMeters.join(", ")}; that usage is metered but counts as zero against every budget.`)}catch(a){n.push(`Usage ingest failed: ${ne(a)}`)}let i=Lc({gate:this.gate,transport:this.options.transport}),s;try{s=await this.service.runCycle({organizationId:e.organizationId,projectId:e.projectId,environmentId:e.environmentId,environmentKind:e.environmentKind,policy:this.options.policy,now:r,handlers:i})}catch(a){return n.push(`Spend evaluation failed: ${ne(a)}`),o.durationMs=this.now().getTime()-r.getTime(),o}o.decisions=s.statuses.map((a)=>a.decision),o.anomalies=s.anomalies;for(let a of s.enforcement)o.applied.push(...a.applied.map((d)=>d.action)),o.released.push(...a.released.map((d)=>d.action)),o.failed.push(...a.failed),o.withheld.push(...a.withheld.map((d)=>d.action));for(let a of o.failed)n.push(`Enforcement for ${a.action} did not complete: ${a.error}`);if(o.withheld.length>0)n.push(`${o.withheld.join(", ")} require approval on this environment and were not applied automatically.`);try{o.released.push(...this.reconcileGate(e))}catch(a){n.push(`Gate reconciliation failed: ${ne(a)}`)}if(this.notifications)try{for(let a of s.statuses)if(o.notificationsSent+=this.notifications.notifyDecision(a.budget,a.decision).deliveries.length,a.decision.releases.length>0)o.notificationsSent+=this.notifications.notifyRelease(a.budget,a.decision,a.decision.releases).deliveries.length;for(let a of s.anomalies)o.notificationsSent+=this.notifications.notifyAnomaly(a,this.options.store.priceBook.currency).deliveries.length}catch(a){n.push(`Spend notifications failed: ${ne(a)}`)}try{this.options.store.pruneUsage(this.options.retentionDays??400,r)}catch(a){n.push(`Usage pruning failed: ${ne(a)}`)}return o.durationMs=this.now().getTime()-r.getTime(),o}reconcileGate(e){let t=new Map(this.options.store.listBudgets({organizationId:e.organizationId}).filter((n)=>n.enabled).map((n)=>[n.id,n])),r=[];for(let n of this.gate.listUnder({organizationId:e.organizationId})){if(t.has(n.budgetId))continue;this.gate.close(n.budgetId,n.action),r.push(n.action)}return r}async runAll(e=[]){let t=[];for(let r of this.options.controlPlane.listOrganizations()){t.push(await this.run({organizationId:r.id},e));for(let n of this.options.controlPlane.listProjects().filter((o)=>o.organizationId===r.id))for(let o of this.options.controlPlane.listEnvironments(n.id))t.push(await this.run({organizationId:r.id,projectId:n.id,environmentId:o.id,environmentKind:o.kind}))}return t}}function ne(e){return e instanceof Error?e.message:String(e)}var yi=60;function Eo(e,t={}){let r=Math.max(10,t.intervalSeconds??yi)*1000,n=!1,o=!1,i=async()=>{if(n||o)return;if(t.lease&&!t.lease.acquire()){t.onSkip?.(t.lease.current()?.owner??"another process");return}n=!0;try{let a=await e.runAll();t.onResult?.(a)}catch(a){t.onError?.(a)}finally{n=!1}},s=setInterval(()=>void i(),r);if(s.unref?.(),t.immediate)i();return()=>{o=!0,clearInterval(s),t.lease?.release()}}function ie(e,t){if(t.code!==0)throw Error(`${e} failed (exit ${t.code}): ${t.stderr.trim().slice(0,400)}`)}class $d{options;constructor(e){this.options=e}async targets(e){let t=await this.options.functions(e);if(t.length===0)throw Error("No Lambda functions were resolved for this scope.");return t}async suspendFunctions(e){let t=await this.targets(e),r={};for(let n of t)r[n]=await this.options.lambda.getFunctionConcurrency(n),await this.options.lambda.putFunctionConcurrency(n,0);return{kind:"lambda_reserved_concurrency",previous:r}}async resumeFunctions(e){let t=e.previous??{};for(let[r,n]of Object.entries(t))if(typeof n==="number")await this.options.lambda.putFunctionConcurrency(r,n);else await this.options.lambda.deleteFunctionConcurrency(r)}async serveStatic(e){return{...await this.suspendFunctions(e),via:"serve_static"}}async restoreDynamic(e){await this.resumeFunctions(e)}async suspendProject(e){let t=await this.targets(e),r={};for(let n of t){let i={...(await this.options.lambda.getFunction(n)).Configuration?.Environment?.Variables??{}};r[n]=i.MAINTENANCE_MODE??null,await this.options.lambda.updateFunctionConfiguration({FunctionName:n,Environment:{Variables:{...i,MAINTENANCE_MODE:"1"}}}),await this.options.republish?.(n)}return{kind:"lambda_maintenance_mode",previous:r}}async resumeProject(e){let t=e.previous??{};for(let r of Object.keys(t)){let o={...(await this.options.lambda.getFunction(r)).Configuration?.Environment?.Variables??{}};o.MAINTENANCE_MODE=typeof t[r]==="string"?t[r]:"0",await this.options.lambda.updateFunctionConfiguration({FunctionName:r,Environment:{Variables:o}}),await this.options.republish?.(r)}}}class Ld{options;constructor(e){this.options=e}async unitsFor(e){let t=await this.options.units(e);if(t.length===0)throw Error("No systemd units were resolved for this scope.");for(let r of t)if(!/^[A-Za-z0-9@._-]+$/.test(r))throw Error(`Refusing to act on an unsafe unit name: ${r}`);return t}async stopUnits(e,t){let r=await this.unitsFor(e),n=[];for(let o of r){let i=await this.options.exec(this.options.host,`systemctl list-units --plain --no-legend --state=active --type=service '${o}@*.service' '${o}.service' 2>/dev/null | awk '{print $1}'`);ie(`listing units for ${o}`,i);let s=i.stdout.split(`
|
|
45
45
|
`).map((a)=>a.trim()).filter((a)=>/^[A-Za-z0-9@._-]+\.service$/.test(a));for(let a of s){let d=await this.options.exec(this.options.host,`systemctl stop '${a}'`);ie(`stopping ${a}`,d),n.push(a)}}return{kind:"systemd_units",via:t,stopped:n}}async startUnits(e){let t=Array.isArray(e.stopped)?e.stopped:[];for(let r of t){if(!/^[A-Za-z0-9@._-]+$/.test(r))continue;let n=await this.options.exec(this.options.host,`systemctl start '${r}'`);ie(`starting ${r}`,n)}}async suspendFunctions(e){return this.stopUnits(e,"suspend_functions")}async resumeFunctions(e){await this.startUnits(e)}async serveStatic(e){return this.stopUnits(e,"serve_static")}async restoreDynamic(e){await this.startUnits(e)}async suspendProject(e){return this.stopUnits(e,"suspend_project")}async resumeProject(e){await this.startUnits(e)}async throttleRequests(e){let t=this.options.renderDdos,r=this.options.ddos;if(!t||!r)throw Error("Request throttling needs a DDoS config and renderer on this transport.");let n={rateLimitFactor:e.factor},o={...r.thresholds,newConnectionsPerSecond:us(r.thresholds?.newConnectionsPerSecond??50,n),concurrentPerSource:us(r.thresholds?.concurrentPerSource??100,n)},i=t({...r,thresholds:o}),s=await this.options.exec(this.options.host,`bash -s <<'TS_CLOUD_THROTTLE_EOF'
|
|
46
46
|
${i}
|
|
47
47
|
TS_CLOUD_THROTTLE_EOF`);return ie("applying the throttled firewall ruleset",s),{kind:"nftables_throttle",factor:e.factor,previousThresholds:r.thresholds??{}}}async restoreRequests(e){let t=this.options.renderDdos,r=this.options.ddos;if(!t||!r)return;let n=e.previousThresholds??{},o=t({...r,thresholds:n}),i=await this.options.exec(this.options.host,`bash -s <<'TS_CLOUD_THROTTLE_EOF'
|
|
48
48
|
${o}
|
|
49
|
-
TS_CLOUD_THROTTLE_EOF`);ie("restoring the firewall ruleset",i)}}function
|
|
49
|
+
TS_CLOUD_THROTTLE_EOF`);ie("restoring the firewall ruleset",i)}}function Yp(e){let t=async(n,o)=>{let i={},s,a=0;for(let[d,c]of e.entries()){let u=c[n];if(!u)continue;a++;try{i[String(d)]=await u.call(c,o)}catch(p){i[String(d)]={error:p instanceof Error?p.message:String(p)},s??=p}}if(a===0)throw Error(`No transport implements ${n}.`);if(s)throw s;return{kind:"composite",legs:i}},r=async(n,o)=>{let i=o.legs??{},s;for(let[a,d]of e.entries()){let c=d[n];if(!c)continue;let u=i[String(a)];if(!u||typeof u!=="object"||Array.isArray(u)||"error"in u)continue;try{await c.call(d,u)}catch(p){s??=p}}if(s)throw s};return{throttleRequests:(n)=>t("throttleRequests",n),restoreRequests:(n)=>r("restoreRequests",n),suspendFunctions:(n)=>t("suspendFunctions",n),resumeFunctions:(n)=>r("resumeFunctions",n),serveStatic:(n)=>t("serveStatic",n),restoreDynamic:(n)=>r("restoreDynamic",n),suspendProject:(n)=>t("suspendProject",n),resumeProject:(n)=>r("resumeProject",n)}}import{createHash as Yn}from"node:crypto";class se extends Error{constructor(){super("Operation cancellation was requested")}}class ye extends Error{timeoutSeconds;constructor(e){super(`Operation exceeded its ${e}s timeout`);this.timeoutSeconds=e}}class $e extends Error{errorClass;constructor(e,t){super(e);this.errorClass=t}}var ve={project:2,environment:1,provider:2,builds:1},mn=30,Dt=16384,pn=["succeeded","failed","cancelled","timed_out"],je=new Map,xt=new WeakMap;function Nt(e){if(e.path===":memory:"){let n=xt.get(e);if(n)return n;let o=new Set;return xt.set(e,o),o}let t=je.get(e.path);if(t)return t;let r=new Set;return je.set(e.path,r),r}function z(e){return typeof e==="string"&&e?e:void 0}function gn(e){try{let t=JSON.parse(String(e));return Array.isArray(t)?t.map(String):[]}catch{return[]}}function hn(e){return{operationId:String(e.operation_id),lockKey:z(e.lock_key),providerKey:z(e.provider_key),buildSlot:Number(e.build_slot)===1,maxAttempts:Number(e.max_attempts),availableAt:String(e.available_at),timeoutSeconds:Number(e.timeout_seconds),heartbeatAt:z(e.heartbeat_at),currentStep:z(e.current_step),blockedReason:z(e.blocked_reason),retryClasses:gn(e.retry_classes),resumePolicy:String(e.resume_policy),cancellationMode:String(e.cancellation_mode),retentionUntil:String(e.retention_until),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function jt(e){return{sequence:Number(e.sequence),id:String(e.id),operationId:String(e.operation_id),stream:String(e.stream),step:z(e.step),message:String(e.message),redacted:Number(e.redacted)===1,truncated:Number(e.truncated)===1,createdAt:String(e.created_at)}}function x(e,t,r){return Number.isFinite(e)?Math.min(r,Math.max(1,Math.floor(e))):t}class S{controlPlane;nowFn;idFn;workerId;leaseMs;limits;constructor(e,t={}){this.controlPlane=e;this.workerId=t.workerId??`worker:${process.pid}:${crypto.randomUUID()}`,this.leaseMs=x(t.leaseMs,60000,3600000),this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID());let r=e.getSetting("queue.concurrency");this.limits={project:x(t.limits?.project??r?.project,ve.project,100),environment:x(t.limits?.environment??r?.environment,ve.environment,100),provider:x(t.limits?.provider??r?.provider,ve.provider,100),builds:x(t.limits?.builds??r?.builds,ve.builds,100)}}now(){return this.nowFn().toISOString()}leaseExpiry(){return new Date(this.nowFn().getTime()+this.leaseMs).toISOString()}enqueue(e){let t=this.controlPlane.createOperation(e);if(this.getJob(t.id))return this.view(t.id);let n=this.now(),o=x(e.maxAttempts,1,20),i=x(e.timeoutSeconds,1800,86400),s=x(e.retentionDays,mn,3650),a=e.availableAt?new Date(e.availableAt).toISOString():n,d=new Date(this.nowFn().getTime()+s*24*60*60*1000).toISOString();this.controlPlane.database.run(`INSERT OR IGNORE INTO operation_jobs (operation_id, lock_key, provider_key, build_slot, max_attempts, available_at, timeout_seconds, retry_classes, resume_policy, cancellation_mode, retention_until, created_at, updated_at)
|
|
50
50
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[t.id,e.lockKey??e.resourceId??null,e.providerKey??null,e.buildSlot?1:0,o,a,i,JSON.stringify([...new Set(e.retryClasses??[])]),e.resumePolicy??"fail",e.cancellationMode??"cooperative",d,n,n]),this.appendLog(t.id,"Queued for durable execution.",{stream:"system"});let c=this.view(t.id);return this.notifyAvailable(),c}onAvailable(e){let t=Nt(this.controlPlane);return t.add(e),()=>{if(t.delete(e),t.size===0&&this.controlPlane.path!==":memory:")je.delete(this.controlPlane.path)}}notifyAvailable(){for(let e of Nt(this.controlPlane))e()}getJob(e){let t=this.controlPlane.database.query("SELECT * FROM operation_jobs WHERE operation_id=?").get(e);return t?hn(t):void 0}view(e){let t=this.controlPlane.getOperation(e),r=this.getJob(e);if(!t||!r)return;let n;if(t.state==="queued")n={ahead:Number(this.controlPlane.database.query("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? AND (o.priority>? OR (o.priority=? AND o.created_at<?))").get(this.now(),t.priority,t.priority,t.createdAt)?.count??0),precision:"bounded"};return{operation:t,job:r,approximatePosition:n}}list(e={}){return this.controlPlane.listOperations({projectId:e.projectId,state:e.state,limit:e.limit??200}).map((t)=>this.view(t.id)).filter((t)=>!!t)}configureConcurrency(e,t={}){let r={project:x(e.project,this.limits.project,100),environment:x(e.environment,this.limits.environment,100),provider:x(e.provider,this.limits.provider,100),builds:x(e.builds,this.limits.builds,100)};return Object.assign(this.limits,r),this.controlPlane.setSetting("queue.concurrency",r),this.controlPlane.appendEvent({organizationId:t.organizationId,actorId:t.actorId,type:"queue.concurrency.updated",level:"warning",payload:r}),r}runningCount(e,t){return Number(this.controlPlane.database.query(e).get(...t)?.count??0)}blockReason(e,t){if(t.lockKey){if(this.controlPlane.database.query("SELECT * FROM operation_locks WHERE lock_key=? AND operation_id!=? AND lease_expires_at>?").get(t.lockKey,e.id,this.now()))return`resource_lock:${t.lockKey}`}if(e.projectId&&this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND project_id=?",[e.projectId])>=this.limits.project)return"project_concurrency";if(e.environmentId&&this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND environment_id=?",[e.environmentId])>=this.limits.environment)return"environment_concurrency";if(t.providerKey&&this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.provider_key=?",[t.providerKey])>=this.limits.provider)return"provider_concurrency";if(t.buildSlot&&this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.build_slot=1",[])>=this.limits.builds)return"build_concurrency";return}claim(e){return this.controlPlane.transaction(()=>{let t=this.now();this.controlPlane.database.run("DELETE FROM operation_locks WHERE lease_expires_at<=?",[t]);let r=this.controlPlane.getOperation(e),n=r?this.getJob(r.id):void 0;if(!r||!n||r.state!=="queued"||n.availableAt>t)return;if(r.cancelRequestedAt){this.controlPlane.transitionOperation(r.id,{to:"cancelled",expectedVersion:r.version,output:{cancelledBeforeStart:!0}}),this.appendLog(r.id,"Cancelled before execution began.",{stream:"system"});return}let o=this.blockReason(r,n);if(o){this.controlPlane.database.run("UPDATE operation_jobs SET blocked_reason=?, updated_at=? WHERE operation_id=?",[o,t,r.id]);return}let i=this.controlPlane.claimOperation(r.id,this.workerId,this.leaseMs);if(!i)return;let s=i.leaseExpiresAt??this.leaseExpiry();if(n.lockKey)this.controlPlane.database.run("INSERT INTO operation_locks (lock_key, operation_id, lease_owner, lease_expires_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)",[n.lockKey,r.id,this.workerId,s,t,t]);return this.controlPlane.database.run("UPDATE operation_jobs SET heartbeat_at=?, blocked_reason=NULL, updated_at=? WHERE operation_id=?",[t,t,r.id]),this.appendLog(r.id,`Claimed by ${this.workerId}; attempt ${i.attempt}.`,{stream:"system"}),this.view(r.id)})}claimNext(e){let t=this.now(),r=e?.length?`AND o.kind IN (${e.map(()=>"?").join(",")})`:"",n=this.controlPlane.database.query(`SELECT o.id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? ${r} ORDER BY o.priority DESC, o.created_at ASC, o.rowid ASC LIMIT 100`).all(t,...e??[]);for(let o of n){let i=this.claim(String(o.id));if(i)return i}return}heartbeat(e,t){let r=this.controlPlane.getOperation(e);if(!r||r.state!=="running"||r.leaseOwner!==this.workerId)throw Error("Operation lease is not owned by this worker");let n=this.now(),o=this.leaseExpiry(),i=this.getJob(e);if(this.controlPlane.database.run("UPDATE operations SET lease_expires_at=?, updated_at=?, version=version+1 WHERE id=? AND state='running' AND lease_owner=? AND version=?",[o,n,e,this.workerId,r.version]).changes!==1)throw Error("Operation lease changed before heartbeat");if(this.controlPlane.database.run("UPDATE operation_jobs SET heartbeat_at=?, current_step=COALESCE(?, current_step), updated_at=? WHERE operation_id=?",[n,t??null,n,e]),i?.lockKey)this.controlPlane.database.run("UPDATE operation_locks SET lease_expires_at=?, updated_at=? WHERE lock_key=? AND operation_id=? AND lease_owner=?",[o,n,i.lockKey,e,this.workerId]);if(t&&t!==i?.currentStep)this.controlPlane.appendEvent({projectId:r.projectId,operationId:e,resourceId:r.resourceId,actorId:r.actorId,correlationId:r.correlationId,type:"operation.step",payload:{step:t}})}appendLog(e,t,r={}){if(!this.getJob(e))throw Error(`Queue job ${e} was not found`);let n=t,o=!1;for(let u of r.secrets??[])if(u&&n.includes(u))n=n.split(u).join("[REDACTED]"),o=!0;let i=h({message:n});if(i.message!==n)o=!0;n=i.message??"[output unavailable]";let s=Buffer.from(n),a=s.byteLength>Dt;if(a)n=`${s.subarray(0,Dt-32).toString("utf8")}
|
|
51
51
|
[output truncated]`;let d=this.idFn(),c=this.now();return this.controlPlane.database.run("INSERT INTO operation_logs (id, operation_id, stream, step, message, redacted, truncated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",[d,e,r.stream??"stdout",r.step??null,n,o?1:0,a?1:0,c]),jt(this.controlPlane.database.query("SELECT * FROM operation_logs WHERE id=?").get(d))}logs(e,t={}){let r=Math.min(1000,Math.max(1,t.limit??200));return this.controlPlane.database.query("SELECT * FROM operation_logs WHERE operation_id=? AND sequence>? ORDER BY sequence ASC LIMIT ?").all(e,t.after??0,r).map(jt)}requestCancellation(e,t){let r=this.controlPlane.getOperation(e);if(!r||pn.includes(r.state))throw Error("Only queued or running operations can be cancelled");let n=this.controlPlane.requestCancellation(e);if(this.controlPlane.appendEvent({projectId:r.projectId,operationId:e,resourceId:r.resourceId,actorId:t,correlationId:r.correlationId,type:"operation.cancellation_requested",level:"warning",payload:{state:r.state}}),this.appendLog(e,r.state==="queued"?"Cancellation accepted before execution.":"Cancellation requested; waiting for the current provider step.",{stream:"system"}),n.state==="queued")return this.finish(e,"cancelled",{cancelledBeforeStart:!0});return n}retry(e,t,r={}){let n=this.controlPlane.getOperation(e),o=this.getJob(e);if(!n||!o||!["failed","cancelled","timed_out"].includes(n.state))throw Error("Only failed, cancelled, or timed-out queue jobs can be retried");if(n.attempt>=o.maxAttempts)throw Error(`Operation reached its ${o.maxAttempts}-attempt limit`);if(!o.retryClasses.includes(t))throw Error(`Retry class ${t} is not allowed for this operation`);let i=this.controlPlane.transitionOperation(e,{to:"queued",expectedVersion:n.version,error:`Retry requested after ${t}`}),s=new Date(this.nowFn().getTime()+Math.max(0,r.delayMs??0)).toISOString();this.controlPlane.database.run("UPDATE operations SET cancel_requested_at=NULL, finished_at=NULL WHERE id=?",[e]),this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason=NULL, updated_at=? WHERE operation_id=?",[s,this.now(),e]),this.controlPlane.appendEvent({projectId:n.projectId,operationId:e,resourceId:n.resourceId,actorId:r.actorId,correlationId:n.correlationId,type:"operation.retry_requested",payload:{errorClass:t,availableAt:s,nextAttempt:n.attempt+1}}),this.appendLog(e,`Retry queued for error class ${t}.`,{stream:"system"});let a=this.controlPlane.getOperation(i.id);return this.notifyAvailable(),a}release(e){this.controlPlane.database.run("DELETE FROM operation_locks WHERE operation_id=?",[e])}finish(e,t,r={},n){let o=this.controlPlane.getOperation(e);if(!o)throw Error(`Operation ${e} was not found`);let i=this.controlPlane.transitionOperation(e,{to:t,expectedVersion:o.version,output:r,error:n});return this.release(e),i}complete(e,t={}){let r=this.controlPlane.getOperation(e);if(!r||r.state!=="running"||r.leaseOwner!==this.workerId)throw Error("Only the lease owner can complete a running operation");return this.appendLog(e,"Operation completed successfully.",{stream:"system"}),this.finish(e,"succeeded",t)}fail(e,t,r={}){let n=this.controlPlane.getOperation(e);if(!n||n.state!=="running"||n.leaseOwner!==this.workerId)throw Error("Only the lease owner can fail a running operation");return this.appendLog(e,t,{stream:"stderr"}),this.finish(e,"failed",r,t)}async runOne(e){let t=this.claimNext(Object.keys(e));if(!t)return{handled:!1};let{operation:r,job:n}=t,o=e[r.kind];if(!o)return{handled:!1};let i=new AbortController,s=!1,a=setTimeout(()=>{s=!0,i.abort(new ye(n.timeoutSeconds))},n.timeoutSeconds*1000),d=setInterval(()=>{try{this.heartbeat(r.id)}catch{}},Math.max(250,Math.floor(this.leaseMs/3))),c=setInterval(()=>{if(this.controlPlane.getOperation(r.id)?.cancelRequestedAt)i.abort(new se)},100),u={operation:r,signal:i.signal,log:(p,l)=>this.appendLog(r.id,p,l),checkpoint:(p,l)=>{this.heartbeat(r.id,p),this.appendLog(r.id,l??p,{stream:"step",step:p})},heartbeat:()=>this.heartbeat(r.id),cancellationRequested:()=>!!this.controlPlane.getOperation(r.id)?.cancelRequestedAt,throwIfCancellationRequested:()=>{if(this.controlPlane.getOperation(r.id)?.cancelRequestedAt)throw new se}};try{let p=await Promise.race([o(u),new Promise((g,y)=>i.signal.addEventListener("abort",()=>y(i.signal.reason),{once:!0}))]);if(this.controlPlane.getOperation(r.id).cancelRequestedAt){let g=n.cancellationMode==="provider_non_cancellable";return this.appendLog(r.id,g?"Provider step completed after cancellation was requested; reconciliation is required.":"Operation cancelled cooperatively.",{stream:"system"}),{handled:!0,operation:this.finish(r.id,"cancelled",{providerCompleted:g,reconciliationRequired:g}),terminalState:"cancelled"}}return{handled:!0,operation:this.complete(r.id,p??{}),terminalState:"succeeded"}}catch(p){if(s||p instanceof ye)return this.appendLog(r.id,`Timed out after ${n.timeoutSeconds}s.`,{stream:"system"}),{handled:!0,operation:this.finish(r.id,"timed_out",{reconciliationRequired:n.cancellationMode==="provider_non_cancellable"},p instanceof Error?p.message:String(p)),terminalState:"timed_out"};if(p instanceof se||this.controlPlane.getOperation(r.id)?.cancelRequestedAt)return{handled:!0,operation:this.finish(r.id,"cancelled",{cooperativelyCancelled:!0}),terminalState:"cancelled"};if(p instanceof $e&&n.retryClasses.includes(p.errorClass)&&r.attempt<n.maxAttempts){let g=this.controlPlane.getOperation(r.id);this.controlPlane.transitionOperation(r.id,{to:"queued",expectedVersion:g.version,error:p.message});let y=Math.min(60000,1000*2**Math.max(0,r.attempt-1)),v=new Date(this.nowFn().getTime()+y).toISOString();return this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason=?, updated_at=? WHERE operation_id=?",[v,`retry_backoff:${p.errorClass}`,this.now(),r.id]),this.release(r.id),this.appendLog(r.id,`Retryable ${p.errorClass} failure; next attempt is delayed.`,{stream:"system"}),{handled:!0,operation:this.controlPlane.getOperation(r.id),requeued:!0}}let l=p instanceof Error?p.message:String(p);return this.appendLog(r.id,l,{stream:"stderr"}),{handled:!0,operation:this.finish(r.id,"failed",{},l),terminalState:"failed"}}finally{clearTimeout(a),clearInterval(d),clearInterval(c)}}recoverExpired(){let e=this.controlPlane.database.query("SELECT o.id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND (o.lease_expires_at IS NULL OR o.lease_expires_at<=?)").all(this.now()),t={requeued:0,failed:0,cancelled:0};for(let r of e){let n=this.controlPlane.getOperation(String(r.id)),o=this.getJob(n.id);if(this.release(n.id),n.cancelRequestedAt){this.finish(n.id,"cancelled",{recoveredAfterWorkerLoss:!0}),t.cancelled++;continue}if(o.resumePolicy==="requeue"&&n.attempt<o.maxAttempts)this.controlPlane.transitionOperation(n.id,{to:"queued",expectedVersion:n.version,error:"Worker lease expired; safely requeued from the last checkpoint."}),this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason='worker_restart', updated_at=? WHERE operation_id=?",[this.now(),this.now(),n.id]),this.appendLog(n.id,"Worker lease expired; operation requeued from its persisted checkpoint.",{stream:"system"}),t.requeued++;else this.finish(n.id,"failed",{recoverable:!0,lastCheckpoint:o.currentStep??null},"Worker lease expired; retry explicitly after reconciling provider state."),t.failed++}return t}clearCompleted(e={}){let t=this.now(),r=[t],n=e.projectId?"AND o.project_id=?":"";if(e.projectId)r.push(e.projectId);let o=e.before?"AND o.finished_at<=?":"";if(e.before)r.push(new Date(e.before).toISOString());let i=this.controlPlane.database.query(`SELECT o.id, o.project_id, o.correlation_id FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state IN ('succeeded','failed','cancelled','timed_out') AND j.retention_until<=? ${n} ${o}`).all(...r);for(let s of i)this.controlPlane.appendEvent({projectId:z(s.project_id),actorId:e.actorId,correlationId:String(s.correlation_id),type:"queue.history.cleared",level:"warning",payload:{operationId:String(s.id),retentionCutoff:t}}),this.controlPlane.database.run("DELETE FROM operations WHERE id=?",[String(s.id)]);return i.length}}function qt(e,t,r){if(!Number.isFinite(e))return t;return Math.min(r,Math.max(1,Math.floor(e)))}class lo{queue;handlers;parallelism;pollIntervalMs;onResult;onError;waits=new Map;nextWaitId=0;lanes=[];running=!1;unsubscribeAvailability;constructor(e,t,r={}){this.queue=e;this.handlers=t;this.parallelism=qt(r.parallelism,4,100),this.pollIntervalMs=qt(r.pollIntervalMs,5000,60000),this.onResult=r.onResult,this.onError=r.onError}get active(){return this.running}start(){if(this.running)return this;return this.running=!0,this.unsubscribeAvailability=this.queue.onAvailable(()=>this.wake()),this.lanes=Array.from({length:this.parallelism},(e,t)=>this.runLane(t)),this}stop(){this.running=!1,this.unsubscribeAvailability?.(),this.unsubscribeAvailability=void 0,this.wake()}wake(){for(let{resolve:e,timer:t}of this.waits.values()){if(t)clearTimeout(t);e()}this.waits.clear()}async settled(){await Promise.allSettled(this.lanes)}async drain(){let e=[];while(!0){let t=await Promise.all(Array.from({length:this.parallelism},()=>this.queue.runOne(this.handlers)));if(e.push(...t.filter((r)=>r.handled)),!t.some((r)=>r.handled))return e}}wait(e){return new Promise((t)=>{let r=++this.nextWaitId,n=e?setTimeout(()=>{this.waits.delete(r),t()},this.pollIntervalMs):void 0;n?.unref?.(),this.waits.set(r,{resolve:t,timer:n})})}async runLane(e){while(this.running){try{let t=await this.queue.runOne(this.handlers);if(!this.running)break;if(t.handled){this.onResult?.(t),this.wake();continue}}catch(t){this.onError?.(t)}await this.wait(e===0)}}}import{createHash as fn}from"node:crypto";var Ut=/^[a-z0-9](?:[a-z0-9_.-]{0,62})$/,yn=/^[A-Za-z_][A-Za-z0-9_]{0,127}$/,vn=/(?:secret|token|password|passwd|private.?key|api.?key|credential)/i,bn=new Set(["image","build","command","entrypoint","environment","ports","volumes","networks","depends_on","healthcheck","restart","deploy","labels"]),Vt=new Map([["privileged","Privileged containers are blocked."],["network_mode","Host/custom network modes are blocked."],["pid","Host PID namespaces are blocked."],["ipc","Host IPC namespaces are blocked."],["devices","Device access is blocked."],["cap_add","Additional Linux capabilities require an external policy exception."],["security_opt","Custom security options require an external policy exception."]]);function R(e){return e&&typeof e==="object"&&!Array.isArray(e)?e:{}}function Ve(e){return Array.isArray(e)?e:e==null?[]:[e]}function Sn(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,63)||"compose-app"}function ae(e){if(Array.isArray(e))return e.map(String);if(typeof e==="string"&&e.trim())return["sh","-c",e];return}function qe(e,t){let r=String(e??""),n=/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(r);if(!n)return t;let o=Number(n[1]);return Math.max(0,Math.round(o*(n[2]==="ms"?0.001:n[2]==="m"?60:n[2]==="h"?3600:1)))}function Bt(e){let t=/^(\d+(?:\.\d+)?)\s*(b|k|kb|kib|m|mb|mib|g|gb|gib)?$/i.exec(String(e??""));if(!t)return;let r=Number(t[1]),n=String(t[2]??"b").toLowerCase(),o=r*(n.startsWith("g")?1073741824:n.startsWith("m")?1048576:n.startsWith("k")?1024:1);return Math.max(1,Math.round(o/1024/1024))}function In(e){if(e==null)return"";return/^\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}$/.exec(String(e))?.[1]}function Ft(e,t,r){let n={},o=Array.isArray(e)?e.map((i)=>{let[s,...a]=String(i).split("=");return[s,a.length?a.join("="):null]}):Object.entries(R(e));for(let[i,s]of o){let a=String(i);if(!yn.test(a)){r.push({severity:"error",path:`${t}.${a}`,code:"environment.name",message:"Environment variable names must use portable shell identifiers."});continue}let d=In(s);if(d!==void 0){n[a]={secretRef:d||a};continue}if(vn.test(a)){r.push({severity:"error",path:`${t}.${a}`,code:"secret.literal",message:"Literal secret-like environment values are not stored.",alternative:`Use \${${a}} and supply ${a} through the secret store.`}),n[a]={secretRef:a};continue}n[a]=String(s??"")}return n}function _n(e,t,r){let n=[];for(let[o,i]of Ve(e).entries()){let s,a,d="tcp";if(typeof i==="number")s=i;else if(typeof i==="string"){let[c,u]=i.split("/");d=u==="udp"?"udp":"tcp";let p=c.split(":");s=Number(p.at(-1)),a=p.length>1?Number(p.at(-2)):void 0}else{let c=R(i);s=Number(c.target),a=c.published==null?void 0:Number(c.published),d=c.protocol==="udp"?"udp":"tcp"}if(!Number.isInteger(s)||s<1||s>65535||a!=null&&(!Number.isInteger(a)||a<1||a>65535))r.push({severity:"error",path:`${t}[${o}]`,code:"port.invalid",message:"Ports must be integers from 1 through 65535."});else n.push({target:s,...a?{published:a}:{},protocol:d})}return n}function En(e,t,r,n){let o=[];for(let[i,s]of Ve(e).entries()){let a="",d="",c=!1,u="volume";if(typeof s==="string"){let p=s.split(":");a=p[0]??"",d=p[1]??"",c=p.slice(2).includes("ro"),u=a.startsWith("/")||a.startsWith(".")?"bind":"volume"}else{let p=R(s);a=String(p.source??""),d=String(p.target??""),c=p.read_only===!0,u=String(p.type??"volume")}if(u!=="volume"||a.startsWith("/")||a.startsWith(".")){n.push({severity:"error",path:`${r}[${i}]`,code:"volume.host_mount",message:"Host and bind mounts are blocked; use a named volume.",alternative:"Declare the volume at the top level and mount it by name."});continue}if(!Ut.test(a)||!d.startsWith("/")){n.push({severity:"error",path:`${r}[${i}]`,code:"volume.invalid",message:"A named source and absolute container target are required."});continue}if(!t.has(a))n.push({severity:"warning",path:`${r}[${i}]`,code:"volume.implicit",message:`Named volume ${a} is implicit and will be declared on export.`});t.add(a),o.push({source:a,target:d,readOnly:c})}return o}function wn(e){return Array.isArray(e)?e.map((t)=>({service:String(t),condition:"service_started"})):Object.entries(R(e)).map(([t,r])=>({service:t,condition:["service_started","service_healthy","service_completed_successfully"].includes(String(R(r).condition))?String(R(r).condition):"service_started"}))}function zt(e){let t=R(e);if(!Object.keys(t).length||t.disable===!0)return;let r=ae(t.test);return r?{test:r,intervalSeconds:qe(t.interval,30),timeoutSeconds:qe(t.timeout,5),retries:Math.max(1,Number(t.retries)||3),...t.start_period?{startPeriodSeconds:qe(t.start_period,0)}:{}}:void 0}function An(e,t,r){if(!e)return;let n=typeof e==="string"?{context:e}:R(e),o=String(n.context??"."),i=String(n.dockerfile??"Dockerfile");if(o.startsWith("/")||o.split("/").includes("..")||i.startsWith("/")||i.split("/").includes(".."))r.push({severity:"error",path:t,code:"build.traversal",message:"Build context and Dockerfile must stay inside the repository."});return{context:o,dockerfile:i,...n.target?{target:String(n.target)}:{},args:Ft(n.args,`${t}.args`,r)}}function Rn(e,t,r){let n=Array.isArray(e)?Object.fromEntries(e.map((i)=>String(i).split("=",2))):R(e),o=String(n["ts-cloud.domains"]??n["ts-cloud.domain"]??"").split(",").map((i)=>i.trim()).filter(Boolean);for(let i of o)if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i.test(i))r.push({severity:"error",path:t,code:"domain.invalid",message:`Invalid service domain ${i}.`});return o.filter((i)=>/\./.test(i))}function Pn(e,t){let r=[],n=new Set,o=new Set,i=(s)=>{if(o.has(s))return;if(n.has(s)){t.push({severity:"error",path:`services.${s}.depends_on`,code:"dependency.cycle",message:"Service dependencies contain a cycle."});return}n.add(s);for(let a of e[s]?.dependsOn??[])if(!e[a.service])t.push({severity:"error",path:`services.${s}.depends_on.${a.service}`,code:"dependency.missing",message:`Dependency ${a.service} does not exist.`});else i(a.service);n.delete(s),o.add(s),r.push(s)};return Object.keys(e).sort().forEach(i),r}function Ot(e,t){if(Buffer.byteLength(e)>524288)throw Error("Compose source exceeds the 512 KiB limit");let r;try{r=R(Bun.YAML.parse(e))}catch(l){throw Error(`Compose YAML could not be parsed: ${l instanceof Error?l.message:String(l)}`)}let n=[],o=R(r.services),i=Object.keys(o);if(!i.length)n.push({severity:"error",path:"services",code:"services.required",message:"At least one service is required."});if(i.length>64)n.push({severity:"error",path:"services",code:"services.limit",message:"A Compose application may contain at most 64 services."});let s=new Set(Object.keys(R(r.volumes))),a=new Set(Object.keys(R(r.networks))),d={};for(let l of i.sort()){let f=`services.${l}`,g=R(o[l]);if(!Ut.test(l)){n.push({severity:"error",path:f,code:"service.name",message:"Service names must be portable lowercase identifiers."});continue}for(let[A,er]of Vt)if(g[A]!=null&&g[A]!==!1&&(!Array.isArray(g[A])||g[A].length))n.push({severity:"error",path:`${f}.${A}`,code:`unsafe.${A}`,message:er});for(let A of Object.keys(g))if(!bn.has(A)&&!Vt.has(A))n.push({severity:"warning",path:`${f}.${A}`,code:"field.unsupported",message:`Compose field ${A} is not in the supported subset and will not be deployed.`});let y=g.image?String(g.image):void 0,v=An(g.build,`${f}.build`,n);if(!y&&!v)n.push({severity:"error",path:f,code:"service.source",message:"Each service requires image or build."});if(y&&!y.includes("@sha256:")&&(!y.includes(":")||y.endsWith(":latest")))n.push({severity:"warning",path:`${f}.image`,code:"image.floating",message:`Image ${y} is not pinned to a digest or explicit tag.`});let b=Ve(g.networks).map((A)=>typeof A==="string"?A:String(R(A).name??"")).filter(Boolean);b.forEach((A)=>a.add(A));let I=R(g.deploy),_=R(I.resources),w=R(_.limits),C=["no","always","on-failure","unless-stopped"].includes(String(g.restart))?String(g.restart):"unless-stopped";d[l]={name:l,...y?{image:y}:{},...v?{build:v}:{},...ae(g.command)?{command:ae(g.command)}:{},...ae(g.entrypoint)?{entrypoint:ae(g.entrypoint)}:{},environment:Ft(g.environment,`${f}.environment`,n),ports:_n(g.ports,`${f}.ports`,n),volumes:En(g.volumes,s,`${f}.volumes`,n),networks:b,dependsOn:wn(g.depends_on),...zt(g.healthcheck)?{healthCheck:zt(g.healthcheck)}:{},restart:C,...Number(w.cpus)>0?{cpu:Number(w.cpus)}:{},...Bt(w.memory)?{memoryMb:Bt(w.memory)}:{},replicas:Math.max(1,Math.min(100,Number(I.replicas)||1)),domains:Rn(g.labels,`${f}.labels`,n)}}let c=Pn(d,n),u={apiVersion:"ts-cloud.dev/v1",kind:"ComposeApplication",metadata:{name:t.name.trim(),slug:Sn(t.slug??t.name),projectId:t.projectId,environmentId:t.environmentId},spec:{services:d,networks:[...a].sort(),volumes:[...s].sort(),dependencyOrder:c}},p=li(u);return{valid:!n.some((l)=>l.severity==="error"),manifest:u,diagnostics:n,redactedSource:p,sourceHash:fn("sha256").update(e).digest("hex")}}function li(e){let t=Object.fromEntries(Object.entries(e.spec.services).map(([r,n])=>[r,{...n.image?{image:n.image}:{},...n.build?{build:{context:n.build.context,dockerfile:n.build.dockerfile,...n.build.target?{target:n.build.target}:{},...Object.keys(n.build.args).length?{args:Object.fromEntries(Object.entries(n.build.args).map(([o,i])=>[o,typeof i==="string"?i:`\${${i.secretRef}:?required secret ${i.secretRef}}`]))}:{}}}:{},...n.command?{command:n.command}:{},...n.entrypoint?{entrypoint:n.entrypoint}:{},...Object.keys(n.environment).length?{environment:Object.fromEntries(Object.entries(n.environment).map(([o,i])=>[o,typeof i==="string"?i:`\${${i.secretRef}:?required secret ${i.secretRef}}`]))}:{},...n.ports.length?{ports:n.ports.map((o)=>`${o.published?`${o.published}:`:""}${o.target}${o.protocol==="udp"?"/udp":""}`)}:{},...n.volumes.length?{volumes:n.volumes.map((o)=>`${o.source}:${o.target}${o.readOnly?":ro":""}`)}:{},...n.networks.length?{networks:n.networks}:{},...n.dependsOn.length?{depends_on:Object.fromEntries(n.dependsOn.map((o)=>[o.service,{condition:o.condition}]))}:{},...n.healthCheck?{healthcheck:{test:n.healthCheck.test,interval:`${n.healthCheck.intervalSeconds}s`,timeout:`${n.healthCheck.timeoutSeconds}s`,retries:n.healthCheck.retries,...n.healthCheck.startPeriodSeconds!=null?{start_period:`${n.healthCheck.startPeriodSeconds}s`}:{}}}:{},restart:n.restart,...n.cpu||n.memoryMb||n.replicas!==1?{deploy:{replicas:n.replicas,resources:{limits:{...n.cpu?{cpus:String(n.cpu)}:{},...n.memoryMb?{memory:`${n.memoryMb}M`}:{}}}}}:{},...n.domains.length?{labels:{"ts-cloud.domains":n.domains.join(",")}}:{}}]));return Bun.YAML.stringify({services:t,...e.spec.networks.length?{networks:Object.fromEntries(e.spec.networks.map((r)=>[r,{}]))}:{},...e.spec.volumes.length?{volumes:Object.fromEntries(e.spec.volumes.map((r)=>[r,{}]))}:{}})}function uo(e,t){let r=[],n=(o,i,s)=>{if(JSON.stringify(i)===JSON.stringify(s))return;if(i&&s&&typeof i==="object"&&typeof s==="object"&&!Array.isArray(i)&&!Array.isArray(s)){for(let a of[...new Set([...Object.keys(i),...Object.keys(s)])].sort())n(o?`${o}.${a}`:a,i[a],s[a]);return}r.push({path:o,...i!==void 0?{before:i}:{},...s!==void 0?{after:s}:{}})};return n("",e,t),r}import{createHash as Ht}from"node:crypto";var Cn="2026-07-21T00:00:00.000Z",Qt=[{id:"bun-postgres-redis",name:"Bun + Postgres + Redis",description:"Web and worker services with durable Postgres and Redis dependencies.",category:"application",version:"1.0.0",sourceVersion:"oven/bun:1.2.21,postgres:17.5,redis:8.0.3",architecture:"web → Postgres + Redis; worker → Postgres + Redis",minimumResources:{cpu:2,memoryMb:3072},exposedServices:["web"],maintenanceNotes:"Back up the Postgres volume before major upgrades.",inputs:[{name:"domain",label:"Web domain",required:!0,secret:!1}],source:`services:
|
|
52
52
|
web:
|
|
@@ -108,4 +108,4 @@ volumes:
|
|
|
108
108
|
`).map((i)=>i.trim()).filter(F.test.bind(F))){let i=await this.inspect(o);if(i)n.push(i)}return n}async create(e){let t=typeof e.desiredState.nativeName==="string"?e.desiredState.nativeName:e.name;if(!F.test(t))throw Error("Docker volume name is invalid.");return await this.run(["volume","create","--label",`ts-cloud.volume=${e.id}`,"--label",`ts-cloud.project=${e.projectId}`,t]),await this.inspect(t)??{providerId:t}}async attach(e,t){}async detach(e,t){}async resize(){throw Error(this.capabilities().resize.reason)}async snapshot(){throw Error(this.capabilities().snapshot.reason)}async restore(e,t,r){throw Error(this.capabilities().restore.reason)}async delete(e){if(!e.providerId||!F.test(e.providerId))throw Error("Docker volume provider identity is missing or invalid.");await this.run(["volume","rm",e.providerId])}async usage(e){let t=await this.run(["system","df","-v","--format","{{json .}}"],!0),r=t.split(`
|
|
109
109
|
`).find((n)=>n.includes(`"Name":"${e.providerId}"`));if(!r)return{};try{let n=JSON.parse(r);return{usedBytes:typeof n.Size==="number"?n.Size:void 0}}catch{return{}}}}class tn{provider="server";type="server_path";root;constructor(e){this.root=Wt(e)}capabilities(){return ze(["create","attach","detach","delete","adopt","usage"],{resize:{supported:!1,reason:"Server paths use the capacity of their containing filesystem."},snapshot:{supported:!1,reason:"Attach a filesystem backup policy for verified recovery points."},restore:{supported:!1,reason:"Restore a filesystem recovery point into a new managed path."}})}path(e){if(!F.test(e))throw Error("Server path volume name is invalid.");let t=Wt(this.root,e);if(!t.startsWith(`${this.root}${Bn}`)||Vn(t)!==e)throw Error("Server path escaped the managed volume root.");return t}async discover(e,t){return await Ue(this.root,{recursive:!0,mode:488}),(await Ln(this.root,{withFileTypes:!0})).filter((n)=>n.isDirectory()&&F.test(n.name)).map((n)=>({providerId:n.name,raw:{path:this.path(n.name)}}))}async create(e){let t=typeof e.desiredState.nativeName==="string"?e.desiredState.nativeName:e.name,r=this.path(t);return await Ue(this.root,{recursive:!0,mode:488}),await Ue(r,{recursive:!1,mode:488}),{providerId:t,filesystem:"host",raw:{path:r}}}async attach(e,t){}async detach(e,t){}async resize(){throw Error(this.capabilities().resize.reason)}async snapshot(){throw Error(this.capabilities().snapshot.reason)}async restore(e,t,r){throw Error(this.capabilities().restore.reason)}async delete(e){if(!e.providerId)throw Error("Server path provider identity is unavailable.");await qn(this.path(e.providerId),{recursive:!0,force:!1})}async usage(e){if(!e.providerId)return{};return{usedBytes:(await $n(this.path(e.providerId))).size}}}var D=(e)=>e==null?void 0:String(e),de=(e,t)=>{try{return JSON.parse(String(e))}catch{return t}},He=(e)=>Number(e)===1,H=(e)=>e().toISOString();function Kt(e){return{id:String(e.id),organizationId:String(e.organization_id),projectId:String(e.project_id),environmentId:D(e.environment_id),resourceId:D(e.resource_id),name:String(e.name),provider:String(e.provider),providerId:D(e.provider_id),type:String(e.type),status:String(e.status),capacityBytes:e.capacity_bytes==null?void 0:Number(e.capacity_bytes),usedBytes:e.used_bytes==null?void 0:Number(e.used_bytes),filesystem:D(e.filesystem),encrypted:He(e.encrypted),capabilities:de(e.capabilities,{}),desiredState:de(e.desired_state,{}),observedState:de(e.observed_state,{}),backupPolicyId:D(e.backup_policy_id),lastBackupAt:D(e.last_backup_at),orphanedAt:D(e.orphaned_at),adoptedAt:D(e.adopted_at),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at),deletedAt:D(e.deleted_at)}}function Fe(e){return{id:String(e.id),volumeId:String(e.volume_id),resourceId:String(e.resource_id),targetPath:String(e.target_path),readOnly:He(e.read_only),uid:e.uid==null?void 0:Number(e.uid),gid:e.gid==null?void 0:Number(e.gid),mode:D(e.mode),propagation:String(e.propagation),driverOptions:de(e.driver_options,{}),desiredState:String(e.desired_state),observedState:String(e.observed_state),operationId:D(e.operation_id),lastError:D(e.last_error),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Gt(e){return{id:String(e.id),volumeId:String(e.volume_id),recoveryPointId:D(e.recovery_point_id),providerId:D(e.provider_id),name:String(e.name),status:String(e.status),sizeBytes:e.size_bytes==null?void 0:Number(e.size_bytes),encrypted:He(e.encrypted),checksum:D(e.checksum),metadata:de(e.metadata,{}),createdAt:String(e.created_at),updatedAt:String(e.updated_at),deletedAt:D(e.deleted_at)}}class mt{controlPlane;now;id;constructor(e,t=()=>new Date,r=()=>crypto.randomUUID()){this.controlPlane=e;this.now=t;this.id=r}get(e){let t=this.controlPlane.database.query("SELECT * FROM persistent_volumes WHERE id=?").get(e);return t?Kt(t):void 0}list(e){let t=["project_id=?"],r=[e.projectId];if(e.environmentId)t.push("environment_id=?"),r.push(e.environmentId);if(!e.includeDeleted)t.push("deleted_at IS NULL");return this.controlPlane.database.query(`SELECT * FROM persistent_volumes WHERE ${t.join(" AND ")} ORDER BY name`).all(...r).map(Kt)}create(e){let t=H(this.now),r=e.id??this.id();return this.controlPlane.database.run("INSERT INTO persistent_volumes (id,organization_id,project_id,environment_id,resource_id,name,provider,provider_id,type,status,capacity_bytes,used_bytes,filesystem,encrypted,capabilities,desired_state,observed_state,backup_policy_id,last_backup_at,orphaned_at,adopted_at,created_at,updated_at,deleted_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[r,e.organizationId,e.projectId,e.environmentId??null,e.resourceId??null,e.name,e.provider,e.providerId??null,e.type,e.status,e.capacityBytes??null,e.usedBytes??null,e.filesystem??null,e.encrypted?1:0,JSON.stringify(e.capabilities),JSON.stringify(e.desiredState),JSON.stringify(e.observedState),e.backupPolicyId??null,e.lastBackupAt??null,e.orphanedAt??null,e.adoptedAt??null,t,t,e.deletedAt??null]),this.get(r)}update(e,t,r){let n=this.get(e);if(!n||n.version!==t)throw Error("Volume changed before this operation could be applied.");let o={...n,...r,updatedAt:H(this.now)};if(this.controlPlane.database.run("UPDATE persistent_volumes SET environment_id=?,resource_id=?,name=?,provider=?,provider_id=?,type=?,status=?,capacity_bytes=?,used_bytes=?,filesystem=?,encrypted=?,capabilities=?,desired_state=?,observed_state=?,backup_policy_id=?,last_backup_at=?,orphaned_at=?,adopted_at=?,deleted_at=?,version=version+1,updated_at=? WHERE id=? AND version=?",[o.environmentId??null,o.resourceId??null,o.name,o.provider,o.providerId??null,o.type,o.status,o.capacityBytes??null,o.usedBytes??null,o.filesystem??null,o.encrypted?1:0,JSON.stringify(o.capabilities),JSON.stringify(o.desiredState),JSON.stringify(o.observedState),o.backupPolicyId??null,o.lastBackupAt??null,o.orphanedAt??null,o.adoptedAt??null,o.deletedAt??null,o.updatedAt,e,t]).changes!==1)throw Error("Volume changed before this operation could be applied.");return this.get(e)}attachments(e){return this.controlPlane.database.query("SELECT * FROM volume_attachments WHERE volume_id=? ORDER BY target_path").all(e).map(Fe)}attachment(e){let t=this.controlPlane.database.query("SELECT * FROM volume_attachments WHERE id=?").get(e);return t?Fe(t):void 0}upsertAttachment(e){let t=this.controlPlane.database.query("SELECT * FROM volume_attachments WHERE volume_id=? AND resource_id=? AND target_path=?").get(e.volumeId,e.resourceId,e.targetPath),r=H(this.now);if(t){let o=Fe(t);return this.controlPlane.database.run("UPDATE volume_attachments SET read_only=?,uid=?,gid=?,mode=?,propagation=?,driver_options=?,desired_state=?,observed_state=?,operation_id=?,last_error=?,version=version+1,updated_at=? WHERE id=?",[e.readOnly?1:0,e.uid??null,e.gid??null,e.mode??null,e.propagation,JSON.stringify(e.driverOptions),e.desiredState,e.observedState,e.operationId??null,e.lastError??null,r,o.id]),this.attachment(o.id)}let n=e.id??this.id();return this.controlPlane.database.run("INSERT INTO volume_attachments (id,volume_id,resource_id,target_path,read_only,uid,gid,mode,propagation,driver_options,desired_state,observed_state,operation_id,last_error,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",[n,e.volumeId,e.resourceId,e.targetPath,e.readOnly?1:0,e.uid??null,e.gid??null,e.mode??null,e.propagation,JSON.stringify(e.driverOptions),e.desiredState,e.observedState,e.operationId??null,e.lastError??null,r,r]),this.attachment(n)}updateAttachment(e,t){let r=this.attachment(e);if(!r)throw Error("Volume attachment was not found.");let n={...r,...t};return this.controlPlane.database.run("UPDATE volume_attachments SET desired_state=?,observed_state=?,operation_id=?,last_error=?,version=version+1,updated_at=? WHERE id=?",[n.desiredState,n.observedState,n.operationId??null,n.lastError??null,H(this.now),e]),this.attachment(e)}snapshots(e){return this.controlPlane.database.query("SELECT * FROM volume_snapshots WHERE volume_id=? AND deleted_at IS NULL ORDER BY created_at DESC").all(e).map(Gt)}snapshot(e){let t=this.controlPlane.database.query("SELECT * FROM volume_snapshots WHERE id=?").get(e);return t?Gt(t):void 0}createSnapshot(e){let t=e.id??this.id(),r=H(this.now);return this.controlPlane.database.run("INSERT INTO volume_snapshots (id,volume_id,recovery_point_id,provider_id,name,status,size_bytes,encrypted,checksum,metadata,created_at,updated_at,deleted_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",[t,e.volumeId,e.recoveryPointId??null,e.providerId??null,e.name,e.status,e.sizeBytes??null,e.encrypted?1:0,e.checksum??null,JSON.stringify(e.metadata),r,r,e.deletedAt??null]),this.snapshot(t)}updateSnapshot(e,t){let r=this.snapshot(e);if(!r)throw Error("Volume snapshot was not found.");let n={...r,...t};return this.controlPlane.database.run("UPDATE volume_snapshots SET recovery_point_id=?,provider_id=?,name=?,status=?,size_bytes=?,encrypted=?,checksum=?,metadata=?,deleted_at=?,updated_at=? WHERE id=?",[n.recoveryPointId??null,n.providerId??null,n.name,n.status,n.sizeBytes??null,n.encrypted?1:0,n.checksum??null,JSON.stringify(n.metadata),n.deletedAt??null,H(this.now),e]),this.snapshot(e)}inventory(e,t){return this.list({projectId:e,environmentId:t}).map((r)=>{let n=this.attachments(r.id),o=this.snapshots(r.id),i=r.lastBackupAt?Date.now()-new Date(r.lastBackupAt).getTime():1/0;return{...r,attachments:n,snapshots:o,orphaned:r.status==="orphaned",usagePercent:r.capacityBytes&&r.usedBytes!=null?Math.round(r.usedBytes/r.capacityBytes*1000)/10:void 0,backupState:r.backupPolicyId?i<=86400000?"protected":"stale":"unprotected"}})}audit(e){this.controlPlane.appendEvent({organizationId:e.organizationId,projectId:e.projectId,resourceId:this.get(e.volumeId)?.resourceId,actorId:e.actorId,type:e.type,level:"warning",payload:{volumeId:e.volumeId,environmentId:e.environmentId??null,...e.payload}})}}function We(e,t){let r=e.getProject(t.projectId);if(!r?.organizationId)return;let n=new mt(e),o=new $t,i=new Set(t.manifest.spec.volumes),s=new Set;for(let a of i){let d=`${t.slug}-${a}`.toLowerCase().replace(/[^a-z0-9_.-]/g,"-").slice(0,63),c=n.list({projectId:t.projectId,environmentId:t.environmentId,includeDeleted:!0}).find((f)=>f.name===d);if(c?.deletedAt)throw Error(`Compose volume ${d} was permanently deleted; rename it before redeploying.`);let u=c?.resourceId?e.getResource(c.resourceId):e.createResource({projectId:t.projectId,environmentId:t.environmentId,kind:"volume",slug:d,name:d,provider:"docker",providerId:d,desiredState:{composeApplicationId:t.id,composeVolume:a}}),p=c??n.create({organizationId:r.organizationId,projectId:t.projectId,environmentId:t.environmentId,resourceId:u?.id,name:d,provider:"docker",providerId:d,type:"docker",status:"available",encrypted:!1,capabilities:o.capabilities(),desiredState:{composeApplicationId:t.id,composeVolume:a,nativeName:d},observedState:{}});s.add(p.id);let l=new Map;for(let f of Object.values(t.manifest.spec.services))for(let g of f.volumes.filter((y)=>y.source===a)){let y=l.get(g.target)??[];y.push(f.name),l.set(g.target,y),n.upsertAttachment({volumeId:p.id,resourceId:t.resourceId,targetPath:g.target,readOnly:g.readOnly,propagation:"private",driverOptions:{composeServices:y},desiredState:"attached",observedState:"pending"})}}for(let a of n.list({projectId:t.projectId,environmentId:t.environmentId}).filter((d)=>d.desiredState.composeApplicationId===t.id&&!s.has(d.id)))for(let d of n.attachments(a.id))n.updateAttachment(d.id,{desiredState:"detached"})}function Yt(e,t,r){let n=new mt(e);for(let o of n.list({projectId:t.projectId,environmentId:t.environmentId}).filter((i)=>i.desiredState.composeApplicationId===t.id)){for(let i of n.attachments(o.id))n.updateAttachment(i.id,{desiredState:"detached",observedState:"detached"});n.update(o.id,o.version,{status:r?"deleted":"available",deletedAt:r?new Date().toISOString():void 0})}}function Q(e){return typeof e==="string"&&e?e:void 0}function Ge(e,t){try{return JSON.parse(String(e))}catch{return t}}function Ie(e){return{id:String(e.id),resourceId:String(e.resource_id),projectId:String(e.project_id),environmentId:String(e.environment_id),name:String(e.name),slug:String(e.slug),status:String(e.status),sourceKind:String(e.source_kind),sourceHash:String(e.source_hash),redactedSource:String(e.redacted_source),manifest:Ge(e.manifest,{}),diagnostics:Ge(e.diagnostics,[]),templateId:Q(e.template_id),templateVersion:Q(e.template_version),latestOperationId:Q(e.latest_operation_id),createdByActorId:Q(e.created_by_actor_id),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at),deletedAt:Q(e.deleted_at)}}function Un(e){return{applicationId:String(e.application_id),serviceName:String(e.service_name),status:String(e.status),replicas:Number(e.replicas),healthyReplicas:Number(e.healthy_replicas),latestOperationId:Q(e.latest_operation_id),observedState:Ge(e.observed_state,{}),updatedAt:String(e.updated_at)}}class gt{controlPlane;now;id;constructor(e,t={}){this.controlPlane=e;this.now=t.now??(()=>new Date),this.id=t.id??(()=>crypto.randomUUID())}persist(e,t){if(!e.valid)throw Error(`Compose definition contains ${e.diagnostics.filter((g)=>g.severity==="error").length} blocking diagnostic(s)`);let{projectId:r,environmentId:n,name:o,slug:i}=e.manifest.metadata;if(!this.controlPlane.listEnvironments(r).find((g)=>g.id===n))throw Error("Compose project and environment scope was not found");let a=this.getBySlug(r,n,i),d=this.now().toISOString(),c=JSON.stringify(e.manifest),u=JSON.stringify(h(e.diagnostics));if(a){if(a.status==="deleted")throw Error("A deleted Compose application cannot be overwritten; choose another slug");let g=this.controlPlane.getResource(a.resourceId);if(!g)throw Error("Compose application resource was not found");this.controlPlane.updateResource(g.id,g.version,{name:o,provider:g.provider,providerId:g.providerId,desiredState:e.manifest,discoveredState:g.discoveredState,metadata:{sourceKind:t.sourceKind,templateId:t.templateId??null,templateVersion:t.templateVersion??null,sourceHash:e.sourceHash}}),this.controlPlane.database.run("UPDATE compose_applications SET name=?, status='ready', source_kind=?, source_hash=?, redacted_source=?, manifest=?, diagnostics=?, template_id=?, template_version=?, version=version+1, updated_at=? WHERE id=?",[o,t.sourceKind,e.sourceHash,e.redactedSource,c,u,t.templateId??null,t.templateVersion??null,d,a.id]);let y=Object.keys(e.manifest.spec.services);if(y.length)this.controlPlane.database.run(`DELETE FROM compose_service_states WHERE application_id=? AND service_name NOT IN (${y.map(()=>"?").join(",")})`,[a.id,...y]);for(let b of Object.values(e.manifest.spec.services))this.controlPlane.database.run("INSERT INTO compose_service_states (application_id, service_name, status, replicas, healthy_replicas, observed_state, updated_at) VALUES (?, ?, 'pending', ?, 0, '{}', ?) ON CONFLICT(application_id, service_name) DO UPDATE SET replicas=excluded.replicas, updated_at=excluded.updated_at",[a.id,b.name,b.replicas,d]);this.controlPlane.appendEvent({projectId:r,resourceId:a.resourceId,actorId:t.createdByActorId,type:"compose.application.updated",payload:{applicationId:a.id,sourceHash:e.sourceHash,diagnosticCount:e.diagnostics.length,templateId:t.templateId??null,templateVersion:t.templateVersion??null}});let v=this.get(a.id);return We(this.controlPlane,v),v}let p=this.controlPlane.createResource({projectId:r,environmentId:n,kind:"compose_application",slug:i,name:o,desiredState:e.manifest,metadata:{sourceKind:t.sourceKind,templateId:t.templateId??null,templateVersion:t.templateVersion??null,sourceHash:e.sourceHash}}),l=this.id();this.controlPlane.database.run("INSERT INTO compose_applications (id, resource_id, project_id, environment_id, name, slug, status, source_kind, source_hash, redacted_source, manifest, diagnostics, template_id, template_version, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, 'ready', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[l,p.id,r,n,o,i,t.sourceKind,e.sourceHash,e.redactedSource,c,u,t.templateId??null,t.templateVersion??null,t.createdByActorId??null,d,d]);for(let g of Object.values(e.manifest.spec.services))this.controlPlane.database.run("INSERT INTO compose_service_states (application_id, service_name, status, replicas, healthy_replicas, observed_state, updated_at) VALUES (?, ?, 'pending', ?, 0, '{}', ?)",[l,g.name,g.replicas,d]);this.controlPlane.appendEvent({projectId:r,resourceId:p.id,actorId:t.createdByActorId,type:"compose.application.created",payload:{applicationId:l,sourceHash:e.sourceHash,serviceNames:Object.keys(e.manifest.spec.services),templateId:t.templateId??null}});let f=this.get(l);return We(this.controlPlane,f),f}import(e,t){let r=Ot(e,t);return{application:this.persist(r,{sourceKind:"compose",createdByActorId:t.createdByActorId}),parsed:r}}fromTemplate(e,t,r){let n=Jt(e,t,r,r.version);return{application:this.persist(n,{sourceKind:"template",templateId:e,templateVersion:r.version??"1.0.0",createdByActorId:r.createdByActorId}),parsed:n}}preview(e,t){return Ot(e,t)}get(e){let t=this.controlPlane.database.query("SELECT * FROM compose_applications WHERE id=?").get(e);return t?Ie(t):void 0}getByResource(e){let t=this.controlPlane.database.query("SELECT * FROM compose_applications WHERE resource_id=?").get(e);return t?Ie(t):void 0}getBySlug(e,t,r){let n=this.controlPlane.database.query("SELECT * FROM compose_applications WHERE project_id=? AND environment_id=? AND slug=?").get(e,t,r);return n?Ie(n):void 0}list(e={}){return this.controlPlane.database.query("SELECT * FROM compose_applications ORDER BY updated_at DESC").all().map(Ie).filter((t)=>(!e.projectId||t.projectId===e.projectId)&&(!e.environmentId||t.environmentId===e.environmentId)&&(e.includeDeleted||t.status!=="deleted"))}services(e){return this.controlPlane.database.query("SELECT * FROM compose_service_states WHERE application_id=? ORDER BY service_name").all(e).map(Un)}transition(e,t,r={}){let n=this.get(e);if(!n)throw Error(`Compose application ${e} was not found`);let o=this.now().toISOString(),i=t==="deleted"?o:null;this.controlPlane.database.run("UPDATE compose_applications SET status=?, latest_operation_id=COALESCE(?, latest_operation_id), version=version+1, updated_at=?, deleted_at=? WHERE id=?",[t,r.operationId??null,o,i,e]);for(let s of r.services??[])if(n.manifest.spec.services[s.name])this.controlPlane.database.run("INSERT INTO compose_service_states (application_id, service_name, status, replicas, healthy_replicas, latest_operation_id, observed_state, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(application_id, service_name) DO UPDATE SET status=excluded.status, replicas=excluded.replicas, healthy_replicas=excluded.healthy_replicas, latest_operation_id=excluded.latest_operation_id, observed_state=excluded.observed_state, updated_at=excluded.updated_at",[e,s.name,s.status,s.replicas??n.manifest.spec.services[s.name].replicas,s.healthyReplicas??0,r.operationId??null,JSON.stringify(h(s.observedState??{})),o]);return this.controlPlane.appendEvent({projectId:n.projectId,resourceId:n.resourceId,operationId:r.operationId,type:`compose.application.${t}`,level:t==="failed"||t==="degraded"?"error":"info",payload:{applicationId:e,error:r.error??null}}),this.get(e)}}class Ke{controlPlane;applications;queue;constructor(e){this.controlPlane=e;this.applications=new gt(e),this.queue=new S(e)}enqueue(e,t,r={}){if(e.status==="deleted")throw Error("Deleted Compose applications cannot be operated");if(r.service&&!e.manifest.spec.services[r.service])throw Error(`Compose service ${r.service} was not found`);if(t==="delete"){let o=r.removeVolumes?`${e.slug} delete volumes`:e.slug;if(r.confirmation!==o)throw Error(`Type ${o} to confirm ${r.removeVolumes?"persistent data removal":"stack deletion"}`)}if(t==="scale"&&(!r.service||!Number.isInteger(r.replicas)||r.replicas<0||r.replicas>100))throw Error("Scale requires a service and 0-100 replicas");let n=this.queue.enqueue({projectId:e.projectId,environmentId:e.environmentId,resourceId:e.resourceId,actorId:r.actorId,kind:`compose.${t}`,idempotencyKey:`compose:${e.id}:${t}:${r.service??"stack"}:${r.replicas??""}:${e.version}`,correlationId:`compose:${e.id}`,input:{applicationId:e.id,service:r.service??null,replicas:r.replicas??null,removeVolumes:!!r.removeVolumes},lockKey:`compose:${e.id}`,providerKey:this.controlPlane.getResource(e.resourceId)?.provider??"default",buildSlot:t==="deploy"||t==="redeploy",maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return this.applications.transition(e.id,t==="delete"?"deleting":t==="stop"?"stopped":t==="start"?"deploying":t==="scale"?e.status:"deploying",{operationId:n.id}),n}}import{createHash as Fn}from"node:crypto";var Hn=/^[a-f0-9]{40,64}$/i,Qn=/^[A-Z][A-Z0-9_]{1,127}$/;function L(e){return typeof e==="string"&&e?e:void 0}function J(e){try{return JSON.parse(String(e))}catch{return{}}}function Jn(e){let t=J(e);return Array.isArray(t)?t.map(String):[]}function Ye(e){return{id:String(e.id),projectId:String(e.project_id),resourceId:String(e.resource_id),baseEnvironmentId:String(e.base_environment_id),enabled:Number(e.enabled)===1,branchRule:L(e.branch_rule),domainPattern:String(e.domain_pattern),ttlHours:Number(e.ttl_hours),keepCount:Number(e.keep_count),publicAccess:Number(e.public_access)===1,authenticationRequired:Number(e.authentication_required)===1,allowForks:Number(e.allow_forks)===1,inheritedSecrets:Jn(e.inherited_secrets),resourceOverrides:J(e.resource_overrides),databaseStrategy:String(e.database_strategy),maxMonthlyCost:Number(e.max_monthly_cost),maxCpu:Number(e.max_cpu),maxMemoryMb:Number(e.max_memory_mb),cleanupOnClose:Number(e.cleanup_on_close)===1,version:Number(e.version),createdByActorId:L(e.created_by_actor_id),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function ce(e){return{id:String(e.id),definitionId:String(e.definition_id),projectId:String(e.project_id),resourceId:String(e.resource_id),baseEnvironmentId:String(e.base_environment_id),identityKey:String(e.identity_key),sourceProvider:L(e.source_provider),repository:L(e.repository),branch:String(e.branch),pullRequestNumber:e.pull_request_number==null?void 0:Number(e.pull_request_number),fork:Number(e.fork)===1,commitSha:String(e.commit_sha),name:String(e.name),stackName:String(e.stack_name),url:L(e.url),status:String(e.status),expiresAt:String(e.expires_at),latestOperationId:L(e.latest_operation_id),createdByActorId:L(e.created_by_actor_id),costEstimate:e.cost_estimate==null?void 0:Number(e.cost_estimate),desiredState:J(e.desired_state),observedState:J(e.observed_state),teardownError:L(e.teardown_error),version:Number(e.version),createdAt:String(e.created_at),updatedAt:String(e.updated_at),destroyedAt:L(e.destroyed_at)}}function Zt(e){return{id:String(e.id),previewId:String(e.preview_id),provider:String(e.provider),providerResourceId:String(e.provider_resource_id),kind:String(e.kind),tags:J(e.tags),observedState:J(e.observed_state),discoveredAt:String(e.discovered_at),deletedAt:L(e.deleted_at)}}function q(e,t,r,n){return Number.isFinite(e)?Math.min(n,Math.max(r,Math.floor(e))):t}function _e(e,t,r,n){return Number.isFinite(e)?Math.min(n,Math.max(r,e)):t}function Ze(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,28)||"preview"}class Le{controlPlane;now;id;constructor(e,t={}){this.controlPlane=e;this.now=t.now??(()=>new Date),this.id=t.id??(()=>crypto.randomUUID())}createDefinition(e){let t=this.controlPlane.getResource(e.resourceId),r=this.controlPlane.listEnvironments(e.projectId).find((c)=>c.id===e.baseEnvironmentId);if(!t||t.projectId!==e.projectId||t.environmentId!==r?.id)throw Error("Preview resource and base environment must belong to the same project scope");if(t.kind!=="application")throw Error("Preview environments currently support application resources only");if(!/^https:\/\//.test(e.domainPattern)||!e.domainPattern.includes("{name}"))throw Error("Preview domainPattern must be HTTPS and include {name}");let n=this.getDefinitionForResource(e.resourceId),o=e.publicAccess??n?.publicAccess??!1,i=e.authenticationRequired??n?.authenticationRequired??!0;if(o&&!i)throw Error("Public preview environments require an authentication policy");let s=[...new Set(e.inheritedSecrets??[])];if(s.some((c)=>!Qn.test(c)))throw Error("Inherited preview secret names must use uppercase environment-variable identifiers");let a=this.now().toISOString();if(n)return this.controlPlane.database.run("UPDATE preview_definitions SET base_environment_id=?, enabled=1, branch_rule=?, domain_pattern=?, ttl_hours=?, keep_count=?, public_access=?, authentication_required=?, allow_forks=?, inherited_secrets=?, resource_overrides=?, database_strategy=?, max_monthly_cost=?, max_cpu=?, max_memory_mb=?, cleanup_on_close=?, version=version+1, updated_at=? WHERE id=?",[e.baseEnvironmentId,e.branchRule??null,e.domainPattern,q(e.ttlHours,n.ttlHours,1,720),q(e.keepCount,n.keepCount,1,100),o?1:0,i?1:0,e.allowForks??n.allowForks?1:0,JSON.stringify(e.inheritedSecrets===void 0?n.inheritedSecrets:s),JSON.stringify(h(e.resourceOverrides??n.resourceOverrides)),e.databaseStrategy??n.databaseStrategy,_e(e.maxMonthlyCost,n.maxMonthlyCost,0,1e4),_e(e.maxCpu,n.maxCpu,0.1,64),q(e.maxMemoryMb,n.maxMemoryMb,128,131072),e.cleanupOnClose??n.cleanupOnClose?1:0,a,n.id]),this.controlPlane.appendEvent({projectId:e.projectId,resourceId:e.resourceId,actorId:e.createdByActorId,type:"preview.definition.updated",payload:{definitionId:n.id,baseEnvironmentId:e.baseEnvironmentId,version:n.version+1}}),this.getDefinition(n.id);let d=this.id();return this.controlPlane.database.run("INSERT INTO preview_definitions (id, project_id, resource_id, base_environment_id, enabled, branch_rule, domain_pattern, ttl_hours, keep_count, public_access, authentication_required, allow_forks, inherited_secrets, resource_overrides, database_strategy, max_monthly_cost, max_cpu, max_memory_mb, cleanup_on_close, created_by_actor_id, created_at, updated_at) VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",[d,e.projectId,e.resourceId,e.baseEnvironmentId,e.branchRule??null,e.domainPattern,q(e.ttlHours,24,1,720),q(e.keepCount,10,1,100),e.publicAccess?1:0,e.authenticationRequired===!1?0:1,e.allowForks?1:0,JSON.stringify(s),JSON.stringify(h(e.resourceOverrides??{})),e.databaseStrategy??"disabled",_e(e.maxMonthlyCost,25,0,1e4),_e(e.maxCpu,1,0.1,64),q(e.maxMemoryMb,1024,128,131072),e.cleanupOnClose===!1?0:1,e.createdByActorId??null,a,a]),this.controlPlane.appendEvent({projectId:e.projectId,resourceId:e.resourceId,actorId:e.createdByActorId,type:"preview.definition.created",payload:{definitionId:d,baseEnvironmentId:e.baseEnvironmentId,ttlHours:q(e.ttlHours,24,1,720),inheritedSecretNames:s}}),this.getDefinition(d)}getDefinition(e){let t=this.controlPlane.database.query("SELECT * FROM preview_definitions WHERE id=?").get(e);return t?Ye(t):void 0}getDefinitionForResource(e){let t=this.controlPlane.database.query("SELECT * FROM preview_definitions WHERE resource_id=?").get(e);return t?Ye(t):void 0}listDefinitions(e){return this.controlPlane.database.query("SELECT * FROM preview_definitions WHERE project_id=? ORDER BY updated_at DESC").all(e).map(Ye)}listInstances(e={}){return this.controlPlane.database.query("SELECT * FROM preview_instances ORDER BY created_at DESC").all().map(ce).filter((r)=>(!e.projectId||r.projectId===e.projectId)&&(!e.definitionId||r.definitionId===e.definitionId)&&(!e.status||r.status===e.status))}getInstance(e){let t=this.controlPlane.database.query("SELECT * FROM preview_instances WHERE id=?").get(e);return t?ce(t):void 0}findForPullRequest(e,t,r){let n=this.controlPlane.database.query("SELECT * FROM preview_instances WHERE definition_id=? AND identity_key=?").get(e,`pr:${t}:${r}`);return n?ce(n):void 0}findForBranch(e,t,r){let n=this.controlPlane.database.query("SELECT * FROM preview_instances WHERE definition_id=? AND identity_key=?").get(e,`branch:${t}:${r}`);return n?ce(n):void 0}upsert(e){let t=this.getDefinition(e.definitionId);if(!t?.enabled)throw Error("Preview environments are not enabled for this application");if(!Hn.test(e.commitSha))throw Error("Preview deployment requires an immutable 40-64 character commit SHA");if(e.fork&&!t.allowForks)throw Error("Untrusted fork previews are disabled");let r=e.pullRequestNumber?`pr:${e.repository??"unknown"}:${e.pullRequestNumber}`:`branch:${e.repository??"local"}:${e.branch}`,n=Fn("sha256").update(`${t.id}:${r}`).digest("hex").slice(0,8),i=`${(e.pullRequestNumber?`pr-${e.pullRequestNumber}`:Ze(e.branch)).slice(0,28)}-${n}`,s=`preview-${i}`.slice(0,63),a=t.domainPattern.replaceAll("{name}",i).replaceAll("{project}",Ze(t.projectId)).replaceAll("{branch}",Ze(e.branch)).replaceAll("{pr}",String(e.pullRequestNumber??"branch")),d=e.now??this.now(),c=d.toISOString(),u=new Date(d.getTime()+t.ttlHours*60*60*1000).toISOString(),p=this.controlPlane.database.query("SELECT * FROM preview_instances WHERE definition_id=? AND identity_key=?").get(t.id,r);if(p){let g=ce(p),y=g.commitSha!==e.commitSha||g.status==="destroyed";if(y)this.controlPlane.database.run("UPDATE preview_instances SET commit_sha=?, branch=?, fork=?, status='queued', expires_at=?, url=?, teardown_error=NULL, destroyed_at=NULL, version=version+1, updated_at=? WHERE id=?",[e.commitSha,e.branch,e.fork?1:0,u,a,c,g.id]);return{preview:this.getInstance(g.id),created:!1,changed:y,inheritedSecrets:e.fork?[]:t.inheritedSecrets}}let l=this.id(),f=h({source:{provider:e.sourceProvider??null,repository:e.repository??null,branch:e.branch,commitSha:e.commitSha,pullRequestNumber:e.pullRequestNumber??null,fork:!!e.fork},policy:{databaseStrategy:t.databaseStrategy,resourceOverrides:t.resourceOverrides,maxMonthlyCost:t.maxMonthlyCost,maxCpu:t.maxCpu,maxMemoryMb:t.maxMemoryMb,publicAccess:t.publicAccess,authenticationRequired:t.authenticationRequired},inheritedSecretNames:e.fork?[]:t.inheritedSecrets});return this.controlPlane.database.run("INSERT INTO preview_instances (id, definition_id, project_id, resource_id, base_environment_id, identity_key, source_provider, repository, branch, pull_request_number, fork, commit_sha, name, stack_name, url, status, expires_at, created_by_actor_id, desired_state, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'queued', ?, ?, ?, ?, ?)",[l,t.id,t.projectId,t.resourceId,t.baseEnvironmentId,r,e.sourceProvider??null,e.repository??null,e.branch,e.pullRequestNumber??null,e.fork?1:0,e.commitSha,i,s,a,u,e.createdByActorId??null,JSON.stringify(f),c,c]),this.controlPlane.appendEvent({projectId:t.projectId,resourceId:t.resourceId,actorId:e.createdByActorId,type:"preview.created",payload:{previewId:l,identityKey:r,commitSha:e.commitSha,expiresAt:u,fork:!!e.fork}}),{preview:this.getInstance(l),created:!0,changed:!0,inheritedSecrets:e.fork?[]:t.inheritedSecrets}}transition(e,t,r={}){let n=this.getInstance(e);if(!n)throw Error(`Preview ${e} was not found`);let o=this.now().toISOString(),i=t==="destroyed"?o:null;return this.controlPlane.database.run("UPDATE preview_instances SET status=?, latest_operation_id=COALESCE(?, latest_operation_id), observed_state=?, teardown_error=?, cost_estimate=COALESCE(?, cost_estimate), destroyed_at=?, version=version+1, updated_at=? WHERE id=?",[t,r.operationId??null,JSON.stringify(h(r.observedState??n.observedState)),r.teardownError??null,r.costEstimate??null,i,o,e]),this.controlPlane.appendEvent({projectId:n.projectId,resourceId:n.resourceId,operationId:r.operationId,type:`preview.${t}`,level:t==="failed"||t==="cleanup_failed"?"error":"info",payload:{previewId:e,commitSha:n.commitSha,teardownError:r.teardownError??null}}),this.getInstance(e)}extend(e,t){let r=this.getInstance(e),n=r?this.getDefinition(r.definitionId):void 0;if(!r||!n)throw Error(`Preview ${e} was not found`);let o=this.now(),i=q(t,n.ttlHours,1,720),s=new Date(Math.max(o.getTime(),new Date(r.expiresAt).getTime())+i*3600000).toISOString();return this.controlPlane.database.run("UPDATE preview_instances SET expires_at=?, version=version+1, updated_at=? WHERE id=?",[s,o.toISOString(),e]),this.getInstance(e)}expired(e=this.now()){return this.listInstances().filter((t)=>["queued","deploying","active","updating","failed","cleanup_failed"].includes(t.status)&&new Date(t.expiresAt)<=e)}recordResource(e){let t=this.getInstance(e.previewId);if(!t)throw Error(`Preview ${e.previewId} was not found`);let r={"ts-cloud:preview":t.id,"ts-cloud:project":t.projectId,"ts-cloud:expires-at":t.expiresAt};for(let[s,a]of Object.entries(r))if(e.tags[s]!==a)throw Error(`Preview resource is missing immutable tag ${s}`);let n=this.id(),o=this.now().toISOString();this.controlPlane.database.run("INSERT INTO preview_resources (id, preview_id, provider, provider_resource_id, kind, tags, observed_state, discovered_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(preview_id, provider, provider_resource_id) DO UPDATE SET kind=excluded.kind, tags=excluded.tags, observed_state=excluded.observed_state, deleted_at=NULL",[n,t.id,e.provider,e.providerResourceId,e.kind,JSON.stringify(e.tags),JSON.stringify(h(e.observedState??{})),o]);let i=this.controlPlane.database.query("SELECT * FROM preview_resources WHERE preview_id=? AND provider=? AND provider_resource_id=?").get(t.id,e.provider,e.providerResourceId);return Zt(i)}listResources(e){return this.controlPlane.database.query("SELECT * FROM preview_resources WHERE preview_id=? ORDER BY kind, provider_resource_id").all(e).map(Zt)}markResourcesDeleted(e){if(!this.getInstance(e))throw Error(`Preview ${e} was not found`);return this.controlPlane.database.run("UPDATE preview_resources SET deleted_at=? WHERE preview_id=? AND deleted_at IS NULL",[this.now().toISOString(),e]).changes}}class Je{controlPlane;previews;queue;constructor(e){this.controlPlane=e;this.previews=new Le(e),this.queue=new S(e)}enqueueDeploy(e,t={}){let r=t.created?"preview.create":"preview.update",n=t.reason==="manual_rebuild"?`:${crypto.randomUUID()}`:"",o=this.queue.enqueue({projectId:e.projectId,environmentId:e.baseEnvironmentId,resourceId:e.resourceId,actorId:t.actorId,kind:r,correlationId:`preview:${e.id}`,idempotencyKey:`preview:${e.id}:${e.commitSha}${n}`,input:{previewId:e.id,reason:t.reason??(t.created?"create":"commit_update"),source:{repository:e.repository??null,branch:e.branch,commitSha:e.commitSha,pullRequestNumber:e.pullRequestNumber??null,fork:e.fork}},lockKey:`preview:${e.id}`,providerKey:"preview",buildSlot:!0,maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return this.previews.transition(e.id,"queued",{operationId:o.id}),o}enqueueDestroy(e,t,r){if(e.status==="destroyed")throw Error("Preview is already destroyed");let n=this.queue.enqueue({projectId:e.projectId,environmentId:e.baseEnvironmentId,resourceId:e.resourceId,actorId:r,kind:"preview.destroy",correlationId:`preview:${e.id}`,idempotencyKey:`preview:${e.id}:destroy:${t}`,input:{previewId:e.id,reason:t},lockKey:`preview:${e.id}`,providerKey:"preview",maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return this.previews.transition(e.id,"queued",{operationId:n.id}),n}cleanup(e={}){let t=e.now??new Date,r=new Map,n=this.previews.listInstances().filter((d)=>!["destroyed","destroying"].includes(d.status)),o=(d,c)=>{let u=r.get(d.id)??{preview:d,reasons:[]};if(!u.reasons.includes(c))u.reasons.push(c);r.set(d.id,u)};for(let d of n){if(new Date(d.expiresAt)<=t)o(d,"ttl_expired");if(e.maxAgeHours&&t.getTime()-new Date(d.createdAt).getTime()>=e.maxAgeHours*3600000)o(d,"max_age")}let i=new Map;for(let d of n)i.set(d.definitionId,[...i.get(d.definitionId)??[],d]);for(let[d,c]of i){let u=this.previews.getDefinition(d),p=e.keepCount??u?.keepCount;if(!p)continue;c.sort((l,f)=>f.createdAt.localeCompare(l.createdAt)).slice(p).forEach((l)=>o(l,"keep_count"))}let s=[...r.values()].sort((d,c)=>d.preview.createdAt.localeCompare(c.preview.createdAt)),a=e.dryRun?[]:s.map((d)=>this.enqueueDestroy(d.preview,d.reasons.sort().join("+"),e.actorId));if(s.length)this.controlPlane.appendEvent({actorId:e.actorId,type:e.dryRun?"preview.cleanup.planned":"preview.cleanup.queued",payload:{previewIds:s.map((d)=>d.preview.id),reasons:Object.fromEntries(s.map((d)=>[d.preview.id,d.reasons])),dryRun:!!e.dryRun}});return{candidates:s,operations:a,dryRun:!!e.dryRun}}reconcile(e){let t=[],r=[],n=[];for(let o of e){let i=o.tags["ts-cloud:preview"],s=o.tags["ts-cloud:project"],a=o.tags["ts-cloud:expires-at"];if(!i||!s||!a){n.push(o.providerResourceId);continue}let d=this.previews.getInstance(i);if(!d||d.projectId!==s||d.expiresAt!==a){r.push(o.providerResourceId);continue}if(this.previews.recordResource({...o,previewId:d.id}),o.estimatedMonthlyCost!==void 0)this.previews.transition(d.id,d.status,{costEstimate:o.estimatedMonthlyCost,observedState:{...d.observedState,lastReconciledAt:new Date().toISOString()}});t.push(o.providerResourceId)}if(r.length)this.controlPlane.appendEvent({type:"preview.reconciliation.leaks",level:"error",payload:{providerResourceIds:r}});return{matched:t,unknownPreviewResources:r,ignoredUntagged:n}}}var Wn=["deployment.create","deployment.rollback","application.create","deploy.source","deploy.preview","preview.create","preview.update","preview.destroy","compose.deploy","compose.redeploy","compose.start","compose.stop","compose.delete","compose.scale"];function Ee(e){return e&&typeof e==="object"&&!Array.isArray(e)?e:{}}function Kn(e,t){if(!t.projectId||!t.environmentId)throw Error(`Queued ${t.kind} operation is missing its project or environment scope`);let r=e.listEnvironments(t.projectId).find((s)=>s.id===t.environmentId);if(!r)throw Error(`Environment ${t.environmentId} was not found for queued ${t.kind} operation`);let n=t.resourceId?e.getResource(t.resourceId):void 0;if(t.resourceId&&(!n||n.projectId!==t.projectId||n.environmentId!==t.environmentId))throw Error(`Resource ${t.resourceId} was not found in the queued deployment scope`);let o=Ee(t.input);if(t.kind.startsWith("compose.")){let s=typeof o.applicationId==="string"?o.applicationId:void 0,a=s?new gt(e).get(s):t.resourceId?new gt(e).getByResource(t.resourceId):void 0;if(!a||a.projectId!==t.projectId||a.environmentId!==t.environmentId||a.resourceId!==t.resourceId)throw Error("Queued Compose application does not match the operation scope");let d=t.kind.slice(8),c=["compose:apply",a.id,"--action",d,"--env",r.slug];if(typeof o.service==="string"&&o.service)c.push("--service",o.service);if(typeof o.replicas==="number")c.push("--replicas",String(o.replicas));if(o.removeVolumes===!0)c.push("--remove-volumes");return{id:`queue:${t.id}`,label:`${d[0].toUpperCase()}${d.slice(1)} Compose application`,description:`${d} ${a.name}.`,command:c,mutates:!0,target:{environment:r.slug,resource:n?.slug,composeId:a.id}}}if(t.kind.startsWith("preview.")){let s=typeof o.previewId==="string"?o.previewId:void 0,a=s?new Le(e).getInstance(s):void 0;if(!a)throw Error(`Preview ${s??"(missing)"} was not found for queued ${t.kind}`);if(a.projectId!==t.projectId||a.resourceId!==t.resourceId)throw Error("Queued preview does not match the operation scope");if(t.kind==="preview.destroy")return{id:`queue:${t.id}`,label:"Destroy preview",description:`Destroy ${a.name}.`,command:["stack:delete",a.stackName,"--yes"],mutates:!0,target:{environment:r.slug,resource:n?.slug,previewId:a.id}};return{id:`queue:${t.id}`,label:t.kind==="preview.create"?"Create preview":"Update preview",description:`Deploy ${a.name} at ${a.commitSha}.`,command:["deploy","--stack",a.stackName,"--env",r.slug,"--yes","--skip-dns-verification",...n?["--site",n.slug]:[]],mutates:!0,target:{environment:r.slug,resource:n?.slug,previewId:a.id}}}if(t.kind==="deployment.rollback"){let s=["deploy:rollback"];if(n)s.push(n.slug);if(s.push("--env",r.slug),typeof o.revision==="string"&&o.revision)s.push("--to",o.revision);return{id:`queue:${t.id}`,label:"Rollback deployment",description:`Roll back ${n?.slug??r.slug}.`,command:s,mutates:!0,target:{environment:r.slug,resource:n?.slug}}}let i=["deploy","--env",r.slug,"--yes"];if(n)i.push("--site",n.slug);return{id:`queue:${t.id}`,label:t.kind==="deploy.preview"?"Deploy preview":"Deploy release",description:`Deploy ${n?.slug??r.slug}.`,command:i,mutates:!0,target:{environment:r.slug,resource:n?.slug}}}function Gn(e){let t=e.stderr?.trim()||`Deployment process exited with code ${e.exitCode}`;if(/\b(?:429|rate.?limit|throttl)/i.test(t))return new $e(t,"provider_throttled");if(/\b(?:502|503|504|temporar(?:y|ily)|unavailable|provider.?error)/i.test(t))return new $e(t,"provider_unavailable");if(/\b(?:network|econn|enotfound|socket|timed?\s*out|fetch failed|dns)\b/i.test(t))return new $e(t,"network");return Error(t)}function yc(e){let t=async(r)=>{r.checkpoint("prepare","Resolving the persisted deployment target.");let n=Kn(e.store,r.operation),o=n.target.previewId?new Le(e.store):void 0,i=n.target.composeId?new gt(e.store):void 0;if(o&&n.target.previewId)o.transition(n.target.previewId,r.operation.kind==="preview.destroy"?"destroying":r.operation.kind==="preview.update"?"updating":"deploying",{operationId:r.operation.id});if(i&&n.target.composeId)i.transition(n.target.composeId,r.operation.kind==="compose.delete"?"deleting":r.operation.kind==="compose.stop"?"stopped":"deploying",{operationId:r.operation.id});r.log(`Target: ${n.target.resource??"all resources"} in ${n.target.environment}.`,{stream:"system"}),r.throwIfCancellationRequested(),r.checkpoint("execute",`Running cloud ${n.command.join(" ")}.`);let s=await e.execute(n,r);if(!s.ok){if(o&&n.target.previewId)o.transition(n.target.previewId,r.operation.kind==="preview.destroy"?"cleanup_failed":"failed",{operationId:r.operation.id,teardownError:r.operation.kind==="preview.destroy"?s.stderr?.trim()||`Process exited with ${s.exitCode}`:void 0});if(i&&n.target.composeId)i.transition(n.target.composeId,r.operation.kind==="compose.delete"?"degraded":"failed",{operationId:r.operation.id,error:s.stderr?.trim()||`Process exited with ${s.exitCode}`});throw Gn(s)}if(r.throwIfCancellationRequested(),o&&n.target.previewId){let a=o.getInstance(n.target.previewId);if(r.operation.kind==="preview.destroy")o.markResourcesDeleted(a.id),o.transition(a.id,"destroyed",{operationId:r.operation.id,observedState:{reconciledResourceIds:o.listResources(a.id).map((d)=>d.providerResourceId),exactCommitSha:a.commitSha}});else{let d=e.store.getResource(a.resourceId)?.provider??"default";o.recordResource({previewId:a.id,provider:d,providerResourceId:a.stackName,kind:"stack",tags:{"ts-cloud:preview":a.id,"ts-cloud:project":a.projectId,"ts-cloud:expires-at":a.expiresAt},observedState:{command:s.command??null,exactCommitSha:a.commitSha}}),o.transition(a.id,"active",{operationId:r.operation.id,observedState:{url:a.url??null,stackName:a.stackName,exactCommitSha:a.commitSha,providerStatus:"deployed"}})}}if(i&&n.target.composeId){let a=i.get(n.target.composeId),d=typeof Ee(r.operation.input).service==="string"?String(Ee(r.operation.input).service):void 0,c=r.operation.kind==="compose.delete"?"deleted":r.operation.kind==="compose.stop"?"stopped":"running",u=i.transition(a.id,c,{operationId:r.operation.id,services:Object.values(a.manifest.spec.services).filter((p)=>!d||p.name===d).map((p)=>({name:p.name,status:c==="stopped"||c==="deleted"?"stopped":"running",replicas:c==="deleted"?0:p.replicas,healthyReplicas:c==="running"?p.replicas:0,observedState:{command:s.command??null,healthGatePassed:c==="running"}}))});if(c==="deleted")Yt(e.store,u,Ee(r.operation.input).removeVolumes===!0)}return r.checkpoint("finalize","Deployment command completed; persisting the terminal result."),{command:s.command??`cloud ${n.command.join(" ")}`,exitCode:s.exitCode,environment:n.target.environment,resource:n.target.resource??null}};return Object.fromEntries(Wn.map((r)=>[r,t]))}class m extends Error{code;status;details;constructor(e,t,r,n){super(t);this.code=e;this.status=r;this.details=n}}function et(e,t){if(e.organizationId!==t.organizationId)return!1;if(e.projectId&&e.projectId!==t.projectId)return!1;if(e.environmentId&&e.environmentId!==t.environmentId)return!1;if(e.resourceId&&e.resourceId!==t.resourceId)return!1;return!0}function Zn(e,t,r){return Yn("sha256").update(`${e.toUpperCase()}
|
|
110
110
|
${t}
|
|
111
|
-
${JSON.stringify(r)}`).digest("hex")}class ls{controlPlane;identities;queue;spendGate;constructor(e,t){this.controlPlane=e;this.identities=t;this.queue=new S(e),this.spendGate=new Mt(e)}target(e,t){let r=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,t),n=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,e.token.scope);if(!r||!n||!et(n,r))throw new m("forbidden","The token does not grant access to this resource.",403);return r}authorize(e,t,r){if(!e.token.capabilities.includes(t))throw new m("forbidden",`The token is missing the ${t} capability.`,403);let n=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,r),o=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,e.token.scope),i=t==="project:read"&&!!n&&!!o&&et(n,o);if(!n||!o||!et(o,n)&&!i)throw new m("forbidden","The token does not grant access to this resource.",403);let s=i?o:n;if(!re({membership:e.membership,grants:this.controlPlane.listGrants(e.membership.id),capability:t,target:s}).allowed)throw new m("forbidden","The service account does not have access to this resource.",403);return n}listProjects(e){return this.controlPlane.listProjects().filter((t)=>t.organizationId===e.serviceAccount.organizationId).filter((t)=>{try{return this.authorize(e,"project:read",{type:"project",id:t.id}),!0}catch{return!1}}).map((t)=>({id:t.id,slug:t.slug,name:t.name,description:t.description,version:t.version,createdAt:t.createdAt,updatedAt:t.updatedAt}))}listEnvironments(e,t){let r=this.controlPlane.getProject(t);if(!r||r.organizationId!==e.serviceAccount.organizationId)throw new m("not_found","Project was not found.",404);return this.controlPlane.listEnvironments(t).filter((n)=>{try{return this.authorize(e,"project:read",{type:"environment",id:n.id}),!0}catch{return!1}}).map((n)=>({id:n.id,projectId:n.projectId,slug:n.slug,name:n.name,kind:n.kind,region:n.region,version:n.version,createdAt:n.createdAt,updatedAt:n.updatedAt}))}listServices(e,t,r){let n=new Set(this.listEnvironments(e,t).map((o)=>String(o.id)));if(r&&!n.has(r))throw new m("not_found","Environment was not found.",404);return this.controlPlane.listResources(t,r).filter((o)=>!o.environmentId||n.has(o.environmentId)).filter((o)=>{try{return this.authorize(e,"project:read",{type:"resource",id:o.id}),!0}catch{return!1}}).map((o)=>({id:o.id,projectId:o.projectId,environmentId:o.environmentId,kind:o.kind,slug:o.slug,name:o.name,provider:o.provider,providerId:o.providerId,metadata:h(o.metadata),version:o.version,createdAt:o.createdAt,updatedAt:o.updatedAt}))}listOperations(e,t){return this.controlPlane.listOperations({projectId:t,limit:500}).filter((n)=>{let o=n.resourceId?{type:"resource",id:n.resourceId}:n.environmentId?{type:"environment",id:n.environmentId}:n.projectId?{type:"project",id:n.projectId}:{type:"organization"};try{return this.authorize(e,"deployments:read",o),!0}catch{return!1}}).map((n)=>this.operation(n))}listEvents(e,t,r){if(t)this.authorize(e,"audit:read",{type:"project",id:t});else this.authorize(e,"audit:read",e.token.scope);return this.controlPlane.listEvents({organizationId:e.serviceAccount.organizationId,projectId:t,afterSequence:r,limit:500}).filter((n)=>{let o=n.resourceId?{type:"resource",id:n.resourceId}:n.projectId?{type:"project",id:n.projectId}:{type:"organization"};try{return this.target(e,o),!0}catch{return!1}}).map((n)=>({id:n.id,sequence:n.sequence,projectId:n.projectId,operationId:n.operationId,resourceId:n.resourceId,correlationId:n.correlationId,type:n.type,level:n.level,payload:h(n.payload),createdAt:n.createdAt}))}createDeployment(e,t,r){if(!this.controlPlane.listEnvironments(t.projectId).find((u)=>u.id===t.environmentId))throw new m("not_found","Environment was not found in this project.",404);let o=t.serviceId?{type:"resource",id:t.serviceId}:{type:"environment",id:t.environmentId};this.authorize(e,"deployments:create",o);let i=this.spendGate.check("deploy",{organizationId:e.serviceAccount.organizationId,projectId:t.projectId,environmentId:t.environmentId});if(!i.allowed)throw new m("spend_cap_exceeded",i.reason??"A spend cap is blocking deployments.",402,{action:i.action,budgetId:i.budgetId});let s=Zn("POST","/api/v1/deployments",t),a=this.identities.getIdempotency(e.token.id,r);if(a){if(a.requestHash!==s)throw new m("idempotency_conflict","Idempotency-Key was already used for another request.",409);let u=a.operationId?this.controlPlane.getOperation(a.operationId):void 0;if(!u)throw new m("idempotency_unavailable","The original operation is no longer available.",409);return{operation:this.operation(u),replay:!0}}if(t.serviceId){let u=this.controlPlane.getResource(t.serviceId);if(!u||u.projectId!==t.projectId||u.environmentId!==t.environmentId)throw new m("not_found","Service was not found in this environment.",404)}let d=t.serviceId?this.controlPlane.getResource(t.serviceId):void 0,c=this.queue.enqueue({projectId:t.projectId,environmentId:t.environmentId,resourceId:t.serviceId,actorId:e.actor.id,kind:t.action==="rollback"?"deployment.rollback":"deployment.create",idempotencyKey:`api:${e.token.id}:${r}`,input:h({action:t.action??"deploy",revision:t.revision??null}),lockKey:t.serviceId?`resource:${t.serviceId}`:`environment:${t.environmentId}`,providerKey:d?.provider??"default",buildSlot:t.action!=="rollback",maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return this.identities.saveIdempotency({tokenId:e.token.id,key:r,requestHash:s,operationId:c.id,responseStatus:202,responseBody:{operationId:c.id}}),{operation:this.operation(c),replay:!1}}operation(e){return{id:e.id,state:e.state,kind:e.kind,projectId:e.projectId,environmentId:e.environmentId,resourceId:e.resourceId,actorId:e.actorId,correlationId:e.correlationId,input:h(e.input),output:h(e.output),error:e.error,attempt:e.attempt,createdAt:e.createdAt,updatedAt:e.updatedAt,startedAt:e.startedAt,finishedAt:e.finishedAt}}}function we(e){return e.serviceAccount.organizationId}function Xt(e){if(e==null)return;if(e==="daily"||e==="weekly"||e==="monthly")return e;throw new m("validation_error","period must be daily, weekly, or monthly.",422)}function W(e,t){if(e==null)return;let r=Number(e);if(!Number.isFinite(r)||r<0||!Number.isInteger(r))throw new m("validation_error",`${t} must be a non-negative integer.`,422);return r}function T(e,t,r,n,o){if(o)e.authorization.authorize(t,r,{type:"environment",id:o});else if(n)e.authorization.authorize(t,r,{type:"project",id:n});else e.authorization.authorize(t,r,{type:"organization"});return{organizationId:we(t),projectId:n,environmentId:o}}async function wo(e,t,r){let{method:n,url:o}=r,i=e.now?.()??new Date,s=o.searchParams.get("projectId")??void 0,a=o.searchParams.get("environmentId")??void 0;if(n==="GET"&&o.pathname==="/api/v1/usage"){let l=T(e,t,"billing:read",s,a);return e.service.usageReport({...l,period:Xt(o.searchParams.get("period")),timezone:o.searchParams.get("timezone")??void 0,now:i})}if(n==="GET"&&o.pathname==="/api/v1/usage/rollups"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("from"),g=o.searchParams.get("to");if(!f||!g)throw new m("validation_error","from and to are required.",422);if(Number.isNaN(Date.parse(f))||Number.isNaN(Date.parse(g)))throw new m("validation_error","from and to must be ISO-8601 timestamps.",422);let y=o.searchParams.getAll("meter");return{data:e.store.listRollups({...l,from:f,to:g,meters:y.length>0?y:void 0},W(o.searchParams.get("limit"),"limit")??1000)}}if(n==="GET"&&o.pathname==="/api/v1/usage/focus"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("from"),g=o.searchParams.get("to");if(!f||!g)throw new m("validation_error","from and to are required.",422);if(Number.isNaN(Date.parse(f))||Number.isNaN(Date.parse(g)))throw new m("validation_error","from and to must be ISO-8601 timestamps.",422);if(new Date(g).getTime()-new Date(f).getTime()>31622400000)throw new m("validation_error","The range must not exceed one year.",422);let y=o.searchParams.get("granularity")==="hourly"?"hourly":"daily",v=e.store.listRollups({...l,from:f,to:g},1e4),b=_c(v,{billingPeriodStart:f,billingPeriodEnd:g,currency:e.store.priceBook.currency,granularity:y});return{contentType:"application/x-ndjson",body:Co(b),recordCount:b.length}}if(n==="GET"&&o.pathname==="/api/v1/spend/budgets"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listBudgets({organizationId:l.organizationId,projectId:l.projectId})}}if(n==="POST"&&o.pathname==="/api/v1/spend/budgets"){let l=await r.body?.()??{},g={organizationId:T(e,t,"billing:manage",l.projectId,l.environmentId).organizationId,projectId:l.projectId,environmentId:l.environmentId,name:String(l.name??"").trim(),period:Xt(l.period??"monthly")??"monthly",timezone:l.timezone,currency:l.currency,softLimitCents:W(l.softLimitCents,"softLimitCents"),hardLimitCents:W(l.hardLimitCents,"hardLimitCents"),thresholds:l.thresholds,meters:l.meters,graceSeconds:W(l.graceSeconds,"graceSeconds"),hysteresisPercent:l.hysteresisPercent,dryRun:l.dryRun!==!1,enabled:l.enabled};try{return{data:e.store.createBudget(g)}}catch(y){throw new m("validation_error",y instanceof Error?y.message:String(y),422)}}let d=/^\/api\/v1\/spend\/budgets\/([^/]+)$/.exec(o.pathname);if(d&&(n==="PATCH"||n==="DELETE")){let l=e.store.getBudget(decodeURIComponent(d[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Budget was not found.",404);if(T(e,t,"billing:manage",l.projectId,l.environmentId),n==="DELETE")return{data:{deleted:e.store.deleteBudget(l.id)}};let f=await r.body?.()??{};try{return{data:e.store.updateBudget(l.id,f,W(f.expectedVersion,"expectedVersion"))}}catch(g){let y=g instanceof Error?g.message:String(g);throw new m(y.includes("concurrently")?"conflict":"validation_error",y,y.includes("concurrently")?409:422)}}if(n==="GET"&&o.pathname==="/api/v1/spend/anomalies"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listAnomalies({organizationId:l.organizationId,projectId:l.projectId,since:o.searchParams.get("since")??void 0,unacknowledgedOnly:o.searchParams.get("unacknowledged")==="true",limit:W(o.searchParams.get("limit"),"limit")})}}let c=/^\/api\/v1\/spend\/anomalies\/([^/]+)\/acknowledge$/.exec(o.pathname);if(c&&n==="POST"){let l=e.store.getAnomaly(decodeURIComponent(c[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Anomaly was not found.",404);return T(e,t,"billing:manage",l.projectId,l.environmentId),{data:{acknowledged:e.store.acknowledgeAnomaly(l.id)}}}if(n==="GET"&&o.pathname==="/api/v1/spend/signals")return T(e,t,"billing:read",s,a),{data:Lt};if(o.pathname==="/api/v1/spend/anomaly-configs"){if(n==="GET"){let l=T(e,t,"billing:read",s,a);return{data:e.service.anomalyConfigs.list({organizationId:l.organizationId,projectId:l.projectId})}}if(n==="POST"){let l=await r.body?.()??{},f=T(e,t,"billing:manage",l.projectId,l.environmentId);try{return{data:e.service.anomalyConfigs.upsert({organizationId:f.organizationId,projectId:l.projectId,environmentId:l.environmentId,signal:String(l.signal??""),enabled:l.enabled,sensitivity:l.sensitivity,seasonLength:l.seasonLength==null?void 0:Number(l.seasonLength),minAbsoluteDelta:l.minAbsoluteDelta==null?void 0:Number(l.minAbsoluteDelta),detectDrops:l.detectDrops,severity:l.severity})}}catch(g){throw new m("validation_error",g instanceof Error?g.message:String(g),422)}}}let u=/^\/api\/v1\/spend\/anomaly-configs\/([^/]+)$/.exec(o.pathname);if(u&&n==="DELETE"){let l=e.service.anomalyConfigs.get(decodeURIComponent(u[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Anomaly config was not found.",404);return T(e,t,"billing:manage",l.projectId,l.environmentId),{data:{deleted:e.service.anomalyConfigs.delete(l.id)}}}if(o.pathname==="/api/v1/spend/anomaly-silences"){if(n==="GET"){let l=T(e,t,"billing:read",s,a);return{data:e.service.anomalyConfigs.listSilences({organizationId:l.organizationId,projectId:l.projectId,includeExpired:o.searchParams.get("includeExpired")==="true"})}}if(n==="POST"){let l=await r.body?.()??{},f=T(e,t,"billing:manage",l.projectId);try{return{data:e.service.anomalyConfigs.silence({organizationId:f.organizationId,projectId:l.projectId,signal:l.signal,routePattern:l.routePattern,statusCode:l.statusCode==null?void 0:Number(l.statusCode),reason:String(l.reason??""),expiresAt:l.expiresAt})}}catch(g){throw new m("validation_error",g instanceof Error?g.message:String(g),422)}}}let p=/^\/api\/v1\/spend\/anomaly-silences\/([^/]+)$/.exec(o.pathname);if(p&&n==="DELETE")return T(e,t,"billing:manage",s),{data:{deleted:e.service.anomalyConfigs.removeSilence(decodeURIComponent(p[1]))}};if(n==="GET"&&o.pathname==="/api/v1/spend/enforcement"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listEnforcements({organizationId:l.organizationId,activeOnly:o.searchParams.get("active")!=="false"})}}if(n==="GET"&&o.pathname==="/api/v1/spend/allowance"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("operation")??"deploy";if(!["build","deploy","function_invoke","request"].includes(f))throw new m("validation_error","operation must be build, deploy, function_invoke, or request.",422);let y=e.store.listEnforcements({organizationId:l.organizationId,activeOnly:!0}).filter((_)=>(!_.projectId||_.projectId===l.projectId)&&(!_.environmentId||_.environmentId===l.environmentId)),v=Nc(f,y),I=e.store.budgetsForScope(l.organizationId,l.projectId,l.environmentId).map((_)=>e.service.status(_,i));return{operation:f,allowed:v.allowed,blockedBy:v.blockedBy??null,reason:v.reason??null,budgets:I.map((_)=>({id:_.budget.id,name:_.budget.name,usedPercent:_.decision.usedPercent,projectedPercent:_.decision.projectedPercent,level:_.decision.level,timeToCap:_.timeToCap}))}}return}function Ao(){let e=[{name:"projectId",in:"query",schema:{type:"string"}},{name:"environmentId",in:"query",schema:{type:"string"}}];return{"/api/v1/usage":{get:{summary:"Current usage, cost, and every budget governing the scope.",parameters:[...e,{name:"period",in:"query",schema:{type:"string",enum:["daily","weekly","monthly"]}},{name:"timezone",in:"query",schema:{type:"string"}}],responses:{"200":{description:"Usage totals, per-meter breakdown, hourly series, and budget status."}}}},"/api/v1/usage/rollups":{get:{summary:"Itemized hourly usage rollups.",parameters:[...e,{name:"from",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"to",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"meter",in:"query",schema:{type:"array",items:{type:"string"}}},{name:"limit",in:"query",schema:{type:"integer"}}],responses:{"200":{description:"Hourly rollups, newest first."}}}},"/api/v1/usage/focus":{get:{summary:"Usage and cost in FOCUS v1.3 format, newline-delimited JSON.",parameters:[...e,{name:"from",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"to",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"granularity",in:"query",schema:{type:"string",enum:["daily","hourly"]}}],responses:{"200":{description:"FOCUS records, one JSON object per line."}}}},"/api/v1/spend/budgets":{get:{summary:"Budgets governing a scope.",parameters:e,responses:{"200":{description:"Budgets."}}},post:{summary:"Create a budget. Starts in dry run unless dryRun is explicitly false.",responses:{"201":{description:"The created budget."},"422":{description:"Validation error."}}}},"/api/v1/spend/budgets/{budgetId}":{patch:{summary:"Update a budget. Pass expectedVersion for optimistic concurrency.",responses:{"200":{description:"The updated budget."},"409":{description:"Version conflict."}}},delete:{summary:"Delete a budget.",responses:{"200":{description:"Deletion result."}}}},"/api/v1/spend/anomalies":{get:{summary:"Detected spend anomalies.",parameters:[...e,{name:"since",in:"query",schema:{type:"string",format:"date-time"}},{name:"unacknowledged",in:"query",schema:{type:"boolean"}}],responses:{"200":{description:"Anomalies, newest first."}}}},"/api/v1/spend/anomalies/{anomalyId}/acknowledge":{post:{summary:"Acknowledge an anomaly.",responses:{"200":{description:"Acknowledgement result."}}}},"/api/v1/spend/signals":{get:{summary:"Signals anomaly detection can run on, with their gap and sample rules.",responses:{"200":{description:"Signal catalog."}}}},"/api/v1/spend/anomaly-configs":{get:{summary:"Anomaly detection configuration.",parameters:e,responses:{"200":{description:"Configs."}}},post:{summary:"Create or update the config for a signal.",responses:{"200":{description:"The config."}}}},"/api/v1/spend/anomaly-configs/{configId}":{delete:{summary:"Delete an anomaly config, returning the signal to its default.",responses:{"200":{description:"Result."}}}},"/api/v1/spend/anomaly-silences":{get:{summary:"Active anomaly silences.",parameters:e,responses:{"200":{description:"Silences."}}},post:{summary:"Silence a signal, route, or status code. A reason is required.",responses:{"200":{description:"The silence."}}}},"/api/v1/spend/anomaly-silences/{silenceId}":{delete:{summary:"Remove a silence.",responses:{"200":{description:"Result."}}}},"/api/v1/spend/enforcement":{get:{summary:"Enforcement actions in force.",parameters:[...e,{name:"active",in:"query",schema:{type:"boolean"}}],responses:{"200":{description:"Enforcement records."}}}},"/api/v1/spend/allowance":{get:{summary:"Whether an operation is allowed under current spend enforcement.",parameters:[...e,{name:"operation",in:"query",schema:{type:"string",enum:["build","deploy","function_invoke","request"]}}],responses:{"200":{description:"Allowance verdict and the budgets behind it."}}}}}}export{$e,S,lo,Ot,li,uo,hr,mc,gc,fc,di,ui,mt,en,hc,$t,tn,gt,Ke,Le,Je,yc,ft,yr,Me,Xe,pi,mi,es,ts,Qe,rn,Lp,nn,rs,oe,Mp,bc,Cd,po,Up,Fp,Bp,Sc,ns,mo,vc,sn,br,jp,gi,Vp,Cc,Td,Ed,go,Tc,Ec,Sr,is,vr,wc,fo,fi,wd,ss,Ac,Rc,os,Ad,Ic,Pc,Dc,Nc,ho,Rd,Id,zp,Pd,kc,as,Dd,Nd,yo,Lt,bo,So,vo,xc,kd,_c,Co,Hp,ht,Gp,Oc,Mt,$c,qp,Lc,xd,Wp,ee,_d,To,Kp,cs,hi,yi,Eo,Od,$d,Jp,m,ls,wo,Ao};
|
|
111
|
+
${JSON.stringify(r)}`).digest("hex")}class ls{controlPlane;identities;queue;spendGate;constructor(e,t){this.controlPlane=e;this.identities=t;this.queue=new S(e),this.spendGate=new Mt(e)}target(e,t){let r=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,t),n=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,e.token.scope);if(!r||!n||!et(n,r))throw new m("forbidden","The token does not grant access to this resource.",403);return r}authorize(e,t,r){if(!e.token.capabilities.includes(t))throw new m("forbidden",`The token is missing the ${t} capability.`,403);let n=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,r),o=this.controlPlane.resolveAuthorizationTarget(e.serviceAccount.organizationId,e.token.scope),i=t==="project:read"&&!!n&&!!o&&et(n,o);if(!n||!o||!et(o,n)&&!i)throw new m("forbidden","The token does not grant access to this resource.",403);let s=i?o:n;if(!re({membership:e.membership,grants:this.controlPlane.listGrants(e.membership.id),capability:t,target:s}).allowed)throw new m("forbidden","The service account does not have access to this resource.",403);return n}listProjects(e){return this.controlPlane.listProjects().filter((t)=>t.organizationId===e.serviceAccount.organizationId).filter((t)=>{try{return this.authorize(e,"project:read",{type:"project",id:t.id}),!0}catch{return!1}}).map((t)=>({id:t.id,slug:t.slug,name:t.name,description:t.description,version:t.version,createdAt:t.createdAt,updatedAt:t.updatedAt}))}listEnvironments(e,t){let r=this.controlPlane.getProject(t);if(!r||r.organizationId!==e.serviceAccount.organizationId)throw new m("not_found","Project was not found.",404);return this.controlPlane.listEnvironments(t).filter((n)=>{try{return this.authorize(e,"project:read",{type:"environment",id:n.id}),!0}catch{return!1}}).map((n)=>({id:n.id,projectId:n.projectId,slug:n.slug,name:n.name,kind:n.kind,region:n.region,version:n.version,createdAt:n.createdAt,updatedAt:n.updatedAt}))}listServices(e,t,r){let n=new Set(this.listEnvironments(e,t).map((o)=>String(o.id)));if(r&&!n.has(r))throw new m("not_found","Environment was not found.",404);return this.controlPlane.listResources(t,r).filter((o)=>!o.environmentId||n.has(o.environmentId)).filter((o)=>{try{return this.authorize(e,"project:read",{type:"resource",id:o.id}),!0}catch{return!1}}).map((o)=>({id:o.id,projectId:o.projectId,environmentId:o.environmentId,kind:o.kind,slug:o.slug,name:o.name,provider:o.provider,providerId:o.providerId,metadata:h(o.metadata),version:o.version,createdAt:o.createdAt,updatedAt:o.updatedAt}))}listOperations(e,t){return this.controlPlane.listOperations({projectId:t,limit:500}).filter((n)=>{let o=n.resourceId?{type:"resource",id:n.resourceId}:n.environmentId?{type:"environment",id:n.environmentId}:n.projectId?{type:"project",id:n.projectId}:{type:"organization"};try{return this.authorize(e,"deployments:read",o),!0}catch{return!1}}).map((n)=>this.operation(n))}listEvents(e,t,r){if(t)this.authorize(e,"audit:read",{type:"project",id:t});else this.authorize(e,"audit:read",e.token.scope);return this.controlPlane.listEvents({organizationId:e.serviceAccount.organizationId,projectId:t,afterSequence:r,limit:500}).filter((n)=>{let o=n.resourceId?{type:"resource",id:n.resourceId}:n.projectId?{type:"project",id:n.projectId}:{type:"organization"};try{return this.target(e,o),!0}catch{return!1}}).map((n)=>({id:n.id,sequence:n.sequence,projectId:n.projectId,operationId:n.operationId,resourceId:n.resourceId,correlationId:n.correlationId,type:n.type,level:n.level,payload:h(n.payload),createdAt:n.createdAt}))}createDeployment(e,t,r){if(!this.controlPlane.listEnvironments(t.projectId).find((u)=>u.id===t.environmentId))throw new m("not_found","Environment was not found in this project.",404);let o=t.serviceId?{type:"resource",id:t.serviceId}:{type:"environment",id:t.environmentId};this.authorize(e,"deployments:create",o);let i=this.spendGate.check("deploy",{organizationId:e.serviceAccount.organizationId,projectId:t.projectId,environmentId:t.environmentId});if(!i.allowed)throw new m("spend_cap_exceeded",i.reason??"A spend cap is blocking deployments.",402,{action:i.action,budgetId:i.budgetId});let s=Zn("POST","/api/v1/deployments",t),a=this.identities.getIdempotency(e.token.id,r);if(a){if(a.requestHash!==s)throw new m("idempotency_conflict","Idempotency-Key was already used for another request.",409);let u=a.operationId?this.controlPlane.getOperation(a.operationId):void 0;if(!u)throw new m("idempotency_unavailable","The original operation is no longer available.",409);return{operation:this.operation(u),replay:!0}}if(t.serviceId){let u=this.controlPlane.getResource(t.serviceId);if(!u||u.projectId!==t.projectId||u.environmentId!==t.environmentId)throw new m("not_found","Service was not found in this environment.",404)}let d=t.serviceId?this.controlPlane.getResource(t.serviceId):void 0,c=this.queue.enqueue({projectId:t.projectId,environmentId:t.environmentId,resourceId:t.serviceId,actorId:e.actor.id,kind:t.action==="rollback"?"deployment.rollback":"deployment.create",idempotencyKey:`api:${e.token.id}:${r}`,input:h({action:t.action??"deploy",revision:t.revision??null}),lockKey:t.serviceId?`resource:${t.serviceId}`:`environment:${t.environmentId}`,providerKey:d?.provider??"default",buildSlot:t.action!=="rollback",maxAttempts:3,retryClasses:["network","provider_throttled","provider_unavailable"],resumePolicy:"fail",cancellationMode:"provider_non_cancellable",retentionDays:90}).operation;return this.identities.saveIdempotency({tokenId:e.token.id,key:r,requestHash:s,operationId:c.id,responseStatus:202,responseBody:{operationId:c.id}}),{operation:this.operation(c),replay:!1}}operation(e){return{id:e.id,state:e.state,kind:e.kind,projectId:e.projectId,environmentId:e.environmentId,resourceId:e.resourceId,actorId:e.actorId,correlationId:e.correlationId,input:h(e.input),output:h(e.output),error:e.error,attempt:e.attempt,createdAt:e.createdAt,updatedAt:e.updatedAt,startedAt:e.startedAt,finishedAt:e.finishedAt}}}function we(e){return e.serviceAccount.organizationId}function Xt(e){if(e==null)return;if(e==="daily"||e==="weekly"||e==="monthly")return e;throw new m("validation_error","period must be daily, weekly, or monthly.",422)}function W(e,t){if(e==null)return;let r=Number(e);if(!Number.isFinite(r)||r<0||!Number.isInteger(r))throw new m("validation_error",`${t} must be a non-negative integer.`,422);return r}function T(e,t,r,n,o){if(o)e.authorization.authorize(t,r,{type:"environment",id:o});else if(n)e.authorization.authorize(t,r,{type:"project",id:n});else e.authorization.authorize(t,r,{type:"organization"});return{organizationId:we(t),projectId:n,environmentId:o}}async function wo(e,t,r){let{method:n,url:o}=r,i=e.now?.()??new Date,s=o.searchParams.get("projectId")??void 0,a=o.searchParams.get("environmentId")??void 0;if(n==="GET"&&o.pathname==="/api/v1/usage"){let l=T(e,t,"billing:read",s,a);return e.service.usageReport({...l,period:Xt(o.searchParams.get("period")),timezone:o.searchParams.get("timezone")??void 0,now:i})}if(n==="GET"&&o.pathname==="/api/v1/usage/rollups"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("from"),g=o.searchParams.get("to");if(!f||!g)throw new m("validation_error","from and to are required.",422);if(Number.isNaN(Date.parse(f))||Number.isNaN(Date.parse(g)))throw new m("validation_error","from and to must be ISO-8601 timestamps.",422);let y=o.searchParams.getAll("meter");return{data:e.store.listRollups({...l,from:f,to:g,meters:y.length>0?y:void 0},W(o.searchParams.get("limit"),"limit")??1000)}}if(n==="GET"&&o.pathname==="/api/v1/usage/focus"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("from"),g=o.searchParams.get("to");if(!f||!g)throw new m("validation_error","from and to are required.",422);if(Number.isNaN(Date.parse(f))||Number.isNaN(Date.parse(g)))throw new m("validation_error","from and to must be ISO-8601 timestamps.",422);if(new Date(g).getTime()-new Date(f).getTime()>31622400000)throw new m("validation_error","The range must not exceed one year.",422);let y=o.searchParams.get("granularity")==="hourly"?"hourly":"daily",v=e.store.listRollups({...l,from:f,to:g},1e4),b=_c(v,{billingPeriodStart:f,billingPeriodEnd:g,currency:e.store.priceBook.currency,granularity:y});return{contentType:"application/x-ndjson",body:Co(b),recordCount:b.length}}if(n==="GET"&&o.pathname==="/api/v1/spend/budgets"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listBudgets({organizationId:l.organizationId,projectId:l.projectId})}}if(n==="POST"&&o.pathname==="/api/v1/spend/budgets"){let l=await r.body?.()??{},g={organizationId:T(e,t,"billing:manage",l.projectId,l.environmentId).organizationId,projectId:l.projectId,environmentId:l.environmentId,name:String(l.name??"").trim(),period:Xt(l.period??"monthly")??"monthly",timezone:l.timezone,currency:l.currency,softLimitCents:W(l.softLimitCents,"softLimitCents"),hardLimitCents:W(l.hardLimitCents,"hardLimitCents"),thresholds:l.thresholds,meters:l.meters,graceSeconds:W(l.graceSeconds,"graceSeconds"),hysteresisPercent:l.hysteresisPercent,dryRun:l.dryRun!==!1,enabled:l.enabled};try{return{data:e.store.createBudget(g)}}catch(y){throw new m("validation_error",y instanceof Error?y.message:String(y),422)}}let d=/^\/api\/v1\/spend\/budgets\/([^/]+)$/.exec(o.pathname);if(d&&(n==="PATCH"||n==="DELETE")){let l=e.store.getBudget(decodeURIComponent(d[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Budget was not found.",404);if(T(e,t,"billing:manage",l.projectId,l.environmentId),n==="DELETE")return{data:{deleted:e.store.deleteBudget(l.id)}};let f=await r.body?.()??{};try{return{data:e.store.updateBudget(l.id,f,W(f.expectedVersion,"expectedVersion"))}}catch(g){let y=g instanceof Error?g.message:String(g);throw new m(y.includes("concurrently")?"conflict":"validation_error",y,y.includes("concurrently")?409:422)}}if(n==="GET"&&o.pathname==="/api/v1/spend/anomalies"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listAnomalies({organizationId:l.organizationId,projectId:l.projectId,since:o.searchParams.get("since")??void 0,unacknowledgedOnly:o.searchParams.get("unacknowledged")==="true",limit:W(o.searchParams.get("limit"),"limit")})}}let c=/^\/api\/v1\/spend\/anomalies\/([^/]+)\/acknowledge$/.exec(o.pathname);if(c&&n==="POST"){let l=e.store.getAnomaly(decodeURIComponent(c[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Anomaly was not found.",404);return T(e,t,"billing:manage",l.projectId,l.environmentId),{data:{acknowledged:e.store.acknowledgeAnomaly(l.id)}}}if(n==="GET"&&o.pathname==="/api/v1/spend/signals")return T(e,t,"billing:read",s,a),{data:Lt};if(o.pathname==="/api/v1/spend/anomaly-configs"){if(n==="GET"){let l=T(e,t,"billing:read",s,a);return{data:e.service.anomalyConfigs.list({organizationId:l.organizationId,projectId:l.projectId})}}if(n==="POST"){let l=await r.body?.()??{},f=T(e,t,"billing:manage",l.projectId,l.environmentId);try{return{data:e.service.anomalyConfigs.upsert({organizationId:f.organizationId,projectId:l.projectId,environmentId:l.environmentId,signal:String(l.signal??""),enabled:l.enabled,sensitivity:l.sensitivity,seasonLength:l.seasonLength==null?void 0:Number(l.seasonLength),minAbsoluteDelta:l.minAbsoluteDelta==null?void 0:Number(l.minAbsoluteDelta),detectDrops:l.detectDrops,severity:l.severity})}}catch(g){throw new m("validation_error",g instanceof Error?g.message:String(g),422)}}}let u=/^\/api\/v1\/spend\/anomaly-configs\/([^/]+)$/.exec(o.pathname);if(u&&n==="DELETE"){let l=e.service.anomalyConfigs.get(decodeURIComponent(u[1]));if(!l||l.organizationId!==we(t))throw new m("not_found","Anomaly config was not found.",404);return T(e,t,"billing:manage",l.projectId,l.environmentId),{data:{deleted:e.service.anomalyConfigs.delete(l.id)}}}if(o.pathname==="/api/v1/spend/anomaly-silences"){if(n==="GET"){let l=T(e,t,"billing:read",s,a);return{data:e.service.anomalyConfigs.listSilences({organizationId:l.organizationId,projectId:l.projectId,includeExpired:o.searchParams.get("includeExpired")==="true"})}}if(n==="POST"){let l=await r.body?.()??{},f=T(e,t,"billing:manage",l.projectId);try{return{data:e.service.anomalyConfigs.silence({organizationId:f.organizationId,projectId:l.projectId,signal:l.signal,routePattern:l.routePattern,statusCode:l.statusCode==null?void 0:Number(l.statusCode),reason:String(l.reason??""),expiresAt:l.expiresAt})}}catch(g){throw new m("validation_error",g instanceof Error?g.message:String(g),422)}}}let p=/^\/api\/v1\/spend\/anomaly-silences\/([^/]+)$/.exec(o.pathname);if(p&&n==="DELETE")return T(e,t,"billing:manage",s),{data:{deleted:e.service.anomalyConfigs.removeSilence(decodeURIComponent(p[1]))}};if(n==="GET"&&o.pathname==="/api/v1/spend/enforcement"){let l=T(e,t,"billing:read",s,a);return{data:e.store.listEnforcements({organizationId:l.organizationId,activeOnly:o.searchParams.get("active")!=="false"})}}if(n==="GET"&&o.pathname==="/api/v1/spend/allowance"){let l=T(e,t,"billing:read",s,a),f=o.searchParams.get("operation")??"deploy";if(!["build","deploy","function_invoke","request"].includes(f))throw new m("validation_error","operation must be build, deploy, function_invoke, or request.",422);let y=e.store.listEnforcements({organizationId:l.organizationId,activeOnly:!0}).filter((_)=>(!_.projectId||_.projectId===l.projectId)&&(!_.environmentId||_.environmentId===l.environmentId)),v=Nc(f,y),I=e.store.budgetsForScope(l.organizationId,l.projectId,l.environmentId).map((_)=>e.service.status(_,i));return{operation:f,allowed:v.allowed,blockedBy:v.blockedBy??null,reason:v.reason??null,budgets:I.map((_)=>({id:_.budget.id,name:_.budget.name,usedPercent:_.decision.usedPercent,projectedPercent:_.decision.projectedPercent,level:_.decision.level,timeToCap:_.timeToCap}))}}return}function Ao(){let e=[{name:"projectId",in:"query",schema:{type:"string"}},{name:"environmentId",in:"query",schema:{type:"string"}}];return{"/api/v1/usage":{get:{summary:"Current usage, cost, and every budget governing the scope.",parameters:[...e,{name:"period",in:"query",schema:{type:"string",enum:["daily","weekly","monthly"]}},{name:"timezone",in:"query",schema:{type:"string"}}],responses:{"200":{description:"Usage totals, per-meter breakdown, hourly series, and budget status."}}}},"/api/v1/usage/rollups":{get:{summary:"Itemized hourly usage rollups.",parameters:[...e,{name:"from",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"to",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"meter",in:"query",schema:{type:"array",items:{type:"string"}}},{name:"limit",in:"query",schema:{type:"integer"}}],responses:{"200":{description:"Hourly rollups, newest first."}}}},"/api/v1/usage/focus":{get:{summary:"Usage and cost in FOCUS v1.3 format, newline-delimited JSON.",parameters:[...e,{name:"from",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"to",in:"query",required:!0,schema:{type:"string",format:"date-time"}},{name:"granularity",in:"query",schema:{type:"string",enum:["daily","hourly"]}}],responses:{"200":{description:"FOCUS records, one JSON object per line."}}}},"/api/v1/spend/budgets":{get:{summary:"Budgets governing a scope.",parameters:e,responses:{"200":{description:"Budgets."}}},post:{summary:"Create a budget. Starts in dry run unless dryRun is explicitly false.",responses:{"201":{description:"The created budget."},"422":{description:"Validation error."}}}},"/api/v1/spend/budgets/{budgetId}":{patch:{summary:"Update a budget. Pass expectedVersion for optimistic concurrency.",responses:{"200":{description:"The updated budget."},"409":{description:"Version conflict."}}},delete:{summary:"Delete a budget.",responses:{"200":{description:"Deletion result."}}}},"/api/v1/spend/anomalies":{get:{summary:"Detected spend anomalies.",parameters:[...e,{name:"since",in:"query",schema:{type:"string",format:"date-time"}},{name:"unacknowledged",in:"query",schema:{type:"boolean"}}],responses:{"200":{description:"Anomalies, newest first."}}}},"/api/v1/spend/anomalies/{anomalyId}/acknowledge":{post:{summary:"Acknowledge an anomaly.",responses:{"200":{description:"Acknowledgement result."}}}},"/api/v1/spend/signals":{get:{summary:"Signals anomaly detection can run on, with their gap and sample rules.",responses:{"200":{description:"Signal catalog."}}}},"/api/v1/spend/anomaly-configs":{get:{summary:"Anomaly detection configuration.",parameters:e,responses:{"200":{description:"Configs."}}},post:{summary:"Create or update the config for a signal.",responses:{"200":{description:"The config."}}}},"/api/v1/spend/anomaly-configs/{configId}":{delete:{summary:"Delete an anomaly config, returning the signal to its default.",responses:{"200":{description:"Result."}}}},"/api/v1/spend/anomaly-silences":{get:{summary:"Active anomaly silences.",parameters:e,responses:{"200":{description:"Silences."}}},post:{summary:"Silence a signal, route, or status code. A reason is required.",responses:{"200":{description:"The silence."}}}},"/api/v1/spend/anomaly-silences/{silenceId}":{delete:{summary:"Remove a silence.",responses:{"200":{description:"Result."}}}},"/api/v1/spend/enforcement":{get:{summary:"Enforcement actions in force.",parameters:[...e,{name:"active",in:"query",schema:{type:"boolean"}}],responses:{"200":{description:"Enforcement records."}}}},"/api/v1/spend/allowance":{get:{summary:"Whether an operation is allowed under current spend enforcement.",parameters:[...e,{name:"operation",in:"query",schema:{type:"string",enum:["build","deploy","function_invoke","request"]}}],responses:{"200":{description:"Allowance verdict and the budgets behind it."}}}}}}export{$e,S,lo,Ot,li,uo,hr,mc,gc,fc,di,ui,mt,en,hc,$t,tn,gt,Ke,Le,Je,yc,ft,yr,Me,Xe,pi,mi,es,ts,Qe,rn,Fp,nn,rs,oe,Bp,bc,Td,po,jp,Vp,zp,Sc,ns,mo,vc,sn,br,Hp,gi,qp,Cc,Ed,wd,go,Tc,Ec,Sr,is,vr,wc,fo,fi,Ad,ss,Ac,Rc,os,Rd,Ic,Pc,Dc,Nc,ho,Id,Pd,Gp,Dd,kc,as,Nd,kd,yo,Lt,bo,So,vo,xc,xd,_c,Co,Wp,ht,Kp,Oc,Mt,$c,Jp,Lc,_d,Xp,ee,Od,To,Qp,cs,hi,yi,Eo,$d,Ld,Yp,m,ls,wo,Ao};
|