@stacksjs/ts-cloud 0.7.23 → 0.7.24
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/cli.js +6 -6
- package/dist/ui/index.html +3 -3
- package/dist/ui/server/actions.html +3 -3
- package/dist/ui/server/backups.html +3 -3
- package/dist/ui/server/database.html +3 -3
- package/dist/ui/server/deployments.html +3 -3
- package/dist/ui/server/firewall.html +3 -3
- package/dist/ui/server/logs.html +3 -3
- package/dist/ui/server/services.html +3 -3
- package/dist/ui/server/sites.html +3 -3
- package/dist/ui/server/ssh-keys.html +3 -3
- package/dist/ui/server/team.html +3 -3
- package/dist/ui/server/terminal.html +3 -3
- package/dist/ui/server/workers.html +3 -3
- package/dist/ui/serverless/alarms.html +3 -3
- package/dist/ui/serverless/assets.html +3 -3
- package/dist/ui/serverless/data.html +3 -3
- package/dist/ui/serverless/deployments.html +3 -3
- package/dist/ui/serverless/functions.html +3 -3
- package/dist/ui/serverless/logs.html +3 -3
- package/dist/ui/serverless/queues.html +3 -3
- package/dist/ui/serverless/scheduler.html +3 -3
- package/dist/ui/serverless/secrets.html +3 -3
- package/dist/ui/serverless/traces.html +3 -3
- package/dist/ui/serverless.html +3 -3
- package/package.json +3 -3
package/dist/bin/cli.js
CHANGED
|
@@ -7576,7 +7576,7 @@ Run \`${this.name??"cli"} --help\` for usage.`;d2.stderr.write(`${G}${Q}${W}
|
|
|
7576
7576
|
`).length-1;this.output.write(M2.move(-999,$*-1))}render(){let $=J4(this._render(this)??"",$4.stdout.columns,{hard:!0,trim:!1});if($===this._prevFrame)return;if(this.state==="initial")this.output.write(M2.hide);else{let J=bV(this._prevFrame,$);if(this.restoreCursor(),J&&J?.length===1){let Y=J[0];this.output.write(M2.move(0,Y)),this.output.write(a5.lines(1));let Z=$.split(`
|
|
7577
7577
|
`);this.output.write(Z[Y]),this._prevFrame=$,this.output.write(M2.move(0,Z.length-Y-1));return}if(J&&J?.length>1){let Y=J[0];this.output.write(M2.move(0,Y)),this.output.write(a5.down());let Q=$.split(`
|
|
7578
7578
|
`).slice(Y);this.output.write(Q.join(`
|
|
7579
|
-
`)),this._prevFrame=$;return}this.output.write(a5.down())}if(this.output.write($),this.state==="initial")this.state="active";this._prevFrame=$}}function dV($,J){if($===void 0)return 0;if(J.length===0)return 0;let Z=J.findIndex((Q)=>Q.value===$);return Z!==-1?Z:0}function cV($,J){return(J.label??String(J.value)).toLowerCase().includes($.toLowerCase())}function mV($,J){if(!J)return;if($)return J;return J[0]}class lV extends JJ{filteredOptions;multiple;isNavigating=!1;selectedValues=[];focusedValue;#$=0;#Y="";#Z;#J;get cursor(){return this.#$}get userInputWithCursor(){if(!this.userInput)return V6.inverse(V6.hidden("_"));if(this._cursor>=this.userInput.length)return`${this.userInput}█`;let $=this.userInput.slice(0,this._cursor),[J,...Y]=this.userInput.slice(this._cursor);return`${$}${V6.inverse(J)}${Y.join("")}`}get options(){if(typeof this.#J==="function")return this.#J();return this.#J}constructor($){super($);this.#J=$.options;let J=this.options;this.filteredOptions=[...J],this.multiple=$.multiple===!0,this.#Z=$.filter??cV;let Y;if($.initialValue&&Array.isArray($.initialValue))if(this.multiple)Y=$.initialValue;else Y=$.initialValue.slice(0,1);else if(!this.multiple&&this.options.length>0)Y=[this.options[0].value];if(Y)for(let Z of Y){let Q=J.findIndex((G)=>G.value===Z);if(Q!==-1)this.toggleSelected(Z),this.#$=Q}this.focusedValue=this.options[this.#$]?.value,this.on("key",(Z,Q)=>this.#Q(Z,Q)),this.on("userInput",(Z)=>this.#G(Z))}_isActionKey($,J){return $==="\t"||this.multiple&&this.isNavigating&&J.name==="space"&&$!==void 0&&$!==""}#Q($,J){let Y=J.name==="up",Z=J.name==="down",Q=J.name==="return";if(Y||Z){if(this.#$=Math.max(0,Math.min(this.#$+(Y?-1:1),this.filteredOptions.length-1)),this.focusedValue=this.filteredOptions[this.#$]?.value,!this.multiple)this.selectedValues=[this.focusedValue];this.isNavigating=!0}else if(Q)this.value=mV(this.multiple,this.selectedValues);else if(this.multiple)if(this.focusedValue!==void 0&&(J.name==="tab"||this.isNavigating&&J.name==="space"))this.toggleSelected(this.focusedValue);else this.isNavigating=!1;else{if(this.focusedValue)this.selectedValues=[this.focusedValue];this.isNavigating=!1}}deselectAll(){this.selectedValues=[]}toggleSelected($){if(this.filteredOptions.length===0)return;if(this.multiple)if(this.selectedValues.includes($))this.selectedValues=this.selectedValues.filter((J)=>J!==$);else this.selectedValues=[...this.selectedValues,$];else this.selectedValues=[$]}#G($){if($!==this.#Y){this.#Y=$;let J=this.options;if($)this.filteredOptions=J.filter((Y)=>this.#Z($,Y));else this.filteredOptions=[...J];if(this.#$=dV(this.focusedValue,this.filteredOptions),this.focusedValue=this.filteredOptions[this.#$]?.value,!this.multiple)if(this.focusedValue!==void 0)this.toggleSelected(this.focusedValue);else this.deselectAll()}}}class pV extends JJ{options;cursor=0;#$;getGroupItems($){return this.options.filter((J)=>J.group===$)}isGroupSelected($){let J=this.getGroupItems($),Y=this.value;if(Y===void 0)return!1;return J.every((Z)=>Y.includes(Z.value))}toggleValue(){let $=this.options[this.cursor];if(this.value===void 0)this.value=[];if($.group===!0){let J=String($.value),Y=this.getGroupItems(J);if(this.isGroupSelected(J))this.value=this.value.filter((Z)=>Y.findIndex((Q)=>Q.value===Z)===-1);else this.value=[...this.value,...Y.map((Z)=>Z.value)];this.value=Array.from(new Set(this.value))}else{let J=this.value.includes($.value);this.value=J?this.value.filter((Y)=>Y!==$.value):[...this.value,$.value]}}constructor($){super($,!1);let{options:J}=$;this.#$=$.selectableGroups!==!1,this.options=Object.entries(J).flatMap(([Y,Z])=>[{value:Y,group:!0,label:Y},...Z.map((Q)=>({...Q,group:Y}))]),this.value=[...$.initialValues??[]],this.cursor=Math.max(this.options.findIndex(({value:Y})=>Y===$.cursorAt),this.#$?0:1),this.on("cursor",(Y)=>{switch(Y){case"left":case"up":{this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;let Z=this.options[this.cursor]?.group===!0;if(!this.#$&&Z)this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break}case"down":case"right":{this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;let Z=this.options[this.cursor]?.group===!0;if(!this.#$&&Z)this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}case"space":this.toggleValue();break}})}}var rV=$V();var P0=($,J)=>rV?$:J,XP=P0("◆","*"),FP=P0("■","x"),KP=P0("▲","x"),BP=P0("◇","o"),VP=P0("┌","T"),nV=P0("│","|"),OP=P0("└","—"),AP=P0("●",">"),_P=P0("○"," "),jP=P0("◻","[•]"),LP=P0("◼","[+]"),MP=P0("◻","[ ]"),EP=P0("▪","•"),qP=P0("─","-"),TP=P0("╮","+"),RP=P0("├","+"),DP=P0("╯","+"),wP=P0("●","•"),NP=P0("◆","*"),PP=P0("▲","!"),SP=P0("■","x");var CP={light:P0("─","-"),heavy:P0("━","="),block:P0("█","#")};function iV(){return`${V6.gray(nV)} `}var xP=iV();var YJ="0.7.
|
|
7579
|
+
`)),this._prevFrame=$;return}this.output.write(a5.down())}if(this.output.write($),this.state==="initial")this.state="active";this._prevFrame=$}}function dV($,J){if($===void 0)return 0;if(J.length===0)return 0;let Z=J.findIndex((Q)=>Q.value===$);return Z!==-1?Z:0}function cV($,J){return(J.label??String(J.value)).toLowerCase().includes($.toLowerCase())}function mV($,J){if(!J)return;if($)return J;return J[0]}class lV extends JJ{filteredOptions;multiple;isNavigating=!1;selectedValues=[];focusedValue;#$=0;#Y="";#Z;#J;get cursor(){return this.#$}get userInputWithCursor(){if(!this.userInput)return V6.inverse(V6.hidden("_"));if(this._cursor>=this.userInput.length)return`${this.userInput}█`;let $=this.userInput.slice(0,this._cursor),[J,...Y]=this.userInput.slice(this._cursor);return`${$}${V6.inverse(J)}${Y.join("")}`}get options(){if(typeof this.#J==="function")return this.#J();return this.#J}constructor($){super($);this.#J=$.options;let J=this.options;this.filteredOptions=[...J],this.multiple=$.multiple===!0,this.#Z=$.filter??cV;let Y;if($.initialValue&&Array.isArray($.initialValue))if(this.multiple)Y=$.initialValue;else Y=$.initialValue.slice(0,1);else if(!this.multiple&&this.options.length>0)Y=[this.options[0].value];if(Y)for(let Z of Y){let Q=J.findIndex((G)=>G.value===Z);if(Q!==-1)this.toggleSelected(Z),this.#$=Q}this.focusedValue=this.options[this.#$]?.value,this.on("key",(Z,Q)=>this.#Q(Z,Q)),this.on("userInput",(Z)=>this.#G(Z))}_isActionKey($,J){return $==="\t"||this.multiple&&this.isNavigating&&J.name==="space"&&$!==void 0&&$!==""}#Q($,J){let Y=J.name==="up",Z=J.name==="down",Q=J.name==="return";if(Y||Z){if(this.#$=Math.max(0,Math.min(this.#$+(Y?-1:1),this.filteredOptions.length-1)),this.focusedValue=this.filteredOptions[this.#$]?.value,!this.multiple)this.selectedValues=[this.focusedValue];this.isNavigating=!0}else if(Q)this.value=mV(this.multiple,this.selectedValues);else if(this.multiple)if(this.focusedValue!==void 0&&(J.name==="tab"||this.isNavigating&&J.name==="space"))this.toggleSelected(this.focusedValue);else this.isNavigating=!1;else{if(this.focusedValue)this.selectedValues=[this.focusedValue];this.isNavigating=!1}}deselectAll(){this.selectedValues=[]}toggleSelected($){if(this.filteredOptions.length===0)return;if(this.multiple)if(this.selectedValues.includes($))this.selectedValues=this.selectedValues.filter((J)=>J!==$);else this.selectedValues=[...this.selectedValues,$];else this.selectedValues=[$]}#G($){if($!==this.#Y){this.#Y=$;let J=this.options;if($)this.filteredOptions=J.filter((Y)=>this.#Z($,Y));else this.filteredOptions=[...J];if(this.#$=dV(this.focusedValue,this.filteredOptions),this.focusedValue=this.filteredOptions[this.#$]?.value,!this.multiple)if(this.focusedValue!==void 0)this.toggleSelected(this.focusedValue);else this.deselectAll()}}}class pV extends JJ{options;cursor=0;#$;getGroupItems($){return this.options.filter((J)=>J.group===$)}isGroupSelected($){let J=this.getGroupItems($),Y=this.value;if(Y===void 0)return!1;return J.every((Z)=>Y.includes(Z.value))}toggleValue(){let $=this.options[this.cursor];if(this.value===void 0)this.value=[];if($.group===!0){let J=String($.value),Y=this.getGroupItems(J);if(this.isGroupSelected(J))this.value=this.value.filter((Z)=>Y.findIndex((Q)=>Q.value===Z)===-1);else this.value=[...this.value,...Y.map((Z)=>Z.value)];this.value=Array.from(new Set(this.value))}else{let J=this.value.includes($.value);this.value=J?this.value.filter((Y)=>Y!==$.value):[...this.value,$.value]}}constructor($){super($,!1);let{options:J}=$;this.#$=$.selectableGroups!==!1,this.options=Object.entries(J).flatMap(([Y,Z])=>[{value:Y,group:!0,label:Y},...Z.map((Q)=>({...Q,group:Y}))]),this.value=[...$.initialValues??[]],this.cursor=Math.max(this.options.findIndex(({value:Y})=>Y===$.cursorAt),this.#$?0:1),this.on("cursor",(Y)=>{switch(Y){case"left":case"up":{this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;let Z=this.options[this.cursor]?.group===!0;if(!this.#$&&Z)this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break}case"down":case"right":{this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;let Z=this.options[this.cursor]?.group===!0;if(!this.#$&&Z)this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}case"space":this.toggleValue();break}})}}var rV=$V();var P0=($,J)=>rV?$:J,XP=P0("◆","*"),FP=P0("■","x"),KP=P0("▲","x"),BP=P0("◇","o"),VP=P0("┌","T"),nV=P0("│","|"),OP=P0("└","—"),AP=P0("●",">"),_P=P0("○"," "),jP=P0("◻","[•]"),LP=P0("◼","[+]"),MP=P0("◻","[ ]"),EP=P0("▪","•"),qP=P0("─","-"),TP=P0("╮","+"),RP=P0("├","+"),DP=P0("╯","+"),wP=P0("●","•"),NP=P0("◆","*"),PP=P0("▲","!"),SP=P0("■","x");var CP={light:P0("─","-"),heavy:P0("━","="),block:P0("█","#")};function iV(){return`${V6.gray(nV)} `}var xP=iV();var YJ="0.7.24";F0();import{existsSync as KJ}from"node:fs";import{mkdir as GO,writeFile as L4}from"node:fs/promises";function BJ($){$.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(J)=>{if(D("Initializing ts-cloud Project"),KJ("cloud.config.ts")){if(!await p("cloud.config.ts already exists. Overwrite?",!1)){F("Initialization cancelled");return}}let Y=J?.name||await D0("Project name","my-app"),Z=J?.mode||await _6("Select deployment mode",["serverless","server"]),Q=J?.region||await _6("Select AWS region",["us-east-1","us-west-2","eu-west-1","eu-central-1","ap-southeast-1"]),G=new P("Creating configuration file...");G.start();let W=`import { defineConfig } from '@ts-cloud/core'
|
|
7580
7580
|
|
|
7581
7581
|
export default defineConfig({
|
|
7582
7582
|
project: {
|
|
@@ -8056,18 +8056,18 @@ This will revoke all access for this team member`),!await p("Remove this team me
|
|
|
8056
8056
|
Team member removed!`),F("All access credentials have been revoked")})}F0();import{existsSync as u1,writeFileSync as aD,copyFileSync as G6,readFileSync as eG,mkdirSync as tD}from"node:fs";import{dirname as sD}from"node:path";_1();k0();z2();b7();G0();class p7{client;region;constructor($="us-east-1",J){this.region=$,this.client=new $0}async describeServices($){let J={cluster:$.cluster,services:$.services};return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DescribeServices","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async listServices($){let J={cluster:$};return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.ListServices","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async listTasks($,J){let Y={cluster:$};if(J)Y.serviceName=J;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.ListTasks","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(Y)})}async describeTasks($,J){let Y={cluster:$,tasks:J};return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DescribeTasks","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(Y)})}async updateService($){let J={cluster:$.cluster,service:$.service};if($.forceNewDeployment!==void 0)J.forceNewDeployment=$.forceNewDeployment;if($.desiredCount!==void 0)J.desiredCount=$.desiredCount;if($.taskDefinition)J.taskDefinition=$.taskDefinition;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.UpdateService","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async createService($){let J={cluster:$.cluster,serviceName:$.serviceName,taskDefinition:$.taskDefinition,desiredCount:$.desiredCount};if($.launchType)J.launchType=$.launchType;if($.networkConfiguration)J.networkConfiguration=$.networkConfiguration;if($.loadBalancers)J.loadBalancers=$.loadBalancers;if($.healthCheckGracePeriodSeconds!==void 0)J.healthCheckGracePeriodSeconds=$.healthCheckGracePeriodSeconds;if($.deploymentConfiguration)J.deploymentConfiguration=$.deploymentConfiguration;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.CreateService","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async deleteService($){let J={cluster:$.cluster,service:$.service};if($.force!==void 0)J.force=$.force;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DeleteService","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async listClusters(){return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.ListClusters","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify({})})}async describeClusters($){let J={clusters:$,include:["ATTACHMENTS","CONFIGURATIONS","SETTINGS","STATISTICS","TAGS"]};return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DescribeClusters","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async stopTask($){let J={cluster:$.cluster,task:$.task};if($.reason)J.reason=$.reason;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.StopTask","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async runTask($){let J={cluster:$.cluster,taskDefinition:$.taskDefinition};if($.count!==void 0)J.count=$.count;if($.launchType)J.launchType=$.launchType;if($.networkConfiguration)J.networkConfiguration=$.networkConfiguration;if($.overrides)J.overrides=$.overrides;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.RunTask","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async registerTaskDefinition($){return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.RegisterTaskDefinition","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify($)})}async deregisterTaskDefinition($){return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DeregisterTaskDefinition","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify({taskDefinition:$})})}async describeTaskDefinition($){return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify({taskDefinition:$,include:["TAGS"]})})}async listTaskDefinitionFamilies($){let J={};if($?.familyPrefix)J.familyPrefix=$.familyPrefix;if($?.status)J.status=$.status;return await this.client.request({service:"ecs",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(J)})}async waitForServiceStable($,J,Y=40,Z=15000){for(let Q=0;Q<Y;Q++){let W=(await this.describeServices({cluster:$,services:[J]})).services?.[0];if(W){let z=W.deployments?.find((U)=>U.status==="PRIMARY");if(z&&z.runningCount===z.desiredCount&&W.deployments?.length===1)return!0}await new Promise((z)=>setTimeout(z,Z))}return!1}async forceNewDeployment($,J){return this.updateService({cluster:$,service:J,forceNewDeployment:!0})}async scaleService($,J,Y){return this.updateService({cluster:$,service:J,desiredCount:Y})}}r7();G0();import{execSync as $W}from"node:child_process";import{tmpdir as oD}from"node:os";import{join as eD}from"node:path";b9();B2();import{existsSync as ST,readdirSync as CT,readFileSync as xT,statSync as IT}from"node:fs";import{join as kT,relative as hT,extname as bT}from"node:path";var yT=[{name:"AWS Access Key ID",pattern:/(?:^|[^A-Z0-9])((AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16})(?:[^A-Z0-9]|$)/g,severity:"critical",description:"AWS Access Key ID detected"},{name:"AWS Secret Access Key",pattern:/(?:aws_secret_access_key|aws_secret_key|secret_access_key|secretAccessKey)\s*[=:]\s*['"]?([A-Za-z0-9/+=]{40})['"]?/gi,severity:"critical",description:"AWS Secret Access Key detected"},{name:"AWS Secret Key (Generic)",pattern:/(?:^|['"`:=\s])([A-Za-z0-9/+=]{40})(?:['"`\s]|$)/g,severity:"high",description:"Potential AWS Secret Key (40-char base64)"},{name:"Generic API Key",pattern:/(?:api[_-]?key|apikey|api[_-]?secret)\s*[=:]\s*['"]?([A-Za-z0-9_\-]{20,})['"]?/gi,severity:"high",description:"Generic API key detected"},{name:"RSA Private Key",pattern:/-----BEGIN RSA PRIVATE KEY-----/g,severity:"critical",description:"RSA private key detected"},{name:"OpenSSH Private Key",pattern:/-----BEGIN OPENSSH PRIVATE KEY-----/g,severity:"critical",description:"OpenSSH private key detected"},{name:"EC Private Key",pattern:/-----BEGIN EC PRIVATE KEY-----/g,severity:"critical",description:"EC private key detected"},{name:"PGP Private Key",pattern:/-----BEGIN PGP PRIVATE KEY BLOCK-----/g,severity:"critical",description:"PGP private key detected"},{name:"GitHub Token",pattern:/(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/g,severity:"critical",description:"GitHub personal access token detected"},{name:"GitHub OAuth",pattern:/github[_-]?oauth[_-]?token\s*[=:]\s*['"]?([A-Za-z0-9_]{40})['"]?/gi,severity:"critical",description:"GitHub OAuth token detected"},{name:"Slack Token",pattern:/xox[baprs]-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*/g,severity:"critical",description:"Slack token detected"},{name:"Slack Webhook",pattern:/https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g,severity:"high",description:"Slack webhook URL detected"},{name:"Discord Webhook",pattern:/https:\/\/discord(?:app)?\.com\/api\/webhooks\/[0-9]+\/[A-Za-z0-9_-]+/g,severity:"high",description:"Discord webhook URL detected"},{name:"JWT Token",pattern:/eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*/g,severity:"high",description:"JWT token detected"},{name:"Google API Key",pattern:/AIza[0-9A-Za-z_-]{35}/g,severity:"critical",description:"Google API key detected"},{name:"Google OAuth ID",pattern:/[0-9]+-[A-Za-z0-9_]{32}\.apps\.googleusercontent\.com/g,severity:"high",description:"Google OAuth client ID detected"},{name:"Firebase API Key",pattern:/(?:firebase[_-]?api[_-]?key)\s*[=:]\s*['"]?([A-Za-z0-9_-]{39})['"]?/gi,severity:"critical",description:"Firebase API key detected"},{name:"Cloudflare API Token",pattern:/(?:cloudflare[_-]?api[_-]?token|cf[_-]?api[_-]?token)\s*[=:]\s*['"]?([A-Za-z0-9_-]{40})['"]?/gi,severity:"critical",description:"Cloudflare API token detected"},{name:"Azure Client Secret",pattern:/(?:azure[_-]?client[_-]?secret|client[_-]?secret)\s*[=:]\s*['"]?([A-Za-z0-9~._-]{34,})['"]?/gi,severity:"critical",description:"Azure client secret detected"},{name:"Heroku API Key",pattern:/(?:heroku[_-]?api[_-]?key)\s*[=:]\s*['"]?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})['"]?/gi,severity:"critical",description:"Heroku API key detected"},{name:"Database Connection String",pattern:/(?:mysql|postgres|postgresql|mongodb|redis|mongodb\+srv):\/\/[^:]+:[^@]+@[^/\s]+/gi,severity:"critical",description:"Database connection string with credentials detected"},{name:"Database Password",pattern:/(?:db[_-]?password|database[_-]?password|mysql[_-]?password|postgres[_-]?password)\s*[=:]\s*['"]?([^'"\s]{8,})['"]?/gi,severity:"critical",description:"Database password detected"},{name:"Stripe API Key",pattern:/(?:sk|pk)_(?:test|live)_[0-9a-zA-Z]{24,}/g,severity:"critical",description:"Stripe API key detected"},{name:"PayPal Client ID",pattern:/(?:paypal[_-]?client[_-]?id)\s*[=:]\s*['"]?([A-Za-z0-9_-]{80})['"]?/gi,severity:"high",description:"PayPal client ID detected"},{name:"Square Access Token",pattern:/sq0[a-z]{3}-[0-9A-Za-z_-]{22,}/g,severity:"critical",description:"Square access token detected"},{name:"Twilio API Key",pattern:/SK[a-f0-9]{32}/g,severity:"critical",description:"Twilio API key detected"},{name:"SendGrid API Key",pattern:/SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/g,severity:"critical",description:"SendGrid API key detected"},{name:"Mailgun API Key",pattern:/key-[0-9a-zA-Z]{32}/g,severity:"critical",description:"Mailgun API key detected"},{name:"Password in Code",pattern:/(?:password|passwd|pwd)\s*[=:]\s*['"]([^'"]{8,})['"](?!\s*[,\]])/gi,severity:"high",description:"Hardcoded password detected"},{name:"Secret/Token Assignment",pattern:/(?:secret|token|auth[_-]?token|access[_-]?token)\s*[=:]\s*['"]([A-Za-z0-9_\-/+=]{16,})['"](?!\s*[,\]])/gi,severity:"high",description:"Hardcoded secret or token detected"},{name:"NPM Token",pattern:/(?:npm[_-]?token)\s*[=:]\s*['"]?([A-Za-z0-9_-]{36})['"]?/gi,severity:"critical",description:"NPM token detected"},{name:"SSH Private Key Path Exposed",pattern:/~\/\.ssh\/id_[a-z]+|\/home\/[^/]+\/\.ssh\/id_[a-z]+/g,severity:"medium",description:"SSH private key path exposed"},{name:"Env Variable with Secret",pattern:/(?:process\.env\.)((?=[A-Z_]*(?:SECRET|KEY|TOKEN|PASSWORD|CREDENTIAL|AUTH))[A-Z_]+)\s*(?:===?\s*['"]([^'"]+)['"])?/g,severity:"medium",description:"Environment variable containing secret may be exposed"}],vT=[".js",".jsx",".ts",".tsx",".mjs",".cjs",".vue",".svelte",".html",".htm",".css",".scss",".less",".json",".yaml",".yml",".toml",".xml",".env",".config",".conf"],fT=["node_modules",".git",".svn",".hg","dist","build","coverage",".nyc_output","__pycache__",".pytest_cache","vendor",".idea",".vscode",".turbo",".next",".nuxt","pantry",".pantry","tests","test","__tests__","spec","__mocks__",".github",".gitlab",".circleci"],gT=["package-lock.json","yarn.lock","pnpm-lock.yaml","bun.lockb","bun.lock","*.min.js","*.min.css","*.map","*.d.ts","*.test.ts","*.test.js","*.spec.ts","*.spec.js",".env",".env.*"];class mQ{patterns;excludeDirs;excludeFiles;maxFileSize;constructor($){this.patterns=[...yT,...$?.customPatterns||[]],this.excludeDirs=[...fT,...$?.excludeDirs||[]],this.excludeFiles=[...gT,...$?.excludeFiles||[]],this.maxFileSize=$?.maxFileSize||1048576}async scan($){let J=Date.now(),Y=[],Z=0,{directory:Q,exclude:G=[],include:W,skipPatterns:z=[]}=$,U=$.failOnSeverity||"critical";if(!ST(Q))throw Error(`Directory not found: ${Q}`);let H=this.getFilesToScan(Q,[...this.excludeDirs,...G],W);for(let O of H){let A=hT(Q,O);if(this.shouldExcludeFile(A))continue;try{if(IT(O).size>this.maxFileSize)continue;let M=xT(O,"utf-8"),j=this.scanContent(M,A,z);Y.push(...j),Z++}catch{continue}}let X={critical:Y.filter((O)=>O.pattern.severity==="critical").length,high:Y.filter((O)=>O.pattern.severity==="high").length,medium:Y.filter((O)=>O.pattern.severity==="medium").length,low:Y.filter((O)=>O.pattern.severity==="low").length},K=["low","medium","high","critical"],B=K.indexOf(U),V=!0;for(let O=B;O<K.length;O++)if(X[K[O]]>0){V=!1;break}return{passed:V,findings:Y,scannedFiles:Z,duration:Date.now()-J,summary:X}}scanContent($,J,Y){let Z=[],Q=$.split(`
|
|
8057
8057
|
`);for(let G of this.patterns){if(Y.includes(G.name))continue;G.pattern.lastIndex=0;let W;while((W=G.pattern.exec($))!==null){let z=$.substring(0,W.index),U=z.split(`
|
|
8058
8058
|
`).length,H=z.lastIndexOf(`
|
|
8059
|
-
`),X=W.index-H,K=Q[U-1]||"";if(this.isLikelyPlaceholder(W[0],K))continue;if(this.isLowEntropy(W[1]||W[0]))continue;Z.push({file:J,line:U,column:X,match:this.maskSecret(W[0]),pattern:G,context:this.maskSecret(K.trim())})}}return Z}isLikelyPlaceholder($,J){let Y=["example","placeholder","your_","YOUR_","xxx","XXX","***","test","TEST","dummy","DUMMY","fake","FAKE","sample","SAMPLE","<your","${","{{","process.env","import.meta.env","CHANGEME","TODO","FIXME"],Z=$.toLowerCase(),Q=J.toLowerCase();for(let W of Y)if(Z.includes(W.toLowerCase())||Q.includes(W.toLowerCase()))return!0;let G=J.trim();if(G.startsWith("//")||G.startsWith("#")||G.startsWith("*")||G.startsWith("/*")){if(Q.includes("example")||Q.includes("format:")||Q.includes("e.g."))return!0}return!1}isLowEntropy($){if($.length<8)return!1;if(new Set($).size<8)return!0;if(/(.)\1{3,}/.test($))return!0;return!1}maskSecret($){if($.length<=8)return"*".repeat($.length);let J=Math.min(4,Math.floor($.length*0.2));return $.substring(0,J)+"*".repeat($.length-J*2)+$.substring($.length-J)}getFilesToScan($,J,Y){let Z=[],Q=Y||vT,G=(W)=>{let z=CT(W,{withFileTypes:!0});for(let U of z){let H=kT(W,U.name);if(U.isDirectory()){if(!J.includes(U.name))G(H)}else if(U.isFile()){let X=bT(U.name).toLowerCase();if(Q.includes(X)||U.name.startsWith(".env")||U.name.endsWith(".config"))Z.push(H)}}};return G($),Z}shouldExcludeFile($){let J=$.split("/").pop()||"";for(let Y of this.excludeFiles)if(Y.startsWith("*")){let Z=Y.substring(1);if(J.endsWith(Z))return!0}else if(Y.endsWith("*")){let Z=Y.substring(0,Y.length-1);if(J.startsWith(Z))return!0}else if(J===Y)return!0;return!1}addPattern($){this.patterns.push($)}getPatterns(){return[...this.patterns]}}z2();F0();function uT($){if(!$)return[];if(Array.isArray($))return $.map(String);let J=$,Y=J.Items??J.Item;if(!Y)return[];if(Array.isArray(Y))return Y.map(String);if(typeof Y==="object"&&Y!==null){let Z=Y;if("Item"in Z){let Q=Z.Item;if(!Q)return[];return Array.isArray(Q)?Q.map(String):[String(Q)]}if("CNAME"in Z){let Q=Z.CNAME;if(!Q)return[];return Array.isArray(Q)?Q.map(String):[String(Q)]}return Object.values(Z).flatMap((Q)=>{if(Array.isArray(Q))return Q.map(String);return typeof Q==="string"?[Q]:[]})}return[String(Y)]}async function t7($){if($.length===0)return;let J=new E0,Y=await J.listDistributions(),Z=[...new Set($.map((Q)=>Q.toLowerCase()))];for(let Q of Z){let G=Y.find((z)=>{return uT(z.Aliases).some((H)=>H.toLowerCase()===Q)});if(!G?.Id){d(`No CloudFront distribution found for ${Q} — skipping dynamic HTTP method sync`);continue}if(await J.ensureDynamicHttpMethods(G.Id))f(`CloudFront ${G.Id} (${Q}): enabled POST/PUT/PATCH/DELETE on dynamic paths`);else F(`CloudFront ${G.Id} (${Q}): already allows dynamic HTTP methods`)}}await u2([f0(),I$(),fG()]);import{execSync as AD}from"node:child_process";async function _D($,J,Y,Z={},Q=process.cwd()){if(!$)return;if(Z.step?.(`Running ${Y} hook`),typeof $==="string"){AD($,{stdio:"inherit",cwd:Q});return}await $(J)}async function $6($,J,Y={},Z){try{return await _D($.hooks?.[J],$,J,Y,Z),!0}catch(Q){return Y.error?.(`${J} hook failed: ${Q?.message||Q}`),!1}}await G$();async function $w($){let J=WJ();if(J.emptyEnvKey||J.emptyEnvSecret)d("Empty AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY env var detected — likely a misconfigured .env file. Remove the empty lines or fill them in.");F(`AWS credentials: ${J.description}`);try{let Z=await new k9($).getCallerIdentity();if(Z.Arn)F(`AWS identity: ${Z.Arn}`)}catch(Y){d(`Could not verify AWS identity: ${Y.message}`)}}function Jw(){try{return $W("git rev-parse --short HEAD",{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{return Date.now().toString(36)}}async function oG($,J,Y){let{ensureManagementDashboard:
|
|
8059
|
+
`),X=W.index-H,K=Q[U-1]||"";if(this.isLikelyPlaceholder(W[0],K))continue;if(this.isLowEntropy(W[1]||W[0]))continue;Z.push({file:J,line:U,column:X,match:this.maskSecret(W[0]),pattern:G,context:this.maskSecret(K.trim())})}}return Z}isLikelyPlaceholder($,J){let Y=["example","placeholder","your_","YOUR_","xxx","XXX","***","test","TEST","dummy","DUMMY","fake","FAKE","sample","SAMPLE","<your","${","{{","process.env","import.meta.env","CHANGEME","TODO","FIXME"],Z=$.toLowerCase(),Q=J.toLowerCase();for(let W of Y)if(Z.includes(W.toLowerCase())||Q.includes(W.toLowerCase()))return!0;let G=J.trim();if(G.startsWith("//")||G.startsWith("#")||G.startsWith("*")||G.startsWith("/*")){if(Q.includes("example")||Q.includes("format:")||Q.includes("e.g."))return!0}return!1}isLowEntropy($){if($.length<8)return!1;if(new Set($).size<8)return!0;if(/(.)\1{3,}/.test($))return!0;return!1}maskSecret($){if($.length<=8)return"*".repeat($.length);let J=Math.min(4,Math.floor($.length*0.2));return $.substring(0,J)+"*".repeat($.length-J*2)+$.substring($.length-J)}getFilesToScan($,J,Y){let Z=[],Q=Y||vT,G=(W)=>{let z=CT(W,{withFileTypes:!0});for(let U of z){let H=kT(W,U.name);if(U.isDirectory()){if(!J.includes(U.name))G(H)}else if(U.isFile()){let X=bT(U.name).toLowerCase();if(Q.includes(X)||U.name.startsWith(".env")||U.name.endsWith(".config"))Z.push(H)}}};return G($),Z}shouldExcludeFile($){let J=$.split("/").pop()||"";for(let Y of this.excludeFiles)if(Y.startsWith("*")){let Z=Y.substring(1);if(J.endsWith(Z))return!0}else if(Y.endsWith("*")){let Z=Y.substring(0,Y.length-1);if(J.startsWith(Z))return!0}else if(J===Y)return!0;return!1}addPattern($){this.patterns.push($)}getPatterns(){return[...this.patterns]}}z2();F0();function uT($){if(!$)return[];if(Array.isArray($))return $.map(String);let J=$,Y=J.Items??J.Item;if(!Y)return[];if(Array.isArray(Y))return Y.map(String);if(typeof Y==="object"&&Y!==null){let Z=Y;if("Item"in Z){let Q=Z.Item;if(!Q)return[];return Array.isArray(Q)?Q.map(String):[String(Q)]}if("CNAME"in Z){let Q=Z.CNAME;if(!Q)return[];return Array.isArray(Q)?Q.map(String):[String(Q)]}return Object.values(Z).flatMap((Q)=>{if(Array.isArray(Q))return Q.map(String);return typeof Q==="string"?[Q]:[]})}return[String(Y)]}async function t7($){if($.length===0)return;let J=new E0,Y=await J.listDistributions(),Z=[...new Set($.map((Q)=>Q.toLowerCase()))];for(let Q of Z){let G=Y.find((z)=>{return uT(z.Aliases).some((H)=>H.toLowerCase()===Q)});if(!G?.Id){d(`No CloudFront distribution found for ${Q} — skipping dynamic HTTP method sync`);continue}if(await J.ensureDynamicHttpMethods(G.Id))f(`CloudFront ${G.Id} (${Q}): enabled POST/PUT/PATCH/DELETE on dynamic paths`);else F(`CloudFront ${G.Id} (${Q}): already allows dynamic HTTP methods`)}}await u2([f0(),I$(),fG()]);import{execSync as AD}from"node:child_process";async function _D($,J,Y,Z={},Q=process.cwd()){if(!$)return;if(Z.step?.(`Running ${Y} hook`),typeof $==="string"){AD($,{stdio:"inherit",cwd:Q});return}await $(J)}async function $6($,J,Y={},Z){try{return await _D($.hooks?.[J],$,J,Y,Z),!0}catch(Q){return Y.error?.(`${J} hook failed: ${Q?.message||Q}`),!1}}await G$();async function $w($){let J=WJ();if(J.emptyEnvKey||J.emptyEnvSecret)d("Empty AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY env var detected — likely a misconfigured .env file. Remove the empty lines or fill them in.");F(`AWS credentials: ${J.description}`);try{let Z=await new k9($).getCallerIdentity();if(Z.Arn)F(`AWS identity: ${Z.Arn}`)}catch(Y){d(`Could not verify AWS identity: ${Y.message}`)}}function Jw(){try{return $W("git rev-parse --short HEAD",{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{return Date.now().toString(36)}}async function oG($,J,Y,Z){let{ensureManagementDashboard:Q}=await e9().then(() => MF);Q($,{logger:{info:F,warn:d}});let G=$.sites||{},W=Object.entries(G);if(W.length===0)return d("infrastructure.compute is set but no sites are configured — nothing to deploy. Add sites to `cloud.config.ts`."),!0;if(Z&&!G[Z])return R(`Site '${Z}' was not found. Configured sites: ${W.map(([_])=>_).join(", ")}`),!1;let z=W.filter(([_,M])=>{if(!M)return!1;if(Z&&_!==Z)return!1;if(n0(M)==="bucket")return d(`Site '${_}' targets a bucket — skipping compute deploy (handled by the static-site path).`),!1;return!0});if(z.length===0)return!0;if(Z)F(`Deploying only '${Z}'. Other sites keep their current release; proxy routes are still regenerated in full.`);let U=$.project.slug,X=($.infrastructure?.compute||{}).runtime||"bun",K=o0({config:$}),B=Jw(),V=new Map,O={step:(_)=>e(_),error:(_)=>R(_)};if(!await $6($,"beforeDeploy",O))return!0;if(!await $6($,"beforeBuild",O))return!0;for(let[_,M]of z){let j=n0(M);if(D(`Preparing site: ${_}`),F(`Domain: ${M.domain||"(none)"}`),F(`Source: ${M.root}`),F(`Kind: ${j==="server-static"?"static (shipped to /var/www)":"app (systemd service)"}`),j==="server-app")F(`Start: ${M.start}`),F(`Port: ${M.port??"(unset)"}`);if(M.build){e(`Running build: ${M.build}`);try{$W(M.build,{stdio:"inherit",cwd:process.cwd()})}catch(E){return R(`Build failed for site '${_}': ${E.message}`),!0}}if(!u1(M.root))return R(`Build output not found at ${M.root} for site '${_}'`),!0;let q=eD(oD(),`${U}-${_}-${B}.tar.gz`);e(`Packaging ${M.root} → ${q}`);try{let E=(M.exclude||[]).map((T)=>`--exclude='${T}'`).join(" ");$W(`tar czf "${q}" -C "${M.root}" ${E} .`,{stdio:"inherit"})}catch(E){return R(`Failed to package '${_}': ${E.message}`),!0}V.set(_,q)}if(!await $6($,"afterBuild",O))return!0;let A=await N5({config:Z?{...$,sites:Object.fromEntries(z)}:$,rpxConfig:Z?$:void 0,environment:J,driver:K,sha:B,runtime:X,tarballForSite:(_)=>{let M=V.get(_);if(!M)throw Error(`Missing tarball for site '${_}'`);return M},logger:{info:(_)=>F(_),warn:(_)=>d(_),error:(_)=>R(_),step:(_)=>e(_),success:(_)=>f(_)}});if(A)await $6($,"afterDeploy",O);return A}async function k5($){let J=new mQ;e("Running pre-deployment security scan...");let Y=await J.scan({directory:$.sourceDir,failOnSeverity:$.failOnSeverity||"critical",skipPatterns:$.skipPatterns});return{passed:Y.passed,result:Y}}function h5($){let{summary:J,findings:Y,scannedFiles:Z,duration:Q}=$;if(F(`
|
|
8060
8060
|
Scanned ${Z} files in ${Q}ms`),J.critical>0)R(` Critical: ${J.critical}`);else F(` Critical: ${J.critical}`);if(J.high>0)d(` High: ${J.high}`);else F(` High: ${J.high}`);if(F(` Medium: ${J.medium}`),F(` Low: ${J.low}`),Y.length>0){F(`
|
|
8061
8061
|
Findings:`);let G=Y.filter((X)=>X.pattern.severity==="critical"),W=Y.filter((X)=>X.pattern.severity==="high"),z=Y.filter((X)=>X.pattern.severity==="medium"),U=Y.filter((X)=>X.pattern.severity==="low"),H=(X,K,B)=>{if(X.length>0){console.log(`
|
|
8062
8062
|
${p2(`[${K}]`,B)}`);for(let V of X.slice(0,10))F(` ${V.pattern.name}`),F(` File: ${V.file}:${V.line}`),F(` Match: ${V.match}`);if(X.length>10)F(` ... and ${X.length-10} more ${K.toLowerCase()} findings`)}};H(G,"CRITICAL","red"),H(W,"HIGH","yellow"),H(z,"MEDIUM","blue"),H(U,"LOW","gray")}}function JW($){$.command("deploy:security-scan","Run pre-deployment security scan").option("--source <path>","Source directory to scan",{default:"."}).option("--fail-on <severity>","Fail on severity level (critical, high, medium, low)",{default:"critical"}).option("--skip-patterns <patterns>","Comma-separated list of pattern names to skip").action(async(J)=>{D("Pre-Deployment Security Scan");try{let Y=J?.source||".",Z=J?.failOn||"critical",Q=J?.skipPatterns?.split(",").map((z)=>z.trim())||[];if(!u1(Y)){R(`Source directory not found: ${Y}`);return}F(`Source: ${Y}`),F(`Fail on: ${Z} or higher severity`);let{passed:G,result:W}=await k5({sourceDir:Y,failOnSeverity:Z,skipPatterns:Q});if(h5(W),G)f(`
|
|
8063
8063
|
✓ Security scan passed - no blocking issues found`);else R(`
|
|
8064
8064
|
✗ Security scan failed - blocking issues detected`),F(`
|
|
8065
|
-
Recommendations:`),F(" 1. Remove any hardcoded credentials from your code"),F(" 2. Use environment variables or AWS Secrets Manager"),F(" 3. Add sensitive files to .gitignore"),F(" 4. Use --skip-patterns to ignore false positives"),process.exit(1)}catch(Y){R(`Security scan failed: ${Y.message}`),process.exit(1)}}),$.command("deploy","Deploy infrastructure").option("--stack <name>","Stack name").option("--env <environment>","Environment to deploy to").option("--site <name>","Deploy specific site only").option("--skip-security-scan","Skip pre-deployment security scan").option("--skip-dns-verification","Skip DNS provider verification and record creation (use when DNS is already configured)").option("--security-fail-on <severity>","Security scan fail threshold (critical, high, medium, low)",{default:"critical"}).option("--yes","Skip confirmation prompts (non-interactive / CI)").action(async(J)=>{D("Deploying Infrastructure");let Y=J?.yes===!0||process.env.CI==="true",Z=J?.env||"staging",Q=null;Q=await Yw(Z);try{let G=await r(),{errors:W,warnings:z}=tQ(G);for(let c of z)d(c);if(W.length>0){R(`
|
|
8065
|
+
Recommendations:`),F(" 1. Remove any hardcoded credentials from your code"),F(" 2. Use environment variables or AWS Secrets Manager"),F(" 3. Add sensitive files to .gitignore"),F(" 4. Use --skip-patterns to ignore false positives"),process.exit(1)}catch(Y){R(`Security scan failed: ${Y.message}`),process.exit(1)}}),$.command("deploy","Deploy infrastructure").option("--stack <name>","Stack name").option("--env <environment>","Environment to deploy to").option("--site <name>","Deploy specific site only (routes are still regenerated in full)").option("--skip-security-scan","Skip pre-deployment security scan").option("--skip-dns-verification","Skip DNS provider verification and record creation (use when DNS is already configured)").option("--security-fail-on <severity>","Security scan fail threshold (critical, high, medium, low)",{default:"critical"}).option("--yes","Skip confirmation prompts (non-interactive / CI)").action(async(J)=>{D("Deploying Infrastructure");let Y=J?.yes===!0||process.env.CI==="true",Z=J?.env||"staging",Q=null;Q=await Yw(Z);try{let G=await r(),{errors:W,warnings:z}=tQ(G);for(let c of z)d(c);if(W.length>0){R(`
|
|
8066
8066
|
✗ Deployment configuration is invalid:`);for(let c of W)R(` • ${c}`);return}let U=G.project?.region||"us-east-1";if(await $w(U),!J?.skipSecurityScan){let c=process.cwd(),{passed:n,result:C}=await k5({sourceDir:c,failOnSeverity:J?.securityFailOn||"critical"});if(h5(C),!n){R(`
|
|
8067
8067
|
✗ Security scan failed - deployment blocked`),F(`
|
|
8068
8068
|
To proceed anyway, use --skip-security-scan flag`),F("To change sensitivity, use --security-fail-on <severity>");return}f(`✓ Security scan passed
|
|
8069
8069
|
`)}else d(`Security scan skipped (--skip-security-scan)
|
|
8070
|
-
`);if(O9(G)==="serverless"){e("Serverless project detected: deploying the Lambda application");let{deployServerlessApp:c}=await t0().then(() => f1);await c(G,Z,{}),f("Serverless deployment complete");return}let H=J?.stack||a0(G,Z),X=G.project.region||"us-east-1",K=G.infrastructure?.deployStack!==!1,B=G.sites&&Object.keys(G.sites).length>0,V=G.infrastructure?.dns?.provider;if(B&&V){if(await Qw(G,J?.site,V,X,J?.skipDnsVerification,Z,Y),!K){if(G.infrastructure?.compute){let c=Object.values(G.sites).map((n)=>n.domain).filter((n)=>!!n);if(c.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(c)}return}}if(!K){F("Infrastructure stack deployment disabled (infrastructure.deployStack: false)");return}let O=C2(G);if(F(`Cloud provider: ${O}`),F(`Stack: ${H}`),F(`Region: ${X}`),F(`Environment: ${Z}`),(O==="hetzner"||G.infrastructure?.compute?.mode==="server")&&G.infrastructure?.compute){e(`Provisioning ${O} compute infrastructure...`);let c=o0({config:G,provider:O});if(!c.provisionComputeInfrastructure){R(`${O} driver does not support compute provisioning`);return}let n=await c.provisionComputeInfrastructure({config:G,environment:Z});if(f(`${O} compute infrastructure ready`),n.appPublicIp)F(`App server: ${n.appPublicIp}`);if(n.appInstanceId)F(`Server ID: ${n.appInstanceId}`);if(!await oG(G,Z,X))R(`App deploy to ${O} compute reported a failure`);else f(`App deployed to ${O} compute`),await Zw(G,n.appPublicIp,V);return}e("Generating CloudFormation template...");let _=new Z8({config:G,environment:Z});_.generate();let M=_.toJSON(),j=JSON.parse(M);if(Object.keys(j.Resources||{}).length===0){F(`No infrastructure resources to deploy for environment '${Z}' — skipping stack ${H}.`);return}e("Validating template...");let E=q9(j),T=T9(M),w=R9(j),N=[...E.errors,...T.errors,...w.errors];if(N.length>0){R("Template validation failed:");for(let c of N)R(` - ${c.path}: ${c.message}`);return}let I=[...E.warnings,...T.warnings,...w.warnings];if(I.length>0)for(let c of I)d(` - ${c.path}: ${c.message}`);f("Template validated successfully");let x=Object.keys(j.Resources).length;F(`
|
|
8070
|
+
`);if(O9(G)==="serverless"){e("Serverless project detected: deploying the Lambda application");let{deployServerlessApp:c}=await t0().then(() => f1);await c(G,Z,{}),f("Serverless deployment complete");return}let H=J?.stack||a0(G,Z),X=G.project.region||"us-east-1",K=G.infrastructure?.deployStack!==!1,B=G.sites&&Object.keys(G.sites).length>0,V=G.infrastructure?.dns?.provider;if(B&&V){if(await Qw(G,J?.site,V,X,J?.skipDnsVerification,Z,Y),!K){if(G.infrastructure?.compute){let c=Object.values(G.sites).map((n)=>n.domain).filter((n)=>!!n);if(c.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(c)}return}}if(!K){F("Infrastructure stack deployment disabled (infrastructure.deployStack: false)");return}let O=C2(G);if(F(`Cloud provider: ${O}`),F(`Stack: ${H}`),F(`Region: ${X}`),F(`Environment: ${Z}`),(O==="hetzner"||G.infrastructure?.compute?.mode==="server")&&G.infrastructure?.compute){e(`Provisioning ${O} compute infrastructure...`);let c=o0({config:G,provider:O});if(!c.provisionComputeInfrastructure){R(`${O} driver does not support compute provisioning`);return}let n=await c.provisionComputeInfrastructure({config:G,environment:Z});if(f(`${O} compute infrastructure ready`),n.appPublicIp)F(`App server: ${n.appPublicIp}`);if(n.appInstanceId)F(`Server ID: ${n.appInstanceId}`);if(!await oG(G,Z,X,J?.site))R(`App deploy to ${O} compute reported a failure`);else f(`App deployed to ${O} compute`),await Zw(G,n.appPublicIp,V);return}e("Generating CloudFormation template...");let _=new Z8({config:G,environment:Z});_.generate();let M=_.toJSON(),j=JSON.parse(M);if(Object.keys(j.Resources||{}).length===0){F(`No infrastructure resources to deploy for environment '${Z}' — skipping stack ${H}.`);return}e("Validating template...");let E=q9(j),T=T9(M),w=R9(j),N=[...E.errors,...T.errors,...w.errors];if(N.length>0){R("Template validation failed:");for(let c of N)R(` - ${c.path}: ${c.message}`);return}let I=[...E.warnings,...T.warnings,...w.warnings];if(I.length>0)for(let c of I)d(` - ${c.path}: ${c.message}`);f("Template validated successfully");let x=Object.keys(j.Resources).length;F(`
|
|
8071
8071
|
Resources to deploy: ${x}`);let h={};for(let c of Object.values(j.Resources)){let n=c.Type;h[n]=(h[n]||0)+1}for(let[c,n]of Object.entries(h).sort((C,b)=>b[1]-C[1]).slice(0,5))F(` - ${c}: ${n}`);if(!(Y||await p(`
|
|
8072
8072
|
Deploy now?`,!0))){F("Deployment cancelled");return}let g=new A0(X);e("Checking stack status...");let k=!1;try{let c=await g.describeStacks({stackName:H});k=c.Stacks&&c.Stacks.length>0}catch(c){k=!1}if(k){F("Stack exists, updating...");let c=new P("Updating CloudFormation stack...");c.start();try{await g.updateStack({stackName:H,templateBody:M,capabilities:["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],tags:[{Key:"Project",Value:G.project.name},{Key:"Environment",Value:Z},{Key:"ManagedBy",Value:"ts-cloud"}]}),c.succeed("Update initiated"),e("Waiting for stack update to complete..."),await g.waitForStack(H,"stack-update-complete"),f("Stack updated successfully!")}catch(n){if(n.message.includes("No updates are to be performed"))c.succeed("No changes detected"),F("Stack is already up to date — continuing to app deploy");else throw n}}else{F("Creating new stack...");let c=new P("Creating CloudFormation stack...");c.start(),await g.createStack({stackName:H,templateBody:M,capabilities:["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],tags:[{Key:"Project",Value:G.project.name},{Key:"Environment",Value:Z},{Key:"ManagedBy",Value:"ts-cloud"}]}),c.succeed("Stack creation initiated"),e("Waiting for stack creation to complete..."),await g.waitForStack(H,"stack-create-complete"),f("Stack created successfully!")}let i=await g.getStackOutputs(H);if(l1(`Deployment Complete!
|
|
8073
8073
|
|
|
@@ -8078,8 +8078,8 @@ Resources: ${x}
|
|
|
8078
8078
|
|
|
8079
8079
|
View in console:
|
|
8080
8080
|
https://console.aws.amazon.com/cloudformation/home?region=${X}#/stacks/stackinfo?stackId=${encodeURIComponent(H)}`,"green"),Object.keys(i).length>0){F(`
|
|
8081
|
-
Stack Outputs:`);for(let[c,n]of Object.entries(i))F(` - ${c}: ${n}`)}if(G.infrastructure?.storage)for(let[c,n]of Object.entries(G.infrastructure.storage)){if(!n.website||!n.root)continue;let C=i[`${c}BucketName`]||i.FrontendBucketName,b=i[`${c}CloudFrontDistributionId`];if(!C){d(`Could not find bucket name for storage '${c}' — skipping file upload`);continue}if(!u1(n.root)){d(`Source directory not found: ${n.root} — skipping file upload for '${c}'`);continue}e(`Uploading files from ${n.root} to s3://${C}...`);let{uploadStaticFiles:u,invalidateCache:m}=await Promise.resolve().then(() => (h9(),n7)),s=await u({sourceDir:n.root,bucket:C,region:X,onProgress:(J0,Z0,B0)=>{if(J0%10===0||J0===Z0)F(` ${J0}/${Z0}: ${B0}`)}});if(s.errors.length>0)d(`Upload completed with errors: ${s.errors.join(", ")}`);else{let J0=s.skipped>0?`Uploaded ${s.uploaded} files (${s.skipped} unchanged)`:`Uploaded ${s.uploaded} files`;f(J0)}if(b&&s.uploaded>0){e("Invalidating CloudFront cache...");let{invalidationId:J0}=await m(b);f(`Cache invalidation created: ${J0}`)}}if(G.infrastructure?.compute)await oG(G,Z,X);if(G.infrastructure?.compute&&G.sites){let c=Object.values(G.sites).map((n)=>n.domain).filter((n)=>!!n);if(c.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(c)}}catch(G){if(R(`Deployment failed: ${G.message}`),G.stack)F(`
|
|
8082
|
-
Stack trace:`),console.error(G.stack)}finally{if(Q)await Q()}}),$.command("deploy:server","Deploy EC2 infrastructure").option("--env <environment>","Environment (production, staging, development)").action(async(J)=>{D("Deploying Server Infrastructure");try{let Y=await r(),Z=J?.env||"production",Q=Y.project.region||"us-east-1",G=J8(Y);if(G){R(G),process.exitCode=1;return}if(!Y.infrastructure?.compute){R("No `infrastructure.compute` configured — nothing to deploy as a server."),F("Add an EC2 compute block to cloud.config, or use `cloud deploy:serverless` for Lambda apps."),process.exitCode=1;return}if(F(`Region: ${Q}`),F(`Environment: ${Z}`),!await oG(Y,Z,Q)){process.exitCode=1;return}if(Y.sites){let z=Object.values(Y.sites).map((U)=>U.domain).filter((U)=>!!U);if(z.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(z)}f(`
|
|
8081
|
+
Stack Outputs:`);for(let[c,n]of Object.entries(i))F(` - ${c}: ${n}`)}if(G.infrastructure?.storage)for(let[c,n]of Object.entries(G.infrastructure.storage)){if(!n.website||!n.root)continue;let C=i[`${c}BucketName`]||i.FrontendBucketName,b=i[`${c}CloudFrontDistributionId`];if(!C){d(`Could not find bucket name for storage '${c}' — skipping file upload`);continue}if(!u1(n.root)){d(`Source directory not found: ${n.root} — skipping file upload for '${c}'`);continue}e(`Uploading files from ${n.root} to s3://${C}...`);let{uploadStaticFiles:u,invalidateCache:m}=await Promise.resolve().then(() => (h9(),n7)),s=await u({sourceDir:n.root,bucket:C,region:X,onProgress:(J0,Z0,B0)=>{if(J0%10===0||J0===Z0)F(` ${J0}/${Z0}: ${B0}`)}});if(s.errors.length>0)d(`Upload completed with errors: ${s.errors.join(", ")}`);else{let J0=s.skipped>0?`Uploaded ${s.uploaded} files (${s.skipped} unchanged)`:`Uploaded ${s.uploaded} files`;f(J0)}if(b&&s.uploaded>0){e("Invalidating CloudFront cache...");let{invalidationId:J0}=await m(b);f(`Cache invalidation created: ${J0}`)}}if(G.infrastructure?.compute)await oG(G,Z,X,J?.site);if(G.infrastructure?.compute&&G.sites){let c=Object.values(G.sites).map((n)=>n.domain).filter((n)=>!!n);if(c.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(c)}}catch(G){if(R(`Deployment failed: ${G.message}`),G.stack)F(`
|
|
8082
|
+
Stack trace:`),console.error(G.stack)}finally{if(Q)await Q()}}),$.command("deploy:server","Deploy EC2 infrastructure").option("--env <environment>","Environment (production, staging, development)").option("--site <name>","Deploy specific site only (routes are still regenerated in full)").action(async(J)=>{D("Deploying Server Infrastructure");try{let Y=await r(),Z=J?.env||"production",Q=Y.project.region||"us-east-1",G=J8(Y);if(G){R(G),process.exitCode=1;return}if(!Y.infrastructure?.compute){R("No `infrastructure.compute` configured — nothing to deploy as a server."),F("Add an EC2 compute block to cloud.config, or use `cloud deploy:serverless` for Lambda apps."),process.exitCode=1;return}if(F(`Region: ${Q}`),F(`Environment: ${Z}`),!await oG(Y,Z,Q,J?.site)){process.exitCode=1;return}if(Y.sites){let z=Object.values(Y.sites).map((U)=>U.domain).filter((U)=>!!U);if(z.length>0)e("Syncing CloudFront dynamic HTTP methods for app domains..."),await t7(z)}f(`
|
|
8083
8083
|
Server deployment complete!`)}catch(Y){R(`Deployment failed: ${Y.message}`),process.exitCode=1}}),$.command("deploy:serverless","Deploy a serverless application (http/queue/cli Lambda functions)").option("--env <environment>","Environment (production, staging, development)").option("--skip-build","Skip local build hooks").option("--skip-hooks","Skip remote deploy hooks (e.g. migrations)").option("--redeploy","Re-activate the last build without rebuilding").action(async(J)=>{try{let Y=await r(),Z=J?.env||"production",Q=J8(Y);if(Q){R(Q),process.exitCode=1;return}let{deployServerlessApp:G,redeployServerlessApp:W}=await t0().then(() => f1);if(J?.redeploy){await W(Y,Z);return}await G(Y,Z,{skipBuild:J?.skipBuild,skipDeployHooks:J?.skipHooks})}catch(Y){R(`Deployment failed: ${Y.message}`),process.exitCode=1}}),$.command("serverless:rollback","Roll back a serverless app to the previous build").option("--env <environment>","Environment (production, staging, development)").action(async(J)=>{try{let Y=await r(),Z=J?.env||"production",{rollbackServerlessApp:Q}=await t0().then(() => f1);await Q(Y,Z)}catch(Y){R(`Rollback failed: ${Y.message}`),process.exitCode=1}}),$.command("deploy:rollback [site]","Roll a compute site back to a previous release").option("--env <environment>","Environment (production, staging, development)").option("--to <release>","Release id to roll back to (default: the previous release)").action(async(J,Y)=>{D("Rolling Back Release");try{let Z=await r(),Q=Y?.env||"production",G=J||Object.keys(Z.sites||{})[0];if(!G){R("No site configured to roll back."),process.exitCode=1;return}let{rollbackComputeSite:W}=await S8().then(() => J6),z=await W({driver:o0({config:Z}),slug:Z.project.slug,environment:Q,logger:z0},{siteName:G,to:Y?.to});if(!z.success){R(`Rollback failed: ${z.error||"unknown error"}`),process.exitCode=1;return}for(let U of z.perInstance||[])F(` ${U.instanceId}: ${U.output?.trim()||U.status}`)}catch(Z){R(`Rollback failed: ${Z.message}`),process.exitCode=1}}),$.command("deploy:history [site]","Show a compute site's deployment history").option("--env <environment>","Environment (production, staging, development)").option("--limit <n>","Number of entries to show",{default:"20"}).action(async(J,Y)=>{D("Deployment History");try{let Z=await r(),Q=Y?.env||"production",G=J||Object.keys(Z.sites||{})[0];if(!G){R("No site configured."),process.exitCode=1;return}let{getComputeDeployHistory:W}=await S8().then(() => J6),z=await W({driver:o0({config:Z}),slug:Z.project.slug,environment:Q,logger:z0},{siteName:G,limit:Number.parseInt(Y?.limit||"20",10)||20});if(!z.success){R(`Could not read history: ${z.error||"unknown error"}`),process.exitCode=1;return}for(let U of z.perInstance||[])F(`
|
|
8084
8084
|
${U.instanceId}:`),F(U.output?.trimEnd()||"(no output)")}catch(Z){R(`History lookup failed: ${Z.message}`),process.exitCode=1}}),$.command("deploy:recipe <name> <script>","Run a reusable server recipe (a local bash file) across servers").option("--env <environment>","Environment (production, staging, development)").option("--user <user>","User to run the recipe as",{default:"root"}).action(async(J,Y,Z)=>{D(`Running Recipe: ${J}`);try{if(!u1(Y)){R(`Recipe script not found: ${Y}`),process.exitCode=1;return}let Q=await r(),G=Z?.env||"production",W=eG(Y,"utf8").split(`
|
|
8085
8085
|
`),{runComputeRecipe:z}=await S8().then(() => J6),U=await z({driver:o0({config:Q}),slug:Q.project.slug,environment:G,logger:z0},{name:J,script:W,user:Z?.user});for(let H of U.perInstance||[])F(`
|