@stacksjs/ts-cloud 0.12.10 → 0.12.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-tfbs8k8v.js → chunk-0x8szp53.js} +1 -1
- package/dist/bin/chunk-1hggd7yz.js +1 -0
- package/dist/bin/{chunk-rtecnmts.js → chunk-2pevjm25.js} +2 -2
- package/dist/bin/{chunk-0zwknfwp.js → chunk-2tsg6e8j.js} +1 -1
- package/dist/{chunk-c8cadhgc.js → bin/chunk-3f27aa5r.js} +2 -2
- package/dist/bin/{chunk-dz1ec589.js → chunk-3g80gjw6.js} +2 -2
- package/dist/bin/chunk-40j9hgzc.js +1 -0
- package/dist/bin/{chunk-82mj52xr.js → chunk-48eb4z0c.js} +1 -1
- package/dist/bin/chunk-4gqfdr7t.js +1 -0
- package/dist/{chunk-pb47hr0h.js → bin/chunk-5gx38418.js} +1 -1
- package/dist/bin/chunk-5jv4cpky.js +1 -0
- package/dist/bin/chunk-5kxm5mx7.js +1 -0
- package/dist/bin/{chunk-my3ewh3a.js → chunk-5rhvcgzt.js} +2 -2
- package/dist/bin/{chunk-mcr0r4at.js → chunk-8223r1xn.js} +2 -2
- package/dist/bin/{chunk-4q6tad44.js → chunk-84703zpq.js} +91 -91
- package/dist/bin/{chunk-3aph4c1w.js → chunk-9edyzdm0.js} +1 -1
- package/dist/bin/{chunk-xhwqpgwq.js → chunk-9xbsmz1f.js} +1 -1
- package/dist/bin/{chunk-mfrf9q4b.js → chunk-a8t3c4qe.js} +1 -1
- package/dist/bin/chunk-aghy01we.js +1 -0
- package/dist/{chunk-w2ddj42w.js → bin/chunk-akwfvn5k.js} +1 -1
- package/dist/bin/chunk-asvz121j.js +1 -0
- package/dist/bin/{chunk-6tfwm33r.js → chunk-b0xtsv8k.js} +3 -3
- package/dist/bin/chunk-bcpdj01b.js +1 -0
- package/dist/bin/{chunk-btsyjhk7.js → chunk-bj4ft4qc.js} +2 -2
- package/dist/bin/chunk-da49my09.js +1 -0
- package/dist/bin/{chunk-hq9x489e.js → chunk-dep2n31v.js} +1 -1
- package/dist/bin/{chunk-b4wt9jcg.js → chunk-ewxf62t8.js} +2 -2
- package/dist/bin/{chunk-e2bybahr.js → chunk-f42gqn6c.js} +1 -1
- package/dist/bin/{chunk-s4yzes15.js → chunk-fc6r1ack.js} +1 -1
- package/dist/bin/{chunk-vj2dp0nh.js → chunk-ftcjjf76.js} +6 -6
- package/dist/bin/chunk-g76sry03.js +1 -0
- package/dist/bin/{chunk-e5ab5twy.js → chunk-hv3w2qy1.js} +2 -2
- package/dist/bin/{chunk-9a88fp00.js → chunk-hwdfky19.js} +2 -2
- package/dist/bin/chunk-j02d6qmn.js +1 -0
- package/dist/bin/{chunk-8ewncfce.js → chunk-j2cb8we4.js} +1 -1
- package/dist/bin/chunk-kmz8vb77.js +1 -0
- package/dist/bin/{chunk-0thy7q96.js → chunk-kyr5rasx.js} +74 -75
- package/dist/bin/{chunk-ja1vjdn1.js → chunk-mhrtx0p1.js} +1 -1
- package/dist/bin/{chunk-w32xv8n4.js → chunk-nc9pp87y.js} +2 -2
- package/dist/bin/{chunk-xk08030d.js → chunk-ncrnbcsa.js} +2 -2
- package/dist/bin/chunk-py1hyeb2.js +1 -0
- package/dist/bin/{chunk-q5cmfpzt.js → chunk-qa06sft7.js} +1 -1
- package/dist/bin/{chunk-azymqbcy.js → chunk-qr0xck72.js} +1 -1
- package/dist/bin/chunk-r85ahkwq.js +1 -0
- package/dist/bin/{chunk-ehc63fvs.js → chunk-re15e6p4.js} +1 -1
- package/dist/bin/chunk-t6y3pkm8.js +1 -0
- package/dist/bin/{chunk-c0bdafbx.js → chunk-tfmx17he.js} +1 -1
- package/dist/bin/chunk-vfcchrby.js +1 -0
- package/dist/bin/chunk-vmdh41kp.js +1 -0
- package/dist/bin/{chunk-cd0ps58j.js → chunk-vrc7eemq.js} +1 -1
- package/dist/bin/{chunk-d7ke90zt.js → chunk-vsd7670h.js} +1 -1
- package/dist/bin/{chunk-kg61p5hw.js → chunk-vwqn3yx6.js} +2 -2
- package/dist/bin/{chunk-71t1gmsq.js → chunk-vxbnjz78.js} +1 -1
- package/dist/bin/chunk-w8s8vgdj.js +1 -0
- package/dist/bin/chunk-yq9vetf8.js +698 -0
- package/dist/bin/{chunk-zpe64t4r.js → chunk-zrgd65r8.js} +1 -1
- package/dist/bin/cli.js +143 -143
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-y3tbcxb7.js → chunk-0a4tqwm9.js} +89 -90
- package/dist/{chunk-982rye5b.js → chunk-2ybcnrte.js} +1 -1
- package/dist/chunk-4884der5.js +1 -0
- package/dist/{bin/chunk-9kf0np8j.js → chunk-4wdxsnn2.js} +1 -1
- package/dist/{bin/chunk-xkfrqqcs.js → chunk-5hhyyhjt.js} +1 -1
- package/dist/chunk-5zkacdw1.js +1 -0
- package/dist/{chunk-557qj7q9.js → chunk-6cxb8d6y.js} +2 -2
- package/dist/chunk-6f68caq0.js +1 -0
- package/dist/{chunk-2qm3rw8b.js → chunk-7z50g5xz.js} +2 -2
- package/dist/chunk-8fh4m5ge.js +1 -0
- package/dist/chunk-97pb7wb1.js +1 -0
- package/dist/{chunk-a368cs92.js → chunk-ac87ds1k.js} +1 -1
- package/dist/{chunk-qrte4gy2.js → chunk-dndxwssj.js} +1 -1
- package/dist/{bin/chunk-a7w13qfm.js → chunk-ess6vxfj.js} +2 -2
- package/dist/chunk-fvpkxznh.js +558 -0
- package/dist/{chunk-rg7d67xk.js → chunk-j06r5rwv.js} +1 -1
- package/dist/{chunk-70v77sqv.js → chunk-j1g67djb.js} +2 -2
- package/dist/{chunk-fbwpm0zm.js → chunk-k8x8mrkr.js} +1 -1
- package/dist/{chunk-82gezmen.js → chunk-mnmz8t7q.js} +1 -1
- package/dist/{chunk-7j100g7w.js → chunk-n1fyryha.js} +1 -1
- package/dist/{chunk-c1hr34a5.js → chunk-n1hg0jxs.js} +2 -2
- package/dist/{chunk-bcffjsnj.js → chunk-n5xmh0ma.js} +1 -1
- package/dist/chunk-q22qfwsc.js +22 -0
- package/dist/{chunk-5hkq5081.js → chunk-q9a1z53k.js} +2 -2
- package/dist/{chunk-fsssdd5k.js → chunk-r8t25tbm.js} +91 -91
- package/dist/{chunk-2k0mt6j5.js → chunk-whyttetx.js} +1 -1
- package/dist/{chunk-gkj1tpsn.js → chunk-yf8stygs.js} +1 -1
- package/dist/{chunk-jphewtbx.js → chunk-ze5x2bpm.js} +1 -1
- package/dist/{chunk-jxrs1219.js → chunk-zh0apedk.js} +2 -2
- package/dist/{chunk-0hw5wjjg.js → chunk-zjyz926j.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/hetzner/cloud-init.d.ts +14 -1
- package/dist/drivers/hetzner/driver.d.ts +2 -15
- package/dist/drivers/hetzner/state.d.ts +17 -2
- package/dist/drivers/index.d.ts +17 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/local-box/driver.d.ts +1 -1
- package/dist/drivers/shared/compute-provision.d.ts +7 -0
- package/dist/drivers/shared/driver-state.d.ts +68 -0
- package/dist/drivers/shared/remote-exec.d.ts +10 -1
- package/dist/drivers/shared/remote-failure.d.ts +41 -0
- package/dist/drivers/shared/ssh-transport.d.ts +121 -0
- package/dist/drivers/ssh/bootstrap.d.ts +61 -0
- package/dist/drivers/ssh/config.d.ts +86 -0
- package/dist/drivers/ssh/config.test.d.ts +1 -0
- package/dist/drivers/ssh/driver.d.ts +107 -0
- package/dist/drivers/ssh/factory-wiring.test.d.ts +1 -0
- package/dist/drivers/ssh/first-boot.d.ts +38 -0
- package/dist/drivers/ssh/preflight.d.ts +76 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -7
- package/dist/operations/index.js +1 -1
- package/dist/operations/inventory.d.ts +46 -1
- package/dist/protection/index.js +1 -1
- package/dist/push/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +2 -2
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +1 -1
- package/dist/ui/applications/compose.html +5 -5
- package/dist/ui/applications/new.html +1 -1
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +5 -5
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +6 -6
- 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 +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +5 -5
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +5 -5
- package/dist/ui/server/ssh-keys.html +5 -5
- 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 +1 -1
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +5 -5
- package/dist/ui/serverless/logs.html +5 -5
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +6 -6
- package/dist/ui-src/src/charts.ts +1 -1
- package/dist/ui-src/src/topology.ts +1 -1
- package/package.json +3 -3
- package/dist/bin/chunk-04dkwaqp.js +0 -1
- package/dist/bin/chunk-5nkqza92.js +0 -1
- package/dist/bin/chunk-64vczwwt.js +0 -1
- package/dist/bin/chunk-7g2ahkse.js +0 -1
- package/dist/bin/chunk-aw8bhggq.js +0 -594
- package/dist/bin/chunk-cxt74wsj.js +0 -1
- package/dist/bin/chunk-djg4zyqk.js +0 -1
- package/dist/bin/chunk-dkaz333b.js +0 -1
- package/dist/bin/chunk-edvvx3hg.js +0 -1
- package/dist/bin/chunk-f06c5np9.js +0 -1
- package/dist/bin/chunk-gq8794k6.js +0 -1
- package/dist/bin/chunk-k3120rx6.js +0 -1
- package/dist/bin/chunk-nw3d4k52.js +0 -1
- package/dist/bin/chunk-p70bc9yr.js +0 -1
- package/dist/bin/chunk-sg1g92cf.js +0 -1
- package/dist/bin/chunk-tvz9c388.js +0 -1
- package/dist/bin/chunk-y1h63vpm.js +0 -1
- package/dist/bin/chunk-zdt2rjk6.js +0 -1
- package/dist/bin/chunk-zh2d4704.js +0 -1
- package/dist/chunk-1bj94sc2.js +0 -1
- package/dist/chunk-3swnmwfc.js +0 -454
- package/dist/chunk-5pbtmy2k.js +0 -1
- package/dist/chunk-7sc8t7v1.js +0 -1
- package/dist/chunk-gny5s4kp.js +0 -1
- package/dist/chunk-qpjcd415.js +0 -22
- package/dist/chunk-xkw7h4pw.js +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{tj as s}from"./chunk-ac87ds1k.js";class a{client;region;constructor(e="us-east-1",r){this.region=e,this.client=new s(void 0,{profile:r})}async createRepository(e){let r={repositoryName:e.repositoryName};if(e.imageTagMutability)r.imageTagMutability=e.imageTagMutability;if(e.imageScanningConfiguration)r.imageScanningConfiguration=e.imageScanningConfiguration;if(e.encryptionConfiguration)r.encryptionConfiguration=e.encryptionConfiguration;if(e.tags&&e.tags.length>0)r.tags=e.tags;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.CreateRepository","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{repository:t.repository?this.parseRepository(t.repository):void 0}}async describeRepositories(e){let r={};if(e?.repositoryNames&&e.repositoryNames.length>0)r.repositoryNames=e.repositoryNames;if(e?.registryId)r.registryId=e.registryId;if(e?.maxResults)r.maxResults=e.maxResults;if(e?.nextToken)r.nextToken=e.nextToken;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.DescribeRepositories","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{repositories:t.repositories?.map((i)=>this.parseRepository(i)),nextToken:t.nextToken}}async getAuthorizationToken(e){let r={};if(e&&e.length>0)r.registryIds=e;return{authorizationData:(await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.GetAuthorizationToken","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)})).authorizationData?.map((i)=>({authorizationToken:i.authorizationToken,expiresAt:i.expiresAt,proxyEndpoint:i.proxyEndpoint}))}}async deleteRepository(e){let r={repositoryName:e.repositoryName};if(e.registryId)r.registryId=e.registryId;if(e.force!==void 0)r.force=e.force;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.DeleteRepository","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{repository:t.repository?this.parseRepository(t.repository):void 0}}async describeImages(e){let r={repositoryName:e.repositoryName};if(e.registryId)r.registryId=e.registryId;if(e.imageIds&&e.imageIds.length>0)r.imageIds=e.imageIds;if(e.filter)r.filter=e.filter;if(e.maxResults)r.maxResults=e.maxResults;if(e.nextToken)r.nextToken=e.nextToken;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.DescribeImages","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{imageDetails:t.imageDetails?.map((i)=>this.parseImageDetail(i)),nextToken:t.nextToken}}async batchDeleteImage(e){let r={repositoryName:e.repositoryName,imageIds:e.imageIds};if(e.registryId)r.registryId=e.registryId;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.BatchDeleteImage","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{imageIds:t.imageIds,failures:t.failures}}async putLifecyclePolicy(e){let r={repositoryName:e.repositoryName,lifecyclePolicyText:e.lifecyclePolicyText};if(e.registryId)r.registryId=e.registryId;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.PutLifecyclePolicy","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{registryId:t.registryId,repositoryName:t.repositoryName,lifecyclePolicyText:t.lifecyclePolicyText}}async getLifecyclePolicy(e){let r={repositoryName:e.repositoryName};if(e.registryId)r.registryId=e.registryId;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.GetLifecyclePolicy","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{registryId:t.registryId,repositoryName:t.repositoryName,lifecyclePolicyText:t.lifecyclePolicyText,lastEvaluatedAt:t.lastEvaluatedAt}}async setRepositoryPolicy(e){let r={repositoryName:e.repositoryName,policyText:e.policyText};if(e.registryId)r.registryId=e.registryId;if(e.force!==void 0)r.force=e.force;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.SetRepositoryPolicy","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{registryId:t.registryId,repositoryName:t.repositoryName,policyText:t.policyText}}async getRepositoryPolicy(e){let r={repositoryName:e.repositoryName};if(e.registryId)r.registryId=e.registryId;let t=await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.GetRepositoryPolicy","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)});return{registryId:t.registryId,repositoryName:t.repositoryName,policyText:t.policyText}}async tagResource(e){let r={resourceArn:e.resourceArn,tags:e.tags};await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.TagResource","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)})}async listTagsForResource(e){let r={resourceArn:e};return{tags:(await this.client.request({service:"ecr",region:this.region,method:"POST",path:"/",headers:{"X-Amz-Target":"AmazonEC2ContainerRegistry_V20150921.ListTagsForResource","Content-Type":"application/x-amz-json-1.1"},body:JSON.stringify(r)})).tags}}createLifecyclePolicyText(e){return JSON.stringify({rules:e.map((r)=>({rulePriority:r.rulePriority,description:r.description,selection:r.selection,action:r.action}))})}async getDockerLoginCommand(){let e=await this.getAuthorizationToken();if(!e.authorizationData?.[0])throw Error("Failed to get authorization token");let r=e.authorizationData[0],t=r.authorizationToken||"",i=r.proxyEndpoint||"";return`echo "${Buffer.from(t,"base64").toString("utf8").split(":")[1]}" | docker login --username AWS --password-stdin ${i}`}getRegistryUri(e){return`${e}.dkr.ecr.${this.region}.amazonaws.com`}parseRepository(e){return{repositoryArn:e.repositoryArn,registryId:e.registryId,repositoryName:e.repositoryName,repositoryUri:e.repositoryUri,createdAt:e.createdAt,imageTagMutability:e.imageTagMutability,imageScanningConfiguration:e.imageScanningConfiguration,encryptionConfiguration:e.encryptionConfiguration}}parseImageDetail(e){return{registryId:e.registryId,repositoryName:e.repositoryName,imageDigest:e.imageDigest,imageTags:e.imageTags,imageSizeInBytes:e.imageSizeInBytes,imagePushedAt:e.imagePushedAt,imageScanStatus:e.imageScanStatus,imageScanFindingsSummary:e.imageScanFindingsSummary}}}
|
|
2
2
|
export{a as Vf};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Uf as U}from"./chunk-
|
|
1
|
+
import{Uf as U}from"./chunk-n1fyryha.js";import{eg as Z,jg as _,ng as K,rg as L,sg as Y}from"./chunk-j06r5rwv.js";import{tg as M}from"./chunk-2ybcnrte.js";import{pj as W}from"./chunk-ess6vxfj.js";import{rj as B}from"./chunk-j1g67djb.js";import{Ov as j}from"./chunk-zjyz926j.js";function J(t){let{bucketName:s,domain:l,aliases:e,certificateArn:m,defaultRootObject:i="index.html",errorDocument:r="404.html",passthroughUrls:a=!1,singlePageApp:d=!1,dynamicApp:b=!1,computeOriginDomain:k,computeOriginPort:R=3008,computeOriginId:P="app-compute",retainOnStackDelete:x=!1}=t,A=x?{DeletionPolicy:"Retain",UpdateReplacePolicy:"Retain"}:{},y=b&&!!k,T=y?["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"]:["GET","HEAD"],F=y?["GET","HEAD"]:["GET","HEAD"],N={},O={};N.S3Bucket={Type:"AWS::S3::Bucket",...A,Properties:{BucketName:s,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!1,IgnorePublicAcls:!0,RestrictPublicBuckets:!1},WebsiteConfiguration:{IndexDocument:i,ErrorDocument:r}}},O.BucketName={Description:"S3 Bucket Name",Value:{Ref:"S3Bucket"}},O.BucketArn={Description:"S3 Bucket ARN",Value:{"Fn::GetAtt":["S3Bucket","Arn"]}},N.CloudFrontOAC={Type:"AWS::CloudFront::OriginAccessControl",...A,Properties:{OriginAccessControlConfig:{Name:`OAC-${s}`,Description:`OAC for ${s}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}};let D;if(a&&y)D="InstallRootRedirectFunction",N[D]={Type:"AWS::CloudFront::Function",Properties:{Name:{"Fn::Sub":"${AWS::StackName}-install-root-redirect"},AutoPublish:!0,FunctionConfig:{Comment:"Redirect curl pantry.dev | bash (GET /) to /install.sh on S3",Runtime:"cloudfront-js-2.0"},FunctionCode:`function handler(event) {
|
|
2
2
|
var request = event.request;
|
|
3
3
|
if (request.uri === '/' || request.uri === '') {
|
|
4
4
|
return {
|
|
@@ -42,7 +42,7 @@ import{Uf as U}from"./chunk-7j100g7w.js";import{eg as Z,jg as _,ng as K,rg as L,
|
|
|
42
42
|
│ │
|
|
43
43
|
│ Verification typically takes 1-2 business days. │
|
|
44
44
|
│ After verification, re-run: bunx bunpress deploy │
|
|
45
|
-
└─────────────────────────────────────────────────────────────────────────────┘`),{success:!1,stackId:O,stackName:i,bucket:y,message:"CloudFront account verification required. Please contact AWS Support."}}return{success:!1,stackId:O,stackName:i,bucket:y,message:`Stack deployment failed: ${o.message}`}}let u=(await r.describeStacks({stackName:i})).Stacks[0]?.Outputs||[],C=(o)=>u.find((n)=>n.OutputKey===o)?.OutputValue,f=C("DistributionDomain");if(f&&d)console.log(`Creating DNS records via ${d.name}...`),await q(d,e,f);else if(f&&!d)console.log("Skipping DNS record creation (DNS verification was skipped)");return{success:!0,stackId:O,stackName:i,bucket:C("BucketName")||y,distributionId:C("DistributionId"),distributionDomain:f,domain:e,certificateArn:b,message:"Static site infrastructure deployed successfully with external DNS"}}async function q(t,s,l){if(!t){console.log("Skipping DNS record creation (DNS verification was skipped)");return}if(s.split(".").length===2)if(t instanceof Z){console.log(`Creating Route53 alias record for apex domain ${s} -> ${l}`);let i=await t.createCloudFrontAlias({domain:s,name:s,cloudFrontDomainName:l});if(!i.success)console.warn(`Warning: Could not create Route53 alias record: ${i.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${s} -> ${l}`);else console.log(`Created Route53 alias record: ${s} -> ${l}`);let r=`www.${s}`;console.log(`Creating Route53 alias record for ${r} -> ${l}`);let a=await t.createCloudFrontAlias({domain:s,name:r,cloudFrontDomainName:l});if(!a.success)console.warn(`Warning: Could not create www Route53 alias: ${a.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${r} -> ${l}`);else console.log(`Created Route53 alias record: ${r} -> ${l}`)}else{try{let d=await t.listRecords(s,"A");if(d.success)for(let b of d.records){let k=b.name.replace(/\.$/,"");if(k===s||k==="")console.log(`Removing existing root A record (${b.content}) to make room for ALIAS...`),await t.deleteRecord(s,{name:s,type:"A",content:b.content})}}catch(d){console.log(`Note: Could not check for conflicting A records: ${d instanceof Error?d.message:d}`)}console.log(`Creating ALIAS record for apex domain ${s} -> ${l}`);let i=await t.upsertRecord(s,{name:s,type:"ALIAS",content:l,ttl:600});if(!i.success)console.warn(`Warning: Could not create ALIAS record: ${i.message}`),console.warn("Please manually create an ALIAS record in your DNS provider:"),console.warn(` ${s} -> ${l}`);else console.log(`Created ALIAS record: ${s} -> ${l}`);let r=`www.${s}`;console.log(`Creating CNAME record for ${r} -> ${l}`);let a=await t.upsertRecord(s,{name:r,type:"CNAME",content:l,ttl:600});if(!a.success)console.warn(`Warning: Could not create www DNS record: ${a.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${r} -> ${l}`);else console.log(`Created CNAME record: ${r} -> ${l}`)}else{console.log(`Creating CNAME record for ${s} -> ${l}`);let i=await t.upsertRecord(s,{name:s,type:"CNAME",content:l,ttl:600});if(!i.success)console.warn(`Warning: Could not create DNS record: ${i.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${s} -> ${l}`);else console.log(`Created CNAME record: ${s} -> ${l}`)}}async function le(t){let{sourceDir:s,cleanBucket:l=!1,onProgress:e,...m}=t;e?.("infrastructure","Deploying CloudFormation stack...");let i=await G(m);if(!i.success)return i;if(l){e?.("clean","Cleaning old files from S3...");try{await new B(m.region||"us-east-1").emptyBucket(i.bucket)}catch(b){console.log(`Note: Could not clean bucket: ${b.message}`)}}e?.("upload","Uploading files to S3...");let{uploadStaticFiles:r}=await import("./chunk-
|
|
45
|
+
└─────────────────────────────────────────────────────────────────────────────┘`),{success:!1,stackId:O,stackName:i,bucket:y,message:"CloudFront account verification required. Please contact AWS Support."}}return{success:!1,stackId:O,stackName:i,bucket:y,message:`Stack deployment failed: ${o.message}`}}let u=(await r.describeStacks({stackName:i})).Stacks[0]?.Outputs||[],C=(o)=>u.find((n)=>n.OutputKey===o)?.OutputValue,f=C("DistributionDomain");if(f&&d)console.log(`Creating DNS records via ${d.name}...`),await q(d,e,f);else if(f&&!d)console.log("Skipping DNS record creation (DNS verification was skipped)");return{success:!0,stackId:O,stackName:i,bucket:C("BucketName")||y,distributionId:C("DistributionId"),distributionDomain:f,domain:e,certificateArn:b,message:"Static site infrastructure deployed successfully with external DNS"}}async function q(t,s,l){if(!t){console.log("Skipping DNS record creation (DNS verification was skipped)");return}if(s.split(".").length===2)if(t instanceof Z){console.log(`Creating Route53 alias record for apex domain ${s} -> ${l}`);let i=await t.createCloudFrontAlias({domain:s,name:s,cloudFrontDomainName:l});if(!i.success)console.warn(`Warning: Could not create Route53 alias record: ${i.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${s} -> ${l}`);else console.log(`Created Route53 alias record: ${s} -> ${l}`);let r=`www.${s}`;console.log(`Creating Route53 alias record for ${r} -> ${l}`);let a=await t.createCloudFrontAlias({domain:s,name:r,cloudFrontDomainName:l});if(!a.success)console.warn(`Warning: Could not create www Route53 alias: ${a.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${r} -> ${l}`);else console.log(`Created Route53 alias record: ${r} -> ${l}`)}else{try{let d=await t.listRecords(s,"A");if(d.success)for(let b of d.records){let k=b.name.replace(/\.$/,"");if(k===s||k==="")console.log(`Removing existing root A record (${b.content}) to make room for ALIAS...`),await t.deleteRecord(s,{name:s,type:"A",content:b.content})}}catch(d){console.log(`Note: Could not check for conflicting A records: ${d instanceof Error?d.message:d}`)}console.log(`Creating ALIAS record for apex domain ${s} -> ${l}`);let i=await t.upsertRecord(s,{name:s,type:"ALIAS",content:l,ttl:600});if(!i.success)console.warn(`Warning: Could not create ALIAS record: ${i.message}`),console.warn("Please manually create an ALIAS record in your DNS provider:"),console.warn(` ${s} -> ${l}`);else console.log(`Created ALIAS record: ${s} -> ${l}`);let r=`www.${s}`;console.log(`Creating CNAME record for ${r} -> ${l}`);let a=await t.upsertRecord(s,{name:r,type:"CNAME",content:l,ttl:600});if(!a.success)console.warn(`Warning: Could not create www DNS record: ${a.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${r} -> ${l}`);else console.log(`Created CNAME record: ${r} -> ${l}`)}else{console.log(`Creating CNAME record for ${s} -> ${l}`);let i=await t.upsertRecord(s,{name:s,type:"CNAME",content:l,ttl:600});if(!i.success)console.warn(`Warning: Could not create DNS record: ${i.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${s} -> ${l}`);else console.log(`Created CNAME record: ${s} -> ${l}`)}}async function le(t){let{sourceDir:s,cleanBucket:l=!1,onProgress:e,...m}=t;e?.("infrastructure","Deploying CloudFormation stack...");let i=await G(m);if(!i.success)return i;if(l){e?.("clean","Cleaning old files from S3...");try{await new B(m.region||"us-east-1").emptyBucket(i.bucket)}catch(b){console.log(`Note: Could not clean bucket: ${b.message}`)}}e?.("upload","Uploading files to S3...");let{uploadStaticFiles:r}=await import("./chunk-8fh4m5ge.js"),a=await r({sourceDir:s,bucket:i.bucket,region:m.region||"us-east-1",cacheControl:m.cacheControl,onProgress:(b,k,R)=>{e?.("upload",`${b}/${k}: ${R}`)}});if(a.errors.length>0)return{...i,success:!1,message:`Upload errors: ${a.errors.join(", ")}`,filesUploaded:a.uploaded};if(i.distributionId&&a.uploaded>0){e?.("invalidate","Invalidating CloudFront cache...");let{invalidateCache:b}=await import("./chunk-8fh4m5ge.js");await b(i.distributionId)}e?.("complete","Deployment complete!");let d=a.skipped>0?`Deployed ${a.uploaded} files (${a.skipped} unchanged) with external DNS`:`Deployed ${a.uploaded} files successfully with external DNS`;return{...i,filesUploaded:a.uploaded,filesSkipped:a.skipped,message:d}}function Q(t){let{bucketName:s,domain:l,certificateArn:e,hostedZoneId:m,defaultRootObject:i="index.html",errorDocument:r="404.html"}=t,a={},d={};a.S3Bucket={Type:"AWS::S3::Bucket",Properties:{BucketName:s,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!1,IgnorePublicAcls:!0,RestrictPublicBuckets:!1},WebsiteConfiguration:{IndexDocument:i,ErrorDocument:r}}},d.BucketName={Description:"S3 Bucket Name",Value:{Ref:"S3Bucket"}},d.BucketArn={Description:"S3 Bucket ARN",Value:{"Fn::GetAtt":["S3Bucket","Arn"]}},a.CloudFrontOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`OAC-${s}`,Description:`OAC for ${s}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},a.UrlRewriteFunction={Type:"AWS::CloudFront::Function",Properties:{Name:{"Fn::Sub":"${AWS::StackName}-url-rewrite"},AutoPublish:!0,FunctionConfig:{Comment:"Append .html extension to URLs without extensions",Runtime:"cloudfront-js-2.0"},FunctionCode:`function handler(event) {
|
|
46
46
|
const request = event.request;
|
|
47
47
|
var uri = request.uri;
|
|
48
48
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as q}from"node:module";var j=Object.create;var{getPrototypeOf:k,defineProperty:i,getOwnPropertyNames:l}=Object;var m=Object.prototype.hasOwnProperty;function n(a){return this[a]}var o,p,r=(a,b,d)=>{var f=a!=null&&typeof a==="object";if(f){var g=b?o??=new WeakMap:p??=new WeakMap,h=g.get(a);if(h)return h}d=a!=null?j(k(a)):{};let c=b||!a||!a.__esModule?i(d,"default",{value:a,enumerable:!0}):d;if(a&&typeof a==="object"||typeof a==="function"){for(let e of l(a))if(!m.call(c,e))i(c,e,{get:n.bind(a,e),enumerable:!0})}if(f)g.set(a,c);return c};var s=(a,b)=>()=>(b||a((b={exports:{}}).exports,b),b.exports);var u=q(import.meta.url);
|
|
2
|
-
export{r as
|
|
2
|
+
export{r as Mv,s as Nv,u as Ov};
|
package/dist/deploy/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$c as ra,Ac as I,Bc as J,Cc as K,Dc as L,Ec as M,Fc as N,Gc as O,Hc as P,Ic as Q,Jc as R,Kc as S,Lc as T,Mc as U,Nc as V,Oc as W,Pc as X,Pd as Ha,Qc as ga,Qd as Ia,Rc as ha,Rd as Ja,Sc as ia,Sd as Ka,Tc as ja,Uc as ka,Vc as la,Wc as ma,Xc as na,Yc as oa,Zc as pa,_c as qa,ad as ta,bd as ua,cd as va,dd as wa,ed as xa,fd as ya,gd as za,hd as Aa,id as Ba,jd as Ca,kd as Da,ld as Ea,md as Fa,nd as Ga,xc as F,yc as G,zc as H}from"../chunk-
|
|
1
|
+
import{$c as ra,Ac as I,Bc as J,Cc as K,Dc as L,Ec as M,Fc as N,Gc as O,Hc as P,Ic as Q,Jc as R,Kc as S,Lc as T,Mc as U,Nc as V,Oc as W,Pc as X,Pd as Ha,Qc as ga,Qd as Ia,Rc as ha,Rd as Ja,Sc as ia,Sd as Ka,Tc as ja,Uc as ka,Vc as la,Wc as ma,Xc as na,Yc as oa,Zc as pa,_c as qa,ad as ta,bd as ua,cd as va,dd as wa,ed as xa,fd as ya,gd as za,hd as Aa,id as Ba,jd as Ca,kd as Da,ld as Ea,md as Fa,nd as Ga,xc as F,yc as G,zc as H}from"../chunk-0a4tqwm9.js";import{$d as fa,Td as Y,Ud as Z,Vd as _,Wd as aa,Xd as ba,Yd as ca,Zd as da,_d as ea}from"../chunk-zh0apedk.js";import{he as sa}from"../chunk-whyttetx.js";import"../chunk-yf8stygs.js";import"../chunk-mnmz8t7q.js";import"../chunk-n1fyryha.js";import"../chunk-ze5x2bpm.js";import"../chunk-k8x8mrkr.js";import"../chunk-j06r5rwv.js";import"../chunk-2ybcnrte.js";import{Ag as y,Ui as z,Vi as A,Wi as B,Xi as C,Yi as D,Zi as E,ug as s,vg as t,wg as u,xg as v,yg as w,zg as x}from"../chunk-fvpkxznh.js";import"../chunk-n5xmh0ma.js";import"../chunk-6cxb8d6y.js";import"../chunk-ess6vxfj.js";import"../chunk-j1g67djb.js";import"../chunk-ac87ds1k.js";import{ok as l,pk as m,qk as n,rk as o,sk as p,tk as q,uk as r}from"../chunk-7z50g5xz.js";import{Ak as f,Bk as g,Ck as h,Dk as i,Ek as j,Fk as k,vk as a,wk as b,xk as c,yk as d,zk as e}from"../chunk-n1hg0jxs.js";import"../chunk-q9a1z53k.js";import"../chunk-4wdxsnn2.js";import"../chunk-r8t25tbm.js";import"../chunk-zjyz926j.js";export{m as DEFAULT_SITE_PORT_RANGE,l as HOST_SITES_DIR,v as IPV6_EXCLUDED_HOST_LABELS,z as MANAGEMENT_DASHBOARD_SITE,F as addSiteToCloudConfig,r as allocateSitePorts,ra as buildAndPushContainerImage,sa as buildAndPushServerlessImage,ua as buildFunctionEnv,p as buildHostSitePortsScript,E as buildManagementDashboardArtifact,Aa as buildServerTopology,Ba as buildServerlessTopology,Ca as buildTopology,Ga as collectEgressMetrics,s as collectServerDnsDomains,qa as createContainerImageDependencies,la as createExistingStaticFullStackDependencies,ha as createStaticApiOriginDependencies,Ia as dashboardActions,A as dashboardCredentialsFile,V as dashboardPageRoutes,ea as deleteStaticSite,na as deployExistingStaticFullStack,va as deployServerlessApp,k as deployShipsFiles,ga as deploySite,ia as deployStaticApiOrigin,ba as deployStaticSite,fa as deployStaticSiteFull,Z as deployStaticSiteWithExternalDns,_ as deployStaticSiteWithExternalDnsFull,Ea as egressReportMetrics,R as ensureDashboardActor,D as ensureManagementDashboard,oa as estimateExistingStaticFullStackMonthlyCost,ka as estimateStaticApiOriginMonthlyCost,Fa as fetchEgressReport,ma as generateExistingStaticFullStackTemplate,Y as generateExternalDnsStaticSiteTemplate,aa as generateStaticSiteTemplate,g as hasComputeConfigured,d as hasProxyUpstream,pa as hashContainerContext,w as hostAcceptsIpv6,ta as infraEnvFromOutputs,S as initializeDashboardControlPlane,da as invalidateCache,b as isPhpSite,M as isValidHostname,u as normalizePublicIpv6,o as occupiedHostPorts,q as parseHostSiteFragments,n as parseUpstreamPort,x as reconcileAddressRecords,wa as redeployServerlessApp,G as removeSiteFromCloudConfig,t as removeStaleServerAddressRecords,N as renderAliasesValue,L as renderEnvValue,O as renderRedirectsValue,P as renderSiteSnippet,J as renderSslValue,K as renderStringValue,Ja as resolveDashboardAction,B as resolveDashboardAuth,Da as resolveDashboardData,W as resolveLegacyDashboardRoute,c as resolveProxyUpstreams,e as resolveSiteDeployTarget,f as resolveSiteKind,C as resolveUiSource,xa as rollbackServerlessApp,X as routesForDashboard,za as runRemoteCommand,Ha as sanitizeCloudConfig,Q as setAttachToInCloudConfig,ya as setMaintenance,I as setSitePropertyInCloudConfig,i as shipsARelease,j as shipsToBucket,a as siteInstallBase,Ka as startLocalDashboardServer,T as synchronizeDashboardUsers,U as trackDashboardOperation,H as updateSiteInCloudConfig,ca as uploadStaticFiles,h as validateDeploymentConfig,y as verifyAddressRecord,ja as verifyStaticApiOrigin};
|
package/dist/dns/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$f as d,Xf as a,Yf as b,Zf as c,ag as e,bg as f,cg as g,dg as h,eg as i,fg as j,gg as k,hg as l,ig as m,jg as n,kg as o,lg as p,mg as q,ng as r,og as s,pg as t,qg as u}from"../chunk-
|
|
1
|
+
import{$f as d,Xf as a,Yf as b,Zf as c,ag as e,bg as f,cg as g,dg as h,eg as i,fg as j,gg as k,hg as l,ig as m,jg as n,kg as o,lg as p,mg as q,ng as r,og as s,pg as t,qg as u}from"../chunk-j06r5rwv.js";import"../chunk-2ybcnrte.js";import"../chunk-ac87ds1k.js";import"../chunk-zjyz926j.js";export{d as CloudflareProvider,t as DnsProviderFactory,c as GoDaddyProvider,a as PROXIABLE_RECORD_TYPES,b as PorkbunProvider,i as Route53Provider,n as UnifiedDnsValidator,l as applyZoneMigration,r as createDnsProvider,p as createGoDaddyValidator,o as createPorkbunValidator,q as createRoute53Validator,s as detectDnsProvider,u as dnsProviders,j as exportRoute53Zone,k as planZoneMigration,e as policyTag,f as qualifyName,h as reconcileDeclaredRecords,g as resolveDeclaredRecords,m as verifyZoneParity};
|
|
@@ -17,4 +17,17 @@ export { buildUbuntuBootstrapScript as generateUbuntuAppCloudInit, type UbuntuBo
|
|
|
17
17
|
* inline under `runcmd:` silently breaks bun/caddy installation. Writing the
|
|
18
18
|
* file (shebang preserved) and running `bash <file>` guarantees a bash shell.
|
|
19
19
|
*/
|
|
20
|
-
export
|
|
20
|
+
export interface CloudInitUserDataExtras {
|
|
21
|
+
/** Where the script is written on the box. @default '/var/lib/cloud/ts-cloud-bootstrap.sh' */
|
|
22
|
+
scriptPath?: string;
|
|
23
|
+
/** File mode of the written script. @default '0755' */
|
|
24
|
+
permissions?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Top-level cloud-config YAML emitted before `write_files:` (hostname,
|
|
27
|
+
* users, packages, ...). Complete lines, already at top-level indentation.
|
|
28
|
+
*/
|
|
29
|
+
before?: string;
|
|
30
|
+
/** Top-level cloud-config YAML emitted after `runcmd:`. */
|
|
31
|
+
after?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function wrapCloudInitUserData(bootstrapScript: string, extras?: CloudInitUserDataExtras): string;
|
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import type { CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTargetsOptions, ProvisionComputeOptions, ReachableResource, RemoteDeployResult, RunRemoteDeployOptions, UploadReleaseOptions, UploadReleaseResult } from '@ts-cloud/core';
|
|
2
2
|
import { HetznerClient } from './client';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* A syntax error names a line number in a file that only ever existed on the
|
|
7
|
-
* box, and the deploy deletes it on the way out — so the one thing needed to
|
|
8
|
-
* understand the failure is the one thing nobody can look at. Without this you
|
|
9
|
-
* are reduced to guessing which generated fragment is unbalanced, or to
|
|
10
|
-
* reproducing the whole script by hand from its builders.
|
|
11
|
-
*
|
|
12
|
-
* Only a window around the reported line, and every `KEY="value"` line inside
|
|
13
|
-
* it is redacted: the script carries the runtime environment, and a deploy
|
|
14
|
-
* failure must not become the reason a database password is in a CI log.
|
|
15
|
-
*/
|
|
16
|
-
export declare function describeScriptSyntaxError(error: unknown, script: string): string;
|
|
17
|
-
export declare function formatSshFailure(error: unknown): string;
|
|
3
|
+
import { describeScriptSyntaxError, formatSshFailure } from '../shared/remote-failure';
|
|
4
|
+
export { describeScriptSyntaxError, formatSshFailure };
|
|
18
5
|
export interface HetznerDriverOptions {
|
|
19
6
|
apiToken?: string;
|
|
20
7
|
/**
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hetzner driver state.
|
|
3
|
+
*
|
|
4
|
+
* The file handling itself lives in `../shared/driver-state` (one reader and
|
|
5
|
+
* writer for every SSH-style driver); this module keeps the Hetzner-typed
|
|
6
|
+
* view of it so the driver, the dashboard and the CLI read `serverId` and
|
|
7
|
+
* friends without a cast at every call site.
|
|
8
|
+
*/
|
|
9
|
+
import type { DriverState } from '../shared/driver-state';
|
|
10
|
+
export { LEGACY_DRIVER_STATE_DIR } from '../shared/driver-state';
|
|
1
11
|
export interface HetznerDriverState {
|
|
2
12
|
provider: 'hetzner';
|
|
3
13
|
stackName: string;
|
|
@@ -30,7 +40,12 @@ export interface HetznerDriverState {
|
|
|
30
40
|
lbServerId?: number;
|
|
31
41
|
appServerIds?: number[];
|
|
32
42
|
}
|
|
33
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The legacy, project-relative driver-state directory. Kept for callers that
|
|
45
|
+
* spell the path by hand; new code should ask `driverStateDir()` instead,
|
|
46
|
+
* which also honours a configured state directory.
|
|
47
|
+
*/
|
|
48
|
+
export declare const STATE_DIR: string;
|
|
34
49
|
export declare function driverStatePath(stackName: string): string;
|
|
35
50
|
export declare function readDriverState(stackName: string): Promise<HetznerDriverState | null>;
|
|
36
|
-
export declare function writeDriverState(stackName: string, state:
|
|
51
|
+
export declare function writeDriverState(stackName: string, state: DriverState): Promise<void>;
|
package/dist/drivers/index.d.ts
CHANGED
|
@@ -2,6 +2,21 @@ export * from './factory';
|
|
|
2
2
|
export { AwsDriver } from './aws/driver';
|
|
3
3
|
export { HetznerDriver } from './hetzner/driver';
|
|
4
4
|
export { isBoxMode, LocalBoxDriver } from './local-box/driver';
|
|
5
|
+
export { assertSshComputeConfig, SSH_DEPLOY_STORAGE_PATH, SSH_SKIP_BOOTSTRAP_ENV, SshDriver } from './ssh/driver';
|
|
6
|
+
export type { SshDriverOptions } from './ssh/driver';
|
|
7
|
+
export { resolveSshHostKeyPolicy, resolveSshHosts, resolveSshLan, resolveSshPort, resolveSshPrivateKeyPath, resolveSshProfile, resolveSshPublicIp, resolveSshSettings, resolveSshSudo, resolveSshUser, SSH_DEFAULTS, } from './ssh/config';
|
|
8
|
+
export type { ResolvedSshHost, ResolvedSshSettings, SshHostKeyPolicyName, SshLanConfig, SshOverrides, SshProfile } from './ssh/config';
|
|
9
|
+
export { assertArchSupported, buildSshBootstrapScript, RASPBERRY_PI_DEFAULT_SWAP_GB, SSH_BOOTSTRAP_MARKER_DIR, SSH_BOOTSTRAP_VERSION, sshBootstrapMarkerPath, } from './ssh/bootstrap';
|
|
10
|
+
export type { SshBootstrapOptions } from './ssh/bootstrap';
|
|
11
|
+
export { evaluatePreflight, formatPreflightFindings, parsePreflightFacts, preflightFailed, SSH_PREFLIGHT_SCRIPT, } from './ssh/preflight';
|
|
12
|
+
export type { PreflightContext, SshPreflightFacts } from './ssh/preflight';
|
|
13
|
+
export { BOOT_PARTITION_LABEL, buildCloudInitFirstBoot, FIRST_BOOT_SCRIPT_PATH } from './ssh/first-boot';
|
|
14
|
+
export type { FirstBootBundle, FirstBootIdentity, FirstBootOptions, FirstBootOs, FirstBootWifi } from './ssh/first-boot';
|
|
15
|
+
export { buildScpArgsFor, buildSshArgsFor, findKnownHostKey, knownHostsLine, knownHostsToken, scanHostKey, SSH_INSECURE_HOST_KEY_OPTS, SSH_KEEPALIVE_OPTS, sshHostKeyFingerprint, sshKnownHostsPath, SystemSshTransport, } from './shared/ssh-transport';
|
|
16
|
+
export type { CommandResult, CommandRunner, ScannedHostKey, SshExecOptions, SshHostKeyPolicy, SshHostKeyResult, SshTransport, SshTransportOptions, SystemSshTransportDeps, } from './shared/ssh-transport';
|
|
17
|
+
export { driverStateDir, driverStatePath, LEGACY_DRIVER_STATE_DIR, readDriverState, writeDriverState, } from './shared/driver-state';
|
|
18
|
+
export type { DriverState, SshDriverState } from './shared/driver-state';
|
|
19
|
+
export { describeScriptSyntaxError, formatSshFailure, summarizeRemoteFailures, surfaceRemoteNotices } from './shared/remote-failure';
|
|
5
20
|
export { HetznerClient, normalizeSshPublicKey, resolveHetznerApiToken } from './hetzner/client';
|
|
6
21
|
export { executeHetznerServerResize, isHetznerCapacityError, planHetznerServerResize, } from './hetzner/resize';
|
|
7
22
|
export type { ExecuteHetznerResizeOptions, HetznerResizeHooks, HetznerResizePhase, HetznerResizePlan, HetznerResizeResult, HetznerResizeVerification, } from './hetzner/resize';
|
|
@@ -12,9 +27,10 @@ export type { HetznerHostOptimizationOptions, HetznerHostOptimizationPlan, Hetzn
|
|
|
12
27
|
export { acquireResizeLock, readResizeCheckpoint, resizeCheckpointPath, resizeLockPath, writeResizeCheckpoint, } from './hetzner/resize-state';
|
|
13
28
|
export type { HetznerResizeCheckpoint } from './hetzner/resize-state';
|
|
14
29
|
export { generateUbuntuAppCloudInit, wrapCloudInitUserData } from './hetzner/cloud-init';
|
|
30
|
+
export type { CloudInitUserDataExtras } from './hetzner/cloud-init';
|
|
15
31
|
export { ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4 } from './hetzner/provision';
|
|
16
32
|
export type { EnsuredResource, EnsuredServer, EnsureFirewallOptions, EnsureServerOptions, EnsureSshKeyOptions, } from './hetzner/provision';
|
|
17
|
-
export { buildSshArgs, scpUpload, sshExec, sshExecOrThrow, waitForCloudInit, waitForSsh } from './shared/remote-exec';
|
|
33
|
+
export { buildSshArgs, REMOTE_SCRIPT_RUNNER, remoteScriptRunner, scpUpload, sshExec, sshExecOrThrow, waitForCloudInit, waitForSsh } from './shared/remote-exec';
|
|
18
34
|
export type { RemoteExecOptions, RemoteExecResult, WaitOptions } from './shared/remote-exec';
|
|
19
35
|
export { AwsBoxProvisioner, buildBoxUserData, createBoxProvisioner, HetznerBoxProvisioner, UBUNTU_2404_AMI_PARAM, } from './shared/box-provision';
|
|
20
36
|
export type { AwsBoxProvisionerOptions, BoxPort, BoxProviderName, BoxProvisioner, BoxSpec, CreateBoxProvisionerOptions, ProvisionedBox, } from './shared/box-provision';
|
package/dist/drivers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$g as q,Ah as Q,Bh as R,Ch as S,Dh as T,Eh as U,Fh as V,Gh as W,Hh as X,Ih as Y,Jh as Z,Kh as _,
|
|
1
|
+
import{$g as q,$h as qa,$i as hb,Ah as Q,Ai as Ra,Bg as a,Bh as R,Bi as Sa,Cg as b,Ch as S,Ci as Ta,Dg as c,Dh as T,Di as Ua,Eg as d,Eh as U,Ei as Va,Fh as V,Fi as Wa,Gh as W,Gi as Xa,Hh as X,Hi as Ya,Ih as Y,Ii as Za,Jh as Z,Ji as _a,Kh as _,Ki as $a,Lh as aa,Mh as ba,Nh as ca,Ni as ab,Oh as da,Oi as bb,Pg as e,Ph as ea,Pi as cb,Qg as f,Qh as fa,Qi as db,Rg as g,Rh as ga,Ri as eb,Sg as h,Sh as ha,Si as fb,Tg as i,Th as ia,Ti as gb,Ug as j,Uh as ja,Vg as k,Vh as ka,Wg as l,Wh as la,Xg as m,Xh as ma,Yg as n,Yh as na,Zg as o,Zh as oa,_g as p,_h as pa,ah as r,ai as ra,aj as ib,bh as s,bi as sa,bj as jb,ch as t,ci as ta,cj as kb,dh as u,di as ua,dj as lb,eh as v,ei as va,ej as mb,fh as w,fi as wa,fj as nb,gh as x,gi as xa,gj as ob,hh as y,hi as ya,ih as z,ii as za,jh as A,ji as Aa,ki as Ba,lh as B,li as Ca,mh as C,mi as Da,nh as D,ni as Ea,oh as E,oi as Fa,ph as F,pi as Ga,qh as G,qi as Ha,rh as H,ri as Ia,sh as I,si as Ja,th as J,ti as Ka,uh as K,ui as La,vh as L,vi as Ma,wh as M,wi as Na,xh as N,xi as Oa,yh as O,yi as Pa,zh as P,zi as Qa}from"../chunk-fvpkxznh.js";import"../chunk-n5xmh0ma.js";import"../chunk-6cxb8d6y.js";import"../chunk-ess6vxfj.js";import"../chunk-j1g67djb.js";import"../chunk-ac87ds1k.js";import"../chunk-n1hg0jxs.js";import"../chunk-4wdxsnn2.js";import"../chunk-r8t25tbm.js";import"../chunk-zjyz926j.js";export{_a as AwsBoxProvisioner,s as AwsDriver,Ba as BOOT_PARTITION_LABEL,ya as CloudDriverFactory,e as DEFAULT_RPX_CERTS_DIR,Aa as FIRST_BOOT_SCRIPT_PATH,Za as HetznerBoxProvisioner,B as HetznerClient,K as HetznerDriver,F as LEGACY_DRIVER_STATE_DIR,L as LocalBoxDriver,mb as MANAGED_CACHE_POLICY_DISABLED,lb as MANAGED_CACHE_POLICY_OPTIMIZED,nb as MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,aa as RASPBERRY_PI_DEFAULT_SWAP_GB,A as REMOTE_SCRIPT_RUNNER,m as RPX_DIR,n as RPX_LAUNCHER_PATH,o as RPX_SERVICE_NAME,Z as SSH_BOOTSTRAP_MARKER_DIR,Y as SSH_BOOTSTRAP_VERSION,da as SSH_DEFAULTS,ta as SSH_DEPLOY_STORAGE_PATH,N as SSH_INSECURE_HOST_KEY_OPTS,O as SSH_KEEPALIVE_OPTS,oa as SSH_PREFLIGHT_SCRIPT,ua as SSH_SKIP_BOOTSTRAP_ENV,wa as SshDriver,X as SystemSshTransport,Xa as UBUNTU_2404_AMI_PARAM,Sa as acquireResizeLock,La as applyHetznerHostOptimization,ba as assertArchSupported,va as assertSshComputeConfig,eb as buildAwsArtifactFetch,Ya as buildBoxUserData,ob as buildCloudFrontOriginConfig,Ca as buildCloudInitFirstBoot,Ka as buildHetznerHostOptimizationScript,gb as buildHostCleanupScript,fb as buildLocalArtifactFetch,j as buildRpxConfig,q as buildRpxFragmentRefreshScript,k as buildRpxLbConfig,p as buildRpxProvisionScript,Q as buildScpArgsFor,bb as buildSiteDeployScript,t as buildSshArgs,P as buildSshArgsFor,ca as buildSshBootstrapScript,cb as buildStaticSiteDeployScript,za as cloudDrivers,Ma as collectHetznerHostOptimizationReport,Ga as collectHetznerResizeManifest,$a as createBoxProvisioner,xa as createCloudDriver,ib as deployAllComputeSites,hb as deploySiteRelease,i as deriveRouteId,a as describeScriptSyntaxError,G as driverStateDir,H as driverStatePath,Ua as ensureFirewall,Va as ensureServer,Ta as ensureSshKey,qa as evaluatePreflight,Fa as executeHetznerServerResize,V as findKnownHostKey,sa as formatPreflightFindings,b as formatSshFailure,g as gatewayHostnames,r as generateUbuntuAppCloudInit,f as hasAutoWwwVariant,M as isBoxMode,Ea as isHetznerCapacityError,U as knownHostsLine,T as knownHostsToken,h as normalizeRoutePath,D as normalizeSshPublicKey,pa as parsePreflightFacts,Da as planHetznerServerResize,ra as preflightFailed,Ha as prepareHetznerResize,I as readDriverState,Qa as readResizeCheckpoint,db as releaseTarballTmpPath,jb as reloadRpxGateway,z as remoteScriptRunner,l as renderRpxLauncher,kb as renewRpxCertificates,Oa as resizeCheckpointPath,Pa as resizeLockPath,ab as resolveExecStart,C as resolveHetznerApiToken,Ja as resolveHetznerHostOptimizationPlan,ia as resolveSshHostKeyPolicy,ea as resolveSshHosts,ma as resolveSshLan,ga as resolveSshPort,ha as resolveSshPrivateKeyPath,ka as resolveSshProfile,la as resolveSshPublicIp,na as resolveSshSettings,ja as resolveSshSudo,fa as resolveSshUser,S as scanHostKey,w as scpUpload,Wa as serverPublicIpv4,_ as sshBootstrapMarkerPath,u as sshExec,v as sshExecOrThrow,R as sshHostKeyFingerprint,W as sshKnownHostsPath,d as summarizeRemoteFailures,c as surfaceRemoteNotices,Na as verifyHetznerHostOptimization,Ia as verifyHetznerResize,y as waitForCloudInit,x as waitForSsh,E as wrapCloudInitUserData,J as writeDriverState,Ra as writeResizeCheckpoint};
|
|
@@ -9,7 +9,7 @@ import type { CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTarget
|
|
|
9
9
|
* the box; provisioning/upload methods are inert (the box is already up).
|
|
10
10
|
*/
|
|
11
11
|
export declare class LocalBoxDriver implements CloudDriver {
|
|
12
|
-
readonly name: '
|
|
12
|
+
readonly name: 'ssh';
|
|
13
13
|
readonly usesCloudFormation = false;
|
|
14
14
|
getComputeOutputs(): Promise<ComputeStackOutputs>;
|
|
15
15
|
uploadRelease(options: UploadReleaseOptions): Promise<UploadReleaseResult>;
|
|
@@ -33,6 +33,13 @@ export interface ComputeProvisionOptions {
|
|
|
33
33
|
* than one that offers SMTP to the internet.
|
|
34
34
|
*/
|
|
35
35
|
environment?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Where the managed `authorized_keys` block is written. Defaults to root's
|
|
38
|
+
* file; a bootstrap that deploys as another user (the ssh provider with a
|
|
39
|
+
* `pi` or `deploy` user) points it at that user's home, or the operator
|
|
40
|
+
* keys in `compute.sshKeys` would authorize logins for the wrong account.
|
|
41
|
+
*/
|
|
42
|
+
authorizedKeysPath?: string;
|
|
36
43
|
}
|
|
37
44
|
/**
|
|
38
45
|
* Build the machine provisioning scripts from a CloudConfig. Returns the
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-stack state a compute driver records on the machine running deploys.
|
|
3
|
+
*
|
|
4
|
+
* Every SSH-style driver has to remember which box a stack lives on: Hetzner
|
|
5
|
+
* pins a server id so CI can find the existing box instead of provisioning a
|
|
6
|
+
* duplicate, and the ssh driver pins the host it adopted plus what it did to
|
|
7
|
+
* it. One file per stack, one reader and one writer, so a driver, the
|
|
8
|
+
* dashboard and the CLI cannot disagree about where that file is.
|
|
9
|
+
*
|
|
10
|
+
* ## Where the file lives
|
|
11
|
+
*
|
|
12
|
+
* Driver state predates the configurable state directory and has a legacy
|
|
13
|
+
* home of its own, `storage/cloud/state/` (the Stacks storage convention),
|
|
14
|
+
* which is meant to be COMMITTED: unlike dashboard credentials it holds
|
|
15
|
+
* nothing secret, and a checkout without it re-provisions. A project that
|
|
16
|
+
* configured `stateDir` (or set `TS_CLOUD_STATE_DIR`) keeps driver state
|
|
17
|
+
* under it instead, in `<stateDir>/state/`. A Stacks application sets
|
|
18
|
+
* `stateDir: 'storage/cloud'`, so for it the two spellings name the same
|
|
19
|
+
* directory and nothing moves.
|
|
20
|
+
*/
|
|
21
|
+
import type { HetznerDriverState } from '../hetzner/state';
|
|
22
|
+
/** The committed driver-state directory used when no state directory is configured. */
|
|
23
|
+
export declare const LEGACY_DRIVER_STATE_DIR = "storage/cloud/state";
|
|
24
|
+
/** What the ssh driver remembers about a host it adopted. */
|
|
25
|
+
export interface SshDriverState {
|
|
26
|
+
provider: 'ssh';
|
|
27
|
+
stackName: string;
|
|
28
|
+
/** The hostname or address deploys connect to, exactly as configured. */
|
|
29
|
+
host: string;
|
|
30
|
+
sshUser: string;
|
|
31
|
+
sshPort: number;
|
|
32
|
+
/** `SHA256:...` of the pinned host key, when the host-key policy pins. */
|
|
33
|
+
hostKeyFingerprint?: string;
|
|
34
|
+
/** The address DNS should point at, when known (configured, or detected). */
|
|
35
|
+
publicIp?: string;
|
|
36
|
+
/** The host's first LAN address, as reported by the preflight. */
|
|
37
|
+
lanIp?: string;
|
|
38
|
+
deployStoragePath?: string;
|
|
39
|
+
profile?: 'raspberry-pi' | 'generic';
|
|
40
|
+
/** The bootstrap recipe version last applied to the host. */
|
|
41
|
+
bootstrapVersion?: number;
|
|
42
|
+
/** When that bootstrap ran, ISO 8601. */
|
|
43
|
+
bootstrappedAt?: string;
|
|
44
|
+
}
|
|
45
|
+
export type DriverState = HetznerDriverState | SshDriverState;
|
|
46
|
+
/**
|
|
47
|
+
* The directory driver state files live in, absolute.
|
|
48
|
+
*
|
|
49
|
+
* `<stateDir>/state` when a state directory is configured, the legacy
|
|
50
|
+
* `storage/cloud/state` otherwise. See the module comment for why the legacy
|
|
51
|
+
* path is not simply `.ts-cloud/state`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function driverStateDir(cwd?: string): string;
|
|
54
|
+
/** Absolute path of the state file for `stackName`. */
|
|
55
|
+
export declare function driverStatePath(stackName: string, cwd?: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Read the state file for `stackName`, or null when there is none (or it is
|
|
58
|
+
* unreadable: a corrupt file is treated as absent, and the atomic write below
|
|
59
|
+
* is what keeps that from ever losing a pin).
|
|
60
|
+
*/
|
|
61
|
+
export declare function readDriverState<T extends DriverState = DriverState>(stackName: string, cwd?: string): Promise<T | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Replace the state file for `stackName` atomically: a crash mid-write would
|
|
64
|
+
* corrupt the JSON, and the reader's catch-all would then lose the pinned box
|
|
65
|
+
* (silently re-provisioning a duplicate). Temp file + rename on the same
|
|
66
|
+
* filesystem is atomic.
|
|
67
|
+
*/
|
|
68
|
+
export declare function writeDriverState(stackName: string, state: DriverState, cwd?: string): Promise<void>;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
export interface RemoteExecOptions {
|
|
10
10
|
/** SSH user. @default 'root' */
|
|
11
11
|
user?: string;
|
|
12
|
+
/** SSH port. Omit for the ambient default (22, or whatever `~/.ssh/config` says). */
|
|
13
|
+
port?: number;
|
|
12
14
|
/** Private key passed as `ssh -i`. Omit to use the ambient SSH config/agent. */
|
|
13
15
|
identityFile?: string;
|
|
14
16
|
/** SSH `ConnectTimeout` in seconds. @default 10 */
|
|
@@ -23,8 +25,11 @@ export interface RemoteExecResult {
|
|
|
23
25
|
* The ssh/scp CLI arguments implied by {@link RemoteExecOptions}. Host key
|
|
24
26
|
* checking is disabled because these helpers target freshly-created servers
|
|
25
27
|
* whose host keys cannot be known in advance.
|
|
28
|
+
*
|
|
29
|
+
* `scp` spells the port flag differently (`-P`; its `-p` preserves file
|
|
30
|
+
* times), so say which binary the arguments are for.
|
|
26
31
|
*/
|
|
27
|
-
export declare function buildSshArgs(options?: RemoteExecOptions): string[];
|
|
32
|
+
export declare function buildSshArgs(options?: RemoteExecOptions, binary?: 'ssh' | 'scp'): string[];
|
|
28
33
|
/** Run a command on the host over SSH, capturing exit code and output. */
|
|
29
34
|
export declare function sshExec(host: string, command: string, options?: RemoteExecOptions): Promise<RemoteExecResult>;
|
|
30
35
|
/** Like {@link sshExec}, but throws on non-zero exit and returns stdout. */
|
|
@@ -63,4 +68,8 @@ export declare function waitForCloudInit(host: string, options?: WaitOptions): P
|
|
|
63
68
|
* `-s` in the first place), and `mktemp` creates the file 0600, so the window
|
|
64
69
|
* where they touch disk is both short and unreadable to other users.
|
|
65
70
|
*/
|
|
71
|
+
export declare function remoteScriptRunner(options?: {
|
|
72
|
+
sudo?: boolean;
|
|
73
|
+
}): string;
|
|
74
|
+
/** The runner for a root deploy user; see {@link remoteScriptRunner}. */
|
|
66
75
|
export declare const REMOTE_SCRIPT_RUNNER: string;
|
|
@@ -12,6 +12,47 @@
|
|
|
12
12
|
* `formatSshFailure`), so this only has to decide what is worth showing.
|
|
13
13
|
*/
|
|
14
14
|
import type { RemoteDeployInstanceResult } from '@ts-cloud/core';
|
|
15
|
+
/**
|
|
16
|
+
* The part of the deploy script bash refused to parse.
|
|
17
|
+
*
|
|
18
|
+
* A syntax error names a line number in a file that only ever existed on the
|
|
19
|
+
* box, and the deploy deletes it on the way out, so the one thing needed to
|
|
20
|
+
* understand the failure is the one thing nobody can look at. Without this you
|
|
21
|
+
* are reduced to guessing which generated fragment is unbalanced, or to
|
|
22
|
+
* reproducing the whole script by hand from its builders.
|
|
23
|
+
*
|
|
24
|
+
* Only a window around the reported line, and every `KEY="value"` line inside
|
|
25
|
+
* it is redacted: the script carries the runtime environment, and a deploy
|
|
26
|
+
* failure must not become the reason a database password is in a CI log.
|
|
27
|
+
*/
|
|
28
|
+
export declare function describeScriptSyntaxError(error: unknown, script: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* One operator-facing line (plus redacted output) for a failed ssh/scp child.
|
|
31
|
+
*
|
|
32
|
+
* Takes the shape Node's `execFileSync` error has (`status`, `signal`,
|
|
33
|
+
* `stdout`, `stderr`) so a `Bun.spawn`-based transport only has to build the
|
|
34
|
+
* same object. Never includes the command line: it carries the deploy script.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatSshFailure(error: unknown): string;
|
|
37
|
+
/**
|
|
38
|
+
* Print the lines a remote deploy script meant a human to read.
|
|
39
|
+
*
|
|
40
|
+
* The remote stdout has always been captured and then dropped on the floor,
|
|
41
|
+
* which is why nothing the box says has ever reached a CI log: not the
|
|
42
|
+
* memory-commitment report, not `migrate`, not `catalog:sync`. A deploy that
|
|
43
|
+
* cannot tell you what it did on the box is one you have to SSH in to
|
|
44
|
+
* understand, and by then you are debugging rather than reading.
|
|
45
|
+
*
|
|
46
|
+
* Only `[ts-cloud]`-prefixed lines are surfaced, and that restraint is
|
|
47
|
+
* deliberate rather than tidy. The script fed to `bash -s` carries the runtime
|
|
48
|
+
* environment here-document - database credentials, APP_KEY, provider tokens -
|
|
49
|
+
* which is why {@link formatSshFailure} refuses to echo a failing command back.
|
|
50
|
+
* Remote *stdout* is not the script, so it does not contain those secrets by
|
|
51
|
+
* construction, but it is whatever arbitrary `preStart` commands chose to
|
|
52
|
+
* print, and an app that logs its own config on boot would leak it here. An
|
|
53
|
+
* explicit marker means ts-cloud only ever republishes lines ts-cloud wrote.
|
|
54
|
+
*/
|
|
55
|
+
export declare function surfaceRemoteNotices(output: string): void;
|
|
15
56
|
/**
|
|
16
57
|
* Build the `error` for a {@link import('@ts-cloud/core').RemoteDeployResult}
|
|
17
58
|
* whose run did not fully succeed. `summary` is the one-line what-failed (e.g.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type SshHostKeyPolicy = 'pin' | 'accept-new' | 'insecure';
|
|
2
|
+
export interface SshTransportOptions {
|
|
3
|
+
user: string;
|
|
4
|
+
/** @default 22 */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** Private key passed as `-i`. */
|
|
7
|
+
identityFile: string;
|
|
8
|
+
/**
|
|
9
|
+
* `'insecure'` disables host-key checking (the cloud drivers' behaviour).
|
|
10
|
+
* Otherwise the policy plus the known_hosts file it reads and writes.
|
|
11
|
+
*/
|
|
12
|
+
hostKey: 'insecure' | {
|
|
13
|
+
policy: 'pin' | 'accept-new';
|
|
14
|
+
knownHostsFile: string;
|
|
15
|
+
};
|
|
16
|
+
/** @default 30 */
|
|
17
|
+
connectTimeoutSec?: number;
|
|
18
|
+
/**
|
|
19
|
+
* How a script is executed on the host once it arrives over stdin. Defaults
|
|
20
|
+
* to {@link remoteScriptRunner} without sudo; `exec` can pick the sudo
|
|
21
|
+
* variant per call.
|
|
22
|
+
*/
|
|
23
|
+
runner?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface SshExecOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Run the script through `sudo -n`. Unset: the transport's configured
|
|
28
|
+
* runner. A deploy user that is not root needs it for everything except
|
|
29
|
+
* the preflight, which must run as the user to find out whether sudo works.
|
|
30
|
+
*/
|
|
31
|
+
sudo?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface SshHostKeyResult {
|
|
34
|
+
/** `SHA256:...`, empty when the key could not be learned (insecure policy, scan failed). */
|
|
35
|
+
fingerprint: string;
|
|
36
|
+
/** True when this call is what recorded the key. */
|
|
37
|
+
pinnedNow: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface SshTransport {
|
|
40
|
+
/** Run `script` on `host`; resolves with stdout, rejects with a redacted failure. */
|
|
41
|
+
exec(host: string, script: string, options?: SshExecOptions): Promise<string>;
|
|
42
|
+
/** Copy one local file to `remotePath` on `host`. */
|
|
43
|
+
scp(host: string, localPath: string, remotePath: string): Promise<void>;
|
|
44
|
+
/** Whether sshd on `host` accepts a connection right now. */
|
|
45
|
+
probe(host: string): Promise<boolean>;
|
|
46
|
+
/** Learn (and, when pinning, record) the host key before the first real command. */
|
|
47
|
+
ensureHostKey(host: string): Promise<SshHostKeyResult>;
|
|
48
|
+
}
|
|
49
|
+
export interface CommandResult {
|
|
50
|
+
code: number;
|
|
51
|
+
signal?: string | null;
|
|
52
|
+
stdout: string;
|
|
53
|
+
stderr: string;
|
|
54
|
+
}
|
|
55
|
+
/** Runs a command; `input`, when given, is piped to stdin. Injectable for tests. */
|
|
56
|
+
export type CommandRunner = (command: string[], input?: string) => Promise<CommandResult>;
|
|
57
|
+
export declare const runCommand: CommandRunner;
|
|
58
|
+
/**
|
|
59
|
+
* Host-key options for a box the provider API identifies: never check, never
|
|
60
|
+
* remember. Byte-for-byte what the Hetzner driver passes.
|
|
61
|
+
*/
|
|
62
|
+
export declare const SSH_INSECURE_HOST_KEY_OPTS: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* Keepalive + connect timeout for every ssh/scp. Without these a connection
|
|
65
|
+
* that stalls mid-transfer (a flaky network, an sshd hiccup) hangs the deploy
|
|
66
|
+
* FOREVER. ServerAlive probes abort a silent connection after ~60s (15s x 4)
|
|
67
|
+
* so the transfer fails loudly (and, for scp, is retried) instead of wedging.
|
|
68
|
+
*/
|
|
69
|
+
export declare const SSH_KEEPALIVE_OPTS: readonly string[];
|
|
70
|
+
/**
|
|
71
|
+
* The `ssh` arguments (everything after the binary, ending in `user@host`)
|
|
72
|
+
* for `options`. `extra` is spliced in before the destination so a caller can
|
|
73
|
+
* add a one-off `-o`. Pure, for tests.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildSshArgsFor(options: SshTransportOptions, host: string, extra?: string[]): string[];
|
|
76
|
+
/** The `scp` arguments for copying `localPath` to `host:remotePath`. Pure, for tests. */
|
|
77
|
+
export declare function buildScpArgsFor(options: SshTransportOptions, host: string, localPath: string, remotePath: string): string[];
|
|
78
|
+
/** `SHA256:...` fingerprint of a base64 host key, as `ssh-keygen -l` prints it. */
|
|
79
|
+
export declare function sshHostKeyFingerprint(key: string): string;
|
|
80
|
+
export interface ScannedHostKey {
|
|
81
|
+
algorithm: string;
|
|
82
|
+
key: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Ask the host for its ed25519 key with `ssh-keyscan`. Bounded (`-T 10`) so an
|
|
86
|
+
* unreachable host fails in seconds rather than at the TCP timeout.
|
|
87
|
+
*/
|
|
88
|
+
export declare function scanHostKey(host: string, port?: number, run?: CommandRunner): Promise<ScannedHostKey>;
|
|
89
|
+
/** The host field ssh looks up in known_hosts: `host` on port 22, `[host]:port` otherwise. */
|
|
90
|
+
export declare function knownHostsToken(host: string, port?: number): string;
|
|
91
|
+
/** The known_hosts entry recorded for `host` (one line, no trailing newline). */
|
|
92
|
+
export declare function knownHostsLine(host: string, port: number, key: ScannedHostKey): string;
|
|
93
|
+
/**
|
|
94
|
+
* The recorded key for `host`, or null when the file has no plain entry for
|
|
95
|
+
* it. Hashed entries (`|1|...`) cannot be matched and are ignored, which is
|
|
96
|
+
* fine: this transport only ever writes plain ones.
|
|
97
|
+
*/
|
|
98
|
+
export declare function findKnownHostKey(content: string, host: string, port?: number): ScannedHostKey | null;
|
|
99
|
+
/** Where the ssh driver keeps the host keys it pinned: `<stateDir>/ssh/known_hosts`. */
|
|
100
|
+
export declare function sshKnownHostsPath(cwd?: string): string;
|
|
101
|
+
export interface SystemSshTransportDeps {
|
|
102
|
+
run?: CommandRunner;
|
|
103
|
+
scan?: typeof scanHostKey;
|
|
104
|
+
readKnownHosts?: (file: string) => Promise<string>;
|
|
105
|
+
appendKnownHosts?: (file: string, line: string) => Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
/** {@link SshTransport} on the system `ssh`, `scp` and `ssh-keyscan` binaries. */
|
|
108
|
+
export declare class SystemSshTransport implements SshTransport {
|
|
109
|
+
private readonly options;
|
|
110
|
+
private readonly run;
|
|
111
|
+
private readonly scan;
|
|
112
|
+
private readonly readKnownHosts;
|
|
113
|
+
private readonly appendKnownHosts;
|
|
114
|
+
constructor(options: SshTransportOptions, deps?: SystemSshTransportDeps);
|
|
115
|
+
/** The runner a script is fed to; see {@link SshExecOptions.sudo}. */
|
|
116
|
+
runnerFor(options?: SshExecOptions): string;
|
|
117
|
+
exec(host: string, script: string, options?: SshExecOptions): Promise<string>;
|
|
118
|
+
scp(host: string, localPath: string, remotePath: string): Promise<void>;
|
|
119
|
+
probe(host: string): Promise<boolean>;
|
|
120
|
+
ensureHostKey(host: string): Promise<SshHostKeyResult>;
|
|
121
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bootstrap for a bring-your-own host.
|
|
3
|
+
*
|
|
4
|
+
* The recipe is the Hetzner driver's, composed the same way from the same
|
|
5
|
+
* builders (the rpx gateway, the machine provisioning, the Ubuntu bootstrap),
|
|
6
|
+
* so an adopted Pi and a cloud box end up running the same stack from the
|
|
7
|
+
* same code. What differs is the machine it lands on:
|
|
8
|
+
*
|
|
9
|
+
* - It may run MORE than once. cloud-init on a Pi has an upstream bug that
|
|
10
|
+
* reruns modules on every boot, an operator may `cloud ssh:bootstrap` twice,
|
|
11
|
+
* and a deploy calls the adopt on every run. So the whole script is guarded
|
|
12
|
+
* by a version marker: once `/var/lib/ts-cloud/bootstrap.v<N>` exists, only
|
|
13
|
+
* the gateway fragment is refreshed. Bumping {@link SSH_BOOTSTRAP_VERSION}
|
|
14
|
+
* is how a changed recipe gets applied to hosts bootstrapped by an older one.
|
|
15
|
+
* - It may run before the clock is right. A Pi 5 has no battery-backed RTC,
|
|
16
|
+
* and apt refuses Release files "from the future" while ACME refuses a
|
|
17
|
+
* skewed clock outright. Time sync is awaited before anything touches apt.
|
|
18
|
+
* - It may run as a user that is not root. The scripts arrive through the
|
|
19
|
+
* sudo runner, so they ARE root, but the deploy user still has to be able
|
|
20
|
+
* to scp into the artifact and staging directories, and the operator keys
|
|
21
|
+
* belong in that user's `authorized_keys`, not root's.
|
|
22
|
+
* - It may run on a small SD card. The raspberry-pi profile halves the
|
|
23
|
+
* swapfile and bounds the journal.
|
|
24
|
+
*/
|
|
25
|
+
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
26
|
+
import type { SshLanConfig, SshProfile } from './config';
|
|
27
|
+
import type { SshPreflightFacts } from './preflight';
|
|
28
|
+
/** Bump when the recipe changes in a way an already-bootstrapped host must pick up. */
|
|
29
|
+
export declare const SSH_BOOTSTRAP_VERSION = 1;
|
|
30
|
+
/** Where the bootstrap records that it ran. */
|
|
31
|
+
export declare const SSH_BOOTSTRAP_MARKER_DIR = "/var/lib/ts-cloud";
|
|
32
|
+
export declare function sshBootstrapMarkerPath(version?: number): string;
|
|
33
|
+
/** Swap the raspberry-pi profile provisions when `compute.swapGb` is unset. */
|
|
34
|
+
export declare const RASPBERRY_PI_DEFAULT_SWAP_GB = 1;
|
|
35
|
+
export interface SshBootstrapOptions {
|
|
36
|
+
config: CloudConfig;
|
|
37
|
+
environment: EnvironmentType;
|
|
38
|
+
profile: SshProfile;
|
|
39
|
+
/** Preflight facts, when the host has been probed; `arch` gates x86_64-only services. */
|
|
40
|
+
facts?: Pick<SshPreflightFacts, 'arch'>;
|
|
41
|
+
/**
|
|
42
|
+
* The non-root deploy user, when there is one. Makes the artifact and
|
|
43
|
+
* staging directories group-writable for it and manages its
|
|
44
|
+
* `authorized_keys` rather than root's.
|
|
45
|
+
*/
|
|
46
|
+
sudoUser?: string;
|
|
47
|
+
/** LAN settings; recorded in the script header today, wired to the gateway by the local-CA work. */
|
|
48
|
+
lan?: SshLanConfig;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Refuse a config that asks for something this host's architecture cannot
|
|
52
|
+
* run. Vitess publishes x86_64 release tarballs only, so on an arm64 host the
|
|
53
|
+
* provision would fail minutes in on a download URL; say so before contact.
|
|
54
|
+
* The raspberry-pi profile is arm64 by definition, so it needs no facts.
|
|
55
|
+
*/
|
|
56
|
+
export declare function assertArchSupported(config: CloudConfig, profile: SshProfile, arch?: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Build the bootstrap script for an adopted host. See the module comment for
|
|
59
|
+
* what makes it different from the cloud drivers' first-boot script.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildSshBootstrapScript(options: SshBootstrapOptions): string;
|