@stacksjs/ts-cloud 0.16.77 → 0.16.78
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/bin/{chunk-kzynrdzx.js → chunk-2xtxktj3.js} +1 -1
- package/dist/bin/{chunk-n4xfb0c9.js → chunk-hkqq09p2.js} +1 -1
- package/dist/bin/{chunk-m6e6g697.js → chunk-n5sapbxq.js} +2 -2
- package/dist/bin/cli.js +4 -4
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-1x328xce.js → chunk-m95n1mbv.js} +1 -1
- package/dist/{chunk-mhdsfs3k.js → chunk-wxy6jk7d.js} +2 -2
- package/dist/deploy/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/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 +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +5 -5
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +5 -5
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- 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 +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +5 -5
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +5 -5
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- 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 +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +5 -5
- 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 +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +5 -5
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +5 -5
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +6 -6
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Pi}from"./chunk-
|
|
1
|
+
import{Pi}from"./chunk-n5sapbxq.js";import"./chunk-9ktyfegk.js";import"./chunk-ps0pzqm0.js";import"./chunk-0r8k7qth.js";import"./chunk-4vtyjj7c.js";import"./chunk-gqstb8zn.js";import"./chunk-540wkkhs.js";import"./chunk-wayhpmn7.js";import"./chunk-33shhgye.js";export{Pi as resolveServerDashboardData};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{ua,ze,I,H,A,U,$e,rr}from"./chunk-wayhpmn7.js";import{ce,Tn,re,En,h,Br,la}from"./chunk-fhqjr3ba.js";import{Be,S,ps,hr,gi,fi,rn,Sc,Ft,nn,gt,Ke,Fe,Je,vc,ht,yr,je,Xe,hi,yi,to,ro,Qe,on,vr,yt,m,uo,Rs,Is}from"./chunk-jcehsvnm.js";import{Jt,Xt,p}from"./chunk-540wkkhs.js";import{v}from"./chunk-4vtyjj7c.js";import{g}from"./chunk-gqstb8zn.js";import{W,w,R,Tt,Po,Et,fn}from"./chunk-ps0pzqm0.js";import{Ze,Er,yo,O,mn,zc,Hc,zt,Ii,Pi}from"./chunk-
|
|
1
|
+
import{ua,ze,I,H,A,U,$e,rr}from"./chunk-wayhpmn7.js";import{ce,Tn,re,En,h,Br,la}from"./chunk-fhqjr3ba.js";import{Be,S,ps,hr,gi,fi,rn,Sc,Ft,nn,gt,Ke,Fe,Je,vc,ht,yr,je,Xe,hi,yi,to,ro,Qe,on,vr,yt,m,uo,Rs,Is}from"./chunk-jcehsvnm.js";import{Jt,Xt,p}from"./chunk-540wkkhs.js";import{v}from"./chunk-4vtyjj7c.js";import{g}from"./chunk-gqstb8zn.js";import{W,w,R,Tt,Po,Et,fn}from"./chunk-ps0pzqm0.js";import{Ze,Er,yo,O,mn,zc,Hc,zt,Ii,Pi}from"./chunk-n5sapbxq.js";import{Vo}from"./chunk-0r8k7qth.js";import{fe}from"./chunk-0e7y7q0t.js";import{Ps,Ds}from"./chunk-vgcscxh1.js";import{Or,Pt,$r,Lr,Mr,Ur,Cn}from"./chunk-0zydd9s4.js";import{ae,q,Ti}from"./chunk-06hwds44.js";import{E}from"./chunk-tf5tf414.js";import{V}from"./chunk-y5gx3dq2.js";import{D}from"./chunk-6xx24qev.js";import{J,ea,ta,qo,Wt,z,ra}from"./chunk-0v5q5sh0.js";import{Js}from"./chunk-kyqe19mh.js";import{bn}from"./chunk-ma0d990n.js";import{L,x,aa}from"./chunk-gbbcp2bw.js";import{createCipheriv as Fb,createDecipheriv as jb,createHash as Bp,randomBytes as zi}from"node:crypto";import{createHmac as Lb,timingSafeEqual as Bb}from"node:crypto";var Bd="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function Wa(e){let t=0,r=0,n="";for(let i of e){r=r<<8|i,t+=8;while(t>=5)n+=Bd[r>>>t-5&31],t-=5}if(t>0)n+=Bd[r<<5-t&31];return n}function Op(e){let t=e.toUpperCase().replace(/[^A-Z2-7]/g,""),r=0,n=0,i=[];for(let o of t){let s=Bd.indexOf(o);if(s<0)throw Error("Invalid base32 secret");if(n=n<<5|s,r+=5,r>=8)i.push(n>>>r-8&255),r-=8}return Buffer.from(i)}function _p(e,t,r=6){let n=Buffer.alloc(8);n.writeBigUInt64BE(BigInt(t));let i=Lb("sha1",Op(e)).update(n).digest(),o=i[i.length-1]&15,s=(i[o]&127)<<24|(i[o+1]&255)<<16|(i[o+2]&255)<<8|i[o+3]&255;return String(s%10**r).padStart(r,"0")}function Ka(e,t,r=Date.now(),n=1){let i=t.replace(/[\s-]/g,"");if(!/^\d{6}$/.test(i))return;let o=Buffer.from(i),s=Math.floor(r/1000/30);for(let c=-n;c<=n;c++){if(s+c<0)continue;let u=Buffer.from(_p(e,s+c));if(o.length===u.length&&Bb(o,u))return s+c}return}function Fd(e){let t=e.issuer?.trim()||"ts-cloud",r=`${t}:${e.account}`;return`otpauth://totp/${encodeURIComponent(r)}?secret=${encodeURIComponent(e.secret)}&issuer=${encodeURIComponent(t)}&algorithm=SHA1&digits=6&period=30`}var Fp=1800000,vo=43200000,jp=3600000,Up=300000,zp=600000;function yn(e){return typeof e==="string"?e:void 0}function Vp(e){if(typeof e!=="string")return{};try{return JSON.parse(e)}catch{return{}}}function Ub(e){let t=e.trim();if(!/^[a-z0-9][a-z0-9._-]{1,31}$/i.test(t))throw Error("Username must be 2-32 characters: letters, numbers, dot, dash or underscore");return t}function jd(e){if(e===void 0||!e.trim())return;let t=e.trim().toLowerCase();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)||t.length>254)throw Error("A valid email address is required");return t}function zb(e){let t=e.trim().toLowerCase();if(!/^[a-z0-9][a-z0-9-]{1,47}$/.test(t))throw Error("OIDC provider slug must be 2-48 lowercase letters, numbers or dashes");return t}function Vb(e){let t=new URL(e.trim());if(t.search||t.hash||t.username||t.password)throw Error("OIDC issuer cannot contain credentials, a query, or a fragment");if(t.protocol!=="https:"&&!(t.protocol==="http:"&&["127.0.0.1","::1","localhost"].includes(t.hostname)))throw Error("OIDC issuer must use HTTPS");return t.href.replace(/\/$/,"")}function qb(e){let t=[...new Set(e.map((r)=>r.trim().toLowerCase()).filter(Boolean))];if(t.length===0)throw Error("At least one explicit OIDC email domain is required");if(t.some((r)=>!/^[a-z0-9](?:[a-z0-9.-]{0,251}[a-z0-9])?$/.test(r)||!r.includes(".")||r.includes("..")))throw Error("OIDC email domains must be explicit DNS names without wildcards");return t}function Gb(e){let t=[...new Set(["openid",...e??["email","profile"]].map((r)=>r.trim()).filter(Boolean))];if(t.some((r)=>!/^[\x21\x23-\x5B\x5D-\x7E]+$/.test(r)))throw Error("OIDC scopes contain unsupported characters");return t}function Nn(e){return Bp("sha256").update(e).digest("hex")}function ga(e){return{id:String(e.id),actorId:String(e.actor_id),username:String(e.username),email:yn(e.email),emailVerifiedAt:yn(e.email_verified_at),passwordHash:String(e.password_hash),credentialVersion:Number(e.credential_version),requiresPasswordUpgrade:Number(e.requires_password_upgrade)===1,disabledAt:yn(e.disabled_at),lastLoginAt:yn(e.last_login_at),createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Np(e,t){let r=yn(e.consumed_at),n=String(e.expires_at);return{id:String(e.id),identityId:String(e.identity_id),type:String(e.type),metadata:Vp(e.metadata),expiresAt:n,consumedAt:r,createdAt:String(e.created_at),state:r?"consumed":n<=t?"expired":"pending"}}function Ud(e,t){let r=yn(e.revoked_at),n=String(e.idle_expires_at),i=String(e.absolute_expires_at);return{id:String(e.id),identityId:String(e.identity_id),credentialVersion:Number(e.credential_version),authMethod:String(e.auth_method),userAgent:yn(e.user_agent),networkHint:yn(e.network_hint),createdAt:String(e.created_at),lastUsedAt:String(e.last_used_at),idleExpiresAt:n,absoluteExpiresAt:i,recentAuthAt:String(e.recent_auth_at),mfaAt:yn(e.mfa_at),revokedAt:r,state:r?"revoked":n<=t||i<=t?"expired":"active"}}function $p(e){let t=yn(e.verified_at),r=yn(e.disabled_at);return{id:String(e.id),identityId:String(e.identity_id),type:"totp",label:String(e.label),createdAt:String(e.created_at),verifiedAt:t,disabledAt:r,state:r?"disabled":t?"active":"pending"}}function zd(e,t){let r=yn(e.consumed_at),n=String(e.expires_at),i=Number(e.attempts);return{id:String(e.id),identityId:String(e.identity_id),purpose:String(e.purpose),attempts:i,expiresAt:n,consumedAt:r,createdAt:String(e.created_at),state:r?"consumed":i>=5?"locked":n<=t?"expired":"pending"}}function Mp(e){let t=Vp(e);return Array.isArray(t)?t.filter((r)=>typeof r==="string"):[]}function Qa(e){return{id:String(e.id),organizationId:String(e.organization_id),slug:String(e.slug),name:String(e.name),issuer:String(e.issuer),clientId:String(e.client_id),hasClientSecret:typeof e.client_secret_ciphertext==="string"&&e.client_secret_ciphertext.length>0,scopes:Mp(e.scopes),allowedDomains:Mp(e.allowed_domains),defaultRole:String(e.default_role),enabled:Number(e.enabled)===1,enforceSso:Number(e.enforce_sso)===1,createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}function Lp(e,t){let r=yn(e.consumed_at),n=String(e.expires_at);return{id:String(e.id),providerId:String(e.provider_id),redirectUri:String(e.redirect_uri),returnPath:String(e.return_path),expiresAt:n,consumedAt:r,createdAt:String(e.created_at),state:r?"consumed":n<=t?"expired":"pending"}}function Jb(e){return{id:String(e.id),providerId:String(e.provider_id),identityId:String(e.identity_id),subject:String(e.subject),email:String(e.email),linkedAt:String(e.linked_at),lastLoginAt:String(e.last_login_at)}}class Me{controlPlane;nowFn;idFn;encryptionKey;constructor(e,t={}){this.controlPlane=e;this.nowFn=t.now??(()=>new Date),this.idFn=t.id??(()=>crypto.randomUUID()),this.encryptionKey=t.encryptionKey?Bp("sha256").update(t.encryptionKey).digest():void 0}now(){return this.nowFn().toISOString()}run(e,t){this.controlPlane.database.run(e,t)}encrypt(e){if(!this.encryptionKey)throw Error("Authentication encryption key is not configured");let t=zi(12),r=Fb("aes-256-gcm",this.encryptionKey,t),n=Buffer.concat([r.update(e,"utf8"),r.final()]);return`v1.${t.toString("base64url")}.${r.getAuthTag().toString("base64url")}.${n.toString("base64url")}`}decrypt(e){if(!this.encryptionKey)throw Error("Authentication encryption key is not configured");let[t,r,n,i]=e.split(".");if(t!=="v1"||!r||!n||!i)throw Error("Encrypted authentication value is unavailable");let o=jb("aes-256-gcm",this.encryptionKey,Buffer.from(r,"base64url"));return o.setAuthTag(Buffer.from(n,"base64url")),Buffer.concat([o.update(Buffer.from(i,"base64url")),o.final()]).toString("utf8")}createIdentity(e){if(!this.controlPlane.getActor(e.actorId))throw Error("Authentication actor was not found");let t=Ub(e.username),r=jd(e.email),n=e.id??this.idFn(),i=this.now();return this.run(`INSERT INTO auth_identities (id, actor_id, username, email, email_verified_at, password_hash, requires_password_upgrade, created_at, updated_at)
|
|
2
2
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[n,e.actorId,t,r??null,e.emailVerified&&r?i:null,e.passwordHash,e.requiresPasswordUpgrade?1:0,i,i]),this.getIdentity(n)}getIdentity(e){let t=this.controlPlane.database.query("SELECT * FROM auth_identities WHERE id = ?").get(e);return t?ga(t):void 0}getIdentityByActor(e){let t=this.controlPlane.database.query("SELECT * FROM auth_identities WHERE actor_id = ?").get(e);return t?ga(t):void 0}getIdentityByUsername(e){let t=this.controlPlane.database.query("SELECT * FROM auth_identities WHERE username = ? COLLATE NOCASE").get(e.trim());return t?ga(t):void 0}getIdentityByEmail(e){let t=this.controlPlane.database.query("SELECT * FROM auth_identities WHERE email = ? COLLATE NOCASE").get(e.trim().toLowerCase());return t?ga(t):void 0}listIdentities(){return this.controlPlane.database.query("SELECT * FROM auth_identities ORDER BY username COLLATE NOCASE").all().map(ga)}updatePassword(e,t,r={}){if(!this.getIdentity(e))throw Error("Authentication identity was not found");let i=this.now();return this.controlPlane.transaction(()=>{if(this.run(`UPDATE auth_identities SET password_hash = ?, credential_version = credential_version + 1,
|
|
3
3
|
requires_password_upgrade = ?, updated_at = ? WHERE id = ?`,[t,r.requiresUpgrade?1:0,i,e]),r.revokeSessions!==!1)this.run("UPDATE auth_sessions SET revoked_at = ? WHERE identity_id = ? AND revoked_at IS NULL",[i,e])}),this.getIdentity(e)}rehashPassword(e,t){let r=this.now();this.run("UPDATE auth_identities SET password_hash = ?, requires_password_upgrade = 0, updated_at = ? WHERE id = ?",[t,r,e]);let n=this.getIdentity(e);if(!n)throw Error("Authentication identity was not found");return n}setVerifiedEmail(e,t){let r=jd(t),n=this.now();this.run("UPDATE auth_identities SET email = ?, email_verified_at = ?, updated_at = ? WHERE id = ?",[r,n,n,e]);let i=this.getIdentity(e);if(!i)throw Error("Authentication identity was not found");return i}recordLogin(e){let t=this.now();this.run("UPDATE auth_identities SET last_login_at = ?, updated_at = ? WHERE id = ?",[t,t,e]);let r=this.getIdentity(e);if(!r)throw Error("Authentication identity was not found");return r}setDisabled(e,t){let r=this.now();this.controlPlane.transaction(()=>{if(this.run("UPDATE auth_identities SET disabled_at = ?, credential_version = credential_version + 1, updated_at = ? WHERE id = ?",[t?r:null,r,e]),t)this.run("UPDATE auth_sessions SET revoked_at = ? WHERE identity_id = ? AND revoked_at IS NULL",[r,e])});let n=this.getIdentity(e);if(!n)throw Error("Authentication identity was not found");return n}createActionToken(e,t,r={}){if(!this.getIdentity(e))throw Error("Authentication identity was not found");let n=zi(32).toString("base64url"),i=this.idFn(),o=this.now(),s=new Date(this.nowFn().getTime()+Math.min(86400000,Math.max(60000,r.ttlMs??jp))).toISOString();return this.run("INSERT INTO auth_action_tokens (id, identity_id, type, token_hash, metadata, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",[i,e,t,Nn(n),JSON.stringify(r.metadata??{}),s,o]),{actionToken:this.getActionToken(i),token:n}}getActionToken(e){let t=this.controlPlane.database.query("SELECT * FROM auth_action_tokens WHERE id = ?").get(e);return t?Np(t,this.now()):void 0}consumeActionToken(e,t){return this.controlPlane.transaction(()=>{let r=this.controlPlane.database.query("SELECT * FROM auth_action_tokens WHERE token_hash = ? AND type = ?").get(Nn(e),t);if(!r)throw Error("Action token is invalid");let n=Np(r,this.now());if(n.state!=="pending")throw Error(`Action token is ${n.state}`);if(this.controlPlane.database.run("UPDATE auth_action_tokens SET consumed_at = ? WHERE id = ? AND consumed_at IS NULL AND expires_at > ?",[this.now(),n.id,this.now()]).changes!==1)throw Error("Action token is no longer available");return this.getActionToken(n.id)})}revokeActionTokens(e,t){return this.controlPlane.database.run("UPDATE auth_action_tokens SET consumed_at = ? WHERE identity_id = ? AND type = ? AND consumed_at IS NULL",[this.now(),e,t]).changes}createSession(e){let t=this.getIdentity(e.identityId);if(!t||t.disabledAt)throw Error("Authentication identity is unavailable");let r=this.idFn(),n=zi(32).toString("base64url"),i=`v2.${r}.${n}`,o=this.now(),s=Math.min(86400000,Math.max(60000,e.idleTtlMs??Fp)),c=Math.min(2592000000,Math.max(s,e.absoluteTtlMs??vo));return this.run(`INSERT INTO auth_sessions (id, identity_id, token_hash, credential_version, auth_method, user_agent, network_hint,
|
|
4
4
|
created_at, last_used_at, idle_expires_at, absolute_expires_at, recent_auth_at, mfa_at)
|
|
@@ -555,9 +555,9 @@ console.log(JSON.stringify({
|
|
|
555
555
|
`}function Ko(e,t){let r=String(t.drainSignal).replace(/^SIG/i,"").toUpperCase();if(!/^[A-Z0-9]+$/.test(r))throw Error(`Box service "${e}" has an invalid drainSignal`);return`SIG${r}`}function su(e){return Boolean(e.drainSignal)&&(e.restart??"always")==="always"}function jo(e){let t=e.user?.name;if(!t)return["SVC_HOME=/root",'svc() { systemctl "$@"; }'];return[`SVC_UID=$(id -u ${t})`,`SVC_HOME=$(getent passwd ${t} | cut -d: -f6)`,`svc() { sudo -u ${t} XDG_RUNTIME_DIR="/run/user/$SVC_UID" systemctl --user "$@"; }`,'for _ in $(seq 1 30); do [ -S "/run/user/$SVC_UID/bus" ] && break; sleep 1; done']}function iu(e){if(e.user?.name)bt("user",e.user.name);let t=Object.entries(e.services??{}).filter(([,n])=>n.drainSignal),r=["set -euo pipefail",`say() { echo "${$t} $*"; }`,...jo(e)];for(let[n,s]of t){bt("service",n);let i=Ko(n,s).slice(3),o=s.drainTimeoutSec??3600;r.push(`if svc is-active --quiet ${n}.service; then`,` PID=$(svc show -p MainPID --value ${n}.service)`,` svc kill --kill-who=main -s SIG${i} ${n}.service`,` say "draining ${n} (SIG${i})"`," WAITED=0",' while [ "$PID" != 0 ] && kill -0 "$PID" 2>/dev/null; do',` if [ "$WAITED" -ge ${o} ]; then say "${n} still busy after ${o}s; not powering off"; exit 4; fi`," sleep 5; WAITED=$((WAITED + 5))"," done",` svc stop ${n}.service`,` say "drained ${n} after \${WAITED}s"`,"fi")}return r.push('say "drained"'),`${r.join(`
|
|
556
556
|
`)}
|
|
557
557
|
`}function Go(e,t){if(!e.resize||t.alreadyComplete)return"none";if(t.capacityAvailable||e.resize.attemptUnavailable)return"resize";if(e.resize.whenUnavailable==="keep-current")return"unavailable";throw Error(`${t.targetType.name} is out of stock in ${t.location}; set resize.attemptUnavailable to ask anyway, or whenUnavailable: 'keep-current' to wait`)}function Kn(e){return e.split(`
|
|
558
|
-
`).filter((t)=>t.startsWith($t)).map((t)=>t.slice($t.length).trim())}async function Co(e){let{box:t}=e;if(e.dryRun)return ou(e);let r=await new gr(e.client).ensureBox({name:t.name,size:t.size,image:t.image,location:t.location,ports:t.ports,sshPublicKey:e.sshPublicKey,labels:{"ts-cloud/role":"box","ts-cloud/managed-by":"ts-cloud",...t.labels}});await at(r.publicIp,{identityFile:e.identityFile});let n=new ft({user:"root",identityFile:e.identityFile,hostKey:{policy:"pin",knownHostsFile:e.knownHostsFile}}),s=[],i=await n.ensureHostKey(r.publicIp);if(i.pinnedNow)s.push(`pinned host key ${i.fingerprint}`);if(t.resize&&!r.created){let a=await rt(e.client,Number(r.id),t.size,t.resize.upgradeDisk!==!1),c=Go(t,a);if(c==="unavailable")s.push(`${a.targetType.name} is out of stock in ${a.location}; keeping ${a.currentType.name}`);if(c==="resize"){let l=await Tr({client:e.client,serverId:Number(r.id),targetType:a.targetType.name,upgradeDisk:a.upgradeDisk,attemptUnavailable:t.resize.attemptUnavailable,hooks:{preflight:async()=>{s.push(...Kn(await n.exec(r.publicIp,iu(t))))},onPhase:(u)=>e.onPhase?.(u)}});if(l.status==="completed")s.push(`resized ${a.currentType.name} to ${a.targetType.name}`);else if(l.status==="recovered")s.push(`could not resize to ${a.targetType.name} (${l.error}); back on ${a.currentType.name}`);else if(l.status==="waiting-capacity")s.push(`${a.targetType.name} is out of stock in ${a.location}; keeping ${a.currentType.name}`);await at(r.publicIp,{identityFile:e.identityFile})}}let o=await n.exec(r.publicIp,Bo(t));return{box:r,report:[...s,...Kn(o)]}}async function ou(e){let{box:t}=e,r=(await e.client.listServers()).find((i)=>i.name===t.name);if(!r)return{box:{provider:"hetzner",id:"",name:t.name,publicIp:"",created:!1},report:[`would create ${t.name} (${t.size})`,"would converge"]};let n={provider:"hetzner",id:String(r.id),name:r.name,publicIp:r.public_net?.ipv4?.ip??"",created:!1},s=[];if(t.resize){let i=await rt(e.client,r.id,t.size,t.resize.upgradeDisk!==!1),o=Go(t,i);if(o==="resize")s.push(`would resize ${i.currentType.name} to ${i.targetType.name}${i.capacityAvailable?"":" (out of stock; asking placement anyway)"}, draining ${Object.entries(t.services??{}).filter(([,a])=>a.drainSignal).map(([a])=>a).join(", ")||"nothing"} first`);else if(o==="unavailable")s.push(`${i.targetType.name} is out of stock in ${i.location}; would keep ${i.currentType.name}`)}else if(r.server_type.name!==t.size)s.push(`runs ${r.server_type.name}, declared ${t.size}; set resize to change it`);return s.push("would converge"),{box:n,report:s}}import{copyFileSync as Iu}from"node:fs";import{tmpdir as Au}from"node:os";import{join as Lu}from"node:path";var au=`${oe}/project`;function Wo(e,t){let r=t.ownerSlug.trim(),n=t.selfSlug?.trim(),s={total:e.length,owner:[],self:[],others:new Map,unmanaged:[]};for(let i of e){let o=i.labels?.[au]?.trim();if(!o){s.unmanaged.push(i.name);continue}if(o===r){s.owner.push(i.name);continue}if(n&&o===n){s.self.push(i.name);continue}let a=s.others.get(o);if(a)a.push(i.name);else s.others.set(o,[i.name])}return s}function jn(e){let t=e.unmanaged.length;for(let r of e.others.values())t+=r.length;return t}function Vo(e,t){let r=jn(e),n=[];if(n.push(`Attaching to '${t.ownerSlug}' shares one provider project, so this deploy's credential can write to all ${e.total} server(s) it can see.`),r===0)return n.push("Nothing outside the two projects being joined is reachable with it."),n;n.push(`${r} of them belong to neither project:`);for(let s of[...e.others.keys()].sort())n.push(` ${s}: ${[...e.others.get(s)].sort().join(", ")}`);if(e.unmanaged.length>0)n.push(` not managed by ts-cloud: ${[...e.unmanaged].sort().join(", ")}`);return n.push("A compromised CI run or a mistargeted teardown in this project now reaches those. Keep the app in its own provider project instead if that is not acceptable, which rules out attaching."),n}var cu=new Set(["laravel","php","statamic","wordpress"]);function mn(e){if(e.framework)return e.framework;if(e.type&&cu.has(e.type))return"laravel";return"stacks"}var qo=`eval "$(cd ${R} && pantry env 2>/dev/null)"`,lu="/usr/local/bin/bun",Sr={PATH:"/usr/local/bin:/usr/bin:/bin",BUN_INSTALL:"/root/.bun",APP_ENV:"production",NODE_ENV:"production"};function Gn(e){if(e.backgroundBun===void 0)return lu;return el(e.current,e.backgroundBun)}function uu(e){let t=e.queue??"default",r=[e.sleep,e.tries,e.timeout,e.processes,e.stopWaitSecs];if(typeof t!=="string"||!/^[a-zA-Z0-9_.:,{}/@+-]+$/.test(t||"default")||r.some((n)=>n!==void 0&&(typeof n!=="number"||!Number.isFinite(n))))throw Error("Stacks background queue options require safe queue names and finite numeric values")}var pu="node_modules/@stacksjs/ts-cloud/dist/bin/stacks-scheduler.js",du="node_modules/@stacksjs/ts-cloud/dist/bin/stacks-queue-worker.js",Xo={id:"stacks",wrapExec:(e)=>e,execEnv:Sr,executionEnvironment:(e)=>{let t=Gn(e);return e.backgroundBun===void 0?Sr:{...Sr,PATH:`${t.slice(0,t.lastIndexOf("/"))}:${Sr.PATH}`,TS_CLOUD_BACKGROUND_BUN:e.backgroundBun}},schedulerMode:"daemon",schedulerCommand:(e)=>`${Gn(e)} ${pu}`,queueWorkerCommand:(e,t)=>{if(t.backgroundBun!==void 0)uu(e);let{current:r}=t,n=[`--queue=${e.queue||"default"}`,`--sleep=${e.sleep??3}`,`--tries=${e.tries??3}`,`--timeout=${e.timeout??60}`];return`${Gn(t)} ${r}/${du} ${n.join(" ")}`}},mu={id:"laravel",wrapExec:(e)=>`/bin/sh -lc '${qo}; exec ${e}'`,schedulerMode:"cron",schedulerCommand:({current:e})=>`cd ${e} && ${qo} && php artisan schedule:run`,queueWorkerCommand:(e,{current:t})=>{let r=`${t}/artisan`;if(e.horizon)return`php ${r} horizon`;let n=[e.connection||"default",`--queue=${e.queue||"default"}`,`--sleep=${e.sleep??3}`,`--tries=${e.tries??3}`,`--timeout=${e.timeout??60}`,`--memory=${e.memory??128}`];if(e.maxJobs)n.push(`--max-jobs=${e.maxJobs}`);if(e.maxTime)n.push(`--max-time=${e.maxTime}`);return`php ${r} queue:work ${n.join(" ")}`}},fu={stacks:Xo,laravel:mu};function Yo(e){return fu[e]??Xo}function Zo(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function gu(e){return`'${e.split("'").join("'\\''")}'`}function Qo(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"unnamed"}function ea(e,t){return`for unit in $(ls /etc/systemd/system/ 2>/dev/null | grep -E '^${Zo(e)}-${Zo(t)}-((queue|daemon)-.*|scheduler)\\.service$' || true); do`}function qn(e){return[ea(e.slug,e.siteName),' systemctl stop "$unit"',"done"]}function hu(e,t,r){return`${e}-${t}-queue-${r}`}function yu(e,t,r,n){return`${e}-${t}-daemon-${r.name?Qo(r.name):Qo(r.command).slice(0,32)||String(n)}`}function Wn(e){let t=["[Unit]",`Description=${e.description}`,"After=network.target","","[Service]","Type=simple",`WorkingDirectory=${e.workingDir}`,...Object.entries(e.environment??{}).map(([r,n])=>`Environment="${r}=${n}"`),`ExecStart=${e.execStart}`,`Restart=${e.restart||"always"}`,"RestartSec=5","MemoryAccounting=true",`MemoryHigh=${e.memoryHigh??"2G"}`,...e.memoryMax?[`MemoryMax=${e.memoryMax}`]:[]];if(e.isolatedUser){if(!e.isolationRoot||!e.isolationSlug)throw Error("Runtime isolation requires its project directory");t.push(...xt(e.isolatedUser,e.isolationRoot,e.isolationSlug))}else if(e.user)t.push(`User=${e.user}`);if(typeof e.stopWaitSecs==="number")t.push(`TimeoutStopSec=${e.stopWaitSecs}`);return t.push("","[Install]","WantedBy=multi-user.target"),`${t.join(`
|
|
558
|
+
`).filter((t)=>t.startsWith($t)).map((t)=>t.slice($t.length).trim())}async function Co(e){let{box:t}=e;if(e.dryRun)return ou(e);let r=await new gr(e.client).ensureBox({name:t.name,size:t.size,image:t.image,location:t.location,ports:t.ports,sshPublicKey:e.sshPublicKey,labels:{"ts-cloud/role":"box","ts-cloud/managed-by":"ts-cloud",...t.labels}});await at(r.publicIp,{identityFile:e.identityFile});let n=new ft({user:"root",identityFile:e.identityFile,hostKey:{policy:"pin",knownHostsFile:e.knownHostsFile}}),s=[],i=await n.ensureHostKey(r.publicIp);if(i.pinnedNow)s.push(`pinned host key ${i.fingerprint}`);if(t.resize&&!r.created){let a=await rt(e.client,Number(r.id),t.size,t.resize.upgradeDisk!==!1),c=Go(t,a);if(c==="unavailable")s.push(`${a.targetType.name} is out of stock in ${a.location}; keeping ${a.currentType.name}`);if(c==="resize"){let l=await Tr({client:e.client,serverId:Number(r.id),targetType:a.targetType.name,upgradeDisk:a.upgradeDisk,attemptUnavailable:t.resize.attemptUnavailable,hooks:{preflight:async()=>{s.push(...Kn(await n.exec(r.publicIp,iu(t))))},onPhase:(u)=>e.onPhase?.(u)}});if(l.status==="completed")s.push(`resized ${a.currentType.name} to ${a.targetType.name}`);else if(l.status==="recovered")s.push(`could not resize to ${a.targetType.name} (${l.error}); back on ${a.currentType.name}`);else if(l.status==="waiting-capacity")s.push(`${a.targetType.name} is out of stock in ${a.location}; keeping ${a.currentType.name}`);await at(r.publicIp,{identityFile:e.identityFile})}}let o=await n.exec(r.publicIp,Bo(t));return{box:r,report:[...s,...Kn(o)]}}async function ou(e){let{box:t}=e,r=(await e.client.listServers()).find((i)=>i.name===t.name);if(!r)return{box:{provider:"hetzner",id:"",name:t.name,publicIp:"",created:!1},report:[`would create ${t.name} (${t.size})`,"would converge"]};let n={provider:"hetzner",id:String(r.id),name:r.name,publicIp:r.public_net?.ipv4?.ip??"",created:!1},s=[];if(t.resize){let i=await rt(e.client,r.id,t.size,t.resize.upgradeDisk!==!1),o=Go(t,i);if(o==="resize")s.push(`would resize ${i.currentType.name} to ${i.targetType.name}${i.capacityAvailable?"":" (out of stock; asking placement anyway)"}, draining ${Object.entries(t.services??{}).filter(([,a])=>a.drainSignal).map(([a])=>a).join(", ")||"nothing"} first`);else if(o==="unavailable")s.push(`${i.targetType.name} is out of stock in ${i.location}; would keep ${i.currentType.name}`)}else if(r.server_type.name!==t.size)s.push(`runs ${r.server_type.name}, declared ${t.size}; set resize to change it`);return s.push("would converge"),{box:n,report:s}}import{copyFileSync as Iu}from"node:fs";import{tmpdir as Au}from"node:os";import{join as Lu}from"node:path";var au=`${oe}/project`;function Wo(e,t){let r=t.ownerSlug.trim(),n=t.selfSlug?.trim(),s={total:e.length,owner:[],self:[],others:new Map,unmanaged:[]};for(let i of e){let o=i.labels?.[au]?.trim();if(!o){s.unmanaged.push(i.name);continue}if(o===r){s.owner.push(i.name);continue}if(n&&o===n){s.self.push(i.name);continue}let a=s.others.get(o);if(a)a.push(i.name);else s.others.set(o,[i.name])}return s}function jn(e){let t=e.unmanaged.length;for(let r of e.others.values())t+=r.length;return t}function Vo(e,t){let r=jn(e),n=[];if(n.push(`Attaching to '${t.ownerSlug}' shares one provider project, so this deploy's credential can write to all ${e.total} server(s) it can see.`),r===0)return n.push("Nothing outside the two projects being joined is reachable with it."),n;n.push(`${r} of them belong to neither project:`);for(let s of[...e.others.keys()].sort())n.push(` ${s}: ${[...e.others.get(s)].sort().join(", ")}`);if(e.unmanaged.length>0)n.push(` not managed by ts-cloud: ${[...e.unmanaged].sort().join(", ")}`);return n.push("A compromised CI run or a mistargeted teardown in this project now reaches those. Keep the app in its own provider project instead if that is not acceptable, which rules out attaching."),n}var cu=new Set(["laravel","php","statamic","wordpress"]);function mn(e){if(e.framework)return e.framework;if(e.type&&cu.has(e.type))return"laravel";return"stacks"}var qo=`eval "$(cd ${R} && pantry env 2>/dev/null)"`,lu="/usr/local/bin/bun",Sr={PATH:"/usr/local/bin:/usr/bin:/bin",BUN_INSTALL:"/root/.bun",APP_ENV:"production",NODE_ENV:"production"};function Gn(e){if(e.backgroundBun===void 0)return lu;return el(e.current,e.backgroundBun)}function uu(e){let t=e.queue??"default",r=[e.sleep,e.tries,e.timeout,e.processes,e.stopWaitSecs];if(typeof t!=="string"||!/^[a-zA-Z0-9_.:,{}/@+-]+$/.test(t||"default")||r.some((n)=>n!==void 0&&(typeof n!=="number"||!Number.isFinite(n))))throw Error("Stacks background queue options require safe queue names and finite numeric values")}var pu="node_modules/@stacksjs/ts-cloud/dist/bin/stacks-scheduler.js",du="node_modules/@stacksjs/ts-cloud/dist/bin/stacks-queue-worker.js",Xo={id:"stacks",wrapExec:(e)=>e,execEnv:Sr,executionEnvironment:(e)=>{let t=Gn(e);return e.backgroundBun===void 0?Sr:{...Sr,PATH:`${t.slice(0,t.lastIndexOf("/"))}:${Sr.PATH}`,TS_CLOUD_BACKGROUND_BUN:e.backgroundBun}},schedulerMode:"daemon",schedulerCommand:(e)=>`${Gn(e)} ${pu}`,queueWorkerCommand:(e,t)=>{if(t.backgroundBun!==void 0)uu(e);let{current:r}=t,n=[`--queue=${e.queue||"default"}`,`--sleep=${e.sleep??3}`,`--tries=${e.tries??3}`,`--timeout=${e.timeout??60}`];return`${Gn(t)} ${r}/${du} ${n.join(" ")}`}},mu={id:"laravel",wrapExec:(e)=>`/bin/sh -lc '${qo}; exec ${e}'`,schedulerMode:"cron",schedulerCommand:({current:e})=>`cd ${e} && ${qo} && php artisan schedule:run`,queueWorkerCommand:(e,{current:t})=>{let r=`${t}/artisan`;if(e.horizon)return`php ${r} horizon`;let n=[e.connection||"default",`--queue=${e.queue||"default"}`,`--sleep=${e.sleep??3}`,`--tries=${e.tries??3}`,`--timeout=${e.timeout??60}`,`--memory=${e.memory??128}`];if(e.maxJobs)n.push(`--max-jobs=${e.maxJobs}`);if(e.maxTime)n.push(`--max-time=${e.maxTime}`);return`php ${r} queue:work ${n.join(" ")}`}},fu={stacks:Xo,laravel:mu};function Yo(e){return fu[e]??Xo}function Zo(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function gu(e){return`'${e.split("'").join("'\\''")}'`}function Qo(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"unnamed"}function ea(e,t){return`for unit in $(ls /etc/systemd/system/ 2>/dev/null | grep -E '^${Zo(e)}-${Zo(t)}-((queue|daemon)-.*|scheduler)\\.service$' || true); do`}function qn(e){return[ea(e.slug,e.siteName),' systemctl stop "$unit"',"done"]}function hu(e,t,r){return`${e}-${t}-queue-${r}`}function yu(e,t,r,n){return`${e}-${t}-daemon-${r.name?Qo(r.name):Qo(r.command).slice(0,32)||String(n)}`}function Wn(e){let t=["[Unit]",`Description=${e.description}`,"After=network.target","","[Service]","Type=simple",`WorkingDirectory=${e.workingDir}`,...Object.entries(e.environment??{}).map(([r,n])=>`Environment="${r}=${n}"`),...e.environmentFile?[`EnvironmentFile=-${e.environmentFile}`]:[],`ExecStart=${e.execStart}`,`Restart=${e.restart||"always"}`,"RestartSec=5","MemoryAccounting=true",`MemoryHigh=${e.memoryHigh??"2G"}`,...e.memoryMax?[`MemoryMax=${e.memoryMax}`]:[]];if(e.isolatedUser){if(!e.isolationRoot||!e.isolationSlug)throw Error("Runtime isolation requires its project directory");t.push(...xt(e.isolatedUser,e.isolationRoot,e.isolationSlug))}else if(e.user)t.push(`User=${e.user}`);if(typeof e.stopWaitSecs==="number")t.push(`TimeoutStopSec=${e.stopWaitSecs}`);return t.push("","[Install]","WantedBy=multi-user.target"),`${t.join(`
|
|
559
559
|
`)}
|
|
560
|
-
`}function Vn(e,t){return[`cat > /etc/systemd/system/${e}.service <<'TS_CLOUD_UNIT_EOF'`,t.replace(/\n$/,""),"TS_CLOUD_UNIT_EOF"]}function Su(e,t){return`/etc/cron.d/${e}-${t}-scheduler`}function Xn(e){let t=e.site.isolation&&!["laravel","php","statamic","wordpress"].includes(e.site.type||"")?st(e.slug):void 0,{slug:r,siteName:n,site:s}=e,i=e.appBase??`/var/www/${n}`,o=`${i}/current`,a=Yo(mn(s)),c=a.id==="stacks"&&s.backgroundBun!==void 0;if(c&&(!e.releaseId||!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(e.releaseId)))throw Error("Stacks backgroundBun requires a safe physical releaseId");let l=c?`${i}/releases/${e.releaseId}`:o,u={current:l,backgroundBun:s.backgroundBun},d=a.executionEnvironment?.(u)??a.execEnv,m=[],h=[];(s.queues||[]).forEach((E,M)=>{let H=a.wrapExec(a.queueWorkerCommand(E,u)),F=Math.max(1,E.processes??1);for(let X=0;X<F;X++){let V=hu(r,n,h.length);h.push(V),m.push(...Vn(V,Wn({description:`${n} queue worker ${M}.${X} (managed by ts-cloud)`,workingDir:l,execStart:H,environment:d,isolatedUser:t,isolationRoot:i,isolationSlug:r,stopWaitSecs:E.stopWaitSecs??90})))}}),(s.daemons||[]).forEach((E,M)=>{if(t&&E.user&&E.user!==t)throw Error("An isolated runtime daemon cannot change its project identity");let H=Math.max(1,E.processes??1),F=E.directory||o,X=E.command.trim().replace(/^\.\//,()=>`${F.replace(/\/+$/,"")}/`);for(let V=0;V<H;V++){let Y=`${yu(r,n,E,M)}-${V}`;h.push(Y),m.push(...Vn(Y,Wn({description:`${n} daemon ${E.name||E.command} (managed by ts-cloud)`,workingDir:F,execStart:a.wrapExec(X),environment:a.execEnv,restart:E.restart,user:E.user,isolatedUser:t,isolationRoot:i,isolationSlug:r})))}});let x=s.scheduler,B=x===!0||typeof x==="object"&&x!==null,L=`${r}-${n}-scheduler`;if(B&&a.schedulerMode==="daemon"){h.push(L);let E=typeof x==="object"&&x!==null?x:{};m.push(...Vn(L,Wn({description:`${n} scheduler (managed by ts-cloud)`,workingDir:l,execStart:a.wrapExec(a.schedulerCommand(u)),environment:d,isolatedUser:t,isolationRoot:i,isolationSlug:r,memoryHigh:E.memoryHigh,memoryMax:E.memoryMax})),...tr(`${L}.service`,{auto:!1,high:Boolean(E.memoryHigh),max:Boolean(E.memoryMax)}))}let N=h.map((E)=>`${E}.service`).join(" ");m.push("systemctl daemon-reload",`TS_CLOUD_DESIRED="${N}"`,ea(r,n),' case " $TS_CLOUD_DESIRED " in',' *" $unit "*) ;;',' *) systemctl stop "$unit"; systemctl disable "$unit"; rm -f "/etc/systemd/system/$unit" ;;'," esac","done","systemctl daemon-reload");for(let E of h)m.push(`systemctl enable ${E}.service`,`systemctl restart ${E}.service`);let D=Su(r,n);if(B&&a.schedulerMode==="cron"){let E=typeof x==="object"&&x!==null?x:void 0,M=`${a.schedulerCommand(u)} >> /dev/null 2>&1`;if(E?.heartbeatUrl){let F=E.heartbeatMethod||"GET",X=F==="GET"?"":`-X ${F} `;M+=` && curl -fsS -m 10 ${X}${gu(E.heartbeatUrl)} >/dev/null 2>&1`}let H=`* * * * * root ${M}
|
|
560
|
+
`}function Vn(e,t){return[`cat > /etc/systemd/system/${e}.service <<'TS_CLOUD_UNIT_EOF'`,t.replace(/\n$/,""),"TS_CLOUD_UNIT_EOF"]}function Su(e,t){return`/etc/cron.d/${e}-${t}-scheduler`}function Xn(e){let t=e.site.isolation&&!["laravel","php","statamic","wordpress"].includes(e.site.type||"")?st(e.slug):void 0,{slug:r,siteName:n,site:s}=e,i=e.appBase??`/var/www/${n}`,o=`${i}/current`,a=Yo(mn(s)),c=a.id==="stacks"&&s.backgroundBun!==void 0;if(c&&(!e.releaseId||!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(e.releaseId)))throw Error("Stacks backgroundBun requires a safe physical releaseId");let l=c?`${i}/releases/${e.releaseId}`:o,u={current:l,backgroundBun:s.backgroundBun},d=a.executionEnvironment?.(u)??a.execEnv,m=[],h=[];(s.queues||[]).forEach((E,M)=>{let H=a.wrapExec(a.queueWorkerCommand(E,u)),F=Math.max(1,E.processes??1);for(let X=0;X<F;X++){let V=hu(r,n,h.length);h.push(V),m.push(...Vn(V,Wn({description:`${n} queue worker ${M}.${X} (managed by ts-cloud)`,workingDir:l,execStart:H,environment:d,isolatedUser:t,isolationRoot:i,isolationSlug:r,stopWaitSecs:E.stopWaitSecs??90})))}}),(s.daemons||[]).forEach((E,M)=>{if(t&&E.user&&E.user!==t)throw Error("An isolated runtime daemon cannot change its project identity");let H=Math.max(1,E.processes??1),F=E.directory||o,X=E.command.trim().replace(/^\.\//,()=>`${F.replace(/\/+$/,"")}/`);for(let V=0;V<H;V++){let Y=`${yu(r,n,E,M)}-${V}`;h.push(Y),m.push(...Vn(Y,Wn({description:`${n} daemon ${E.name||E.command} (managed by ts-cloud)`,workingDir:F,execStart:a.wrapExec(X),environment:a.execEnv,environmentFile:`${o}/.env`,restart:E.restart,user:E.user,isolatedUser:t,isolationRoot:i,isolationSlug:r})))}});let x=s.scheduler,B=x===!0||typeof x==="object"&&x!==null,L=`${r}-${n}-scheduler`;if(B&&a.schedulerMode==="daemon"){h.push(L);let E=typeof x==="object"&&x!==null?x:{};m.push(...Vn(L,Wn({description:`${n} scheduler (managed by ts-cloud)`,workingDir:l,execStart:a.wrapExec(a.schedulerCommand(u)),environment:d,isolatedUser:t,isolationRoot:i,isolationSlug:r,memoryHigh:E.memoryHigh,memoryMax:E.memoryMax})),...tr(`${L}.service`,{auto:!1,high:Boolean(E.memoryHigh),max:Boolean(E.memoryMax)}))}let N=h.map((E)=>`${E}.service`).join(" ");m.push("systemctl daemon-reload",`TS_CLOUD_DESIRED="${N}"`,ea(r,n),' case " $TS_CLOUD_DESIRED " in',' *" $unit "*) ;;',' *) systemctl stop "$unit"; systemctl disable "$unit"; rm -f "/etc/systemd/system/$unit" ;;'," esac","done","systemctl daemon-reload");for(let E of h)m.push(`systemctl enable ${E}.service`,`systemctl restart ${E}.service`);let D=Su(r,n);if(B&&a.schedulerMode==="cron"){let E=typeof x==="object"&&x!==null?x:void 0,M=`${a.schedulerCommand(u)} >> /dev/null 2>&1`;if(E?.heartbeatUrl){let F=E.heartbeatMethod||"GET",X=F==="GET"?"":`-X ${F} `;M+=` && curl -fsS -m 10 ${X}${gu(E.heartbeatUrl)} >/dev/null 2>&1`}let H=`* * * * * root ${M}
|
|
561
561
|
`.replace(/%/g,"\\%");m.push(`cat > ${D} <<'TS_CLOUD_CRON_EOF'`,H.replace(/\n$/,""),"TS_CLOUD_CRON_EOF",`chmod 644 ${D}`)}else m.push(`rm -f ${D}`);return m}function ta(e){return!!(e.queues?.length||e.daemons?.length||e.scheduler)}function Yn(e){if(e.ssl?.provider)return e.ssl.provider;return e.domain?"letsencrypt":"none"}var ra={cloudflare:{pkg:"python3-certbot-dns-cloudflare",plugin:"dns-cloudflare"},route53:{pkg:"python3-certbot-dns-route53",plugin:"dns-route53"},digitalocean:{pkg:"python3-certbot-dns-digitalocean",plugin:"dns-digitalocean"},google:{pkg:"python3-certbot-dns-google",plugin:"dns-google"}};function na(e){return`/etc/letsencrypt/ts-cloud-${e}.ini`}function vu(e){let t=e?ra[e.provider]:void 0,r=["certbot","python3-certbot-nginx",...t?[t.pkg]:[]].join(" ");return["export DEBIAN_FRONTEND=noninteractive",t?`apt-get update -y && apt-get install -y ${r}`:`command -v certbot >/dev/null 2>&1 || { apt-get update -y && apt-get install -y ${r}; }`,"mkdir -p /etc/letsencrypt/renewal-hooks/deploy","cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'TS_CLOUD_HOOK_EOF'","#!/bin/sh","systemctl reload ts-cloud-nginx 2>/dev/null || systemctl reload nginx 2>/dev/null || true","TS_CLOUD_HOOK_EOF","chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh","systemctl enable certbot.timer 2>/dev/null || true","systemctl start certbot.timer 2>/dev/null || true"]}function bu(e){if(!e.credentials||Object.keys(e.credentials).length===0)return[];let t=na(e.provider),r=Object.entries(e.credentials).map(([n,s])=>`${n} = ${s}`).join(`
|
|
562
562
|
`);return[`cat > ${t} <<'TS_CLOUD_DNSCREDS_EOF'`,r,"TS_CLOUD_DNSCREDS_EOF",`chmod 600 ${t}`]}function wu(e){let t=e.dns,r=e.wildcard?[`*.${e.domain}`,e.domain]:[e.domain,...e.aliases||[]].filter(Boolean),n=["certbot","--non-interactive","--agree-tos","--keep-until-expiring"];if(t){let s=ra[t.provider].plugin;if(n.push(`--${s}`),t.provider!=="route53"&&t.credentials)n.push(`--${s}-credentials ${na(t.provider)}`);if(typeof t.propagationSeconds==="number"&&t.provider!=="route53")n.push(`--${s}-propagation-seconds ${t.propagationSeconds}`);n.push("certonly")}else n.push("--nginx",`--nginx-ctl ${xe}`,e.redirect===!1?"--no-redirect":"--redirect");if(e.email)n.push(`-m ${e.email}`);else n.push("--register-unsafely-without-email");for(let s of r)n.push(`-d ${s}`);return[n.join(" ")]}function Jn(e){if(Yn(e)!=="letsencrypt"||!e.domain)return[];let t=e.ssl,r=t?.dns,n=t?.wildcard===!0;if(n&&!r)return[];return[...vu(r),...r?bu(r):[],...wu({domain:e.domain,aliases:e.aliases,email:t?.email,wildcard:n,dns:r})]}function sa(e){let{repository:t,releaseDir:r,commit:n}=e,s=t.branch||"main",i=t.url,o=[`rm -rf ${r}`,`mkdir -p ${r}`];if(t.strategy==="tag")if(t.tag)o.push(`git clone -q --depth 1 --branch ${be(t.tag)} ${be(i)} ${r}`),o.push(`printf '%s' ${be(t.tag)} > ${r}/.ts-cloud-tag`);else{let a=t.tagPattern||"v*";o.push(`TS_CLOUD_TAG="$(git ls-remote --tags --refs --sort=-v:refname ${be(i)} ${be(`refs/tags/${a}`)} | head -n1 | sed 's#.*refs/tags/##')"`,`test -n "$TS_CLOUD_TAG" || { echo "no tags matching" ${be(a)} "found in" ${be(i)} >&2; exit 1; }`,`git clone -q --depth 1 --branch "$TS_CLOUD_TAG" ${be(i)} ${r}`,`printf '%s' "$TS_CLOUD_TAG" > ${r}/.ts-cloud-tag`)}else if(n)o.push(`git -C ${r} init -q`,`git -C ${r} remote add origin ${be(i)}`,`git -C ${r} fetch -q --depth 1 origin ${be(n)}`,`git -C ${r} checkout -q FETCH_HEAD`);else o.push(`git clone -q --depth 1 --branch ${be(s)} ${be(i)} ${r}`);return o.push(`git -C ${r} rev-parse HEAD > ${r}/.ts-cloud-sha`),o}function be(e){return`'${e.split("'").join("'\\''")}'`}var vr="$CREATE_RELEASE",br="$ACTIVATE_RELEASE",aa="$RESTART_QUEUES",ia="composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev",$u=["php artisan migrate --force","php artisan config:cache","php artisan route:cache","php artisan view:cache","php artisan event:cache","php artisan storage:link"];function _u(e){switch(e){case"laravel":case"statamic":return[vr,ia,...$u,br,aa];case"php":case"wordpress":return[vr,`${ia} || true`,br];case"static":case"spa":return[vr,br]}}function Tu(e,t){return e.replace(/^php\s+/,`${t} `).replace(/(\s)php\s+artisan\s+/g,`$1${t} artisan `)}function Cu(e,t){let r=Jt(t);return[`cat > ${e} <<'TS_CLOUD_ENV_EOF'`,r,"TS_CLOUD_ENV_EOF",`chmod 600 ${e}`]}function oa(e,t,r){return[`cat > ${e} <<'${r}'`,t.replace(/\n$/,""),r,`chmod 600 ${e}`]}function Pu(e,t){if(!t)return[];let r=[];if(t.composerAuth){let n=typeof t.composerAuth==="string"?t.composerAuth:JSON.stringify(t.composerAuth,null,2);r.push(...oa(`${e}/auth.json`,n,"TS_CLOUD_AUTHJSON_EOF"))}if(t.npmrc)r.push(...oa(`${e}/.npmrc`,t.npmrc,"TS_CLOUD_NPMRC_EOF"));return r}function ca(e){let t=e.healthCheck?.path;if(!t||!e.domain)return[];let n=`http://127.0.0.1${t.startsWith("/")?t:`/${t}`}`;return[`echo "[ts-cloud] health check ${n} (Host: ${e.domain})"`,"TS_CLOUD_HC_OK=0",`for i in $(seq 1 10); do TS_CLOUD_HC=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${e.domain}" -m 10 "${n}" 2>/dev/null || echo 000); case "$TS_CLOUD_HC" in 2*|3*) TS_CLOUD_HC_OK=1; break ;; esac; sleep 3; done`,'[ "$TS_CLOUD_HC_OK" = 1 ] && echo "health check passed ($TS_CLOUD_HC)" || { echo "health check FAILED (last=$TS_CLOUD_HC)" >&2; exit 1; }']}function la(e){let{siteName:t,site:r,releaseId:n,commit:s}=e;if(!r.repository?.url)throw Error(`Site '${t}' is a PHP/git site but has no repository.url to clone`);let i=e.appBase??`/var/www/${t}`,o="php",a=Ht(i,n),c=r.sharedPaths??No,l=[...c,...Zt(r.env,c)],u=r.keepReleases??_i,d=r.deployScript?.length?r.deployScript:_u(r.type??"laravel"),m=["set -euo pipefail",'export HOME="${HOME:-/root}"','export COMPOSER_HOME="${COMPOSER_HOME:-/root/.composer}"',"export COMPOSER_ALLOW_SUPERUSER=1",Ve()];if(m.push(...Oo(i,{releaseId:n,commit:s,branch:r.repository.branch,keepLogs:u})),m.push(...$i(a,l)),r.env&&Object.keys(r.env).length>0)m.push(...Cu(`${a.shared}/.env`,r.env));for(let h of d){let f=h.trim();if(f===vr)m.push(...sa({repository:r.repository,releaseDir:a.release,commit:s})),m.push(..._o(a,l)),m.push(`cd ${a.release}`),m.push(...Pu(a.release,r.credentials)),m.push(`chown -R www-data:www-data ${a.shared}/storage 2>/dev/null || true`,`[ -d ${a.release}/bootstrap/cache ] && chown -R www-data:www-data ${a.release}/bootstrap/cache 2>/dev/null || true`,`chmod -R ug+rwX ${a.shared}/storage 2>/dev/null || true`);else if(f===br)m.push(...hn(a)),m.push(...yn(a,u)),m.push(`(cd ${R} && pantry restart php-fpm) 2>/dev/null || true`);else if(f===aa)m.push(`${o} artisan queue:restart || true`);else m.push(Tu(h,o))}return m}var $r={mysql:{port:3306,binaries:["mysqld","mysql"]},mariadb:{port:3306,binaries:["mariadbd","mariadb","mysqld"]},postgres:{port:5432,binaries:["postgres","psql"]},redis:{port:6379,binaries:["redis-server","redis-cli"]},memcached:{port:11211,binaries:["memcached"]},meilisearch:{port:7700,binaries:["meilisearch"]},vitess:{port:15306,binaries:["vtgate"]}},Bt="ts-cloud-service:";function Ru(e){return e===!0||typeof e==="object"&&e!=null}function ua(e){if(!e)return[];return Object.keys($r).filter((t)=>Ru(e[t]))}function da(e){if(e.length===0)return[];return[Ve(),"ts_cloud_port_open() {",' if command -v ss >/dev/null 2>&1; then ss -ltn 2>/dev/null | grep -qE "[:.]$1[[:space:]]" && return 0; fi',' if command -v netstat >/dev/null 2>&1; then netstat -ltn 2>/dev/null | grep -qE "[:.]$1[[:space:]]" && return 0; fi'," (exec 3<>/dev/tcp/127.0.0.1/$1) 2>/dev/null && { exec 3<&- 3>&-; return 0; }"," return 1","}","ts_cloud_probe() {",' TS_CLOUD_SVC="$1"; TS_CLOUD_PORT="$2"; shift 2',' for TS_CLOUD_BIN in "$@"; do',` if command -v "$TS_CLOUD_BIN" >/dev/null 2>&1; then echo "${Bt}$TS_CLOUD_SVC:present"; return 0; fi`," done",` if ts_cloud_port_open "$TS_CLOUD_PORT"; then echo "${Bt}$TS_CLOUD_SVC:present"; return 0; fi`,` echo "${Bt}$TS_CLOUD_SVC:missing"`," return 0","}",...e.filter((t)=>$r[t]).map((t)=>`ts_cloud_probe ${t} ${$r[t].port} ${$r[t].binaries.join(" ")}`),"exit 0"]}function ma(e,t){if(!e)return[];let r=new Map;for(let n of e.split(`
|
|
563
563
|
`)){let s=n.indexOf(Bt);if(s===-1)continue;let[i,o]=n.slice(s+Bt.length).trim().split(":");if(i)r.set(i,o)}return t.filter((n)=>r.get(n)==="missing")}function fa(e,t,r){let n=r?` on ${r}`:"",s=e.map((o)=>`managedServices.${o}`).join(", "),i=e.length===1?`no ${e[0]}`:`none of ${e.join(", ")}`;return`This project declares ${s}, but '${t}' has ${i}${n}. Attach mode does not provision services on the owner's box, so nothing will install ${e.length===1?"it":"them"}. Point the app at an external service, or ask the owner of '${t}' to add ${e.length===1?"it":"them"} to their own config and re-provision.`}var ha="/var/lib/pantry/php-fpm/pool.d",Eu=9100,xu=400;function _r(e){return(e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"site").slice(0,28)}function ya(e){return`web_${_r(e)}`}function Ou(e){let t=_r(e),r=0;for(let n=0;n<t.length;n++)r=r*31+t.charCodeAt(n)>>>0;return Eu+r%xu}function Zn(e){return`127.0.0.1:${Ou(e)}`}function Du(e){let t=_r(e.siteName),r=ya(e.siteName),n=e.maxChildren??10;return[`; ts-cloud-managed pool for ${e.siteName} (site isolation)`,`[${t}]`,`user = ${r}`,`group = ${r}`,`listen = ${Zn(e.siteName)}`,"pm = dynamic",`pm.max_children = ${n}`,"pm.start_servers = 2","pm.min_spare_servers = 1","pm.max_spare_servers = 3","pm.max_requests = 500","catch_workers_output = yes",`php_admin_value[open_basedir] = ${e.appBase}:/tmp`,""].join(`
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import{C,Kt,n,r,a,_r,e,u,i,s,P,d,Wo,c,vn,Ee,na,ia,oa,sa,f}from"./chunk-4m2k5mvd.js";import{ma,H,Fr,A,U,Xo,l,o,T,fa,ha,ya,$e,He,st,Yo,An,Fi,Rn,Zo,Ca,Ta,Ea,wa,Ra,j,b,M,at,N,ye,ts,qe,Yt,ji,Ie,rs,Vi,Zt,Nt,Ia,Pa}from"./chunk-wayhpmn7.js";import"./chunk-33shhgye.js";import{Me,_,$n,y,Ln,Yi,Mn,ds,qr,lt,xe,Un,Bn,jn,Vn,zn,Hn,Gn,qn,oe,sr,ar,Wn,Wr,Kn,Jn,Xn,Qn,Yn,Zn,ei,ti,dt,cr,lr,$t,Kr,dr,ur,Zi,Lt,ri,de,ni,ii,oi,Jr,Xr,si,Qr,pr,mr,ut,Mt,Ut,Yr,ue,ai,mc,gc,gr,fc,G,eo,We,pt,mt,ci,Zr,li,en,di,ui,tn,us,pe,ve,Ue,Ce,pi,fr}from"./chunk-
|
|
2
|
+
import{C,Kt,n,r,a,_r,e,u,i,s,P,d,Wo,c,vn,Ee,na,ia,oa,sa,f}from"./chunk-4m2k5mvd.js";import{ma,H,Fr,A,U,Xo,l,o,T,fa,ha,ya,$e,He,st,Yo,An,Fi,Rn,Zo,Ca,Ta,Ea,wa,Ra,j,b,M,at,N,ye,ts,qe,Yt,ji,Ie,rs,Vi,Zt,Nt,Ia,Pa}from"./chunk-wayhpmn7.js";import"./chunk-33shhgye.js";import{Me,_,$n,y,Ln,Yi,Mn,ds,qr,lt,xe,Un,Bn,jn,Vn,zn,Hn,Gn,qn,oe,sr,ar,Wn,Wr,Kn,Jn,Xn,Qn,Yn,Zn,ei,ti,dt,cr,lr,$t,Kr,dr,ur,Zi,Lt,ri,de,ni,ii,oi,Jr,Xr,si,Qr,pr,mr,ut,Mt,Ut,Yr,ue,ai,mc,gc,gr,fc,G,eo,We,pt,mt,ci,Zr,li,en,di,ui,tn,us,pe,ve,Ue,Ce,pi,fr}from"./chunk-hkqq09p2.js";import{p,ca}from"./chunk-540wkkhs.js";import{ce,h,Br}from"./chunk-fhqjr3ba.js";import{Or,Pt,$r,Lr,Mr,Ur,Cn}from"./chunk-0zydd9s4.js";import{S,Bt,mi,ms,hr,hc,yc,bc,gi,fi,rn,Ft,nn,gt,ft,Ke,Fe,Je,ht,yr,je,Xe,hi,yi,Qe,on,sn,no,oo,vr,jt,yt,Vt,Z,lo,vi,Ci,As}from"./chunk-jcehsvnm.js";import{ot,Gt,Dr,Xs,Qs,kr,he,Li,Nr,$o,Lo,Mo,Uo,Bo,Fo,K,qt,B,Mi}from"./chunk-s076q9sj.js";import{W,w,Ro,Bs,Fs,qc,Wc,gn,wt,xi}from"./chunk-ps0pzqm0.js";import{v}from"./chunk-4vtyjj7c.js";import{Q}from"./chunk-9ktyfegk.js";import{It,g}from"./chunk-gqstb8zn.js";import{Ze,ks,me,po,Ei,mo,go,cn,fo,ho,Te,ee,et,_e,ln,St,Oe,Cr,dn,tt,rt,Tr,un,wi,Ai,ge,vt,Ri,wr,Ar,Rr,pn,Ir,O,bo,So,Vc,vo,Ns,xs,_s,Os,Ct,$s,Co,To,Eo}from"./chunk-n5sapbxq.js";import"./chunk-0r8k7qth.js";import{D}from"./chunk-6xx24qev.js";import{fe}from"./chunk-0e7y7q0t.js";import{J,Rt,Go}from"./chunk-0v5q5sh0.js";import{ae,q,Fc,jc,Ye}from"./chunk-06hwds44.js";import{ir,_n,or,Xi,On,ls}from"./chunk-by7dtwtj.js";import"./chunk-vgcscxh1.js";import{E}from"./chunk-tf5tf414.js";import{bt}from"./chunk-kq526rgc.js";import{te,we}from"./chunk-nbffypj8.js";import{V}from"./chunk-y5gx3dq2.js";import"./chunk-kyqe19mh.js";import"./chunk-rdqcr78z.js";import{Qi}from"./chunk-eyzdhtp4.js";import"./chunk-th05q1gs.js";import"./chunk-p35e4j11.js";import{Di}from"./chunk-k3cyh23p.js";import{Pr}from"./chunk-hhbmtgkq.js";import{At}from"./chunk-gq4htm3f.js";import{F}from"./chunk-e12679p1.js";import{x}from"./chunk-gbbcp2bw.js";import{existsSync as _u}from"node:fs";import Oa from"node:fs/promises";import Vl from"node:os";import La from"node:path";import to from"node:process";import{EventEmitter as Mu}from"node:events";import _i from"node:process";import ql from"node:process";import Ba from"node:process";import Ls from"node:process";import Jo from"node:process";import Jl from"node:tty";import Pm,{stdin as sy,stdout as ay}from"node:process";class Yl{configPath;config=null;events=[];retryCount=0;maxRetries=3;retryDelayMs=1000;constructor(){let R=Vl.homedir(),t=La.join(R,".config","clapp");this.configPath=La.join(t,"telemetry.json")}async isEnabled(){if(to.env.DO_NOT_TRACK==="1"||to.env.DO_NOT_TRACK==="true")return!1;if(to.env.NO_TELEMETRY==="1"||to.env.NO_TELEMETRY==="true")return!1;return(await this.loadConfig()).enabled}async enable(){let R=await this.loadConfig();if(R.enabled=!0,!R.userId)R.userId=this.generateUserId();await this.saveConfig(R)}async disable(){let R=await this.loadConfig();R.enabled=!1,await this.saveConfig(R)}async track(R,t){if(!await this.isEnabled())return;let k={event:R,...t,timestamp:Date.now(),platform:Vl.platform(),nodeVersion:to.version};if(this.events.push(k),this.events.length>=10)await this.send()}async trackCommand(R,t){await this.track("command",{command:R,duration:t})}async trackError(R,t){await this.track("error",{error:R,command:t})}async send(){if(!await this.isEnabled()||this.events.length===0)return!0;try{this.events=[],this.retryCount=0;let t=await this.loadConfig();return t.lastSent=Date.now(),await this.saveConfig(t),!0}catch{if(this.retryCount<this.maxRetries){this.retryCount++;let t=this.retryDelayMs*2**(this.retryCount-1);return await this.sleep(t),this.send()}return this.events=[],this.retryCount=0,!1}}async flush(){if(this.events.length===0)return!0;return this.send()}sleep(R){return new Promise((t)=>setTimeout(t,R))}async status(){let R=await this.loadConfig();return{enabled:R.enabled,doNotTrack:to.env.DO_NOT_TRACK==="1"||to.env.DO_NOT_TRACK==="true",eventsQueued:this.events.length,lastSent:R.lastSent}}async loadConfig(){if(this.config)return this.config;try{if(_u(this.configPath)){let R=await Oa.readFile(this.configPath,"utf-8");return this.config=JSON.parse(R),this.config}}catch{}return this.config={enabled:!1},this.config}async saveConfig(R){this.config=R;try{let t=La.dirname(this.configPath);await Oa.mkdir(t,{recursive:!0}),await Oa.writeFile(this.configPath,JSON.stringify(R,null,2),"utf-8")}catch{}}generateUserId(){let R=Math.random().toString(36).substring(2,15),t=Date.now().toString(36);return`${R}-${t}`}}var Gh=new Yl;function ja(R){return R.replace(/[<[].+/,"").trim()}function zu(R){let t=/<([^>]+)>/g,m=/\[([^\]]+)\]/g,k=[],I=(Y)=>{let X=!1,ne=Y[1];if(ne.startsWith("..."))ne=ne.slice(3),X=!0;return{required:Y[0].startsWith("<"),value:ne,variadic:X}},L;while(L=t.exec(R))k.push(I(L));let z;while(z=m.exec(R))k.push(I(z));return k}function Uu(R){let t={alias:{},boolean:[]};for(let[m,k]of R.entries()){if(k.names.length>1)t.alias[k.names[0]]=k.names.slice(1);if(k.isBoolean)if(k.negated){if(!R.some((L,z)=>z!==m&&L.names.some((Y)=>k.names.includes(Y))&&typeof L.required==="boolean"))t.boolean.push(k.names[0])}else t.boolean.push(k.names[0])}return t}function Hl(R){return R.reduce((t,m)=>t.length>=m.length?t:m,"")}function Fa(R,t){return R.length>=t?R:`${R}${" ".repeat(t-R.length)}`}function Ts(R){return R.replace(/([a-z])-([a-z])/g,(t,m,k)=>m+k.toUpperCase())}function Wu(R,t,m){let k=0,I=t.length,L=R,z;for(;k<I;++k)z=L[t[k]],L=L[t[k]]=k===I-1?m:z!=null?z:!!~t[k+1].indexOf(".")||!(+t[k+1]>-1)?{}:[]}function Vu(R,t){for(let m of Object.keys(t)){let k=t[m];if(k.shouldTransform){if(R[m]=Array.prototype.concat.call([],R[m]),typeof k.transformFunction==="function")R[m]=R[m].map(k.transformFunction)}}}function qu(R){let t=/([^\\/]+)$/.exec(R);return t?t[1]:""}function Qo(R){return R.split(".").map((t,m)=>m===0?Ts(t):t).join(".")}class es extends Error{exitCode=2;isUsageError=!0;usage;constructor(R,t){super(R);if(this.name=this.constructor.name,t!==void 0)this.usage=t;if(typeof Error.captureStackTrace==="function")Error.captureStackTrace(this,this.constructor);else this.stack=Error(R).stack}format(R=!1){if(R&&this.stack)return`${this.message}
|
|
3
3
|
|
|
4
4
|
Stack trace:
|
|
5
5
|
${this.stack}`;return this.message}}function Hu(R){if(R instanceof es)return!0;return!!R&&typeof R==="object"&&R.name==="ClappError"&&typeof R.message==="string"}function Gu(){let{env:R}=ql,{TERM:t,TERM_PROGRAM:m}=R;if(ql.platform!=="win32")return t!=="linux";return Boolean(R.WT_SESSION)||Boolean(R.TERMINUS_SUBLIME)||R.ConEmuTask==="{cmd::Cmder}"||m==="Terminus-Sublime"||m==="vscode"||t==="xterm-256color"||t==="alacritty"||t==="rxvt-unicode"||t==="rxvt-unicode-256color"||R.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var js="\x1B",mn=`${js}[`;var Gl={to(R,t){if(!t)return`${mn}${R+1}G`;return`${mn}${t+1};${R+1}H`},move(R,t){let m="";if(R<0)m+=`${mn}${-R}D`;else if(R>0)m+=`${mn}${R}C`;if(t<0)m+=`${mn}${-t}A`;else if(t>0)m+=`${mn}${t}B`;return m},up:(R=1)=>`${mn}${R}A`,down:(R=1)=>`${mn}${R}B`,forward:(R=1)=>`${mn}${R}C`,backward:(R=1)=>`${mn}${R}D`,nextLine:(R=1)=>`${mn}E`.repeat(R),prevLine:(R=1)=>`${mn}F`.repeat(R),left:`${mn}G`,hide:`${mn}?25l`,show:`${mn}?25h`,save:`${js}7`,restore:`${js}8`};var Zh={screen:`${mn}2J`,up:(R=1)=>`${mn}1J`.repeat(R),down:(R=1)=>`${mn}J`.repeat(R),line:`${mn}2K`,lineEnd:`${mn}K`,lineStart:`${mn}1K`,lines(R){let t="";for(let m=0;m<R;m++)t+=this.line+(m<R-1?Gl.up():"");if(R)t+=Gl.left;return t}},Qh={screen:`${js}c`};function Ku(R,t){let m=[];for(let k=0;k<=t.length;k++)m[k]=[k];for(let k=0;k<=R.length;k++)m[0][k]=k;for(let k=1;k<=t.length;k++)for(let I=1;I<=R.length;I++)if(t.charAt(k-1)===R.charAt(I-1))m[k][I]=m[k-1][I-1];else m[k][I]=Math.min(m[k-1][I-1]+1,m[k][I-1]+1,m[k-1][I]+1);return m[t.length][R.length]}function Zl(R,t,m=2,k=3){return t.map((I)=>({cmd:I,distance:Ku(R,I)})).filter(({distance:I})=>I<=m).sort((I,L)=>I.distance-L.distance).slice(0,k).map(({cmd:I})=>I)}function Ju(R,t={}){let m={_:[]},k=t.alias||{},I=new Set(t.boolean||[]),L={};for(let X of Object.keys(k))for(let ne of k[X])L[ne]=X;for(let X of I)if(k[X])for(let ne of k[X])I.add(ne);function z(X,ne){if(X===void 0)return ne;if(typeof ne==="boolean")return ne;return Array.isArray(X)?[...X,ne]:[X,ne]}function Y(X,ne){let re=L[X]||X,ie=z(m[re],ne);if(m[re]=ie,k[re])for(let se of k[re])m[se]=ie;if(L[X]&&k[L[X]])for(let se of k[L[X]])m[se]=ie;m[X]=ie}for(let X=0;X<R.length;X++){let ne=R[X];if(ne==="--"){m._.push(...R.slice(X+1));break}if(ne.startsWith("--")){let re=ne.indexOf("=");if(re!==-1){let ie=Ts(ne.slice(2,re)),se=ne.slice(re+1);Y(ie,se)}else{let ie=ne.slice(2);if(ie.startsWith("no-")){let Ae=Ts(ie.slice(3));Y(Ae,!1);continue}let se=Ts(ie),be=L[se]||se;if(I.has(be)||I.has(se))Y(se,!0);else{let Ae=R[X+1];if(Ae!==void 0&&!Ae.startsWith("-"))Y(se,Ae),X++;else Y(se,!0)}}}else if(ne.startsWith("-")&&ne.length>1){let re=ne.slice(1);for(let ie=0;ie<re.length;ie++){let se=re[ie],be=L[se]||se;if(ie===re.length-1&&!I.has(be)&&!I.has(se)){let Ae=R[X+1];if(Ae!==void 0&&!Ae.startsWith("-"))Y(se,Ae),X++;else Y(se,!0)}else Y(se,!0)}}else m._.push(ne)}return m}class Ql{rawName;description;name;names;isBoolean;required;config;negated;constructor(R,t,m){if(this.rawName=R,this.description=t,this.config=Object.assign({},m),R=R.replace(/\.\*/g,""),this.negated=!1,this.names=ja(R).split(",").map((k)=>{let I=k.trim().replace(/^-{1,2}/,"");if(I.startsWith("no-"))this.negated=!0,I=I.replace(/^no-/,"");return Qo(I)}).sort((k,I)=>k.length>I.length?1:-1),this.name=this.names[this.names.length-1],this.negated&&this.config.default==null)this.config.default=!0;if(R.includes("<"))this.required=!0;else if(R.includes("["))this.required=!1;else this.isBoolean=!0}}var ey=Ba.argv,Yu=`${Ba.platform}-${Ba.arch} bun-v${typeof Bun<"u"?Bun.version:"unknown"}`,Kl=Ls.argv,Zu=`${Ls.platform}-${Ls.arch} node-${Ls.version}`;class _a{rawName;description;config;cli;options;aliasNames;name;namespace;args;commandAction;usageText;versionNumber;examples;helpCallback;globalCommand;beforeHooks;afterHooks;middleware;constructor(R,t,m,k){this.rawName=R,this.description=t,this.config=m,this.cli=k,this.options=[],this.aliasNames=[],this.name=ja(R);let I=ja(R),L=I.indexOf(":");if(L>0)this.namespace=I.substring(0,L),this.name=I.substring(L+1);if(this.args=zu(R),this.examples=[],this.beforeHooks=[],this.afterHooks=[],this.middleware=[],!m)this.config={}}usage(R){return this.usageText=R,this}allowUnknownOptions(){return this.config.allowUnknownOptions=!0,this}ignoreOptionDefaultValue(){return this.config.ignoreOptionDefaultValue=!0,this}version(R,t="-v, --version"){return this.versionNumber=R,this.option(t,"Display version number"),this}example(R){return this.examples.push(R),this}option(R,t,m){let k=new Ql(R,t,m);return this.options.push(k),this}alias(R){return this.aliasNames.push(R),this}action(R){return this.commandAction=R,this}before(R){return this.beforeHooks.push(R),this}after(R){return this.afterHooks.push(R),this}use(R){return this.middleware.push(R),this}isMatched(R){if(this.aliasNames.includes(R))return!0;if(this.namespace)return`${this.namespace}:${this.name}`===R;return this.name===R}get isDefaultCommand(){return this.name===""||this.aliasNames.includes("!")}get isGlobalCommand(){return this instanceof Ma}get displayName(){return this.namespace?`${this.namespace}:${this.name}`:this.name}hasOption(R){let t=Qo(R.split(".")[0]);return!!this.options.find((m)=>m.names.some((k)=>Qo(k)===t))}outputHelp(){let{name:R,commands:t}=this.cli,{versionNumber:m,options:k,helpCallback:I}=this.cli.globalCommand,L=[{body:`${R}${m?`/${m}`:""}`}];if(L.push({title:"Usage",body:` $ ${R} ${this.usageText||this.rawName}`}),(this.isGlobalCommand||this.isDefaultCommand)&&t.length>0){let ne=Hl(t.map((Ae)=>Ae.rawName)),re=new Map,ie=[];for(let Ae of t)if(Ae.namespace){if(!re.has(Ae.namespace))re.set(Ae.namespace,[]);re.get(Ae.namespace).push(Ae)}else ie.push(Ae);let se="";if(ie.sort((Ae,le)=>Ae.rawName<le.rawName?-1:Ae.rawName>le.rawName?1:0),ie.length>0)se+=ie.map((Ae)=>` ${Fa(Ae.rawName,ne.length)} ${Ae.description}`).join(`
|
|
@@ -28,7 +28,7 @@ Received ${m}, cleaning up...`),R)try{await R()}catch(k){console.error("Error du
|
|
|
28
28
|
`)),this.enableDidYouMean){let t=[];for(let k of this.commands){if(k.displayName)t.push(k.displayName);if(k.aliasNames)t.push(...k.aliasNames)}let m=Zl(R,t);if(m.length>0)console.log(Ko.yellow("Did you mean one of these?")),m.forEach((k)=>console.log(` ${Ko.dim("•")} ${this.name} ${k}`)),console.log("")}console.log(Ko.dim("Run"),`${this.name} --help`,Ko.dim("to see all available commands")),_i.exit(1)}async parse(R=Kl,t={}){let{run:m=!0,exitOnError:k=!1}=t;if(k)try{return await this.parse(R,{run:m})}catch(X){throw this.handleUsageError(X),X}if(this.rawArgs=R,!this.name)this.name=R[1]?qu(R[1]):"cli";let I=!0,L=R.slice(2),z=L[0];if(z&&!z.startsWith("-")){for(let X of this.commands)if(X.isMatched(z)){let ne=this.mri(L,X);I=!1;let re={...ne,args:ne.args.slice(1)};this.setParsedInfo(re,X,z),this.emit(`command:${z}`,X);break}if(I){let X=L[1];if(X&&!X.startsWith("-")){let ne=`${z}:${X}`;for(let re of this.commands)if(re.isMatched(ne)){let ie=this.mri(L,re);I=!1;let se={...ie,args:ie.args.slice(2)};this.setParsedInfo(se,re,ne),this.emit(`command:${ne}`,re);break}}}}if(I){for(let X of this.commands)if(X.name===""){I=!1;let ne=this.mri(L,X);this.setParsedInfo(ne,X),this.emit("command:!",X);break}}if(I){let X=this.mri(R.slice(2));this.setParsedInfo(X)}if(this.options.verbose)this.isVerbose=!0;if(this.options.quiet)this.isQuiet=!0;if(this.options.debug)this.isDebug=!0;if(this.options.noInteraction||this.options.interaction===!1)this.isNoInteraction=!0;if(this.options.env)this.environment=String(this.options.env);if(this.options.dryRun)this.isDryRun=!0;if(this.options.force)this.isForce=!0;if(this.options.noEmoji||this.options.emoji===!1)this.useEmoji=!1;if(this.options.theme)this.theme=String(this.options.theme);if(this.options.noCache||this.options.cache===!1)this.isNoCache=!0;if(this.options.help&&this.showHelpOnExit)this.outputHelp(),m=!1,this.unsetMatchedCommand();if(this.options.version&&this.showVersionOnExit&&this.matchedCommandName==null)this.outputVersion(),m=!1,this.unsetMatchedCommand();let Y={args:this.args,options:this.options};if(m)await this.runMatchedCommand();if(!this.matchedCommand&&this.args[0]){if(this.emit("command:*"),!(this.listenerCount("command:*")>0))this.showCommandNotFound(this.args[0])}return Y}mri(R,t){let m=[...this.globalCommand.options,...t?t.options:[]],k=Uu(m),I=[],L=R.indexOf("--");if(L>-1)I=R.slice(L+1),R=R.slice(0,L);let z=Ju(R,k),Y={_:z._};for(let se of Object.keys(z))if(se!=="_")Y[Qo(se)]=z[se];let X=Y._,ne={"--":I},re=t&&t.config.ignoreOptionDefaultValue?t.config.ignoreOptionDefaultValue:this.globalCommand.config.ignoreOptionDefaultValue,ie=Object.create(null);for(let se of m){if(!re&&se.config.default!==void 0)for(let be of se.names)ne[be]=se.config.default;if(Array.isArray(se.config.type)){if(ie[se.name]===void 0)ie[se.name]={shouldTransform:!0,transformFunction:se.config.type[0]}}}for(let se of Object.keys(Y))if(se!=="_"){let be=se.split(".");Wu(ne,be,Y[se]),Vu(ne,ie)}return{args:X,options:ne}}async run(R=Kl){return this.parse(R,{run:!0,exitOnError:!0})}handleUsageError(R){if(!Hu(R)||R.isUsageError===!1)return;let t=R.message||"command-line error",m=this.name?`${this.name}: `:"",k=/--help/.test(t)?"":R.usage?`
|
|
29
29
|
Usage: ${R.usage}`:`
|
|
30
30
|
Run \`${this.name??"cli"} --help\` for usage.`;_i.stderr.write(`${m}${t}${k}
|
|
31
|
-
`),_i.exit(R.exitCode??2)}async runMatchedCommand(){let{args:R,options:t,matchedCommand:m}=this;if(!m||!m.commandAction)return;m.checkUnknownOptions(),m.checkOptionValue(),m.checkRequiredArgs();let k=[];m.args.forEach((Y,X)=>{if(Y.variadic)k.push(R.slice(X));else k.push(R[X])}),k.push(t);let I={command:m,args:k,options:t};for(let Y of m.beforeHooks)await Y(I);let L,z=async()=>{let Y=m.commandAction.apply(this,k);if(Y instanceof Promise)L=await Y;else L=Y;return L};if(m.middleware.length>0){let Y=0,X=async()=>{if(Y<m.middleware.length){let ne=m.middleware[Y++];await ne({...I,next:X})}else await z()};await X()}else await z();for(let Y of m.afterHooks)await Y(I);return L}removeSignalHandlers(){if(!this.signalHandlersSet)return this;return _i.removeAllListeners("SIGINT"),_i.removeAllListeners("SIGTERM"),this.signalHandlersSet=!1,this}destroy(){this.removeSignalHandlers(),this.commands=[],this.rawArgs=[],this.args=[],this.options={},this.matchedCommand=void 0,this.matchedCommandName=void 0,this.removeAllListeners()}}class Xl{cache;enabled;cleanupInterval=null;hits=0;misses=0;constructor(){this.cache=new Map,this.enabled=!0,this.startCleanupInterval()}startCleanupInterval(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanup()},30000),this.cleanupInterval.unref()}stopCleanup(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}isEnabled(){return this.enabled}get(R){if(!this.enabled){this.misses++;return}let t=this.cache.get(R);if(!t){this.misses++;return}if(Date.now()-t.timestamp>t.ttl){this.cache.delete(R),this.misses++;return}return this.hits++,t.value}set(R,t,m=5000){if(!this.enabled)return;this.cache.set(R,{value:t,timestamp:Date.now(),ttl:m})}has(R){if(!this.enabled)return!1;let t=this.cache.get(R);if(!t)return!1;if(Date.now()-t.timestamp>t.ttl)return this.cache.delete(R),!1;return!0}delete(R){this.cache.delete(R)}clear(){this.cache.clear()}disable(){this.enabled=!1,this.clear()}enable(){this.enabled=!0}stats(){return{size:this.cache.size,enabled:this.enabled,hits:this.hits,misses:this.misses}}resetStats(){this.hits=0,this.misses=0}keys(){return Array.from(this.cache.keys())}cleanup(){let R=Date.now();for(let[t,m]of this.cache.entries())if(R-m.timestamp>m.ttl)this.cache.delete(t)}destroy(){this.stopCleanup(),this.clear(),this.resetStats()}}var ny=new Xl;function tm(){if("FORCE_COLOR"in Jo.env)return Jo.env.FORCE_COLOR!=="0";if("NO_COLOR"in Jo.env||Jo.env.TERM==="dumb")return!1;if(Jo.platform==="win32")return!0;return Jl.isatty(1)&&Jl.isatty(2)}var ed=tm();function an(R,t){if(!ed)return(m)=>m;return(m)=>R+m+t}var nm=an("\x1B[0m","\x1B[0m"),rm=an("\x1B[31m","\x1B[39m"),im=an("\x1B[32m","\x1B[39m"),om=an("\x1B[33m","\x1B[39m"),sm=an("\x1B[34m","\x1B[39m"),am=an("\x1B[35m","\x1B[39m"),cm=an("\x1B[36m","\x1B[39m"),lm=an("\x1B[37m","\x1B[39m"),dm=an("\x1B[90m","\x1B[39m"),um=an("\x1B[1m","\x1B[22m"),mm=an("\x1B[3m","\x1B[23m"),pm=an("\x1B[4m","\x1B[24m"),fm=an("\x1B[2m","\x1B[22m"),gm=an("\x1B[7m","\x1B[27m"),hm=an("\x1B[8m","\x1B[28m"),ym=an("\x1B[9m","\x1B[29m"),vm=an("\x1B[41m","\x1B[49m"),bm=an("\x1B[42m","\x1B[49m"),wm=an("\x1B[43m","\x1B[49m"),Sm=an("\x1B[44m","\x1B[49m"),Cm=an("\x1B[45m","\x1B[49m"),$m=an("\x1B[46m","\x1B[49m"),km=an("\x1B[47m","\x1B[49m"),Am=ed,Rm={reset:nm,red:rm,green:im,yellow:om,blue:sm,magenta:am,cyan:cm,white:lm,gray:dm,bold:um,italic:mm,underline:pm,dim:fm,inverse:gm,hidden:hm,strikethrough:ym,bgRed:vm,bgGreen:bm,bgYellow:wm,bgBlue:Sm,bgMagenta:Cm,bgCyan:$m,bgWhite:km,isColorSupported:Am},Im=Rm,xm=["up","down","left","right","space","enter","cancel"],cy={actions:new Set(xm),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["\x03","cancel"],["escape","cancel"]]),messages:{cancel:"Canceled",error:"Something went wrong"}};var ly=Pm.platform.startsWith("win"),dy=Symbol("clapp:cancel");var Dm=Gu();var Xt=(R,t)=>Dm?R:t,uy=Xt("◆","*"),my=Xt("■","x"),py=Xt("▲","x"),fy=Xt("◇","o"),gy=Xt("┌","T"),Em=Xt("│","|"),hy=Xt("└","—"),yy=Xt("●",">"),vy=Xt("○"," "),by=Xt("◻","[•]"),wy=Xt("◼","[+]"),Sy=Xt("◻","[ ]"),Cy=Xt("▪","•"),$y=Xt("─","-"),ky=Xt("╮","+"),Ay=Xt("├","+"),Ry=Xt("╯","+"),Iy=Xt("●","•"),Py=Xt("◆","*"),xy=Xt("▲","!"),Dy=Xt("■","x");var Ey={light:Xt("─","-"),heavy:Xt("━","="),block:Xt("█","#")};function Tm(){return`${Im.gray(Em)} `}var Ty=Tm();var Ua="0.16.
|
|
31
|
+
`),_i.exit(R.exitCode??2)}async runMatchedCommand(){let{args:R,options:t,matchedCommand:m}=this;if(!m||!m.commandAction)return;m.checkUnknownOptions(),m.checkOptionValue(),m.checkRequiredArgs();let k=[];m.args.forEach((Y,X)=>{if(Y.variadic)k.push(R.slice(X));else k.push(R[X])}),k.push(t);let I={command:m,args:k,options:t};for(let Y of m.beforeHooks)await Y(I);let L,z=async()=>{let Y=m.commandAction.apply(this,k);if(Y instanceof Promise)L=await Y;else L=Y;return L};if(m.middleware.length>0){let Y=0,X=async()=>{if(Y<m.middleware.length){let ne=m.middleware[Y++];await ne({...I,next:X})}else await z()};await X()}else await z();for(let Y of m.afterHooks)await Y(I);return L}removeSignalHandlers(){if(!this.signalHandlersSet)return this;return _i.removeAllListeners("SIGINT"),_i.removeAllListeners("SIGTERM"),this.signalHandlersSet=!1,this}destroy(){this.removeSignalHandlers(),this.commands=[],this.rawArgs=[],this.args=[],this.options={},this.matchedCommand=void 0,this.matchedCommandName=void 0,this.removeAllListeners()}}class Xl{cache;enabled;cleanupInterval=null;hits=0;misses=0;constructor(){this.cache=new Map,this.enabled=!0,this.startCleanupInterval()}startCleanupInterval(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanup()},30000),this.cleanupInterval.unref()}stopCleanup(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}isEnabled(){return this.enabled}get(R){if(!this.enabled){this.misses++;return}let t=this.cache.get(R);if(!t){this.misses++;return}if(Date.now()-t.timestamp>t.ttl){this.cache.delete(R),this.misses++;return}return this.hits++,t.value}set(R,t,m=5000){if(!this.enabled)return;this.cache.set(R,{value:t,timestamp:Date.now(),ttl:m})}has(R){if(!this.enabled)return!1;let t=this.cache.get(R);if(!t)return!1;if(Date.now()-t.timestamp>t.ttl)return this.cache.delete(R),!1;return!0}delete(R){this.cache.delete(R)}clear(){this.cache.clear()}disable(){this.enabled=!1,this.clear()}enable(){this.enabled=!0}stats(){return{size:this.cache.size,enabled:this.enabled,hits:this.hits,misses:this.misses}}resetStats(){this.hits=0,this.misses=0}keys(){return Array.from(this.cache.keys())}cleanup(){let R=Date.now();for(let[t,m]of this.cache.entries())if(R-m.timestamp>m.ttl)this.cache.delete(t)}destroy(){this.stopCleanup(),this.clear(),this.resetStats()}}var ny=new Xl;function tm(){if("FORCE_COLOR"in Jo.env)return Jo.env.FORCE_COLOR!=="0";if("NO_COLOR"in Jo.env||Jo.env.TERM==="dumb")return!1;if(Jo.platform==="win32")return!0;return Jl.isatty(1)&&Jl.isatty(2)}var ed=tm();function an(R,t){if(!ed)return(m)=>m;return(m)=>R+m+t}var nm=an("\x1B[0m","\x1B[0m"),rm=an("\x1B[31m","\x1B[39m"),im=an("\x1B[32m","\x1B[39m"),om=an("\x1B[33m","\x1B[39m"),sm=an("\x1B[34m","\x1B[39m"),am=an("\x1B[35m","\x1B[39m"),cm=an("\x1B[36m","\x1B[39m"),lm=an("\x1B[37m","\x1B[39m"),dm=an("\x1B[90m","\x1B[39m"),um=an("\x1B[1m","\x1B[22m"),mm=an("\x1B[3m","\x1B[23m"),pm=an("\x1B[4m","\x1B[24m"),fm=an("\x1B[2m","\x1B[22m"),gm=an("\x1B[7m","\x1B[27m"),hm=an("\x1B[8m","\x1B[28m"),ym=an("\x1B[9m","\x1B[29m"),vm=an("\x1B[41m","\x1B[49m"),bm=an("\x1B[42m","\x1B[49m"),wm=an("\x1B[43m","\x1B[49m"),Sm=an("\x1B[44m","\x1B[49m"),Cm=an("\x1B[45m","\x1B[49m"),$m=an("\x1B[46m","\x1B[49m"),km=an("\x1B[47m","\x1B[49m"),Am=ed,Rm={reset:nm,red:rm,green:im,yellow:om,blue:sm,magenta:am,cyan:cm,white:lm,gray:dm,bold:um,italic:mm,underline:pm,dim:fm,inverse:gm,hidden:hm,strikethrough:ym,bgRed:vm,bgGreen:bm,bgYellow:wm,bgBlue:Sm,bgMagenta:Cm,bgCyan:$m,bgWhite:km,isColorSupported:Am},Im=Rm,xm=["up","down","left","right","space","enter","cancel"],cy={actions:new Set(xm),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["\x03","cancel"],["escape","cancel"]]),messages:{cancel:"Canceled",error:"Something went wrong"}};var ly=Pm.platform.startsWith("win"),dy=Symbol("clapp:cancel");var Dm=Gu();var Xt=(R,t)=>Dm?R:t,uy=Xt("◆","*"),my=Xt("■","x"),py=Xt("▲","x"),fy=Xt("◇","o"),gy=Xt("┌","T"),Em=Xt("│","|"),hy=Xt("└","—"),yy=Xt("●",">"),vy=Xt("○"," "),by=Xt("◻","[•]"),wy=Xt("◼","[+]"),Sy=Xt("◻","[ ]"),Cy=Xt("▪","•"),$y=Xt("─","-"),ky=Xt("╮","+"),Ay=Xt("├","+"),Ry=Xt("╯","+"),Iy=Xt("●","•"),Py=Xt("◆","*"),xy=Xt("▲","!"),Dy=Xt("■","x");var Ey={light:Xt("─","-"),heavy:Xt("━","="),block:Xt("█","#")};function Tm(){return`${Im.gray(Em)} `}var Ty=Tm();var Ua="0.16.78";function td(R,t,m=process.env){let k=t?.options.find((z)=>z.name==="profile");if((!k||/\baws\b/i.test(k.description))&&typeof R.profile==="string"&&R.profile)m.AWS_PROFILE=R.profile,delete m.AWS_ACCESS_KEY_ID,delete m.AWS_SECRET_ACCESS_KEY,delete m.AWS_SESSION_TOKEN;if(!t?.options.some((z)=>z.name==="region")&&typeof R.region==="string"&&R.region)m.AWS_REGION=R.region,m.AWS_DEFAULT_REGION=R.region}import{existsSync as Wa}from"node:fs";import{mkdir as Om,writeFile as nd}from"node:fs/promises";function Va(R){R.command("init","Initialize a new ts-cloud project").option("--mode <mode>","Deployment mode: server or serverless").option("--name <name>","Project name").option("--region <region>","AWS Region").action(async(t)=>{if(i("Initializing ts-cloud Project"),Wa("cloud.config.ts")){if(!await d("cloud.config.ts already exists. Overwrite?",!1)){e("Initialization cancelled");return}}let m=t?.name||await P("Project name","my-app"),k=t?.mode||await Wo("Select deployment mode",["serverless","server"]),I=t?.region||await Wo("Select AWS region",["us-east-1","us-west-2","eu-west-1","eu-central-1","ap-southeast-1"]),L=new s("Creating configuration file...");L.start();let z=`import { defineConfig } from '@ts-cloud/core'
|
|
32
32
|
|
|
33
33
|
export default defineConfig({
|
|
34
34
|
project: {
|
|
@@ -315,7 +315,7 @@ Resources to create: ${Pe}`);let ze={};for(let Le of Object.values(ne.Resources|
|
|
|
315
315
|
No changes detected - infrastructure is up to date`);return}if(e(`
|
|
316
316
|
Changes detected:
|
|
317
317
|
`),ke.length>0){n(`Resources to add (${ke.length}):`);for(let Re of ke){let Pe=be[Re].Type;e(` + ${Re} (${Pe})`)}console.log()}if(De.length>0){r(`Resources to remove (${De.length}):`);for(let Re of De){let Pe=se[Re].Type;e(` - ${Re} (${Pe})`)}console.log()}if(Se.length>0){a(`Resources to modify (${Se.length}):`);for(let Re of Se){let Pe=be[Re].Type;e(` ~ ${Re} (${Pe})`)}console.log()}e("Summary:"),e(` - Add: ${ke.length}`),e(` - Remove: ${De.length}`),e(` - Modify: ${Se.length}`),e("\nRun `cloud deploy` to apply these changes")}catch(m){r(`Diff failed: ${m.message}`)}})}function Ui(R,t=0){let m=Number(R);return Number.isFinite(m)?m:t}function Za(R){return Ui(R)*1024}function mp(R){let t=R?.date?.trim(),m=R?.time?.trim();if(!t||!m)return null;let k=new Date(`${t}T${m}Z`);return Number.isFinite(k.getTime())?k.toISOString():null}function pp(R,t,m){let k;try{k=JSON.parse(R)}catch{return[]}let I=(k?.sysstat?.hosts??[]).flatMap((z)=>z.statistics??[]),L=[];for(let z of I){let Y=mp(z.timestamp);if(!Y)continue;let X=new Date(Y).getTime();if(X<t.getTime()||X>m.getTime())continue;let ne=z["cpu-load"]?.find((ie)=>ie.cpu==="all")??z["cpu-load"]?.[0],re=Ui(ne?.idle,100);L.push({timestamp:Y,cpuUsedPercent:Math.max(0,Math.min(100,100-re)),cpuUserPercent:Ui(ne?.user),cpuSystemPercent:Ui(ne?.system),cpuIowaitPercent:Ui(ne?.iowait),memoryUsedPercent:Ui(z.memory?.["memused-percent"]),memoryUsedBytes:Za(z.memory?.memused),memoryAvailableBytes:Za(z.memory?.avail),swapUsedPercent:Ui(z.memory?.["swpused-percent"]),swapUsedBytes:Za(z.memory?.swpused)})}return L.sort((z,Y)=>z.timestamp.localeCompare(Y.timestamp))}function fp(R){return Object.fromEntries(Object.entries(R.time_series??{}).map(([t,m])=>[t,(m.values??[]).map(([k,I])=>({timestamp:new Date(Number(k)*1000).toISOString(),value:Ui(I,Number.NaN)})).filter((k)=>Number.isFinite(k.value))]))}function hd(R){return R.length?R.reduce((t,m)=>t+m,0)/R.length:null}function Qa(R){return R.length?Math.max(...R):null}function gp(R){return R.length?Math.min(...R):null}async function yd(R){let[t,m]=await Promise.all([R.client.getServerMetrics(R.serverId,{types:["cpu","disk","network"],start:R.from,end:R.to,step:R.step}),_e(R.remote.host,"LC_ALL=C sadf -j -- -u -r -S",R.remote).catch(()=>"")]),k=pp(m,R.from,R.to),I=fp(t),z=(I.cpu??[]).map((ie)=>Math.max(0,Math.min(100,ie.value/Math.max(1,R.cores)))),Y=k.map((ie)=>ie.cpuUsedPercent),X=z.length?z:Y,ne=k.map((ie)=>ie.memoryUsedPercent),re=k.map((ie)=>ie.swapUsedPercent);return{from:R.from.toISOString(),to:R.to.toISOString(),cores:R.cores,host:k,provider:I,summary:{cpuAveragePercent:hd(X),cpuPeakPercent:Qa(X),memoryAveragePercent:hd(ne),memoryPeakPercent:Qa(ne),memoryMinimumAvailableBytes:gp(k.map((ie)=>ie.memoryAvailableBytes)),swapPeakPercent:Qa(re)}}}function hp(R){if(R.length===0)throw Error("A server name cannot be empty.");if(R.length>253)throw Error(`'${R}' is longer than the 253 characters a hostname allows.`);for(let t of R.split(".")){if(t.length===0)throw Error(`'${R}' has an empty label — a hostname cannot contain '..'.`);if(t.length>63)throw Error(`'${t}' is longer than the 63 characters a hostname label allows.`);if(!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(t))throw Error(`'${t}' is not a valid hostname label. Use letters, digits and hyphens, not starting or ending with a hyphen.`)}}async function vd(R,t,m){if(hp(t),R===t)throw Error(`'${R}' is already named that.`);if((await m.takenNames()).some((L)=>L===t&&L!==R))throw Error(`'${t}' is already taken. Server names have to be unique within a provider project.`);let I=[];if(m.providerName&&m.renameProvider){let{providerName:L,renameProvider:z}=m;I.push({id:"provider",title:"Rename the server at the provider",change:{from:R,to:t},satisfied:async()=>await L()===t,apply:()=>z(t)})}if(m.stateName&&m.writeStateName){let{stateName:L,writeStateName:z}=m;I.push({id:"state-pin",title:"Update the recorded name in the local driver state",change:{from:R,to:t},satisfied:async()=>{let Y=await L();return Y===void 0||Y===t},apply:()=>z(t)})}if(m.remoteHostname&&m.setRemoteHostname){let{remoteHostname:L,setRemoteHostname:z}=m;I.push({id:"hostname",title:"Set the hostname on the box",change:{from:R,to:t},satisfied:async()=>await L()===t,apply:()=>z(t)})}return I.push({id:"inventory",title:"Rename the fleet inventory record",change:{from:R,to:t},satisfied:async()=>m.inventoryName()===t,apply:async()=>{await m.renameInventory(t)}}),{operation:"server:rename",target:R,steps:I}}function bd(R){let t=`'${R.replace(/'/g,`'"'"'`)}'`;return["set -eu",'TS_CLOUD_OLD="$(hostname)"',`hostnamectl set-hostname ${t} 2>/dev/null || { echo ${t} > /etc/hostname && hostname ${t}; }`,'if grep -q "^127.0.1.1" /etc/hosts; then',` TS_CLOUD_HOSTS="$(sed -E "s/^127\\.0\\.1\\.1.*/127.0.1.1\\t${R}/" /etc/hosts)"`,` printf '%s\\n' "$TS_CLOUD_HOSTS" > /etc/hosts`,"else",` printf '127.0.1.1\\t%s\\n' ${t} >> /etc/hosts`,"fi",'printf "%s -> %s\\n" "$TS_CLOUD_OLD" "$(hostname)"'].join(`
|
|
318
|
-
`)}async function yp(){let R=await Ne(),t=y(process.cwd(),R),m=new xe(t.store),k=new Un(m,[new lt("aws"),new lt("hetzner"),new lt("ssh")]);return{controlPlane:t,store:m,service:k}}async function bi(R){let t=await yp();try{return await R(t)}finally{t.controlPlane.store.close()}}var Wi=(R,t)=>{let m=R.store.list(R.controlPlane.project.id).find((k)=>k.id===t||k.name===t);if(!m)throw Error(`Server ${t} was not found.`);return m},kn=(R)=>{r(R instanceof Error?R.message:String(R)),process.exitCode=1};function Xa(R,t){let m=Number.parseInt(R??"",10);return Number.isFinite(m)&&m>=0?m:t}function vp(R="3h"){let t=R.match(/^(\d+)(m|h)$/);if(!t)throw Error("--range must use minutes or hours, for example 30m or 3h.");let m=Number(t[1])*(t[2]==="h"?3600000:60000);if(m<300000||m>86400000)throw Error("--range must be between 5 minutes and 24 hours.");return m}function ss(R,t="%"){return R==null?"unavailable":`${R.toFixed(1)}${t}`}async function bp(R,t){let m=await Ne();if(m.cloud?.provider!=="hetzner")throw Error("server:monitoring currently requires the Hetzner provider.");let k=t.env??process.env.CLOUD_ENV??"production",I=T(m,k),L=await ge(I);if(!L?.serverId)throw Error(`No pinned Hetzner server was found for ${I}.`);if(![L.serverName,String(L.serverId),L.stackName].includes(R))throw Error(`Refusing to read ${R}: project state is pinned to ${L.serverName}.`);let z=St(m),Y=new Oe({apiToken:Cr(z.apiToken,m)}),X=await Y.getServer(L.serverId),ne=L.publicIp??X.public_net.ipv4?.ip;if(!ne)throw Error(`Server ${X.name} has no public IPv4 address.`);let re=new Date,ie=new Date(re.getTime()-vp(t.range)),se=Math.min(3600,Math.max(60,Xa(t.step,60))),be=await yd({client:Y,serverId:X.id,cores:Math.max(1,Number(X.server_type.cores)||1),from:ie,to:re,step:se,remote:{host:ne,user:L.sshUser??z.sshUser,identityFile:z.sshPrivateKeyPath,connectTimeoutSec:15}});if(t.json){console.log(JSON.stringify({schemaVersion:1,server:X.name,result:be},null,2));return}c(["Server","Window","CPU average / peak","RAM average / peak","Minimum available","Swap peak"],[[X.name,`${be.from} to ${be.to}`,`${ss(be.summary.cpuAveragePercent)} / ${ss(be.summary.cpuPeakPercent)}`,`${ss(be.summary.memoryAveragePercent)} / ${ss(be.summary.memoryPeakPercent)}`,be.summary.memoryMinimumAvailableBytes==null?"unavailable":`${(be.summary.memoryMinimumAvailableBytes/1073741824).toFixed(2)} GB`,ss(be.summary.swapPeakPercent)]])}function wd(R){let t=R.targetType.prices?.find((m)=>m.location===R.location);return{serverId:R.serverId,serverName:R.serverName,location:R.location,from:R.currentType.name,to:R.targetType.name,capacityAvailable:R.capacityAvailable,alreadyComplete:R.alreadyComplete,upgradeDisk:R.upgradeDisk,target:{cores:R.targetType.cores,memoryGb:R.targetType.memory,diskGb:R.targetType.disk,architecture:R.targetType.architecture,cpuType:R.targetType.cpu_type},price:t?{hourlyNet:t.price_hourly.net,hourlyGross:t.price_hourly.gross,monthlyNet:t.price_monthly.net,monthlyGross:t.price_monthly.gross}:void 0}}function wp(R){let t=wd(R);c(["Server","Location","Resize","Capacity","CPU / RAM / disk","Monthly"],[[`${t.serverName} (${t.serverId})`,t.location,`${t.from} -> ${t.to}`,t.capacityAvailable?"available":"waiting",`${t.target.cores??0} / ${t.target.memoryGb??0} GB / ${t.target.diskGb??0} GB`,t.price?.monthlyGross??t.price?.monthlyNet??"not reported"]])}async function Sp(R,t,m){let k=await Ne();if(k.cloud?.provider!=="hetzner")throw Error("server:resize currently requires the Hetzner provider.");let I=m.env??process.env.CLOUD_ENV??"production",L=T(k,I),z=await ge(L),Y=St(k),X=new Oe({apiToken:Cr(Y.apiToken,k)}),re=z&&(R===z.serverName||R===String(z.serverId)||R===z.stackName)?await X.getServer(z.serverId):(await X.listServers()).find((Le)=>Le.name===R||String(Le.id)===R);if(!re)throw Error(`Hetzner server ${R} was not found.`);if(z?.serverId&&z.serverId!==re.id)throw Error(`Refusing to resize ${R}: project state is pinned to server ${z.serverId}.`);let ie=tt(t),se=m.upgradeDisk!==!1,be=await rt(X,re.id,ie,se);if(m.json)console.log(JSON.stringify({schemaVersion:1,plan:wd(be)},null,2));else wp(be);if(!m.apply){if(!m.json)e(`Preview only. Re-run with --apply --confirm ${re.name} to execute.`);return}if(m.confirm!==re.name)throw Error(`Resize requires --confirm ${re.name}.`);let Ae=z?.publicIp??re.public_net.ipv4?.ip;if(!Ae)throw Error(`Server ${re.name} has no public IPv4 address for verification.`);let le={host:Ae,user:z?.sshUser??Y.sshUser,identityFile:Y.sshPrivateKeyPath,connectTimeoutSec:15,sshTimeoutMs:600000,routeTimeoutMs:20000},ke=await Os(L),De=new Date().toISOString(),Se={schemaVersion:1,operationId:ke?.targetType===ie&&ke.serverId===re.id?ke.operationId:crypto.randomUUID(),stackName:L,serverId:re.id,serverName:re.name,sourceType:be.currentType.name,targetType:ie,upgradeDisk:se,phase:"planning",status:"running",attempts:ke?.targetType===ie?ke.attempts:0,startedAt:ke?.targetType===ie?ke.startedAt:De,updatedAt:De,manifest:ke?.targetType===ie?ke.manifest:void 0};await Ct(Se);let Re=Xa(m.pollSeconds,900)*1000,Pe=Xa(m.maxWaitMinutes,0)*60000,ze=Date.now();for(;;){let Le=await rt(X,re.id,ie,se);if(!Le.capacityAvailable&&!Le.alreadyComplete){if(Se={...Se,phase:"waiting-capacity",status:"waiting-capacity",updatedAt:new Date().toISOString()},await Ct(Se),!m.wait){if(!m.json)e(`${ie} has no capacity in ${Le.location}. The server remains running and unchanged. Use --wait to poll safely.`);return}if(Pe>0&&Date.now()-ze>=Pe)throw Error(`Timed out waiting for ${ie} capacity in ${Le.location}.`);if(!m.json)e(`Waiting ${Math.round(Re/1000)} seconds for ${ie} capacity...`);await Bun.sleep(Re);continue}let Be=await $s(L);try{let Ve=await(async()=>{try{return Se={...Se,status:"running",attempts:Se.attempts+1,updatedAt:new Date().toISOString()},await Ct(Se),await Tr({client:X,serverId:re.id,targetType:ie,upgradeDisk:se,resumeFromOff:Se.phase==="shutting-down"||Se.phase==="resizing"||Se.phase==="powering-on"||Se.phase==="verifying",manifest:Se.manifest,hooks:{preflight:async()=>{let ct=await wi(le);return Se={...Se,manifest:ct,updatedAt:new Date().toISOString()},await Ct(Se),ct},afterBoot:async(ct,Dt,nt,xt)=>Ai(le,Dt,nt,xt),onPhase:async(ct,Dt)=>{if(Se={...Se,phase:ct,status:ct==="waiting-capacity"?"waiting-capacity":ct==="complete"?"completed":"running",updatedAt:new Date().toISOString()},await Ct(Se),!m.json)e(`${ct}${Dt?` ${JSON.stringify(Dt)}`:""}`)}}})}finally{await Be()}})();if(Se={...Se,status:Ve.status==="completed"||Ve.status==="already-complete"?"completed":Ve.status==="recovered"?"recovered":"waiting-capacity",lastError:Ve.status==="recovered"?Ve.error:void 0,updatedAt:new Date().toISOString()},await Ct(Se),m.json)console.log(JSON.stringify({schemaVersion:1,result:Ve},null,2));else if(Ve.status==="completed"||Ve.status==="already-complete")n(`${re.name} is on ${ie} and passed full post-boot verification.`);else if(Ve.status==="recovered"&&Ve.retryable&&m.wait){e(`Capacity race recovered safely. Waiting ${Math.round(Re/1000)} seconds before retry.`),await Bun.sleep(Re);continue}else if(Ve.status==="recovered")throw Error(`Resize did not complete and the original server was recovered: ${Ve.error}`);return}catch(Ve){throw Se={...Se,status:"failed",lastError:Ve instanceof Error?Ve.message:String(Ve),updatedAt:new Date().toISOString()},await Ct(Se),Ve}}}async function Cp(R,t){let m=await Ne();if(m.cloud?.provider!=="hetzner")throw Error("server:optimize currently requires the Hetzner provider.");let k=t.env??process.env.CLOUD_ENV??"production",I=T(m,k),L=await ge(I);if(!L?.serverId)throw Error(`No pinned Hetzner server was found for ${I}.`);if(![L.serverName,String(L.serverId),L.stackName].includes(R))throw Error(`Refusing to optimize ${R}: project state is pinned to ${L.serverName}.`);let z=St(m),Y=new Oe({apiToken:Cr(z.apiToken,m)}),X=await Y.getServer(L.serverId),ne=L.publicIp??X.public_net.ipv4?.ip;if(!ne)throw Error(`Server ${X.name} has no public IPv4 address.`);let re=vo(m);if(t.json)console.log(JSON.stringify({schemaVersion:1,server:X.name,plan:re},null,2));else c(["Server","Firewall ports","Monitoring","Auto updates","Swap","SSH passwords"],[[X.name,re.firewallPorts.join(","),re.monitoring?"on":"off",re.autoUpdates?"on":"off",`${re.swapGb} GB`,"disabled"]]);if(!t.apply){if(!t.json)e(`Preview only. Re-run with --apply --confirm ${X.name} to execute.`);return}if(t.confirm!==X.name)throw Error(`Optimization requires --confirm ${X.name}.`);let ie={host:ne,user:L.sshUser??z.sshUser,identityFile:z.sshPrivateKeyPath,connectTimeoutSec:15},se=await un(ie),be=se.routeProbes.filter((nt)=>!nt.ok),Ae=m.infrastructure?.compute,le=ee(Ae)?new Set(["nginx.service","bun-gateway.service","ts-cloud-nginx.service"]):new Set,ke=se.failedUnits.filter((nt)=>!le.has(nt));if(ke.length>0)throw Error(`Preflight found failed services: ${ke.join(", ")}`);if(be.length>0)throw Error(`Preflight found unhealthy routes: ${be.map((nt)=>nt.domain).join(", ")}`);let De=ee(Ae)?[]:Object.values(m.sites??{}).flatMap((nt)=>typeof nt?.port==="number"&&![80,443].includes(nt.port)?[nt.port]:[]),Se=dn({allowSsh:Ae?.allowSsh!==!1,sitePorts:De,allowedPorts:Ae?.firewall?.allowedPorts}),Re=(L.firewallId?(await Y.listFirewalls()).find((nt)=>nt.id===L.firewallId):void 0)??(await Y.listFirewalls()).find((nt)=>nt.name===`${m.project.slug}-${k}-app-fw`);if(!Re)throw Error(`Managed firewall for ${X.name} was not found.`);let Pe=await Y.setFirewallRules(Re.id,Se);await Promise.all(Pe.map((nt)=>Y.waitForAction(nt.id))),await Ns(m,ie);let[ze,Le]=await Promise.all([un(ie),xs(ie)]),Be=_s(re,Le),Ve=Vc(se,ze),ct=ze.routeProbes.filter((nt)=>!nt.ok);if(Ve.stoppedServices.length>0)Be.push(`services stopped: ${Ve.stoppedServices.join(", ")}`);if(Ve.changedRouteFragments.length>0)Be.push(`route fragments changed: ${Ve.changedRouteFragments.join(", ")}`);if(Ve.missingRouteIds.length>0)Be.push(`routes disappeared: ${Ve.missingRouteIds.join(", ")}`);if(Ve.changedReleaseLinks.length>0)Be.push(`release links changed: ${Ve.changedReleaseLinks.join(", ")}`);if(Ve.missingData.length>0)Be.push(`databases or volumes disappeared: ${Ve.missingData.join(", ")}`);if(ct.length>0)Be.push(`unhealthy routes: ${ct.map((nt)=>nt.domain).join(", ")}`);if(Be.length>0)throw Error(`Host optimization verification failed: ${Be.join("; ")}`);let Dt={serverId:X.id,serverName:X.name,services:ze.runningServices.length,routes:ze.routeIds.length,healthyDomains:ze.routeProbes.length,releaseLinks:ze.releaseLinks.length,databasesAndVolumes:ze.dataCatalog.length,report:Le};if(t.json)console.log(JSON.stringify({schemaVersion:1,result:Dt},null,2));else n(`${X.name} passed full host, rpx route, service, release, and data verification.`)}async function $p(R,t,m){let k=await Ne(),I=m.env??"production",L=T(k,I);await bi(async(z)=>{let Y=Wi(z,R),X=z.store.list(z.controlPlane.project.id,!0),ne=Y.provider==="hetzner"&&Y.providerId?(()=>{try{let Re=St(k);return new Oe({apiToken:Cr(Re.apiToken,k)})}catch{return null}})():null,re=Y.providerId?Number(Y.providerId):Number.NaN,ie=await ge(L),se=ie!=null&&ie.serverId===re,be=new qr,Ae=Y.trustState==="pinned",le={takenNames:async()=>{let Re=X.map((Pe)=>Pe.name);if(ne)Re.push(...(await ne.listServers()).map((Pe)=>Pe.name));return Re},inventoryName:()=>z.store.get(Y.id)?.name??Y.name,renameInventory:(Re)=>{z.store.update(Y.id,{name:Re})},...ne&&Number.isFinite(re)?{providerName:async()=>(await ne.getServer(re)).name,renameProvider:async(Re)=>{await ne.renameServer(re,Re)}}:{},...se?{stateName:async()=>(await ge(L))?.serverName,writeStateName:async(Re)=>{let Pe=await ge(L);if(Pe)await vt(L,{...Pe,serverName:Re})}}:{},...Ae?{remoteHostname:async()=>{let Re=await be.exec(Y,"hostname");return Re.code===0?Re.stdout.trim():void 0},setRemoteHostname:async(Re)=>{let Pe=await be.exec(Y,bd(Re));if(Pe.code!==0)throw Error(Pe.stderr.trim()||`hostname exited ${Pe.code}`)}}:{}},ke=await vd(Y.name,t,le),De=await zs(ke);if(!m.apply){let Re=[ne?"":"provider record (no provider id or no API token)",se?"":"local state pin (none points at this server)",Ae?"":"box hostname (host key is not pinned — run server:validate first)"].filter(Boolean);if(m.json){console.log(JSON.stringify({schemaVersion:1,operation:ke.operation,target:ke.target,rename:{from:Y.name,to:t},notCovered:Re,steps:De.map((Pe)=>({id:Pe.step.id,title:Pe.step.title,state:Pe.state,change:Pe.step.change,reason:Pe.reason}))},null,2));return}for(let Pe of Us(ke,De))console.log(Pe);for(let Pe of Re)console.log(` not covered: ${Pe}`);console.log(" Re-run with --apply to perform it.");return}let Se=await Ws(ke,De,{log:(Re)=>e(Re),audit:(Re)=>z.controlPlane.store.appendEvent({projectId:z.controlPlane.project.id,resourceId:Y.resourceId,type:`${Re.operation}.${Re.step}.${Re.state}`,level:Re.state==="failed"?"error":"info",payload:{target:Re.target,renameTo:t,...Re.error?{error:Re.error}:{}}})});if(m.json)console.log(JSON.stringify({schemaVersion:1,outcome:Se},null,2));if(!Se.success){let Re=Se.steps.find((Pe)=>Pe.state==="failed");throw Error(`${ke.operation} stopped at '${Re?.title}': ${Re?.error}. Earlier steps stayed applied; re-run the same command to continue from here.`)}if(!m.json)n(`Renamed ${Y.name} to ${t}.`)})}function ec(R){R.command("capabilities [server]","Show provider and target operation support").option("--json","Print structured JSON").action(async(t,m)=>{try{await bi(async(k)=>{let I=t?[Wi(k,t)]:k.store.list(k.controlPlane.project.id),L=I.flatMap((z)=>Object.entries(z.capabilities).map(([Y,X])=>({server:z.name,provider:z.provider,action:Y,...X})));if(m.json)console.log(JSON.stringify({schemaVersion:1,targets:L},null,2));else c(["Server","Provider","Action","Support","Explanation"],L.map((z)=>[z.server,z.provider,z.action,z.supported?"supported":"unsupported",z.reason??"—"]))})}catch(k){kn(k)}}),R.command("server:resize <name> <type>","Safely resize Hetzner compute with full host verification").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Execute the reviewed resize plan").option("--confirm <name>","Exact server name required for mutation").option("--upgrade-disk","Permanently expand the root disk to the target size",{default:!0}).option("--wait","Poll capacity without taking the server offline until placement is available").option("--poll-seconds <seconds>","Capacity retry interval",{default:"900"}).option("--max-wait-minutes <minutes>","Stop waiting after this many minutes; 0 waits indefinitely",{default:"0"}).option("--json","Print structured JSON").action(async(t,m,k)=>{try{await Sp(t,m,k)}catch(I){kn(I)}}),R.command("server:optimize <name>","Reconcile and verify a production Hetzner host").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Apply the reviewed host optimization plan").option("--confirm <name>","Exact server name required for mutation").option("--json","Print structured JSON").action(async(t,m)=>{try{await Cp(t,m)}catch(k){kn(k)}}),R.command("server:monitoring <name>","Read historical Hetzner CPU, RAM, swap, disk, and network metrics").option("--env <environment>","Deployment environment",{default:"production"}).option("--range <duration>","Historical window from 5m to 24h",{default:"3h"}).option("--step <seconds>","Hetzner provider sample interval",{default:"60"}).option("--json","Print structured JSON").action(async(t,m)=>{try{await bp(t,m)}catch(k){kn(k)}}),R.command("server:list","List fleet servers").option("--json","Print structured JSON").action(async(t)=>{try{await bi(async(m)=>{let k=m.store.list(m.controlPlane.project.id);if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Provider ID","Provider / region","Status / trust","Roles","CPU / memory","Heartbeat"],k.map((I)=>[I.name,I.providerId??"—",`${I.provider} / ${I.region??"external"}`,`${I.status} / ${I.trustState}`,I.roles.join(","),`${I.capacity.cpu??0} / ${I.capacity.memoryBytes??0}`,I.heartbeatAt??"never"]))})}catch(m){kn(m)}}),R.command("server:create <name>","Enroll a provisioned or existing server").option("--provider <provider>","aws, hetzner, or ssh",{default:"ssh"}).option("--provider-id <id>","Stable provider identity").option("--endpoint <host>","SSH hostname or IP").option("--user <user>","Non-root SSH user",{default:"deploy"}).option("--credential-ref <ref>","Secret reference",{default:"secret://fleet/agent"}).option("--region <region>","Provider region").option("--roles <roles>","Comma-separated roles",{default:"application"}).option("--labels <labels>","Comma-separated key=value labels").action(async(t,m)=>{try{await bi(async(k)=>{let I=m.provider;if(!["aws","hetzner","ssh"].includes(I)||!m.endpoint)throw Error("A supported --provider and --endpoint are required; provisioning and enrollment are separate operations.");let L=k.service.enroll({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,provider:I,providerId:m.providerId,endpoint:m.endpoint,sshUser:m.user??"deploy",credentialRef:m.credentialRef??"secret://fleet/agent",region:m.region,roles:String(m.roles??"application").split(","),labels:Object.fromEntries(String(m.labels??"").split(",").map((z)=>z.split("=")).filter((z)=>z[0]&&z[1]))});n(`Enrolled ${L.name} as ${L.id}; no remote mutation was performed.`)})}catch(k){kn(k)}}),R.command("server:validate <name>","Pin trust and validate a server").option("--accept-host-key <fingerprint>","Accept reviewed rotation").option("--json","Print JSON").action(async(t,m)=>{try{await bi(async(k)=>{let I=Wi(k,t);if(I=await k.service.test(I.id),I.trustState==="rotation_pending"){if(!m.acceptHostKey)throw Error(`Host key changed to ${I.pendingHostKey}; review it first.`);I=k.service.reviewHostKey(I.id,m.acceptHostKey)}let L=await k.service.validate(I.id);if(m.json)console.log(JSON.stringify(L.validation,null,2));else c(["Severity","Code","Finding","Remediation"],(L.validation?.findings??[]).map((z)=>[z.severity,z.code,z.message,z.remediation??"—"]));if(!L.validation?.valid)process.exitCode=1})}catch(k){kn(k)}}),R.command("server:bootstrap <name>","Preview or queue bootstrap").option("--apply","Apply reviewed plan").action(async(t,m)=>{try{await bi(async(k)=>{let I=k.service.bootstrap(Wi(k,t).id,!!m.apply);if(I.preview)c(["Step"],I.steps.map((L)=>[L]));else n(`Bootstrap queued: ${I.operation?.id}`)})}catch(k){kn(k)}}),R.command("server:rename <name> <new-name>","Rename a server in place, without recreating it").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Perform the reviewed rename plan").option("--json","Print structured JSON").action(async(t,m,k)=>{try{await $p(t,m,k)}catch(I){kn(I)}}),R.command("server:drain <name>","Drain without terminating").option("--complete","Mark movement complete").action(async(t,m)=>{try{await bi(async(k)=>n(k.service.drain(Wi(k,t).id,!!m.complete).status))}catch(k){kn(k)}}),R.command("server:uncordon <name>","Return a server to scheduling").action(async(t)=>{try{await bi(async(m)=>{m.service.uncordon(Wi(m,t).id),n(`Uncordoned ${t}.`)})}catch(m){kn(m)}}),R.command("server:archive <name>","Archive inventory without termination").option("--confirm <name>","Exact name").action(async(t,m)=>{try{await bi(async(k)=>{k.service.archive(Wi(k,t).id,m.confirm??""),n(`Archived ${t}; provider infrastructure was not terminated.`)})}catch(k){kn(k)}}),R.command("server:ssh <name>","Open strict SSH using the enrolled endpoint").action(async(t)=>{try{await bi(async(m)=>{let k=Wi(m,t);if(k.trustState!=="pinned")throw Error("Validate and pin the server host key first.");let I=Bun.spawn(["ssh","-p",String(k.sshPort),"-o","StrictHostKeyChecking=yes",`${k.sshUser}@${k.endpoint}`],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}),L=await I.exited;if(L)process.exitCode=L})}catch(m){kn(m)}});for(let[t,m]of[["server:logs <name>","Use the runtime log service"],["server:deploy <name>","Use immutable release deployment"],["server:reboot <name>","Reboot provider compute"],["server:destroy <name>","Terminate provider compute"],["server:recipe <name> <recipe>","Apply a server recipe"],["server:firewall:add <name> <rule>","Add firewall rule"],["server:firewall:list <name>","List firewall rules"],["server:firewall:remove <name> <rule>","Remove firewall rule"],["server:ssl:install <domain>","Install TLS"],["server:ssl:renew <domain>","Renew TLS"],["server:snapshot <name>","Create provider snapshot"],["server:snapshot:restore <name> <snapshot-id>","Restore provider snapshot"],["server:update <name>","Update OS packages"],["server:secure <name>","Apply OS hardening"]])R.command(t,m).action(async(...k)=>En(t.split(" ")[0],{target:String(k[0]??""),nextAction:"Use the dashboard capability view or the corresponding runtime, release, firewall, backup, or maintenance service."}))}import{existsSync as Sd,mkdirSync as kp,readFileSync as Ap,writeFileSync as Rp}from"node:fs";import{join as Cd,resolve as Ip}from"node:path";var tc=(R)=>{r(R instanceof Error?R.message:String(R)),process.exitCode=1};async function Pp(){try{return await Ne()}catch{return}}function xp(R){if(R===void 0)return;let t=Number(R);if(!Number.isInteger(t)||t<1||t>65535)throw Error(`--port must be a port number, not '${R}'.`);return t}function $d(R,t,m){let k=R?.ssh?.hosts?.find((I)=>I.host===t);return new Ir({hosts:t?[k??{host:t}]:R?.ssh?.hosts,user:m.user,port:xp(m.port),privateKeyPath:m.key,hostKey:R?.ssh?.hostKey,sudo:R?.ssh?.sudo,profile:m.profile??R?.ssh?.profile,publicIp:R?.ssh?.publicIp,lan:R?.ssh?.lan})}var kd=1073741824;function nc(R){R.command("ssh:preflight [host]","Check a bring-your-own Linux host before adopting it").option("--user <user>","SSH user (default: ssh.hosts[].user, then root)").option("--port <port>","SSH port (default: ssh.hosts[].port, then 22)").option("--key <path>","SSH private key (default: ssh.hosts[].privateKeyPath, then ~/.ssh/id_ed25519)").option("--profile <profile>","raspberry-pi or generic (default: ssh.profile, then generic)").option("--json","Print the facts and findings as JSON").action(async(t,m)=>{try{let k=await Pp(),I=$d(k,t,m),L=t??I.targetHost(),z=await I.ensureHostKey(L),{facts:Y,findings:X}=await I.preflight(L);if(m.json)console.log(JSON.stringify({schemaVersion:1,host:L,hostKeyFingerprint:z.fingerprint,facts:Y,findings:X},null,2));else{if(i(`Preflight ${L}`),z.pinnedNow)e(`Pinned host key ${z.fingerprint}`);if(e(`${Y.os} on ${Y.arch}, ${Y.cpuCores} cores, ${(Y.memoryBytes/kd).toFixed(1)} GiB memory, ${(Y.diskFreeBytes/kd).toFixed(1)} GiB free`),Y.piModel)e(Y.piModel);if(Y.lanIp)e(`LAN address ${Y.lanIp}`);if(console.log(pn(X)),Rr(X))r("The host is not ready; fix the errors above and run the preflight again.");else n("The host is ready to adopt.")}if(Rr(X))process.exitCode=1}catch(k){tc(k)}}),R.command("ssh:bootstrap","Adopt the configured host: pin its key, run the preflight, then bootstrap it").option("--env <environment>","Deployment environment",{default:"production"}).option("--dry-run","Print the bootstrap script instead of running it").action(async(t)=>{try{let m=await Ne(),k=t.env??"production";if(t.dryRun){let z=Ar(m),[Y]=z.hosts;console.log(wr({config:m,environment:k,profile:z.profile,sudoUser:Y.user!=="root"?Y.user:void 0,lan:z.lan}));return}let I=$d(m,void 0,{});i(`Adopt ${I.targetHost()}`);let L=await I.provisionComputeInfrastructure({config:m,environment:k});n(`${L.appPublicIp} is bootstrapped; deploy with: cloud deploy --env ${k}`)}catch(m){tc(m)}}),R.command("ssh:first-boot","Write cloud-init first-boot files for a freshly flashed Raspberry Pi OS or Ubuntu image").option("--os <os>","raspberry-pi-os or ubuntu",{default:"raspberry-pi-os"}).option("--out <dir>","Directory to write user-data, network-config and meta-data into (never a mounted card; copy them yourself)").option("--hostname <name>","Hostname of the new host").option("--user <user>","Deploy user created on first boot (default: ssh.hosts[].user, then pi)").option("--key <path>","Public key authorized for the user",{default:"~/.ssh/id_ed25519.pub"}).option("--wifi-ssid <ssid>","Join this Wi-Fi network on first boot").option("--wifi-passphrase-env <name>","Environment variable holding the Wi-Fi passphrase",{default:"WIFI_PASSWORD"}).option("--wifi-country <cc>","Wi-Fi regulatory domain, e.g. DE").option("--timezone <tz>","IANA timezone, e.g. Europe/Berlin").option("--locale <locale>","System locale, e.g. en_US.UTF-8").option("--env <environment>","Deployment environment the embedded bootstrap is built for",{default:"production"}).option("--force","Overwrite files already in --out").action(async(t)=>{try{if(!t.out)throw Error("--out <dir> is required.");if(!t.hostname)throw Error("--hostname <name> is required.");let m=t.os??"raspberry-pi-os";if(!(m in bo))throw Error(`--os must be raspberry-pi-os or ubuntu, not '${m}'.`);let k=await Ne(),I=t.env??"production",L=Ar(k,{hosts:k.ssh?.hosts?.length?void 0:[{host:t.hostname}],profile:m==="raspberry-pi-os"?"raspberry-pi":void 0}),z=t.user??(k.ssh?.hosts?.[0]?.user??"pi"),Y=ln(t.key??"~/.ssh/id_ed25519.pub");if(!Sd(Y))throw Error(`Public key not found at ${Y}; pass --key <path to a .pub file>.`);let X=Ap(Y,"utf8").trim(),ne;if(t.wifiSsid){let Ae=t.wifiPassphraseEnv??"WIFI_PASSWORD",le=process.env[Ae];if(!le)throw Error(`--wifi-ssid needs the passphrase in $${Ae} (set it in the environment, not on the command line).`);if(!t.wifiCountry)throw Error("--wifi-country <cc> is required with --wifi-ssid.");ne={ssid:t.wifiSsid,passphrase:le,country:t.wifiCountry}}let re=wr({config:k,environment:I,profile:L.profile,sudoUser:z!=="root"?z:void 0,lan:L.lan}),ie=So({hostname:t.hostname,user:z,publicKey:X,timezone:t.timezone,locale:t.locale,wifi:ne},re,{os:m}),se=Ip(t.out);kp(se,{recursive:!0});let be=Object.keys(ie.files).filter((Ae)=>Sd(Cd(se,Ae)));if(be.length>0&&!t.force)throw Error(`${be.join(", ")} already exist in ${se}; pass --force to overwrite.`);for(let[Ae,le]of Object.entries(ie.files))Rp(Cd(se,Ae),le,{mode:384});i(`First boot for ${t.hostname}`),n(`Wrote ${Object.keys(ie.files).join(", ")} to ${se}`),console.log(ie.instructions)}catch(m){tc(m)}})}async function Dp(){let R=await Ne(),t=y(process.cwd(),R),m=new Bn(t.store),k=new jn(m,new xe(t.store));return{controlPlane:t,store:m,service:k}}async function as(R){let t=await Dp();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}var Vs=(R)=>Object.fromEntries(String(R??"").split(",").map((t)=>t.split("=")).filter((t)=>t[0]&&t[1])),Ad=(R)=>Object.fromEntries(Object.entries(Vs(R)).map(([t,m])=>[t,Number(m)]));function rc(R){R.command("pool:list","List capacity pools and reservations").option("--json","Print structured JSON").action(async(t)=>as((m)=>{let k=m.store.listPools(m.controlPlane.project.id);if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Purpose","Backend","Region / arch","Status","Capacity","Concurrency"],k.map((I)=>[I.name,I.purpose,I.backend,`${I.region??"any"} / ${I.architecture??"any"}`,I.status,JSON.stringify(I.capacity),String(I.concurrency)]))})),R.command("pool:create <name>","Create a capacity pool").option("--purpose <purpose>","application, build, worker, monitoring, or backup",{default:"application"}).option("--backend <backend>","server, ecs, or asg",{default:"server"}).option("--capacity <values>","cpu=4,memoryBytes=8589934592,diskBytes=...").option("--region <region>","Required region").option("--arch <architecture>","Required architecture").option("--labels <labels>","Pool key=value labels").option("--selector <labels>","Required server labels").option("--max <count>","Maximum workloads",{default:"10"}).option("--concurrency <count>","Build concurrency",{default:"1"}).action(async(t,m)=>as((k)=>{let{purpose:I,backend:L}=m;if(!["application","build","worker","monitoring","backup"].includes(I)||!["server","ecs","asg"].includes(L))throw Error("Unsupported pool purpose or backend.");let z=k.store.createPool({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,purpose:I,backend:L,region:m.region,architecture:m.arch,labels:Vs(m.labels),requiredServerLabels:Vs(m.selector),toleratedTaints:[],capacity:{cpu:0,memoryBytes:0,diskBytes:0,gpu:0,...Ad(m.capacity)},maxWorkloads:Number(m.max),costWeight:1,concurrency:Number(m.concurrency),ephemeralWorkspaces:!0,allowProductionSecrets:!1,status:"active"});n(`Created ${z.name} (${z.id}).`)})),R.command("pool:add-server <pool> <server>","Attach an enrolled server to a pool").action(async(t,m)=>as((k)=>{let I=k.store.listPools(k.controlPlane.project.id).find((z)=>z.id===t||z.name===t),L=new xe(k.controlPlane.store).list(k.controlPlane.project.id).find((z)=>z.id===m||z.name===m);if(!I||!L)throw Error("Pool or server was not found.");k.store.addMember(I.id,L.id),n(`Attached ${L.name} to ${I.name}.`)})),R.command("placement:explain","Explain eligible and rejected placement targets").option("--purpose <purpose>","Workload purpose",{default:"application"}).option("--resources <values>","Requested resources").option("--region <region>","Required region").option("--arch <architecture>","Required architecture").option("--labels <labels>","Required pool labels").option("--json","Print structured JSON").action(async(t)=>as((m)=>{let k=m.service.explain(m.controlPlane.project.id,{purpose:t.purpose,resources:Ad(t.resources),region:t.region,architecture:t.arch,labels:Vs(t.labels)});if(t.json)console.log(JSON.stringify(k,null,2));else c(["Pool","Server","Eligible","Available","Fit / spread / cost","Reasons"],k.map((I)=>[I.poolName,I.serverId??"provider-managed",I.eligible?"yes":"no",JSON.stringify(I.available),`${I.score.fit.toFixed(2)} / ${I.score.spread} / ${I.score.cost}`,I.reasons.join("; ")||"eligible"]))})),R.command("pool:drain <pool>","Move stateless placements and block stateful placements").action(async(t)=>as((m)=>{let k=m.store.listPools(m.controlPlane.project.id).find((L)=>L.id===t||L.name===t);if(!k)throw Error("Pool was not found.");let I=m.service.drainPool(k.id);n(`Draining ${k.name}: moved ${I.moved.length}, blocked ${I.blocked.length} stateful placement(s).`)}))}async function Ep(){let R=await Ne(),t=y(process.cwd(),R),m=new Vn(t.store),k=new zn(m);return{controlPlane:t,store:m,service:k}}async function io(R){let t=await Ep();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}var cs=(R,t)=>{let m=R.store.list(R.controlPlane.project.id).find((k)=>k.id===t||k.name===t);if(!m)throw Error("Regional topology was not found.");return m},Tp=(R)=>R.split(",").map((t,m)=>{let[k,I="aws"]=t.split(":");return{region:String(k),provider:I,role:m===0?"primary":"secondary"}}),Np=(R)=>{let t=new Set(["s3","dynamodb","secrets"]),m=R.split(",").map((I)=>I.trim()),k=m.find((I)=>!t.has(I));if(k)throw Error(`Unsupported replication kind: ${k}`);return m};function ic(R){R.command("region:list","List regional topology, traffic, and replication health").option("--json","Print structured JSON").action(async(t)=>io((m)=>{let k=m.store.list(m.controlPlane.project.id).map((I)=>({topology:I,targets:m.store.targets(I.id),channels:m.store.channels(I.id),route:m.store.route(I.id),executions:m.store.executions(I.id)}));if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Hostname","Active","Status","Revision","Replication"],k.map((I)=>[I.topology.name,I.topology.hostname,I.topology.activeRegion,I.topology.status,I.topology.revision??"—",`${I.channels.filter((L)=>L.status==="in_sync").length}/${I.channels.length} in sync`]))})),R.command("region:create <name>","Create a persistent multi-region topology").option("--hostname <hostname>","Traffic hostname").option("--regions <regions>","Comma-separated region[:provider], primary first").option("--replicate <kinds>","s3,dynamodb,secrets",{default:"s3,dynamodb,secrets"}).option("--max-lag <seconds>","Maximum failover lag",{default:"30"}).option("--cdn","Enable CloudFront edge state").option("--waf","Enable WAF edge state").action(async(t,m)=>io((k)=>{if(!m.hostname||!m.regions)throw Error("--hostname and --regions are required.");let I=k.service.create({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,hostname:m.hostname,regions:Tp(m.regions),trafficPolicy:"active_passive",dataPolicy:{replicate:Np(String(m.replicate)),maxLagSeconds:Number(m.maxLag),retainOnDestroy:!0},dnsProvider:"route53",cdnEnabled:!!m.cdn,wafEnabled:!!m.waf});n(`Created ${I.name} (${I.id}); run region:rollout with an immutable manifest.`)})),R.command("region:plan <name> <operation>","Preview exact regional execution steps").option("--target <region>","Failover or failback region").action(async(t,m,k)=>io((I)=>c(["Step"],I.service.plan(cs(I,t).id,m,k.target).map((L)=>[L])))),R.command("region:rollout <name> <revision>","Queue secondary-first regional stack rollout").option("--manifest <file>","Regional stack manifest JSON").action(async(t,m,k)=>io(async(I)=>{let L=k.manifest?await Bun.file(k.manifest).json():{},z=I.service.enqueue({topologyId:cs(I,t).id,kind:"rollout",revision:m,manifest:L});n(`Regional rollout queued: ${z.operation.id}`)})),R.command("region:failover <name> <region>","Queue health and RPO-gated failover").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"failover",targetRegion:m});n(`Failover queued: ${I.operation.id}`)})),R.command("region:failback <name> <region>","Queue health and RPO-gated failback").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"failback",targetRegion:m});n(`Failback queued: ${I.operation.id}`)})),R.command("region:destroy <name>","Drain traffic and delete regional stacks while retaining data").option("--confirm <name>","Exact topology name").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"destroy",confirmation:m.confirm});n(`Regional teardown queued: ${I.operation.id}; replicated data remains retained.`)}))}var ps="0.16.77";async function Lp(){let R=await Ne(),t=y(process.cwd(),R),m=new Hn(t.store),k=new Gn(m),I=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((L)=>new qn(L,t.store,t.project.id,t.organization.id));return{controlPlane:t,store:m,service:k,cleanup:I}}async function Ii(R){let t=await Lp();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}function oc(R){R.command("maintenance:list","List updates, campaigns, cleanup plans, and DR drills").option("--json","Print structured JSON").action(async(t)=>Ii((m)=>{let k={manifests:m.store.manifests(m.controlPlane.organization.id),windows:m.store.windows(m.controlPlane.project.id),campaigns:m.store.campaigns(m.controlPlane.project.id),cleanups:m.store.cleanups(m.controlPlane.project.id),drills:m.store.drills(m.controlPlane.project.id)},I=[...k.manifests.map((L)=>["update",L.version,L.compatibility.compatible?"compatible":"blocked",L.compatibility.reasons.join("; ")||L.channel]),...k.campaigns.map((L)=>["upgrade",L.id,L.status,L.currentStage??L.fromVersion]),...k.cleanups.map((L)=>["cleanup",L.kind,L.status,`${L.candidates.length} items / ${L.estimatedBytes} bytes`]),...k.drills.map((L)=>["DR drill",L.scenario,L.status,L.isolatedTarget])];if(t.json)console.log(JSON.stringify(k,null,2));else c(["Area","Name / version","Status","Detail"],I)})),R.command("maintenance:key:add <name> <pem>","Trust an Ed25519 update signing key").action(async(t,m)=>Ii(async(k)=>{let I=k.store.addTrustedKey({organizationId:k.controlPlane.organization.id,name:t,publicKeyPem:await Bun.file(m).text()});n(`Trusted ${I.name}: ${I.fingerprint}`)})),R.command("maintenance:manifest <document> <signature> <key>","Verify and import a signed update manifest").action(async(t,m,k)=>Ii(async(I)=>{let L=await Bun.file(t).json(),z=(await Bun.file(m).text()).trim(),Y=I.store.importManifest({organizationId:I.controlPlane.organization.id,keyId:k,document:L,signature:z,current:{schemaVersion:I.controlPlane.store.health().schemaVersion,currentVersion:ps,platform:process.platform,architecture:process.arch}});n(`Verified ${Y.version}; ${Y.compatibility.compatible?"compatible":"blocked: "+Y.compatibility.reasons.join("; ")}`)})),R.command("maintenance:window <name> <schedule>","Create an approved maintenance window").option("--timezone <timezone>","IANA timezone",{default:"UTC"}).option("--minutes <minutes>","Duration",{default:"60"}).action(async(t,m,k)=>Ii((I)=>{let L=I.store.createWindow({projectId:I.controlPlane.project.id,name:t,schedule:m,timezone:k.timezone,durationMinutes:Number(k.minutes),allowedOperations:["platform.upgrade"],requireApproval:!0});n(`Created ${L.name} (${L.id}).`)})),R.command("platform:upgrade <manifest> <backup>","Plan and queue a signed staged platform update").option("--strategy <strategy>","canary or rolling",{default:"canary"}).option("--batch <count>","Rolling batch size",{default:"1"}).action(async(t,m,k)=>Ii((I)=>{let L=new xe(I.controlPlane.store).list(I.controlPlane.project.id).filter((X)=>X.status==="ready").map((X)=>({serverId:X.id,target:X.name,previousVersion:X.bootstrapVersion??ps}));if(!L.length)L.push({target:"control-plane",previousVersion:ps});let z=I.store.createCampaign({projectId:I.controlPlane.project.id,manifestId:t,fromVersion:ps,strategy:k.strategy==="rolling"?"rolling":"canary",batchSize:Number(k.batch),healthGate:{kind:"platform"},backupId:m,targets:L}),Y=I.service.enqueueCampaign(z.id);n(`Staged upgrade queued: ${Y.operation.id}`)})),R.command("cleanup:preview <kind>","Discover a bounded cleanup candidate set without deleting").option("--older-than <days>","Minimum age",{default:"30"}).action(async(t,m)=>Ii(async(k)=>{let I=await k.service.previewCleanup({projectId:k.controlPlane.project.id,kind:t,criteria:{olderThanDays:Number(m.olderThan)}},k.cleanup);c(["ID","Candidate","Bytes"],I.candidates.map((L)=>[L.id,L.label,String(L.bytes)])),e(`Apply with: cloud cleanup:apply ${I.id} --confirm "DELETE ${I.candidates.length} ${I.kind}"`)})),R.command("cleanup:apply <plan>","Apply an unchanged cleanup preview").option("--confirm <text>","Exact preview confirmation").action(async(t,m)=>Ii((k)=>{let I=k.service.enqueueCleanup(t,String(m.confirm??""));n(`Cleanup queued: ${I.operation.id}`)})),R.command("dr:plan <scenario> <target>","Plan an isolated disaster-recovery drill").option("--rpo <minutes>","RPO objective",{default:"60"}).option("--rto <minutes>","RTO objective",{default:"30"}).option("--recovery-point <id>","Recovery point").option("--topology <id>","Regional topology").action(async(t,m,k)=>Ii((I)=>{let L=I.store.createDrill({projectId:I.controlPlane.project.id,scenario:t,isolatedTarget:m,expectedRpoMinutes:Number(k.rpo),expectedRtoMinutes:Number(k.rto),recoveryPointId:k.recoveryPoint,topologyId:k.topology});n(`Planned isolated drill ${L.id}.`)})),R.command("dr:run <drill>","Queue an isolated disaster-recovery drill").action(async(t)=>Ii((m)=>{let k=m.service.enqueueDrill(t);n(`DR drill queued: ${k.operation.id}`)}))}async function sc(){try{return(await Ne()).project.region||process.env.AWS_REGION||"us-east-1"}catch{return process.env.AWS_REGION||"us-east-1"}}function ac(R){R.command("function:list","List all Lambda functions").option("--region <region>","AWS region").action(async(t)=>{i("Lambda Functions");let m=t?.region||await sc(),k=new D(m);try{let{Functions:I=[]}=await k.listFunctions({MaxItems:50});if(!I.length){e("No functions found");return}c(["Name","Runtime","Memory","Timeout","Last Modified"],I.map((L)=>[L.FunctionName??"-",L.Runtime??"-",L.MemorySize?`${L.MemorySize} MB`:"-",L.Timeout?`${L.Timeout}s`:"-",L.LastModified??"-"]))}catch(I){r(`Failed to list functions: ${I.message}`),process.exitCode=1}}),R.command("function:invoke <name>","Invoke a Lambda function").option("--payload <json>","Event payload as JSON",{default:"{}"}).option("--async","Fire-and-forget (Event invocation)").option("--region <region>","AWS region").action(async(t,m)=>{i(`Invoking ${t}`);let k=m?.region||await sc(),I=new D(k),L=new s("Invoking function...");L.start();try{let z=await I.invoke({FunctionName:t,InvocationType:m?.async?"Event":"RequestResponse",Payload:m?.payload||"{}",LogType:m?.async?"None":"Tail"});if(z.FunctionError){if(L.fail(`Function returned an error (${z.FunctionError})`),z.Payload)e(z.Payload);process.exitCode=1;return}if(L.succeed(`Invoked (status ${z.StatusCode})`),z.Payload)e(`
|
|
318
|
+
`)}async function yp(){let R=await Ne(),t=y(process.cwd(),R),m=new xe(t.store),k=new Un(m,[new lt("aws"),new lt("hetzner"),new lt("ssh")]);return{controlPlane:t,store:m,service:k}}async function bi(R){let t=await yp();try{return await R(t)}finally{t.controlPlane.store.close()}}var Wi=(R,t)=>{let m=R.store.list(R.controlPlane.project.id).find((k)=>k.id===t||k.name===t);if(!m)throw Error(`Server ${t} was not found.`);return m},kn=(R)=>{r(R instanceof Error?R.message:String(R)),process.exitCode=1};function Xa(R,t){let m=Number.parseInt(R??"",10);return Number.isFinite(m)&&m>=0?m:t}function vp(R="3h"){let t=R.match(/^(\d+)(m|h)$/);if(!t)throw Error("--range must use minutes or hours, for example 30m or 3h.");let m=Number(t[1])*(t[2]==="h"?3600000:60000);if(m<300000||m>86400000)throw Error("--range must be between 5 minutes and 24 hours.");return m}function ss(R,t="%"){return R==null?"unavailable":`${R.toFixed(1)}${t}`}async function bp(R,t){let m=await Ne();if(m.cloud?.provider!=="hetzner")throw Error("server:monitoring currently requires the Hetzner provider.");let k=t.env??process.env.CLOUD_ENV??"production",I=T(m,k),L=await ge(I);if(!L?.serverId)throw Error(`No pinned Hetzner server was found for ${I}.`);if(![L.serverName,String(L.serverId),L.stackName].includes(R))throw Error(`Refusing to read ${R}: project state is pinned to ${L.serverName}.`);let z=St(m),Y=new Oe({apiToken:Cr(z.apiToken,m)}),X=await Y.getServer(L.serverId),ne=L.publicIp??X.public_net.ipv4?.ip;if(!ne)throw Error(`Server ${X.name} has no public IPv4 address.`);let re=new Date,ie=new Date(re.getTime()-vp(t.range)),se=Math.min(3600,Math.max(60,Xa(t.step,60))),be=await yd({client:Y,serverId:X.id,cores:Math.max(1,Number(X.server_type.cores)||1),from:ie,to:re,step:se,remote:{host:ne,user:L.sshUser??z.sshUser,identityFile:z.sshPrivateKeyPath,connectTimeoutSec:15}});if(t.json){console.log(JSON.stringify({schemaVersion:1,server:X.name,result:be},null,2));return}c(["Server","Window","CPU average / peak","RAM average / peak","Minimum available","Swap peak"],[[X.name,`${be.from} to ${be.to}`,`${ss(be.summary.cpuAveragePercent)} / ${ss(be.summary.cpuPeakPercent)}`,`${ss(be.summary.memoryAveragePercent)} / ${ss(be.summary.memoryPeakPercent)}`,be.summary.memoryMinimumAvailableBytes==null?"unavailable":`${(be.summary.memoryMinimumAvailableBytes/1073741824).toFixed(2)} GB`,ss(be.summary.swapPeakPercent)]])}function wd(R){let t=R.targetType.prices?.find((m)=>m.location===R.location);return{serverId:R.serverId,serverName:R.serverName,location:R.location,from:R.currentType.name,to:R.targetType.name,capacityAvailable:R.capacityAvailable,alreadyComplete:R.alreadyComplete,upgradeDisk:R.upgradeDisk,target:{cores:R.targetType.cores,memoryGb:R.targetType.memory,diskGb:R.targetType.disk,architecture:R.targetType.architecture,cpuType:R.targetType.cpu_type},price:t?{hourlyNet:t.price_hourly.net,hourlyGross:t.price_hourly.gross,monthlyNet:t.price_monthly.net,monthlyGross:t.price_monthly.gross}:void 0}}function wp(R){let t=wd(R);c(["Server","Location","Resize","Capacity","CPU / RAM / disk","Monthly"],[[`${t.serverName} (${t.serverId})`,t.location,`${t.from} -> ${t.to}`,t.capacityAvailable?"available":"waiting",`${t.target.cores??0} / ${t.target.memoryGb??0} GB / ${t.target.diskGb??0} GB`,t.price?.monthlyGross??t.price?.monthlyNet??"not reported"]])}async function Sp(R,t,m){let k=await Ne();if(k.cloud?.provider!=="hetzner")throw Error("server:resize currently requires the Hetzner provider.");let I=m.env??process.env.CLOUD_ENV??"production",L=T(k,I),z=await ge(L),Y=St(k),X=new Oe({apiToken:Cr(Y.apiToken,k)}),re=z&&(R===z.serverName||R===String(z.serverId)||R===z.stackName)?await X.getServer(z.serverId):(await X.listServers()).find((Le)=>Le.name===R||String(Le.id)===R);if(!re)throw Error(`Hetzner server ${R} was not found.`);if(z?.serverId&&z.serverId!==re.id)throw Error(`Refusing to resize ${R}: project state is pinned to server ${z.serverId}.`);let ie=tt(t),se=m.upgradeDisk!==!1,be=await rt(X,re.id,ie,se);if(m.json)console.log(JSON.stringify({schemaVersion:1,plan:wd(be)},null,2));else wp(be);if(!m.apply){if(!m.json)e(`Preview only. Re-run with --apply --confirm ${re.name} to execute.`);return}if(m.confirm!==re.name)throw Error(`Resize requires --confirm ${re.name}.`);let Ae=z?.publicIp??re.public_net.ipv4?.ip;if(!Ae)throw Error(`Server ${re.name} has no public IPv4 address for verification.`);let le={host:Ae,user:z?.sshUser??Y.sshUser,identityFile:Y.sshPrivateKeyPath,connectTimeoutSec:15,sshTimeoutMs:600000,routeTimeoutMs:20000},ke=await Os(L),De=new Date().toISOString(),Se={schemaVersion:1,operationId:ke?.targetType===ie&&ke.serverId===re.id?ke.operationId:crypto.randomUUID(),stackName:L,serverId:re.id,serverName:re.name,sourceType:be.currentType.name,targetType:ie,upgradeDisk:se,phase:"planning",status:"running",attempts:ke?.targetType===ie?ke.attempts:0,startedAt:ke?.targetType===ie?ke.startedAt:De,updatedAt:De,manifest:ke?.targetType===ie?ke.manifest:void 0};await Ct(Se);let Re=Xa(m.pollSeconds,900)*1000,Pe=Xa(m.maxWaitMinutes,0)*60000,ze=Date.now();for(;;){let Le=await rt(X,re.id,ie,se);if(!Le.capacityAvailable&&!Le.alreadyComplete){if(Se={...Se,phase:"waiting-capacity",status:"waiting-capacity",updatedAt:new Date().toISOString()},await Ct(Se),!m.wait){if(!m.json)e(`${ie} has no capacity in ${Le.location}. The server remains running and unchanged. Use --wait to poll safely.`);return}if(Pe>0&&Date.now()-ze>=Pe)throw Error(`Timed out waiting for ${ie} capacity in ${Le.location}.`);if(!m.json)e(`Waiting ${Math.round(Re/1000)} seconds for ${ie} capacity...`);await Bun.sleep(Re);continue}let Be=await $s(L);try{let Ve=await(async()=>{try{return Se={...Se,status:"running",attempts:Se.attempts+1,updatedAt:new Date().toISOString()},await Ct(Se),await Tr({client:X,serverId:re.id,targetType:ie,upgradeDisk:se,resumeFromOff:Se.phase==="shutting-down"||Se.phase==="resizing"||Se.phase==="powering-on"||Se.phase==="verifying",manifest:Se.manifest,hooks:{preflight:async()=>{let ct=await wi(le);return Se={...Se,manifest:ct,updatedAt:new Date().toISOString()},await Ct(Se),ct},afterBoot:async(ct,Dt,nt,xt)=>Ai(le,Dt,nt,xt),onPhase:async(ct,Dt)=>{if(Se={...Se,phase:ct,status:ct==="waiting-capacity"?"waiting-capacity":ct==="complete"?"completed":"running",updatedAt:new Date().toISOString()},await Ct(Se),!m.json)e(`${ct}${Dt?` ${JSON.stringify(Dt)}`:""}`)}}})}finally{await Be()}})();if(Se={...Se,status:Ve.status==="completed"||Ve.status==="already-complete"?"completed":Ve.status==="recovered"?"recovered":"waiting-capacity",lastError:Ve.status==="recovered"?Ve.error:void 0,updatedAt:new Date().toISOString()},await Ct(Se),m.json)console.log(JSON.stringify({schemaVersion:1,result:Ve},null,2));else if(Ve.status==="completed"||Ve.status==="already-complete")n(`${re.name} is on ${ie} and passed full post-boot verification.`);else if(Ve.status==="recovered"&&Ve.retryable&&m.wait){e(`Capacity race recovered safely. Waiting ${Math.round(Re/1000)} seconds before retry.`),await Bun.sleep(Re);continue}else if(Ve.status==="recovered")throw Error(`Resize did not complete and the original server was recovered: ${Ve.error}`);return}catch(Ve){throw Se={...Se,status:"failed",lastError:Ve instanceof Error?Ve.message:String(Ve),updatedAt:new Date().toISOString()},await Ct(Se),Ve}}}async function Cp(R,t){let m=await Ne();if(m.cloud?.provider!=="hetzner")throw Error("server:optimize currently requires the Hetzner provider.");let k=t.env??process.env.CLOUD_ENV??"production",I=T(m,k),L=await ge(I);if(!L?.serverId)throw Error(`No pinned Hetzner server was found for ${I}.`);if(![L.serverName,String(L.serverId),L.stackName].includes(R))throw Error(`Refusing to optimize ${R}: project state is pinned to ${L.serverName}.`);let z=St(m),Y=new Oe({apiToken:Cr(z.apiToken,m)}),X=await Y.getServer(L.serverId),ne=L.publicIp??X.public_net.ipv4?.ip;if(!ne)throw Error(`Server ${X.name} has no public IPv4 address.`);let re=vo(m);if(t.json)console.log(JSON.stringify({schemaVersion:1,server:X.name,plan:re},null,2));else c(["Server","Firewall ports","Monitoring","Auto updates","Swap","SSH passwords"],[[X.name,re.firewallPorts.join(","),re.monitoring?"on":"off",re.autoUpdates?"on":"off",`${re.swapGb} GB`,"disabled"]]);if(!t.apply){if(!t.json)e(`Preview only. Re-run with --apply --confirm ${X.name} to execute.`);return}if(t.confirm!==X.name)throw Error(`Optimization requires --confirm ${X.name}.`);let ie={host:ne,user:L.sshUser??z.sshUser,identityFile:z.sshPrivateKeyPath,connectTimeoutSec:15},se=await un(ie),be=se.routeProbes.filter((nt)=>!nt.ok),Ae=m.infrastructure?.compute,le=ee(Ae)?new Set(["nginx.service","bun-gateway.service","ts-cloud-nginx.service"]):new Set,ke=se.failedUnits.filter((nt)=>!le.has(nt));if(ke.length>0)throw Error(`Preflight found failed services: ${ke.join(", ")}`);if(be.length>0)throw Error(`Preflight found unhealthy routes: ${be.map((nt)=>nt.domain).join(", ")}`);let De=ee(Ae)?[]:Object.values(m.sites??{}).flatMap((nt)=>typeof nt?.port==="number"&&![80,443].includes(nt.port)?[nt.port]:[]),Se=dn({allowSsh:Ae?.allowSsh!==!1,sitePorts:De,allowedPorts:Ae?.firewall?.allowedPorts}),Re=(L.firewallId?(await Y.listFirewalls()).find((nt)=>nt.id===L.firewallId):void 0)??(await Y.listFirewalls()).find((nt)=>nt.name===`${m.project.slug}-${k}-app-fw`);if(!Re)throw Error(`Managed firewall for ${X.name} was not found.`);let Pe=await Y.setFirewallRules(Re.id,Se);await Promise.all(Pe.map((nt)=>Y.waitForAction(nt.id))),await Ns(m,ie);let[ze,Le]=await Promise.all([un(ie),xs(ie)]),Be=_s(re,Le),Ve=Vc(se,ze),ct=ze.routeProbes.filter((nt)=>!nt.ok);if(Ve.stoppedServices.length>0)Be.push(`services stopped: ${Ve.stoppedServices.join(", ")}`);if(Ve.changedRouteFragments.length>0)Be.push(`route fragments changed: ${Ve.changedRouteFragments.join(", ")}`);if(Ve.missingRouteIds.length>0)Be.push(`routes disappeared: ${Ve.missingRouteIds.join(", ")}`);if(Ve.changedReleaseLinks.length>0)Be.push(`release links changed: ${Ve.changedReleaseLinks.join(", ")}`);if(Ve.missingData.length>0)Be.push(`databases or volumes disappeared: ${Ve.missingData.join(", ")}`);if(ct.length>0)Be.push(`unhealthy routes: ${ct.map((nt)=>nt.domain).join(", ")}`);if(Be.length>0)throw Error(`Host optimization verification failed: ${Be.join("; ")}`);let Dt={serverId:X.id,serverName:X.name,services:ze.runningServices.length,routes:ze.routeIds.length,healthyDomains:ze.routeProbes.length,releaseLinks:ze.releaseLinks.length,databasesAndVolumes:ze.dataCatalog.length,report:Le};if(t.json)console.log(JSON.stringify({schemaVersion:1,result:Dt},null,2));else n(`${X.name} passed full host, rpx route, service, release, and data verification.`)}async function $p(R,t,m){let k=await Ne(),I=m.env??"production",L=T(k,I);await bi(async(z)=>{let Y=Wi(z,R),X=z.store.list(z.controlPlane.project.id,!0),ne=Y.provider==="hetzner"&&Y.providerId?(()=>{try{let Re=St(k);return new Oe({apiToken:Cr(Re.apiToken,k)})}catch{return null}})():null,re=Y.providerId?Number(Y.providerId):Number.NaN,ie=await ge(L),se=ie!=null&&ie.serverId===re,be=new qr,Ae=Y.trustState==="pinned",le={takenNames:async()=>{let Re=X.map((Pe)=>Pe.name);if(ne)Re.push(...(await ne.listServers()).map((Pe)=>Pe.name));return Re},inventoryName:()=>z.store.get(Y.id)?.name??Y.name,renameInventory:(Re)=>{z.store.update(Y.id,{name:Re})},...ne&&Number.isFinite(re)?{providerName:async()=>(await ne.getServer(re)).name,renameProvider:async(Re)=>{await ne.renameServer(re,Re)}}:{},...se?{stateName:async()=>(await ge(L))?.serverName,writeStateName:async(Re)=>{let Pe=await ge(L);if(Pe)await vt(L,{...Pe,serverName:Re})}}:{},...Ae?{remoteHostname:async()=>{let Re=await be.exec(Y,"hostname");return Re.code===0?Re.stdout.trim():void 0},setRemoteHostname:async(Re)=>{let Pe=await be.exec(Y,bd(Re));if(Pe.code!==0)throw Error(Pe.stderr.trim()||`hostname exited ${Pe.code}`)}}:{}},ke=await vd(Y.name,t,le),De=await zs(ke);if(!m.apply){let Re=[ne?"":"provider record (no provider id or no API token)",se?"":"local state pin (none points at this server)",Ae?"":"box hostname (host key is not pinned — run server:validate first)"].filter(Boolean);if(m.json){console.log(JSON.stringify({schemaVersion:1,operation:ke.operation,target:ke.target,rename:{from:Y.name,to:t},notCovered:Re,steps:De.map((Pe)=>({id:Pe.step.id,title:Pe.step.title,state:Pe.state,change:Pe.step.change,reason:Pe.reason}))},null,2));return}for(let Pe of Us(ke,De))console.log(Pe);for(let Pe of Re)console.log(` not covered: ${Pe}`);console.log(" Re-run with --apply to perform it.");return}let Se=await Ws(ke,De,{log:(Re)=>e(Re),audit:(Re)=>z.controlPlane.store.appendEvent({projectId:z.controlPlane.project.id,resourceId:Y.resourceId,type:`${Re.operation}.${Re.step}.${Re.state}`,level:Re.state==="failed"?"error":"info",payload:{target:Re.target,renameTo:t,...Re.error?{error:Re.error}:{}}})});if(m.json)console.log(JSON.stringify({schemaVersion:1,outcome:Se},null,2));if(!Se.success){let Re=Se.steps.find((Pe)=>Pe.state==="failed");throw Error(`${ke.operation} stopped at '${Re?.title}': ${Re?.error}. Earlier steps stayed applied; re-run the same command to continue from here.`)}if(!m.json)n(`Renamed ${Y.name} to ${t}.`)})}function ec(R){R.command("capabilities [server]","Show provider and target operation support").option("--json","Print structured JSON").action(async(t,m)=>{try{await bi(async(k)=>{let I=t?[Wi(k,t)]:k.store.list(k.controlPlane.project.id),L=I.flatMap((z)=>Object.entries(z.capabilities).map(([Y,X])=>({server:z.name,provider:z.provider,action:Y,...X})));if(m.json)console.log(JSON.stringify({schemaVersion:1,targets:L},null,2));else c(["Server","Provider","Action","Support","Explanation"],L.map((z)=>[z.server,z.provider,z.action,z.supported?"supported":"unsupported",z.reason??"—"]))})}catch(k){kn(k)}}),R.command("server:resize <name> <type>","Safely resize Hetzner compute with full host verification").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Execute the reviewed resize plan").option("--confirm <name>","Exact server name required for mutation").option("--upgrade-disk","Permanently expand the root disk to the target size",{default:!0}).option("--wait","Poll capacity without taking the server offline until placement is available").option("--poll-seconds <seconds>","Capacity retry interval",{default:"900"}).option("--max-wait-minutes <minutes>","Stop waiting after this many minutes; 0 waits indefinitely",{default:"0"}).option("--json","Print structured JSON").action(async(t,m,k)=>{try{await Sp(t,m,k)}catch(I){kn(I)}}),R.command("server:optimize <name>","Reconcile and verify a production Hetzner host").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Apply the reviewed host optimization plan").option("--confirm <name>","Exact server name required for mutation").option("--json","Print structured JSON").action(async(t,m)=>{try{await Cp(t,m)}catch(k){kn(k)}}),R.command("server:monitoring <name>","Read historical Hetzner CPU, RAM, swap, disk, and network metrics").option("--env <environment>","Deployment environment",{default:"production"}).option("--range <duration>","Historical window from 5m to 24h",{default:"3h"}).option("--step <seconds>","Hetzner provider sample interval",{default:"60"}).option("--json","Print structured JSON").action(async(t,m)=>{try{await bp(t,m)}catch(k){kn(k)}}),R.command("server:list","List fleet servers").option("--json","Print structured JSON").action(async(t)=>{try{await bi(async(m)=>{let k=m.store.list(m.controlPlane.project.id);if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Provider ID","Provider / region","Status / trust","Roles","CPU / memory","Heartbeat"],k.map((I)=>[I.name,I.providerId??"—",`${I.provider} / ${I.region??"external"}`,`${I.status} / ${I.trustState}`,I.roles.join(","),`${I.capacity.cpu??0} / ${I.capacity.memoryBytes??0}`,I.heartbeatAt??"never"]))})}catch(m){kn(m)}}),R.command("server:create <name>","Enroll a provisioned or existing server").option("--provider <provider>","aws, hetzner, or ssh",{default:"ssh"}).option("--provider-id <id>","Stable provider identity").option("--endpoint <host>","SSH hostname or IP").option("--user <user>","Non-root SSH user",{default:"deploy"}).option("--credential-ref <ref>","Secret reference",{default:"secret://fleet/agent"}).option("--region <region>","Provider region").option("--roles <roles>","Comma-separated roles",{default:"application"}).option("--labels <labels>","Comma-separated key=value labels").action(async(t,m)=>{try{await bi(async(k)=>{let I=m.provider;if(!["aws","hetzner","ssh"].includes(I)||!m.endpoint)throw Error("A supported --provider and --endpoint are required; provisioning and enrollment are separate operations.");let L=k.service.enroll({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,provider:I,providerId:m.providerId,endpoint:m.endpoint,sshUser:m.user??"deploy",credentialRef:m.credentialRef??"secret://fleet/agent",region:m.region,roles:String(m.roles??"application").split(","),labels:Object.fromEntries(String(m.labels??"").split(",").map((z)=>z.split("=")).filter((z)=>z[0]&&z[1]))});n(`Enrolled ${L.name} as ${L.id}; no remote mutation was performed.`)})}catch(k){kn(k)}}),R.command("server:validate <name>","Pin trust and validate a server").option("--accept-host-key <fingerprint>","Accept reviewed rotation").option("--json","Print JSON").action(async(t,m)=>{try{await bi(async(k)=>{let I=Wi(k,t);if(I=await k.service.test(I.id),I.trustState==="rotation_pending"){if(!m.acceptHostKey)throw Error(`Host key changed to ${I.pendingHostKey}; review it first.`);I=k.service.reviewHostKey(I.id,m.acceptHostKey)}let L=await k.service.validate(I.id);if(m.json)console.log(JSON.stringify(L.validation,null,2));else c(["Severity","Code","Finding","Remediation"],(L.validation?.findings??[]).map((z)=>[z.severity,z.code,z.message,z.remediation??"—"]));if(!L.validation?.valid)process.exitCode=1})}catch(k){kn(k)}}),R.command("server:bootstrap <name>","Preview or queue bootstrap").option("--apply","Apply reviewed plan").action(async(t,m)=>{try{await bi(async(k)=>{let I=k.service.bootstrap(Wi(k,t).id,!!m.apply);if(I.preview)c(["Step"],I.steps.map((L)=>[L]));else n(`Bootstrap queued: ${I.operation?.id}`)})}catch(k){kn(k)}}),R.command("server:rename <name> <new-name>","Rename a server in place, without recreating it").option("--env <environment>","Deployment environment",{default:"production"}).option("--apply","Perform the reviewed rename plan").option("--json","Print structured JSON").action(async(t,m,k)=>{try{await $p(t,m,k)}catch(I){kn(I)}}),R.command("server:drain <name>","Drain without terminating").option("--complete","Mark movement complete").action(async(t,m)=>{try{await bi(async(k)=>n(k.service.drain(Wi(k,t).id,!!m.complete).status))}catch(k){kn(k)}}),R.command("server:uncordon <name>","Return a server to scheduling").action(async(t)=>{try{await bi(async(m)=>{m.service.uncordon(Wi(m,t).id),n(`Uncordoned ${t}.`)})}catch(m){kn(m)}}),R.command("server:archive <name>","Archive inventory without termination").option("--confirm <name>","Exact name").action(async(t,m)=>{try{await bi(async(k)=>{k.service.archive(Wi(k,t).id,m.confirm??""),n(`Archived ${t}; provider infrastructure was not terminated.`)})}catch(k){kn(k)}}),R.command("server:ssh <name>","Open strict SSH using the enrolled endpoint").action(async(t)=>{try{await bi(async(m)=>{let k=Wi(m,t);if(k.trustState!=="pinned")throw Error("Validate and pin the server host key first.");let I=Bun.spawn(["ssh","-p",String(k.sshPort),"-o","StrictHostKeyChecking=yes",`${k.sshUser}@${k.endpoint}`],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}),L=await I.exited;if(L)process.exitCode=L})}catch(m){kn(m)}});for(let[t,m]of[["server:logs <name>","Use the runtime log service"],["server:deploy <name>","Use immutable release deployment"],["server:reboot <name>","Reboot provider compute"],["server:destroy <name>","Terminate provider compute"],["server:recipe <name> <recipe>","Apply a server recipe"],["server:firewall:add <name> <rule>","Add firewall rule"],["server:firewall:list <name>","List firewall rules"],["server:firewall:remove <name> <rule>","Remove firewall rule"],["server:ssl:install <domain>","Install TLS"],["server:ssl:renew <domain>","Renew TLS"],["server:snapshot <name>","Create provider snapshot"],["server:snapshot:restore <name> <snapshot-id>","Restore provider snapshot"],["server:update <name>","Update OS packages"],["server:secure <name>","Apply OS hardening"]])R.command(t,m).action(async(...k)=>En(t.split(" ")[0],{target:String(k[0]??""),nextAction:"Use the dashboard capability view or the corresponding runtime, release, firewall, backup, or maintenance service."}))}import{existsSync as Sd,mkdirSync as kp,readFileSync as Ap,writeFileSync as Rp}from"node:fs";import{join as Cd,resolve as Ip}from"node:path";var tc=(R)=>{r(R instanceof Error?R.message:String(R)),process.exitCode=1};async function Pp(){try{return await Ne()}catch{return}}function xp(R){if(R===void 0)return;let t=Number(R);if(!Number.isInteger(t)||t<1||t>65535)throw Error(`--port must be a port number, not '${R}'.`);return t}function $d(R,t,m){let k=R?.ssh?.hosts?.find((I)=>I.host===t);return new Ir({hosts:t?[k??{host:t}]:R?.ssh?.hosts,user:m.user,port:xp(m.port),privateKeyPath:m.key,hostKey:R?.ssh?.hostKey,sudo:R?.ssh?.sudo,profile:m.profile??R?.ssh?.profile,publicIp:R?.ssh?.publicIp,lan:R?.ssh?.lan})}var kd=1073741824;function nc(R){R.command("ssh:preflight [host]","Check a bring-your-own Linux host before adopting it").option("--user <user>","SSH user (default: ssh.hosts[].user, then root)").option("--port <port>","SSH port (default: ssh.hosts[].port, then 22)").option("--key <path>","SSH private key (default: ssh.hosts[].privateKeyPath, then ~/.ssh/id_ed25519)").option("--profile <profile>","raspberry-pi or generic (default: ssh.profile, then generic)").option("--json","Print the facts and findings as JSON").action(async(t,m)=>{try{let k=await Pp(),I=$d(k,t,m),L=t??I.targetHost(),z=await I.ensureHostKey(L),{facts:Y,findings:X}=await I.preflight(L);if(m.json)console.log(JSON.stringify({schemaVersion:1,host:L,hostKeyFingerprint:z.fingerprint,facts:Y,findings:X},null,2));else{if(i(`Preflight ${L}`),z.pinnedNow)e(`Pinned host key ${z.fingerprint}`);if(e(`${Y.os} on ${Y.arch}, ${Y.cpuCores} cores, ${(Y.memoryBytes/kd).toFixed(1)} GiB memory, ${(Y.diskFreeBytes/kd).toFixed(1)} GiB free`),Y.piModel)e(Y.piModel);if(Y.lanIp)e(`LAN address ${Y.lanIp}`);if(console.log(pn(X)),Rr(X))r("The host is not ready; fix the errors above and run the preflight again.");else n("The host is ready to adopt.")}if(Rr(X))process.exitCode=1}catch(k){tc(k)}}),R.command("ssh:bootstrap","Adopt the configured host: pin its key, run the preflight, then bootstrap it").option("--env <environment>","Deployment environment",{default:"production"}).option("--dry-run","Print the bootstrap script instead of running it").action(async(t)=>{try{let m=await Ne(),k=t.env??"production";if(t.dryRun){let z=Ar(m),[Y]=z.hosts;console.log(wr({config:m,environment:k,profile:z.profile,sudoUser:Y.user!=="root"?Y.user:void 0,lan:z.lan}));return}let I=$d(m,void 0,{});i(`Adopt ${I.targetHost()}`);let L=await I.provisionComputeInfrastructure({config:m,environment:k});n(`${L.appPublicIp} is bootstrapped; deploy with: cloud deploy --env ${k}`)}catch(m){tc(m)}}),R.command("ssh:first-boot","Write cloud-init first-boot files for a freshly flashed Raspberry Pi OS or Ubuntu image").option("--os <os>","raspberry-pi-os or ubuntu",{default:"raspberry-pi-os"}).option("--out <dir>","Directory to write user-data, network-config and meta-data into (never a mounted card; copy them yourself)").option("--hostname <name>","Hostname of the new host").option("--user <user>","Deploy user created on first boot (default: ssh.hosts[].user, then pi)").option("--key <path>","Public key authorized for the user",{default:"~/.ssh/id_ed25519.pub"}).option("--wifi-ssid <ssid>","Join this Wi-Fi network on first boot").option("--wifi-passphrase-env <name>","Environment variable holding the Wi-Fi passphrase",{default:"WIFI_PASSWORD"}).option("--wifi-country <cc>","Wi-Fi regulatory domain, e.g. DE").option("--timezone <tz>","IANA timezone, e.g. Europe/Berlin").option("--locale <locale>","System locale, e.g. en_US.UTF-8").option("--env <environment>","Deployment environment the embedded bootstrap is built for",{default:"production"}).option("--force","Overwrite files already in --out").action(async(t)=>{try{if(!t.out)throw Error("--out <dir> is required.");if(!t.hostname)throw Error("--hostname <name> is required.");let m=t.os??"raspberry-pi-os";if(!(m in bo))throw Error(`--os must be raspberry-pi-os or ubuntu, not '${m}'.`);let k=await Ne(),I=t.env??"production",L=Ar(k,{hosts:k.ssh?.hosts?.length?void 0:[{host:t.hostname}],profile:m==="raspberry-pi-os"?"raspberry-pi":void 0}),z=t.user??(k.ssh?.hosts?.[0]?.user??"pi"),Y=ln(t.key??"~/.ssh/id_ed25519.pub");if(!Sd(Y))throw Error(`Public key not found at ${Y}; pass --key <path to a .pub file>.`);let X=Ap(Y,"utf8").trim(),ne;if(t.wifiSsid){let Ae=t.wifiPassphraseEnv??"WIFI_PASSWORD",le=process.env[Ae];if(!le)throw Error(`--wifi-ssid needs the passphrase in $${Ae} (set it in the environment, not on the command line).`);if(!t.wifiCountry)throw Error("--wifi-country <cc> is required with --wifi-ssid.");ne={ssid:t.wifiSsid,passphrase:le,country:t.wifiCountry}}let re=wr({config:k,environment:I,profile:L.profile,sudoUser:z!=="root"?z:void 0,lan:L.lan}),ie=So({hostname:t.hostname,user:z,publicKey:X,timezone:t.timezone,locale:t.locale,wifi:ne},re,{os:m}),se=Ip(t.out);kp(se,{recursive:!0});let be=Object.keys(ie.files).filter((Ae)=>Sd(Cd(se,Ae)));if(be.length>0&&!t.force)throw Error(`${be.join(", ")} already exist in ${se}; pass --force to overwrite.`);for(let[Ae,le]of Object.entries(ie.files))Rp(Cd(se,Ae),le,{mode:384});i(`First boot for ${t.hostname}`),n(`Wrote ${Object.keys(ie.files).join(", ")} to ${se}`),console.log(ie.instructions)}catch(m){tc(m)}})}async function Dp(){let R=await Ne(),t=y(process.cwd(),R),m=new Bn(t.store),k=new jn(m,new xe(t.store));return{controlPlane:t,store:m,service:k}}async function as(R){let t=await Dp();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}var Vs=(R)=>Object.fromEntries(String(R??"").split(",").map((t)=>t.split("=")).filter((t)=>t[0]&&t[1])),Ad=(R)=>Object.fromEntries(Object.entries(Vs(R)).map(([t,m])=>[t,Number(m)]));function rc(R){R.command("pool:list","List capacity pools and reservations").option("--json","Print structured JSON").action(async(t)=>as((m)=>{let k=m.store.listPools(m.controlPlane.project.id);if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Purpose","Backend","Region / arch","Status","Capacity","Concurrency"],k.map((I)=>[I.name,I.purpose,I.backend,`${I.region??"any"} / ${I.architecture??"any"}`,I.status,JSON.stringify(I.capacity),String(I.concurrency)]))})),R.command("pool:create <name>","Create a capacity pool").option("--purpose <purpose>","application, build, worker, monitoring, or backup",{default:"application"}).option("--backend <backend>","server, ecs, or asg",{default:"server"}).option("--capacity <values>","cpu=4,memoryBytes=8589934592,diskBytes=...").option("--region <region>","Required region").option("--arch <architecture>","Required architecture").option("--labels <labels>","Pool key=value labels").option("--selector <labels>","Required server labels").option("--max <count>","Maximum workloads",{default:"10"}).option("--concurrency <count>","Build concurrency",{default:"1"}).action(async(t,m)=>as((k)=>{let{purpose:I,backend:L}=m;if(!["application","build","worker","monitoring","backup"].includes(I)||!["server","ecs","asg"].includes(L))throw Error("Unsupported pool purpose or backend.");let z=k.store.createPool({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,purpose:I,backend:L,region:m.region,architecture:m.arch,labels:Vs(m.labels),requiredServerLabels:Vs(m.selector),toleratedTaints:[],capacity:{cpu:0,memoryBytes:0,diskBytes:0,gpu:0,...Ad(m.capacity)},maxWorkloads:Number(m.max),costWeight:1,concurrency:Number(m.concurrency),ephemeralWorkspaces:!0,allowProductionSecrets:!1,status:"active"});n(`Created ${z.name} (${z.id}).`)})),R.command("pool:add-server <pool> <server>","Attach an enrolled server to a pool").action(async(t,m)=>as((k)=>{let I=k.store.listPools(k.controlPlane.project.id).find((z)=>z.id===t||z.name===t),L=new xe(k.controlPlane.store).list(k.controlPlane.project.id).find((z)=>z.id===m||z.name===m);if(!I||!L)throw Error("Pool or server was not found.");k.store.addMember(I.id,L.id),n(`Attached ${L.name} to ${I.name}.`)})),R.command("placement:explain","Explain eligible and rejected placement targets").option("--purpose <purpose>","Workload purpose",{default:"application"}).option("--resources <values>","Requested resources").option("--region <region>","Required region").option("--arch <architecture>","Required architecture").option("--labels <labels>","Required pool labels").option("--json","Print structured JSON").action(async(t)=>as((m)=>{let k=m.service.explain(m.controlPlane.project.id,{purpose:t.purpose,resources:Ad(t.resources),region:t.region,architecture:t.arch,labels:Vs(t.labels)});if(t.json)console.log(JSON.stringify(k,null,2));else c(["Pool","Server","Eligible","Available","Fit / spread / cost","Reasons"],k.map((I)=>[I.poolName,I.serverId??"provider-managed",I.eligible?"yes":"no",JSON.stringify(I.available),`${I.score.fit.toFixed(2)} / ${I.score.spread} / ${I.score.cost}`,I.reasons.join("; ")||"eligible"]))})),R.command("pool:drain <pool>","Move stateless placements and block stateful placements").action(async(t)=>as((m)=>{let k=m.store.listPools(m.controlPlane.project.id).find((L)=>L.id===t||L.name===t);if(!k)throw Error("Pool was not found.");let I=m.service.drainPool(k.id);n(`Draining ${k.name}: moved ${I.moved.length}, blocked ${I.blocked.length} stateful placement(s).`)}))}async function Ep(){let R=await Ne(),t=y(process.cwd(),R),m=new Vn(t.store),k=new zn(m);return{controlPlane:t,store:m,service:k}}async function io(R){let t=await Ep();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}var cs=(R,t)=>{let m=R.store.list(R.controlPlane.project.id).find((k)=>k.id===t||k.name===t);if(!m)throw Error("Regional topology was not found.");return m},Tp=(R)=>R.split(",").map((t,m)=>{let[k,I="aws"]=t.split(":");return{region:String(k),provider:I,role:m===0?"primary":"secondary"}}),Np=(R)=>{let t=new Set(["s3","dynamodb","secrets"]),m=R.split(",").map((I)=>I.trim()),k=m.find((I)=>!t.has(I));if(k)throw Error(`Unsupported replication kind: ${k}`);return m};function ic(R){R.command("region:list","List regional topology, traffic, and replication health").option("--json","Print structured JSON").action(async(t)=>io((m)=>{let k=m.store.list(m.controlPlane.project.id).map((I)=>({topology:I,targets:m.store.targets(I.id),channels:m.store.channels(I.id),route:m.store.route(I.id),executions:m.store.executions(I.id)}));if(t.json)console.log(JSON.stringify(k,null,2));else c(["Name","Hostname","Active","Status","Revision","Replication"],k.map((I)=>[I.topology.name,I.topology.hostname,I.topology.activeRegion,I.topology.status,I.topology.revision??"—",`${I.channels.filter((L)=>L.status==="in_sync").length}/${I.channels.length} in sync`]))})),R.command("region:create <name>","Create a persistent multi-region topology").option("--hostname <hostname>","Traffic hostname").option("--regions <regions>","Comma-separated region[:provider], primary first").option("--replicate <kinds>","s3,dynamodb,secrets",{default:"s3,dynamodb,secrets"}).option("--max-lag <seconds>","Maximum failover lag",{default:"30"}).option("--cdn","Enable CloudFront edge state").option("--waf","Enable WAF edge state").action(async(t,m)=>io((k)=>{if(!m.hostname||!m.regions)throw Error("--hostname and --regions are required.");let I=k.service.create({organizationId:k.controlPlane.organization.id,projectId:k.controlPlane.project.id,name:t,hostname:m.hostname,regions:Tp(m.regions),trafficPolicy:"active_passive",dataPolicy:{replicate:Np(String(m.replicate)),maxLagSeconds:Number(m.maxLag),retainOnDestroy:!0},dnsProvider:"route53",cdnEnabled:!!m.cdn,wafEnabled:!!m.waf});n(`Created ${I.name} (${I.id}); run region:rollout with an immutable manifest.`)})),R.command("region:plan <name> <operation>","Preview exact regional execution steps").option("--target <region>","Failover or failback region").action(async(t,m,k)=>io((I)=>c(["Step"],I.service.plan(cs(I,t).id,m,k.target).map((L)=>[L])))),R.command("region:rollout <name> <revision>","Queue secondary-first regional stack rollout").option("--manifest <file>","Regional stack manifest JSON").action(async(t,m,k)=>io(async(I)=>{let L=k.manifest?await Bun.file(k.manifest).json():{},z=I.service.enqueue({topologyId:cs(I,t).id,kind:"rollout",revision:m,manifest:L});n(`Regional rollout queued: ${z.operation.id}`)})),R.command("region:failover <name> <region>","Queue health and RPO-gated failover").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"failover",targetRegion:m});n(`Failover queued: ${I.operation.id}`)})),R.command("region:failback <name> <region>","Queue health and RPO-gated failback").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"failback",targetRegion:m});n(`Failback queued: ${I.operation.id}`)})),R.command("region:destroy <name>","Drain traffic and delete regional stacks while retaining data").option("--confirm <name>","Exact topology name").action(async(t,m)=>io((k)=>{let I=k.service.enqueue({topologyId:cs(k,t).id,kind:"destroy",confirmation:m.confirm});n(`Regional teardown queued: ${I.operation.id}; replicated data remains retained.`)}))}var ps="0.16.78";async function Lp(){let R=await Ne(),t=y(process.cwd(),R),m=new Hn(t.store),k=new Gn(m),I=["releases","artifacts","operations","logs","previews","snapshots","orphaned_resources"].map((L)=>new qn(L,t.store,t.project.id,t.organization.id));return{controlPlane:t,store:m,service:k,cleanup:I}}async function Ii(R){let t=await Lp();try{await R(t)}catch(m){r(m instanceof Error?m.message:String(m)),process.exitCode=1}finally{t.controlPlane.store.close()}}function oc(R){R.command("maintenance:list","List updates, campaigns, cleanup plans, and DR drills").option("--json","Print structured JSON").action(async(t)=>Ii((m)=>{let k={manifests:m.store.manifests(m.controlPlane.organization.id),windows:m.store.windows(m.controlPlane.project.id),campaigns:m.store.campaigns(m.controlPlane.project.id),cleanups:m.store.cleanups(m.controlPlane.project.id),drills:m.store.drills(m.controlPlane.project.id)},I=[...k.manifests.map((L)=>["update",L.version,L.compatibility.compatible?"compatible":"blocked",L.compatibility.reasons.join("; ")||L.channel]),...k.campaigns.map((L)=>["upgrade",L.id,L.status,L.currentStage??L.fromVersion]),...k.cleanups.map((L)=>["cleanup",L.kind,L.status,`${L.candidates.length} items / ${L.estimatedBytes} bytes`]),...k.drills.map((L)=>["DR drill",L.scenario,L.status,L.isolatedTarget])];if(t.json)console.log(JSON.stringify(k,null,2));else c(["Area","Name / version","Status","Detail"],I)})),R.command("maintenance:key:add <name> <pem>","Trust an Ed25519 update signing key").action(async(t,m)=>Ii(async(k)=>{let I=k.store.addTrustedKey({organizationId:k.controlPlane.organization.id,name:t,publicKeyPem:await Bun.file(m).text()});n(`Trusted ${I.name}: ${I.fingerprint}`)})),R.command("maintenance:manifest <document> <signature> <key>","Verify and import a signed update manifest").action(async(t,m,k)=>Ii(async(I)=>{let L=await Bun.file(t).json(),z=(await Bun.file(m).text()).trim(),Y=I.store.importManifest({organizationId:I.controlPlane.organization.id,keyId:k,document:L,signature:z,current:{schemaVersion:I.controlPlane.store.health().schemaVersion,currentVersion:ps,platform:process.platform,architecture:process.arch}});n(`Verified ${Y.version}; ${Y.compatibility.compatible?"compatible":"blocked: "+Y.compatibility.reasons.join("; ")}`)})),R.command("maintenance:window <name> <schedule>","Create an approved maintenance window").option("--timezone <timezone>","IANA timezone",{default:"UTC"}).option("--minutes <minutes>","Duration",{default:"60"}).action(async(t,m,k)=>Ii((I)=>{let L=I.store.createWindow({projectId:I.controlPlane.project.id,name:t,schedule:m,timezone:k.timezone,durationMinutes:Number(k.minutes),allowedOperations:["platform.upgrade"],requireApproval:!0});n(`Created ${L.name} (${L.id}).`)})),R.command("platform:upgrade <manifest> <backup>","Plan and queue a signed staged platform update").option("--strategy <strategy>","canary or rolling",{default:"canary"}).option("--batch <count>","Rolling batch size",{default:"1"}).action(async(t,m,k)=>Ii((I)=>{let L=new xe(I.controlPlane.store).list(I.controlPlane.project.id).filter((X)=>X.status==="ready").map((X)=>({serverId:X.id,target:X.name,previousVersion:X.bootstrapVersion??ps}));if(!L.length)L.push({target:"control-plane",previousVersion:ps});let z=I.store.createCampaign({projectId:I.controlPlane.project.id,manifestId:t,fromVersion:ps,strategy:k.strategy==="rolling"?"rolling":"canary",batchSize:Number(k.batch),healthGate:{kind:"platform"},backupId:m,targets:L}),Y=I.service.enqueueCampaign(z.id);n(`Staged upgrade queued: ${Y.operation.id}`)})),R.command("cleanup:preview <kind>","Discover a bounded cleanup candidate set without deleting").option("--older-than <days>","Minimum age",{default:"30"}).action(async(t,m)=>Ii(async(k)=>{let I=await k.service.previewCleanup({projectId:k.controlPlane.project.id,kind:t,criteria:{olderThanDays:Number(m.olderThan)}},k.cleanup);c(["ID","Candidate","Bytes"],I.candidates.map((L)=>[L.id,L.label,String(L.bytes)])),e(`Apply with: cloud cleanup:apply ${I.id} --confirm "DELETE ${I.candidates.length} ${I.kind}"`)})),R.command("cleanup:apply <plan>","Apply an unchanged cleanup preview").option("--confirm <text>","Exact preview confirmation").action(async(t,m)=>Ii((k)=>{let I=k.service.enqueueCleanup(t,String(m.confirm??""));n(`Cleanup queued: ${I.operation.id}`)})),R.command("dr:plan <scenario> <target>","Plan an isolated disaster-recovery drill").option("--rpo <minutes>","RPO objective",{default:"60"}).option("--rto <minutes>","RTO objective",{default:"30"}).option("--recovery-point <id>","Recovery point").option("--topology <id>","Regional topology").action(async(t,m,k)=>Ii((I)=>{let L=I.store.createDrill({projectId:I.controlPlane.project.id,scenario:t,isolatedTarget:m,expectedRpoMinutes:Number(k.rpo),expectedRtoMinutes:Number(k.rto),recoveryPointId:k.recoveryPoint,topologyId:k.topology});n(`Planned isolated drill ${L.id}.`)})),R.command("dr:run <drill>","Queue an isolated disaster-recovery drill").action(async(t)=>Ii((m)=>{let k=m.service.enqueueDrill(t);n(`DR drill queued: ${k.operation.id}`)}))}async function sc(){try{return(await Ne()).project.region||process.env.AWS_REGION||"us-east-1"}catch{return process.env.AWS_REGION||"us-east-1"}}function ac(R){R.command("function:list","List all Lambda functions").option("--region <region>","AWS region").action(async(t)=>{i("Lambda Functions");let m=t?.region||await sc(),k=new D(m);try{let{Functions:I=[]}=await k.listFunctions({MaxItems:50});if(!I.length){e("No functions found");return}c(["Name","Runtime","Memory","Timeout","Last Modified"],I.map((L)=>[L.FunctionName??"-",L.Runtime??"-",L.MemorySize?`${L.MemorySize} MB`:"-",L.Timeout?`${L.Timeout}s`:"-",L.LastModified??"-"]))}catch(I){r(`Failed to list functions: ${I.message}`),process.exitCode=1}}),R.command("function:invoke <name>","Invoke a Lambda function").option("--payload <json>","Event payload as JSON",{default:"{}"}).option("--async","Fire-and-forget (Event invocation)").option("--region <region>","AWS region").action(async(t,m)=>{i(`Invoking ${t}`);let k=m?.region||await sc(),I=new D(k),L=new s("Invoking function...");L.start();try{let z=await I.invoke({FunctionName:t,InvocationType:m?.async?"Event":"RequestResponse",Payload:m?.payload||"{}",LogType:m?.async?"None":"Tail"});if(z.FunctionError){if(L.fail(`Function returned an error (${z.FunctionError})`),z.Payload)e(z.Payload);process.exitCode=1;return}if(L.succeed(`Invoked (status ${z.StatusCode})`),z.Payload)e(`
|
|
319
319
|
Response:`),e(z.Payload);if(z.LogResult)e(`
|
|
320
320
|
Logs:`),e(Buffer.from(z.LogResult,"base64").toString("utf-8"))}catch(z){L.fail(`Invocation failed: ${z.message}`),process.exitCode=1}}),R.command("function:logs <name>","View recent function logs").option("--tail","Continuously stream new log events").option("--filter <pattern>","CloudWatch filter pattern").option("--since <minutes>","Look back this many minutes",{default:"15"}).option("--region <region>","AWS region").action(async(t,m)=>{i(`Logs for ${t}`);let k=m?.region||await sc(),I=new ae(k),L=t.startsWith("/aws/lambda/")?t:`/aws/lambda/${t}`,z=Number(m?.since??15),Y=(X)=>{for(let ne of X){let re=ne.timestamp?new Date(ne.timestamp).toISOString():"";e(`${re} ${(ne.message??"").trimEnd()}`)}};try{let X=Date.now()-z*60000,{events:ne=[]}=await I.filterLogEvents({logGroupName:L,startTime:X,filterPattern:m?.filter,limit:200});if(Y(ne),ne.length)X=(ne[ne.length-1].timestamp??X)+1;if(m?.tail){e(`
|
|
321
321
|
(streaming — Ctrl+C to stop)`);for(;;){await new Promise((ie)=>setTimeout(ie,3000));let{events:re=[]}=await I.filterLogEvents({logGroupName:L,startTime:X,filterPattern:m?.filter,limit:200});if(re.length)Y(re),X=(re[re.length-1].timestamp??X)+1}}}catch(X){r(`Failed to read logs: ${X.message}`),process.exitCode=1}})}async function Rd(R){let t=Bun.spawn(["docker",...R],{stdin:"inherit",stdout:"inherit",stderr:"pipe"}),[m,k]=await Promise.all([t.exited,new Response(t.stderr).text()]);return{ok:m===0,exitCode:m,command:["docker",...R].join(" "),stderr:k.trim()}}function cc(R){R.command("container:build","Build a Docker image").option("--tag <tag>","Image tag",{default:"latest"}).option("--file <dockerfile>","Dockerfile",{default:"Dockerfile"}).option("--dry-run","Print the exact command").option("--json","Print result JSON").action(async(t)=>{let m=["build","--file",t.file??"Dockerfile","--tag",t.tag??"latest","."];if(t.dryRun){console.log(`docker ${m.join(" ")}`);return}let k=await Rd(m);if(t.json)console.log(JSON.stringify(k));if(!k.ok)r(k.stderr||`docker exited ${k.exitCode}`),process.exitCode=k.exitCode;else n(`Built ${t.tag??"latest"}.`)}),R.command("container:push","Push an already-tagged image").option("--image <image>","Full registry image reference").option("--dry-run","Print command").option("--json","Print JSON").action(async(t)=>{if(!t.image){r("--image with a full registry reference is required; credentials must come from docker credential helpers."),process.exitCode=2;return}if(t.dryRun){console.log(`docker push ${t.image}`);return}let m=await Rd(["push",t.image]);if(t.json)console.log(JSON.stringify(m));if(!m.ok)r(m.stderr),process.exitCode=m.exitCode;else n(`Pushed ${t.image}.`)}),R.command("container:deploy","Deploy a container image").action(async()=>En("container:deploy",{message:"Direct ECS mutation is not registered as a shared release driver.",nextAction:"Import the image as an application and use the immutable release deployment workflow."}))}function lc(R){R.command("domain:list","List all domains").option("--provider <provider>","DNS provider: porkbun, godaddy, cloudflare, or route53").action(async(t)=>{i("Domains");try{let m=Vr(t?.provider),k=bn(t?.provider)?.provider||"unknown",I=new s(`Fetching domains from ${k}...`);I.start();let L=await m.listDomains();if(I.succeed(`Found ${L.length} domain(s)`),L.length===0){e("No domains found in this provider");return}let z=L.map((Y)=>[Y,"Active","-",k.charAt(0).toUpperCase()+k.slice(1)]);c(["Domain","Status","SSL","Provider"],z)}catch(m){r(`Failed to list domains: ${m instanceof Error?m.message:String(m)}`)}}),R.command("domain:add <domain>","Add a new domain").option("--provider <provider>","DNS provider: porkbun, godaddy, cloudflare, or route53").action(async(t,m)=>{i(`Adding Domain: ${t}`);try{let k=Vr(m?.provider),I=bn(m?.provider)?.provider||"unknown",L=new s(`Checking if ${I} can manage ${t}...`);if(L.start(),await k.canManageDomain(t))L.succeed(`Domain ${t} is already available in ${I}`),e(`
|
|
@@ -400,7 +400,7 @@ ${X.instanceId}:`),e(X.output?.trimEnd()||"(no output)")}catch(k){r(`History loo
|
|
|
400
400
|
`),{runComputeRecipe:Y}=await import("./chunk-nzky7rgv.js"),X=await Y({driver:O({config:I}),slug:I.project.slug,environment:L,logger:f},{name:t,script:z,user:k?.user});for(let ne of X.perInstance||[])e(`
|
|
401
401
|
${ne.instanceId}:`),e(ne.output?.trimEnd()||"(no output)");if(!X.success)process.exitCode=1}catch(I){r(`Recipe failed: ${I.message}`),process.exitCode=1}}),R.command("db:restore-backup [from]","Restore the app database from an on-box ts-backups dump (latest, or a given file)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m)=>{i("Database Restore");try{let k=await Ne(),I=m?.env||"production",{restoreDatabaseBackup:L}=await import("./chunk-nzky7rgv.js"),z=await L({driver:O({config:k}),slug:k.project.slug,environment:I,logger:f},{database:A(k),from:t});for(let Y of z.perInstance||[])e(` ${Y.instanceId}: ${Y.output?.trim()||Y.status}`);if(!z.success)r(`Restore failed: ${z.error||"unknown error"}`),process.exitCode=1}catch(k){r(`Restore failed: ${k.message}`),process.exitCode=1}}),R.command("quick-deploy","Generate a push-to-deploy CI pipeline for your git provider (Forge Quick Deploy)").option("--env <environment>","Environment to deploy on push",{default:"production"}).option("--provider <provider>","CI provider (github, gitlab, bitbucket); defaults to the origin remote").option("--site <site>","Deploy only this configured site").option("--skip-dns-verification","Generate a deploy that skips DNS verification and record creation").option("--ssh-key-secret <name>","CI secret/variable containing the Hetzner deployment SSH private key",{default:"SSH_PRIVATE_KEY"}).option("--force","Overwrite an existing pipeline file").action(async(t)=>{i("Quick Deploy (push-to-deploy)");try{let m=await Ne(),{buildQuickDeployCi:k,inferQuickDeployProvider:I}=await import("./chunk-c1znyyca.js"),L=t?.provider?.toLowerCase();if(L&&!["github","gitlab","bitbucket"].includes(L))throw Error(`Unsupported CI provider '${t?.provider}'. Use github, gitlab, or bitbucket.`);let z=L;if(!z)try{let X=dl("git remote get-url origin",{stdio:["ignore","pipe","ignore"]}).toString().trim();z=I(X)}catch{}let Y=k(m,t?.env||"production",{provider:z,site:t?.site,skipDnsVerification:t?.skipDnsVerification,setup:In("pantry.lock")?"pantry":"bun",sshPrivateKeySecret:t?.sshKeySecret});if(!Y){a("Could not resolve a GitHub, GitLab, or Bitbucket provider from --provider, the origin remote, or a configured site repository."),process.exitCode=1;return}if(In(Y.path)&&!t?.force){a(`${Y.path} already exists — re-run with --force to overwrite.`);return}au(Qf(Y.path),{recursive:!0}),Zf(Y.path,Y.content),n(`Wrote ${Y.path} (${Y.provider}, deploys on push to '${Y.branch}').`),e("Next: commit it and add your provider credentials as CI secrets/variables.")}catch(m){r(`Quick deploy setup failed: ${m.message}`),process.exitCode=1}}),R.command("down","Put the serverless app into maintenance mode (503)").option("--env <environment>","Environment (production, staging, development)").option("--secret <secret>","Bypass secret (send as x-maintenance-bypass header)").action(async(t)=>{try{let m=await Ne(),k=t?.env||"production",{setMaintenance:I}=await import("./chunk-nwcpck34.js");await I(m,k,!0,t?.secret)}catch(m){r(`Failed to enable maintenance mode: ${m.message}`),process.exitCode=1}}),R.command("up","Bring the serverless app out of maintenance mode").option("--env <environment>","Environment (production, staging, development)").action(async(t)=>{try{let m=await Ne(),k=t?.env||"production",{setMaintenance:I}=await import("./chunk-nwcpck34.js");await I(m,k,!1)}catch(m){r(`Failed to disable maintenance mode: ${m.message}`),process.exitCode=1}}),R.command("command <cmd>","Run a command on the serverless CLI function (e.g. migrations)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m)=>{try{let k=await Ne(),I=m?.env||"production",{runAndRecordCommand:L}=await import("./chunk-nwcpck34.js"),{id:z,output:Y}=await L(k,I,t);if(e(Y),z>0)e(`
|
|
402
402
|
(recorded as #${z} — re-run with \`cloud command:again ${z}\`)`)}catch(k){r(`Command failed: ${k.message}`),process.exitCode=1}}),R.command("command:history","List recorded CLI-function command invocations").option("--env <environment>","Environment (production, staging, development)").option("--limit <n>","Show at most this many (most recent)",{default:"20"}).action(async(t)=>{try{let m=await Ne(),k=t?.env||"production",{listCommandHistory:I}=await import("./chunk-nwcpck34.js"),L=await I(m,k);if(!L.length){e("No command history yet.");return}let z=Number(t?.limit??20);i(`Command history — ${m.project.slug} (${k})`),c(["#","When","Status","Command"],L.slice(-z).reverse().map((Y)=>[String(Y.id),Y.timestamp,Y.status,Y.command]))}catch(m){r(`Failed to read history: ${m.message}`),process.exitCode=1}}),R.command("command:again [id]","Re-run a recorded command (defaults to the most recent)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m)=>{try{let k=await Ne(),I=m?.env||"production",{getCommandRecord:L,runAndRecordCommand:z}=await import("./chunk-nwcpck34.js"),Y=await L(k,I,t?Number(t):void 0);if(!Y){r(t?`No command #${t} in history.`:"No command history to re-run."),process.exitCode=1;return}e(`Re-running #${Y.id}: ${Y.command}`);let X=await z(k,I,Y.command);if(e(X.output),X.id>0)e(`
|
|
403
|
-
(recorded as #${X.id})`)}catch(k){r(`Command failed: ${k.message}`),process.exitCode=1}}),R.command("serverless:db-shell <sql>","Run a SQL statement against a private serverless database (via the CLI function)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m)=>{try{let k=await Ne(),I=m?.env||"production",{runDbQuery:L}=await import("./chunk-nwcpck34.js"),z=await L(k,I,t);e(z)}catch(k){r(`Query failed: ${k.message}`),process.exitCode=1}}),R.command("serverless:db-scale <min> <max>","Rescale the serverless Aurora cluster (min/max ACUs)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m,k)=>{i("Scaling serverless database");try{let I=await Ne(),L=k?.env||"production",z=Number(t),Y=Number(m);if(!(z>0)||!(Y>=z)){r("Provide valid capacities: min > 0 and max >= min (e.g. `serverless:db-scale 0.5 8`)."),process.exitCode=1;return}let{scaleServerlessDatabase:X}=await import("./chunk-nwcpck34.js");await X(I,L,z,Y)}catch(I){r(`Scale failed: ${I.message}`),process.exitCode=1}}),R.command("serverless:db-restore","Restore the serverless Aurora cluster to a point in time (as a new cluster)").option("--env <environment>","Environment (production, staging, development)").option("--to <timestamp>","Restore to this ISO-8601 time (UTC)").option("--latest","Restore to the latest restorable time").option("--target <id>","New cluster identifier (defaults to <cluster>-restore-<stamp>)").action(async(t)=>{i("Restoring serverless database");try{let m=await Ne(),k=t?.env||"production",I;if(t?.to){if(I=new Date(t.to),Number.isNaN(I.getTime())){r(`Invalid --to timestamp: ${t.to} (use ISO-8601, e.g. 2026-06-18T10:00:00Z).`),process.exitCode=1;return}}let{restoreServerlessDatabase:L}=await import("./chunk-nwcpck34.js");await L(m,k,{toTime:I,latest:t?.latest,target:t?.target})}catch(m){r(`Restore failed: ${m.message}`),process.exitCode=1}}),R.command("serverless:info","Show an operational summary of a deployed serverless app").option("--env <environment>","Environment (production, staging, development)").action(async(t)=>{try{let m=await Ne(),k=t?.env||"production",{serverlessInfo:I}=await import("./chunk-nwcpck34.js"),L=await I(m,k);if(i(`${L.slug} (${L.environment})`),e(`Stack: ${L.stackStatus}`),e(`Region: ${L.region}`),L.endpoint)e(`URL: ${L.endpoint}`);if(L.assetUrl)e(`Assets: ${L.assetUrl}`);if(e(`Scheduler:${L.scheduler==="off"?" off":` ${L.scheduler}`}`),e(`Queues: ${L.queues.length?L.queues.join(", "):"none"}`),e(`Warming: ${L.provisionedConcurrency>0?`provisioned concurrency ×${L.provisionedConcurrency}`:"none / ping-warm"}`),L.lastRelease)e(`Release: ${L.lastRelease.sha.slice(0,12)} @ ${L.lastRelease.timestamp}`);c(["Function","Version","Provisioned"],L.functions.map((z)=>[z.name,z.version,z.provisioned?`${z.provisioned.status} ${z.provisioned.allocated}/${z.provisioned.requested}`:"—"]))}catch(m){r(`Failed to read info: ${m.message}`),process.exitCode=1}}),R.command("dashboard:build","Build the management dashboard with live data baked in").option("--env <environment>","Environment (production, staging, development)").option("--ui <dir>","UI directory (default ./ui)",{default:"ui"}).action(async(t)=>{i("Building management dashboard (live data)");try{let{existsSync:m}=await import("node:fs"),k=t?.ui||"ui";if(!m(`${k}/package.json`)){r(`No UI project at ${k}/ (expected ${k}/package.json). Pass --ui <dir>.`),process.exitCode=1;return}let I=await Ne(),L=t?.env||"production";u("Gathering live data from AWS");let z=null;if(I.environments?.[L]?.app){let{resolveDashboardData:re}=await import("./chunk-8zc4kx6k.js"),ie=await re(I,L).catch((se)=>(a(`Serverless data unavailable (${se.message}) — that view uses sample data.`),null));if(ie)z={...z??{},...ie}}if(I.infrastructure?.compute){let{resolveServerDashboardData:re}=await import("./chunk-
|
|
403
|
+
(recorded as #${X.id})`)}catch(k){r(`Command failed: ${k.message}`),process.exitCode=1}}),R.command("serverless:db-shell <sql>","Run a SQL statement against a private serverless database (via the CLI function)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m)=>{try{let k=await Ne(),I=m?.env||"production",{runDbQuery:L}=await import("./chunk-nwcpck34.js"),z=await L(k,I,t);e(z)}catch(k){r(`Query failed: ${k.message}`),process.exitCode=1}}),R.command("serverless:db-scale <min> <max>","Rescale the serverless Aurora cluster (min/max ACUs)").option("--env <environment>","Environment (production, staging, development)").action(async(t,m,k)=>{i("Scaling serverless database");try{let I=await Ne(),L=k?.env||"production",z=Number(t),Y=Number(m);if(!(z>0)||!(Y>=z)){r("Provide valid capacities: min > 0 and max >= min (e.g. `serverless:db-scale 0.5 8`)."),process.exitCode=1;return}let{scaleServerlessDatabase:X}=await import("./chunk-nwcpck34.js");await X(I,L,z,Y)}catch(I){r(`Scale failed: ${I.message}`),process.exitCode=1}}),R.command("serverless:db-restore","Restore the serverless Aurora cluster to a point in time (as a new cluster)").option("--env <environment>","Environment (production, staging, development)").option("--to <timestamp>","Restore to this ISO-8601 time (UTC)").option("--latest","Restore to the latest restorable time").option("--target <id>","New cluster identifier (defaults to <cluster>-restore-<stamp>)").action(async(t)=>{i("Restoring serverless database");try{let m=await Ne(),k=t?.env||"production",I;if(t?.to){if(I=new Date(t.to),Number.isNaN(I.getTime())){r(`Invalid --to timestamp: ${t.to} (use ISO-8601, e.g. 2026-06-18T10:00:00Z).`),process.exitCode=1;return}}let{restoreServerlessDatabase:L}=await import("./chunk-nwcpck34.js");await L(m,k,{toTime:I,latest:t?.latest,target:t?.target})}catch(m){r(`Restore failed: ${m.message}`),process.exitCode=1}}),R.command("serverless:info","Show an operational summary of a deployed serverless app").option("--env <environment>","Environment (production, staging, development)").action(async(t)=>{try{let m=await Ne(),k=t?.env||"production",{serverlessInfo:I}=await import("./chunk-nwcpck34.js"),L=await I(m,k);if(i(`${L.slug} (${L.environment})`),e(`Stack: ${L.stackStatus}`),e(`Region: ${L.region}`),L.endpoint)e(`URL: ${L.endpoint}`);if(L.assetUrl)e(`Assets: ${L.assetUrl}`);if(e(`Scheduler:${L.scheduler==="off"?" off":` ${L.scheduler}`}`),e(`Queues: ${L.queues.length?L.queues.join(", "):"none"}`),e(`Warming: ${L.provisionedConcurrency>0?`provisioned concurrency ×${L.provisionedConcurrency}`:"none / ping-warm"}`),L.lastRelease)e(`Release: ${L.lastRelease.sha.slice(0,12)} @ ${L.lastRelease.timestamp}`);c(["Function","Version","Provisioned"],L.functions.map((z)=>[z.name,z.version,z.provisioned?`${z.provisioned.status} ${z.provisioned.allocated}/${z.provisioned.requested}`:"—"]))}catch(m){r(`Failed to read info: ${m.message}`),process.exitCode=1}}),R.command("dashboard:build","Build the management dashboard with live data baked in").option("--env <environment>","Environment (production, staging, development)").option("--ui <dir>","UI directory (default ./ui)",{default:"ui"}).action(async(t)=>{i("Building management dashboard (live data)");try{let{existsSync:m}=await import("node:fs"),k=t?.ui||"ui";if(!m(`${k}/package.json`)){r(`No UI project at ${k}/ (expected ${k}/package.json). Pass --ui <dir>.`),process.exitCode=1;return}let I=await Ne(),L=t?.env||"production";u("Gathering live data from AWS");let z=null;if(I.environments?.[L]?.app){let{resolveDashboardData:re}=await import("./chunk-8zc4kx6k.js"),ie=await re(I,L).catch((se)=>(a(`Serverless data unavailable (${se.message}) — that view uses sample data.`),null));if(ie)z={...z??{},...ie}}if(I.infrastructure?.compute){let{resolveServerDashboardData:re}=await import("./chunk-2xtxktj3.js"),ie=await re(I,L).catch(()=>null);if(ie){if(ie._serverReachable===!1)a("Server box not reachable over SSM — server view uses config + sample data.");z={...z??{},...ie}}}u("Building dashboard");let{encodeDashboardPayload:Y}=await import("./chunk-x9dep4ew.js"),{execSync:X}=await import("node:child_process"),{rmSync:ne}=await import("node:fs");for(let re of[".stx/ssg-cache",".stx/cache"])ne(`${k}/${re}`,{recursive:!0,force:!0});X("bun run build",{cwd:k,stdio:"inherit",env:{...process.env,...z?{TSCLOUD_DASHBOARD_DATA:Y(z)}:{}}}),n(`Dashboard built → ${k}/dist${z?" (live data)":" (sample data)"}`)}catch(m){r(`Dashboard build failed: ${m.message}`),process.exitCode=1}}),R.command("serverless:build-php-layer","Build + publish the ts-cloud PHP runtime layer (requires Docker)").option("--arch <architecture>","x86_64 or arm64",{default:"x86_64"}).option("--php <version>","PHP version",{default:"8.3"}).option("--name <name>","Layer name",{default:"tscloud-php"}).option("--bucket <bucket>","S3 bucket to stage the layer zip (defaults to {slug}-layers)").option("--region <region>","AWS region").action(async(t)=>{i("Building PHP runtime layer");try{let m=await Ne().catch(()=>null),k=t?.region||m?.project.region||"us-east-1",I=t?.arch||"x86_64",L=t?.php||"8.3",z=`${t?.name||"tscloud-php"}-${L.replace(".","")}-${I}`,Y=t?.bucket||`${m?.project.slug||"tscloud"}-layers`,{buildPhpRuntimeLayerZip:X}=await import("./chunk-v0fkhtgq.js"),{S3Client:ne}=await import("./chunk-sky689gw.js"),{LambdaClient:re}=await import("./chunk-8esaawk6.js"),ie=X({architecture:I,phpVersion:L,onStep:(ke)=>u(ke)});e(`Layer: ${ie.fileCount} files, ${(ie.zip.length/1024/1024).toFixed(1)} MB`);let se=new ne(k);if(!await se.bucketExists(Y))u(`Creating layer bucket ${Y}`),await se.createBucket(Y);let be=`layers/${z}.zip`;u("Uploading layer zip"),await se.putObject({bucket:Y,key:be,body:ie.zip,contentType:"application/zip"}),u("Publishing layer version");let le=await new re(k).publishLayerVersion({LayerName:z,Description:`ts-cloud PHP ${L} runtime (${I})`,Content:{S3Bucket:Y,S3Key:be},CompatibleRuntimes:["provided.al2023"],CompatibleArchitectures:[I]});Ee(["PHP runtime layer published","",`ARN: ${le.LayerVersionArn}`,"","Reference it in your config:",` app: { kind: 'php', layers: ['${le.LayerVersionArn}'] }`,"or set TSCLOUD_PHP_LAYER_ARN before deploying."].join(`
|
|
404
404
|
`),"green")}catch(m){r(`Layer build failed: ${m.message}`),process.exitCode=1}}),R.command("serverless:build-node-layer","Build + publish a ts-cloud Node custom runtime layer (any version, incl. 24)").option("--arch <architecture>","x86_64 or arm64",{default:"x86_64"}).option("--node <version>","Node version (e.g. 24)",{default:"24"}).option("--name <name>","Layer name",{default:"tscloud-node"}).option("--bucket <bucket>","S3 bucket to stage the layer zip (defaults to {slug}-layers)").option("--region <region>","AWS region").action(async(t)=>{i("Building Node runtime layer");try{let m=await Ne().catch(()=>null),k=t?.region||m?.project.region||"us-east-1",I=t?.arch||"x86_64",L=t?.node||"24",{buildNodeRuntimeLayerZip:z}=await import("./chunk-v0fkhtgq.js"),{S3Client:Y}=await import("./chunk-sky689gw.js"),{LambdaClient:X}=await import("./chunk-8esaawk6.js"),ne=z({architecture:I,version:L,onStep:(ke)=>u(ke)}),re=`${t?.name||"tscloud-node"}-${ne.version.split(".")[0]}-${I}`,ie=t?.bucket||`${m?.project.slug||"tscloud"}-layers`;e(`Layer: Node ${ne.version}, ${(ne.zip.length/1024/1024).toFixed(1)} MB`);let se=new Y(k);if(!await se.bucketExists(ie))u(`Creating layer bucket ${ie}`),await se.createBucket(ie);let be=`layers/${re}.zip`;u("Uploading layer zip"),await se.putObject({bucket:ie,key:be,body:ne.zip,contentType:"application/zip"}),u("Publishing layer version");let le=await new X(k).publishLayerVersion({LayerName:re,Description:`ts-cloud Node ${ne.version} runtime (${I})`,Content:{S3Bucket:ie,S3Key:be},CompatibleRuntimes:["provided.al2023"],CompatibleArchitectures:[I]});Ee(["Node runtime layer published","",`ARN: ${le.LayerVersionArn}`,"","Reference it in your config:",` app: { kind: 'node', runtimeVersion: '${ne.version.split(".")[0]}', layers: ['${le.LayerVersionArn}'] }`,"or set TSCLOUD_NODE_LAYER_ARN before deploying."].join(`
|
|
405
405
|
`),"green")}catch(m){r(`Layer build failed: ${m.message}`),process.exitCode=1}}),R.command("serverless:build-bun-layer","Build + publish a ts-cloud Bun custom runtime layer").option("--arch <architecture>","x86_64 or arm64",{default:"x86_64"}).option("--bun <version>",'Bun version (e.g. 1.3.13, or "latest")',{default:"latest"}).option("--name <name>","Layer name",{default:"tscloud-bun"}).option("--bucket <bucket>","S3 bucket to stage the layer zip (defaults to {slug}-layers)").option("--region <region>","AWS region").action(async(t)=>{i("Building Bun runtime layer");try{let m=await Ne().catch(()=>null),k=t?.region||m?.project.region||"us-east-1",I=t?.arch||"x86_64",L=t?.bun||"latest",{buildBunRuntimeLayerZip:z}=await import("./chunk-v0fkhtgq.js"),{S3Client:Y}=await import("./chunk-sky689gw.js"),{LambdaClient:X}=await import("./chunk-8esaawk6.js"),ne=z({architecture:I,version:L,onStep:(ke)=>u(ke)}),re=`${t?.name||"tscloud-bun"}-${ne.version.replace(/\./g,"")}-${I}`,ie=t?.bucket||`${m?.project.slug||"tscloud"}-layers`;e(`Layer: Bun ${ne.version}, ${(ne.zip.length/1024/1024).toFixed(1)} MB`);let se=new Y(k);if(!await se.bucketExists(ie))u(`Creating layer bucket ${ie}`),await se.createBucket(ie);let be=`layers/${re}.zip`;u("Uploading layer zip"),await se.putObject({bucket:ie,key:be,body:ne.zip,contentType:"application/zip"}),u("Publishing layer version");let le=await new X(k).publishLayerVersion({LayerName:re,Description:`ts-cloud Bun ${ne.version} runtime (${I})`,Content:{S3Bucket:ie,S3Key:be},CompatibleRuntimes:["provided.al2023"],CompatibleArchitectures:[I]});Ee(["Bun runtime layer published","",`ARN: ${le.LayerVersionArn}`,"","Reference it in your config:",` app: { kind: 'bun', layers: ['${le.LayerVersionArn}'] }`,"or set TSCLOUD_BUN_LAYER_ARN before deploying."].join(`
|
|
406
406
|
`),"green")}catch(m){r(`Layer build failed: ${m.message}`),process.exitCode=1}}),R.command("deploy:status","Check deployment status").option("--stack <name>","Stack name").option("--env <environment>","Environment").action(async(t)=>{i("Deployment Status");try{let m=await Ne(),k=t?.env||"production",I=t?.stack||T(m,k),L=m.project.region||"us-east-1";e(`Stack: ${I}`),e(`Region: ${L}`);let z=new s("Checking deployment status...");z.start();let X=await new v(L).describeStacks({stackName:I});if(X.Stacks.length===0){z.fail("Stack not found"),_r("No deployment found for this environment");return}let ne=X.Stacks[0];if(z.succeed("Status retrieved"),e(`
|