@stacksjs/cloud 0.72.102 → 0.73.0
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/helpers.d.ts +4 -3
- package/dist/index.js +7 -7
- package/package.json +12 -12
package/dist/helpers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CountryCode } from '@stacksjs/ts-cloud';
|
|
1
2
|
import type { Result } from '@stacksjs/error-handling';
|
|
2
3
|
export declare function getSecurityGroupId(securityGroupName: string): Promise<Result<string | undefined, string>>;
|
|
3
4
|
export declare function purchaseDomain(domain: string, options: PurchaseOptions): Result<Promise<{ OperationId: string }>, Error>;
|
|
@@ -34,7 +35,7 @@ export declare interface PurchaseOptions {
|
|
|
34
35
|
adminAddressLine2: string
|
|
35
36
|
adminCity: string
|
|
36
37
|
adminState: string
|
|
37
|
-
adminCountry:
|
|
38
|
+
adminCountry: CountryCode
|
|
38
39
|
adminZip: string
|
|
39
40
|
adminPhone: string
|
|
40
41
|
adminEmail: string
|
|
@@ -45,7 +46,7 @@ export declare interface PurchaseOptions {
|
|
|
45
46
|
techAddressLine2: string
|
|
46
47
|
techCity: string
|
|
47
48
|
techState: string
|
|
48
|
-
techCountry:
|
|
49
|
+
techCountry: CountryCode
|
|
49
50
|
techZip: string
|
|
50
51
|
techPhone: string
|
|
51
52
|
techEmail: string
|
|
@@ -56,7 +57,7 @@ export declare interface PurchaseOptions {
|
|
|
56
57
|
registrantAddressLine2: string
|
|
57
58
|
registrantCity: string
|
|
58
59
|
registrantState: string
|
|
59
|
-
registrantCountry:
|
|
60
|
+
registrantCountry: CountryCode
|
|
60
61
|
registrantZip: string
|
|
61
62
|
registrantPhone: string
|
|
62
63
|
registrantEmail: string
|
package/dist/index.js
CHANGED
|
@@ -11,23 +11,23 @@ git clone https://github.com/stacksjs/stacks.git /mnt/efs
|
|
|
11
11
|
`,l=btoa(m),u=await he();if(u.isErr)return y(u.error);let h=u.value;if(!h)return y("Jump-box IAM instance profile not found");let A=(await B("RunInstances",{ImageId:"ami-03a6eaae9938c858c",InstanceType:"t2.micro",MaxCount:"1",MinCount:"1","SecurityGroupId.1":s,SubnetId:"subnet-004c5f196358b00f0","TagSpecification.1.ResourceType":"instance","TagSpecification.1.Tag.1.Key":"Name","TagSpecification.1.Tag.1.Value":`${F}-jump-box`,UserData:l,"IamInstanceProfile.Name":h})).instancesSet?.item??[],T=Array.isArray(A)?A[0]:void 0;return T?p(`Jump-box created with id ${T.instanceId}`):y("Jump-box creation failed")}async function ye(){let e=await H();if(!e)return y("Jump-box not found");let r=await new L("us-east-1").describeInstances({InstanceIds:[e]});if(r.Reservations?.[0]?.Instances?.[0]){let s=r.Reservations[0].Instances[0].SecurityGroups;if(s?.[0])return p(s[0].GroupName)}return y("Security group not found")}async function Me(e){let r=await new L("us-east-1").describeInstances({InstanceIds:[e]});if(r.Reservations?.[0]?.Instances?.[0]){let s=r.Reservations[0].Instances[0].SecurityGroups;if(s?.[0])return s[0].GroupId}return}async function Ue(){let e=F;return!(await new J("us-east-1").listStacks(["CREATE_COMPLETE","UPDATE_COMPLETE"])).StackSummaries?.some((s)=>s.StackName===e)}async function ze(){return!(await new J("us-east-1").listStacks(["CREATE_FAILED","UPDATE_FAILED","ROLLBACK_COMPLETE","UPDATE_ROLLBACK_COMPLETE"])).StackSummaries?.some((n)=>n.StackName===F)}async function Ve(){let t=new Y("us-east-1");try{let r=await t.getParameter({Name:"/stacks/timestamp"}),n=r.Parameter?r.Parameter.Value:void 0;if(!n)throw Error("Timestamp parameter not found");return n}catch(r){let n=new Date().getTime().toString();return R.debug(`Creating timestamp parameter /stacks/timestamp with value ${n}`,r),await t.putParameter({Name:"/stacks/timestamp",Value:n,Type:"String"}),n}}async function He(){return""}import*as K from"crypto";import{XMLParser as pe}from"@stacksjs/ts-xml";class j{credentials;config;cache;xmlParser;constructor(e,t){this.credentials=e||this.loadCredentials(),this.config={maxRetries:3,retryDelay:1000,cacheEnabled:!0,defaultCacheTTL:60000,...t},this.cache=new Map,this.xmlParser=new pe({ignoreAttributes:!1,attributeNamePrefix:"@_",textNodeName:"#text",parseAttributeValue:!0,trimValues:!0})}loadCredentials(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY,r=process.env.AWS_SESSION_TOKEN;if(e&&t)return{accessKeyId:e,secretAccessKey:t,sessionToken:r};return{accessKeyId:"",secretAccessKey:""}}ec2CredentialsCache;async getCredentials(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY;if(e&&t)return{accessKeyId:e,secretAccessKey:t,sessionToken:process.env.AWS_SESSION_TOKEN};if(this.ec2CredentialsCache){let r=Date.now();if(this.ec2CredentialsCache.expiration>r+300000)return this.ec2CredentialsCache.credentials}try{let n=await(await fetch("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}})).text(),i=await(await fetch("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":n}})).text(),o=await(await fetch(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${i}`,{headers:{"X-aws-ec2-metadata-token":n}})).json(),c={accessKeyId:o.AccessKeyId,secretAccessKey:o.SecretAccessKey,sessionToken:o.Token};return this.ec2CredentialsCache={credentials:c,expiration:new Date(o.Expiration).getTime()},c}catch(r){throw Error("AWS credentials not found. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or run on an EC2 instance with an IAM role.")}}async request(e){if(e.method==="GET"&&this.config.cacheEnabled&&e.cacheKey){let n=this.getFromCache(e.cacheKey);if(n!==null)return n}let t=e.retries??this.config.maxRetries??3,r=null;for(let n=0;n<=t;n++)try{let s=await this.makeRequest(e);if(e.method==="GET"&&this.config.cacheEnabled&&e.cacheKey)this.setInCache(e.cacheKey,s,e.cacheTTL??this.config.defaultCacheTTL??60000);return s}catch(s){if(r=s,!this.shouldRetry(s))throw s;if(n===t)throw s;let a=this.calculateRetryDelay(n);await this.sleep(a)}throw r||Error("Request failed after retries")}async makeRequest(e){let t=e.credentials||await this.getCredentials();if(!t||!t.accessKeyId||!t.secretAccessKey)throw Error("AWS credentials not provided");let r=this.buildUrl(e),n=this.signRequest(e,t),s=await fetch(r,{method:e.method,headers:n,body:e.body}),i=await s.text();if(!s.ok)throw this.parseError(i,s.status,s.headers);if(!i||i.trim()===""){if(e.returnHeaders)return{body:null,headers:this.headersToObject(s.headers)};return null}if(e.rawResponse){if(e.returnHeaders)return{body:i,headers:this.headersToObject(s.headers)};return i}let a;if(i.startsWith("<"))a=this.parseXmlResponse(i);else try{a=JSON.parse(i)}catch{a=i}if(e.returnHeaders)return{body:a,headers:this.headersToObject(s.headers)};return a}headersToObject(e){let t={};return e.forEach((r,n)=>{t[n]=r}),t}buildUrl(e){let{service:t,region:r,path:n,queryParams:s}=e,i;if(t==="s3")i=`s3.${r}.amazonaws.com`;else if(t==="cloudfront")i="cloudfront.amazonaws.com";else if(t==="iam")i="iam.amazonaws.com";else if(t==="route53")i="route53.amazonaws.com";else if(t==="route53domains")i="route53domains.us-east-1.amazonaws.com";else if(t==="ecr")i=`api.ecr.${r}.amazonaws.com`;else if(t==="ses")i=`email.${r}.amazonaws.com`;else i=`${t}.${r}.amazonaws.com`;let a=`https://${i}${n}`;if(s&&Object.keys(s).length>0){let o=new URLSearchParams(s).toString();a+=`?${o}`}return a}signRequest(e,t){let{service:r,region:n,method:s,path:i,queryParams:a,body:o}=e,c=new Date,d=this.getAmzDate(c),m=this.getDateStamp(c),l;if(r==="s3")l=`s3.${n}.amazonaws.com`;else if(r==="cloudfront")l="cloudfront.amazonaws.com";else if(r==="iam")l="iam.amazonaws.com";else if(r==="route53")l="route53.amazonaws.com";else if(r==="route53domains")l="route53domains.us-east-1.amazonaws.com";else if(r==="ecr")l=`api.ecr.${n}.amazonaws.com`;else if(r==="ses")l=`email.${n}.amazonaws.com`;else l=`${r}.${n}.amazonaws.com`;let u={host:l,"x-amz-date":d,...e.headers||{}};if(t.sessionToken)u["x-amz-security-token"]=t.sessionToken;if(o){if(!Object.keys(u).some((b)=>b.toLowerCase()==="content-type"))u["content-type"]="application/x-www-form-urlencoded";u["content-length"]=Buffer.byteLength(o).toString()}let h=this.sha256(o||"");u["x-amz-content-sha256"]=h;let S=i,P=a?new URLSearchParams(a).toString():"",A=Object.keys(u).sort((f,b)=>f.toLowerCase().localeCompare(b.toLowerCase())),T=A.map((f)=>`${f.toLowerCase()}:${u[f].trim()}
|
|
12
12
|
`).join(""),w=A.map((f)=>f.toLowerCase()).join(";"),v=[s,S,P,T,w,h].join(`
|
|
13
13
|
`),I="AWS4-HMAC-SHA256",N=r;if(r==="email")N="ses";if(r==="pinpoint")N="mobiletargeting";let D=`${m}/${n}/${N}/aws4_request`,O=[I,d,D,this.sha256(v)].join(`
|
|
14
|
-
`),q=this.getSignatureKey(t.secretAccessKey,m,n,N),
|
|
14
|
+
`),q=this.getSignatureKey(t.secretAccessKey,m,n,N),C=this.hmac(q,O),E=`${I} Credential=${t.accessKeyId}/${D}, SignedHeaders=${w}, Signature=${C}`;return{...u,Authorization:E}}getAmzDate(e){return e.toISOString().replace(/[:-]|\.\d{3}/g,"")}getDateStamp(e){return e.toISOString().slice(0,10).replace(/-/g,"")}sha256(e){return K.createHash("sha256").update(e,"utf8").digest("hex")}hmac(e,t){return K.createHmac("sha256",e).update(t,"utf8").digest("hex")}getSignatureKey(e,t,r,n){let s=K.createHmac("sha256",`AWS4${e}`).update(t).digest(),i=K.createHmac("sha256",s).update(r).digest(),a=K.createHmac("sha256",i).update(n).digest();return K.createHmac("sha256",a).update("aws4_request").digest()}parseXmlResponse(e){try{let t=this.xmlParser.parse(e);if(t.ErrorResponse)throw this.createErrorFromXml(t.ErrorResponse.Error);let r=Object.keys(t);if(r.length===1)return t[r[0]];return t}catch(t){if(t.code||t.statusCode)throw t;return{}}}parseError(e,t,r){let n=Error();if(n.statusCode=t,n.requestId=r.get("x-amzn-requestid")||r.get("x-amz-request-id")||void 0,e.startsWith("<"))try{let s=this.xmlParser.parse(e);if(s.ErrorResponse?.Error){let i=s.ErrorResponse.Error;return n.code=i.Code,n.message=`AWS Error [${i.Code}]: ${i.Message||"Unknown error"}`,n.type=i.Type,n}if(s.Error)return n.code=s.Error.Code,n.message=`AWS Error [${s.Error.Code}]: ${s.Error.Message||"Unknown error"}`,n}catch{}try{let s=JSON.parse(e);if(s.__type||s.code)return n.code=s.__type||s.code,n.message=`AWS Error [${n.code}]: ${s.message||s.Message||"Unknown error"}`,n}catch{}return n.message=`AWS API Error (${t}): ${e}`,n}createErrorFromXml(e){let t=Error();return t.code=e.Code,t.message=`AWS Error [${e.Code}]: ${e.Message||"Unknown error"}`,t.type=e.Type,t}isRetryableError(e){return["RequestTimeout","RequestTimeoutException","PriorRequestNotComplete","ConnectionError","ThrottlingException","Throttling","TooManyRequestsException","ProvisionedThroughputExceededException","RequestLimitExceeded","BandwidthLimitExceeded","SlowDown","ServiceUnavailable","ServiceUnavailableException","InternalError","InternalFailure","InternalServerError","InternalServiceException","TransientError","TransientFailure","IDPCommunicationErrorException","NetworkError","ConnectionRefusedException","EC2ThrottledException","503 Slow Down","500 InternalError"].includes(e)}isRetryableStatusCode(e){return e>=500||e===429}shouldRetry(e){if(e.name==="FetchError"||e.name==="TypeError"||e.code==="ECONNRESET")return!0;if(e.code&&this.isRetryableError(e.code))return!0;if(e.statusCode&&this.isRetryableStatusCode(e.statusCode))return!0;if(e.statusCode&&e.statusCode>=400&&e.statusCode<500&&e.statusCode!==429)return!1;if(e.statusCode)return!1;return!0}calculateRetryDelay(e){let t=this.config.retryDelay??1000,r=30000,n=Math.min(t*2**e,30000),s=Math.random()*0.3*n;return n+s}sleep(e){return new Promise((t)=>setTimeout(t,e))}getFromCache(e){let t=this.cache.get(e);if(!t)return null;if(Date.now()>t.expires)return this.cache.delete(e),null;return t.data}setInCache(e,t,r){this.cache.set(e,{data:t,expires:Date.now()+r})}clearCache(){this.cache.clear()}clearExpiredCache(){let e=Date.now();for(let[t,r]of this.cache.entries())if(e>r.expires)this.cache.delete(t)}}function Ge(e){let t={};for(let[r,n]of Object.entries(e)){if(n===void 0||n===null)continue;if(Array.isArray(n))n.forEach((s,i)=>{t[`${r}.${i+1}`]=String(s)});else if(typeof n==="object")for(let[s,i]of Object.entries(n))t[`${r}.${s}`]=String(i);else t[r]=String(n)}return t}import*as g from"crypto";import{readdir as Se}from"fs/promises";import{join as fe}from"path";import{readFileSync as Z}from"fs";class W{client;region;constructor(e="us-east-1",t){this.region=e,this.client=new j}getCredentials(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY,r=process.env.AWS_SESSION_TOKEN;if(!e||!t)throw Error("AWS credentials not found. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.");return{accessKeyId:e,secretAccessKey:t,sessionToken:r}}async listBuckets(){let e=await this.client.request({service:"s3",region:this.region,method:"GET",path:"/"}),t=[],r=e?.ListAllMyBucketsResult?.Buckets?.Bucket;if(r){let n=Array.isArray(r)?r:[r];for(let s of n)t.push({Name:s.Name,CreationDate:s.CreationDate})}return{Buckets:t}}async createBucket(e,t){let r={};if(t?.acl)r["x-amz-acl"]=t.acl;let n;if(this.region!=="us-east-1")n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
15
15
|
<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
16
16
|
<LocationConstraint>${this.region}</LocationConstraint>
|
|
17
|
-
</CreateBucketConfiguration>`,r["Content-Type"]="application/xml";await this.client.request({service:"s3",region:this.region,method:"PUT",path:`/${e}`,headers:r,body:n})}async deleteBucket(e){await this.client.request({service:"s3",region:this.region,method:"DELETE",path:`/${e}`})}async emptyAndDeleteBucket(e){let t=!0;while(t){let r=await this.listAllObjects({bucket:e});if(r.length===0){t=!1;break}let n=r.map((s)=>s.Key);for(let s=0;s<n.length;s+=1000){let i=n.slice(s,s+1000);await this.deleteObjects(e,i)}}await this.deleteBucket(e)}async listAllObjects(e){let t=[],r;do{let n={"list-type":"2","max-keys":"1000"};if(e.prefix)n.prefix=e.prefix;if(r)n["continuation-token"]=r;let s=await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e.bucket}`,queryParams:n}),i=s?.ListBucketResult?.Contents;if(i){let o=Array.isArray(i)?i:[i];for(let c of o)t.push({Key:c.Key,LastModified:c.LastModified||"",Size:Number.parseInt(c.Size||"0",10),ETag:c.ETag})}let a=s?.ListBucketResult?.IsTruncated;r=a==="true"||a===!0?s?.ListBucketResult?.NextContinuationToken:void 0}while(r);return t}async list(e){let t=await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e.bucket}`}),r=[],n=t?.ListBucketResult?.Contents;if(n){let s=Array.isArray(n)?n:[n];for(let i of s){if(e.prefix&&!i.Key?.startsWith(e.prefix))continue;if(r.push({Key:i.Key||"",LastModified:i.LastModified||"",Size:Number.parseInt(i.Size||"0",10),ETag:i.ETag}),e.maxKeys&&r.length>=e.maxKeys)break}}return r}async putObject(e){let t={};if(e.acl)t["x-amz-acl"]=e.acl;if(e.cacheControl)t["Cache-Control"]=e.cacheControl;if(e.contentType)t["Content-Type"]=e.contentType;if(e.metadata)for(let[n,s]of Object.entries(e.metadata))t[`x-amz-meta-${n}`]=s;let r=typeof e.body==="string"?e.body:Buffer.isBuffer(e.body)?e.body.toString("base64"):String(e.body);if(Buffer.isBuffer(e.body)){let{accessKeyId:n,secretAccessKey:s,sessionToken:i}=this.getCredentials(),a=`${e.bucket}.s3.${this.region}.amazonaws.com`,o=`https://${a}/${e.key}`,c=new Date,d=c.toISOString().replace(/[:-]|\.\d{3}/g,""),m=c.toISOString().slice(0,10).replace(/-/g,""),l=g.createHash("sha256").update(e.body).digest("hex"),u={host:a,"x-amz-date":d,"x-amz-content-sha256":l,...t};if(i)u["x-amz-security-token"]=i;let h=Object.keys(u).sort().map((
|
|
18
|
-
`).join(""),S=Object.keys(u).sort().map((
|
|
17
|
+
</CreateBucketConfiguration>`,r["Content-Type"]="application/xml";await this.client.request({service:"s3",region:this.region,method:"PUT",path:`/${e}`,headers:r,body:n})}async deleteBucket(e){await this.client.request({service:"s3",region:this.region,method:"DELETE",path:`/${e}`})}async emptyAndDeleteBucket(e){let t=!0;while(t){let r=await this.listAllObjects({bucket:e});if(r.length===0){t=!1;break}let n=r.map((s)=>s.Key);for(let s=0;s<n.length;s+=1000){let i=n.slice(s,s+1000);await this.deleteObjects(e,i)}}await this.deleteBucket(e)}async listAllObjects(e){let t=[],r;do{let n={"list-type":"2","max-keys":"1000"};if(e.prefix)n.prefix=e.prefix;if(r)n["continuation-token"]=r;let s=await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e.bucket}`,queryParams:n}),i=s?.ListBucketResult?.Contents;if(i){let o=Array.isArray(i)?i:[i];for(let c of o)t.push({Key:c.Key,LastModified:c.LastModified||"",Size:Number.parseInt(c.Size||"0",10),ETag:c.ETag})}let a=s?.ListBucketResult?.IsTruncated;r=a==="true"||a===!0?s?.ListBucketResult?.NextContinuationToken:void 0}while(r);return t}async list(e){let t=await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e.bucket}`}),r=[],n=t?.ListBucketResult?.Contents;if(n){let s=Array.isArray(n)?n:[n];for(let i of s){if(e.prefix&&!i.Key?.startsWith(e.prefix))continue;if(r.push({Key:i.Key||"",LastModified:i.LastModified||"",Size:Number.parseInt(i.Size||"0",10),ETag:i.ETag}),e.maxKeys&&r.length>=e.maxKeys)break}}return r}async putObject(e){let t={};if(e.acl)t["x-amz-acl"]=e.acl;if(e.cacheControl)t["Cache-Control"]=e.cacheControl;if(e.contentType)t["Content-Type"]=e.contentType;if(e.metadata)for(let[n,s]of Object.entries(e.metadata))t[`x-amz-meta-${n}`]=s;let r=typeof e.body==="string"?e.body:Buffer.isBuffer(e.body)?e.body.toString("base64"):String(e.body);if(Buffer.isBuffer(e.body)){let{accessKeyId:n,secretAccessKey:s,sessionToken:i}=this.getCredentials(),a=`${e.bucket}.s3.${this.region}.amazonaws.com`,o=`https://${a}/${e.key}`,c=new Date,d=c.toISOString().replace(/[:-]|\.\d{3}/g,""),m=c.toISOString().slice(0,10).replace(/-/g,""),l=g.createHash("sha256").update(e.body).digest("hex"),u={host:a,"x-amz-date":d,"x-amz-content-sha256":l,...t};if(i)u["x-amz-security-token"]=i;let h=Object.keys(u).sort().map((E)=>`${E.toLowerCase()}:${u[E].trim()}
|
|
18
|
+
`).join(""),S=Object.keys(u).sort().map((E)=>E.toLowerCase()).join(";"),P=["PUT",`/${e.key}`,"",h,S,l].join(`
|
|
19
19
|
`),A="AWS4-HMAC-SHA256",T=`${m}/${this.region}/s3/aws4_request`,w=[A,d,T,g.createHash("sha256").update(P).digest("hex")].join(`
|
|
20
|
-
`),v=g.createHmac("sha256",`AWS4${s}`).update(m).digest(),I=g.createHmac("sha256",v).update(this.region).digest(),N=g.createHmac("sha256",I).update("s3").digest(),D=g.createHmac("sha256",N).update("aws4_request").digest(),O=g.createHmac("sha256",D).update(w).digest("hex"),q=`${A} Credential=${n}/${T}, SignedHeaders=${S}, Signature=${O}`,
|
|
20
|
+
`),v=g.createHmac("sha256",`AWS4${s}`).update(m).digest(),I=g.createHmac("sha256",v).update(this.region).digest(),N=g.createHmac("sha256",I).update("s3").digest(),D=g.createHmac("sha256",N).update("aws4_request").digest(),O=g.createHmac("sha256",D).update(w).digest("hex"),q=`${A} Credential=${n}/${T}, SignedHeaders=${S}, Signature=${O}`,C=await fetch(o,{method:"PUT",headers:{...u,Authorization:q},body:typeof e.body==="string"?e.body:new Uint8Array(e.body)});if(!C.ok){let E=await C.text();throw Error(`S3 PUT failed: ${C.status} ${E}`)}return}await this.client.request({service:"s3",region:this.region,method:"PUT",path:`/${e.bucket}/${e.key}`,headers:t,body:r})}async getObject(e,t){return await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e}/${t}`,rawResponse:!0})}async copyObject(e){let t={"x-amz-copy-source":`/${e.sourceBucket}/${e.sourceKey}`};if(e.metadataDirective)t["x-amz-metadata-directive"]=e.metadataDirective;if(e.contentType)t["Content-Type"]=e.contentType;if(e.metadata)for(let[r,n]of Object.entries(e.metadata))t[`x-amz-meta-${r}`]=n;await this.client.request({service:"s3",region:this.region,method:"PUT",path:`/${e.destinationBucket}/${e.destinationKey}`,headers:t})}async deleteObject(e,t){await this.client.request({service:"s3",region:this.region,method:"DELETE",path:`/${e}/${t}`})}async deleteObjects(e,t){let r=`<?xml version="1.0" encoding="UTF-8"?>
|
|
21
21
|
<Delete>
|
|
22
22
|
${t.map((n)=>`<Object><Key>${n}</Key></Object>`).join(`
|
|
23
23
|
`)}
|
|
24
24
|
</Delete>`;await this.client.request({service:"s3",region:this.region,method:"POST",path:`/${e}`,queryParams:{delete:""},body:r,headers:{"Content-Type":"application/xml"}})}async bucketExists(e){try{return await this.client.request({service:"s3",region:this.region,method:"HEAD",path:`/${e}`}),!0}catch{return!1}}async copy(e){let t=Z(e.source);await this.putObject({bucket:e.bucket,key:e.key,body:t,acl:e.acl,cacheControl:e.cacheControl,contentType:e.contentType,metadata:e.metadata})}async sync(e){let t=await this.listFilesRecursive(e.source);for(let r of t){if(e.exclude&&e.exclude.some((i)=>r.includes(i)))continue;if(e.include&&!e.include.some((i)=>r.includes(i)))continue;let n=r.substring(e.source.length+1),s=e.prefix?`${e.prefix}/${n}`:n;if(!e.dryRun){let i=Z(r);await this.putObject({bucket:e.bucket,key:s,body:i,acl:e.acl,cacheControl:e.cacheControl,contentType:e.contentType,metadata:e.metadata})}}}async delete(e,t){await this.deleteObject(e,t)}async deletePrefix(e,t){let n=(await this.list({bucket:e,prefix:t})).map((s)=>s.Key);if(n.length>0)await this.deleteObjects(e,n)}async getBucketSize(e,t){return(await this.list({bucket:e,prefix:t})).reduce((n,s)=>n+s.Size,0)}async listFilesRecursive(e){let t=[],r=await Se(e,{withFileTypes:!0});for(let n of r){let s=fe(e,n.name);if(n.isDirectory()){let i=await this.listFilesRecursive(s);t.push(...i)}else t.push(s)}return t}async putBucketPolicy(e,t){let{accessKeyId:r,secretAccessKey:n,sessionToken:s}=this.getCredentials(),i=`s3.${this.region}.amazonaws.com`,a=typeof t==="string"?t:JSON.stringify(t),o=new Date,c=o.toISOString().replace(/[:-]|\.\d{3}/g,""),d=o.toISOString().slice(0,10).replace(/-/g,""),m=g.createHash("sha256").update(a).digest("hex"),l=`/${e}`,u="policy=",h={host:i,"x-amz-date":c,"x-amz-content-sha256":m,"content-type":"application/json"};if(s)h["x-amz-security-token"]=s;let S=Object.keys(h).sort().map((b)=>`${b.toLowerCase()}:${h[b].trim()}
|
|
25
25
|
`).join(""),P=Object.keys(h).sort().map((b)=>b.toLowerCase()).join(";"),A=["PUT",l,"policy=",S,P,m].join(`
|
|
26
26
|
`),T="AWS4-HMAC-SHA256",w=`${d}/${this.region}/s3/aws4_request`,v=[T,c,w,g.createHash("sha256").update(A).digest("hex")].join(`
|
|
27
|
-
`),I=g.createHmac("sha256",`AWS4${n}`).update(d).digest(),N=g.createHmac("sha256",I).update(this.region).digest(),D=g.createHmac("sha256",N).update("s3").digest(),O=g.createHmac("sha256",D).update("aws4_request").digest(),q=g.createHmac("sha256",O).update(v).digest("hex"),
|
|
27
|
+
`),I=g.createHmac("sha256",`AWS4${n}`).update(d).digest(),N=g.createHmac("sha256",I).update(this.region).digest(),D=g.createHmac("sha256",N).update("s3").digest(),O=g.createHmac("sha256",D).update("aws4_request").digest(),q=g.createHmac("sha256",O).update(v).digest("hex"),C=`${T} Credential=${r}/${w}, SignedHeaders=${P}, Signature=${q}`,E=`https://${i}${l}?policy=`,f=await fetch(E,{method:"PUT",headers:{...h,Authorization:C},body:a});if(!f.ok){let b=await f.text();throw Error(`Failed to put bucket policy: ${f.status} ${b}`)}}async getBucketPolicy(e){let{accessKeyId:t,secretAccessKey:r,sessionToken:n}=this.getCredentials(),s=`s3.${this.region}.amazonaws.com`,i=new Date,a=i.toISOString().replace(/[:-]|\.\d{3}/g,""),o=i.toISOString().slice(0,10).replace(/-/g,""),c=g.createHash("sha256").update("").digest("hex"),d=`/${e}`,m="policy=",l={host:s,"x-amz-date":a,"x-amz-content-sha256":c};if(n)l["x-amz-security-token"]=n;let u=Object.keys(l).sort().map((f)=>`${f.toLowerCase()}:${l[f].trim()}
|
|
28
28
|
`).join(""),h=Object.keys(l).sort().map((f)=>f.toLowerCase()).join(";"),S=["GET",d,"policy=",u,h,c].join(`
|
|
29
29
|
`),P="AWS4-HMAC-SHA256",A=`${o}/${this.region}/s3/aws4_request`,T=[P,a,A,g.createHash("sha256").update(S).digest("hex")].join(`
|
|
30
|
-
`),w=g.createHmac("sha256",`AWS4${r}`).update(o).digest(),v=g.createHmac("sha256",w).update(this.region).digest(),I=g.createHmac("sha256",v).update("s3").digest(),N=g.createHmac("sha256",I).update("aws4_request").digest(),D=g.createHmac("sha256",N).update(T).digest("hex"),O=`${P} Credential=${t}/${A}, SignedHeaders=${h}, Signature=${D}`,q=`https://${s}${d}?policy=`,
|
|
30
|
+
`),w=g.createHmac("sha256",`AWS4${r}`).update(o).digest(),v=g.createHmac("sha256",w).update(this.region).digest(),I=g.createHmac("sha256",v).update("s3").digest(),N=g.createHmac("sha256",I).update("aws4_request").digest(),D=g.createHmac("sha256",N).update(T).digest("hex"),O=`${P} Credential=${t}/${A}, SignedHeaders=${h}, Signature=${D}`,q=`https://${s}${d}?policy=`,C=await fetch(q,{method:"GET",headers:{...l,Authorization:O}});if(C.status===404)return null;if(!C.ok){let f=await C.text();throw Error(`Failed to get bucket policy: ${C.status} ${f}`)}let E=await C.text();try{return JSON.parse(E)}catch{throw Error(`Failed to parse bucket policy JSON: ${E.slice(0,200)}`)}}async deleteBucketPolicy(e){await this.client.request({service:"s3",region:this.region,method:"DELETE",path:`/${e}`,queryParams:{policy:""}})}async headBucket(e){try{return{exists:!0,region:(await this.client.request({service:"s3",region:this.region,method:"HEAD",path:`/${e}`,returnHeaders:!0}))?.headers?.["x-amz-bucket-region"]}}catch(t){if(t.statusCode===404)return{exists:!1};throw t}}async headObject(e,t){try{let r=await this.client.request({service:"s3",region:this.region,method:"HEAD",path:`/${e}/${t}`,returnHeaders:!0});return{ContentLength:r?.headers?.["content-length"]?parseInt(r.headers["content-length"]):void 0,ContentType:r?.headers?.["content-type"],ETag:r?.headers?.etag,LastModified:r?.headers?.["last-modified"],ServerSideEncryption:r?.headers?.["x-amz-server-side-encryption"]}}catch(r){if(r.statusCode===404)return null;throw r}}async getObjectBuffer(e,t){let r=await this.getObject(e,t);return Buffer.from(r)}async getObjectJson(e,t){let r=await this.getObject(e,t);try{return JSON.parse(r)}catch{throw Error(`Failed to parse JSON from s3://${e}/${t}`)}}async putObjectJson(e,t,r,n){await this.putObject({bucket:e,key:t,body:JSON.stringify(r),contentType:"application/json",...n})}async getBucketVersioning(e){return{Status:(await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e}`,queryParams:{versioning:""}}))?.VersioningConfiguration?.Status}}async putBucketVersioning(e,t){let r=`<?xml version="1.0" encoding="UTF-8"?>
|
|
31
31
|
<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
32
32
|
<Status>${t}</Status>
|
|
33
33
|
</VersioningConfiguration>`;await this.client.request({service:"s3",region:this.region,method:"PUT",path:`/${e}`,queryParams:{versioning:""},headers:{"Content-Type":"application/xml"},body:r})}async getBucketLifecycleConfiguration(e){try{return(await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e}`,queryParams:{lifecycle:""}}))?.LifecycleConfiguration}catch(t){if(t.statusCode===404)return null;throw t}}async putBucketLifecycleConfiguration(e,t){let n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -76,7 +76,7 @@ host:${a}
|
|
|
76
76
|
`),P=g.createHmac("sha256",`AWS4${i}`).update(d).digest(),A=g.createHmac("sha256",P).update(this.region).digest(),T=g.createHmac("sha256",A).update("s3").digest(),w=g.createHmac("sha256",T).update("aws4_request").digest(),v=g.createHmac("sha256",w).update(S).digest("hex");return u.append("X-Amz-Signature",v),`https://${a}/${t}?${u.toString()}`}async createMultipartUpload(e,t,r){let n={};if(r?.contentType)n["Content-Type"]=r.contentType;if(r?.metadata)for(let[i,a]of Object.entries(r.metadata))n[`x-amz-meta-${i}`]=a;return{UploadId:(await this.client.request({service:"s3",region:this.region,method:"POST",path:`/${e}/${t}`,queryParams:{uploads:""},headers:n}))?.InitiateMultipartUploadResult?.UploadId}}async uploadPart(e,t,r,n,s){let{accessKeyId:i,secretAccessKey:a,sessionToken:o}=this.getCredentials(),c=`${e}.s3.${this.region}.amazonaws.com`,d=`https://${c}/${t}?partNumber=${n}&uploadId=${encodeURIComponent(r)}`,m=new Date,l=m.toISOString().replace(/[:-]|\.\d{3}/g,""),u=m.toISOString().slice(0,10).replace(/-/g,""),h=g.createHash("sha256").update(s).digest("hex"),S={host:c,"x-amz-date":l,"x-amz-content-sha256":h};if(o)S["x-amz-security-token"]=o;let P=Object.keys(S).sort().map((b)=>`${b.toLowerCase()}:${S[b].trim()}
|
|
77
77
|
`).join(""),A=Object.keys(S).sort().map((b)=>b.toLowerCase()).join(";"),T=["PUT",`/${t}`,`partNumber=${n}&uploadId=${encodeURIComponent(r)}`,P,A,h].join(`
|
|
78
78
|
`),w="AWS4-HMAC-SHA256",v=`${u}/${this.region}/s3/aws4_request`,I=[w,l,v,g.createHash("sha256").update(T).digest("hex")].join(`
|
|
79
|
-
`),N=g.createHmac("sha256",`AWS4${a}`).update(u).digest(),D=g.createHmac("sha256",N).update(this.region).digest(),O=g.createHmac("sha256",D).update("s3").digest(),q=g.createHmac("sha256",O).update("aws4_request").digest(),
|
|
79
|
+
`),N=g.createHmac("sha256",`AWS4${a}`).update(u).digest(),D=g.createHmac("sha256",N).update(this.region).digest(),O=g.createHmac("sha256",D).update("s3").digest(),q=g.createHmac("sha256",O).update("aws4_request").digest(),C=g.createHmac("sha256",q).update(I).digest("hex"),E=`${w} Credential=${i}/${v}, SignedHeaders=${A}, Signature=${C}`,f=await fetch(d,{method:"PUT",headers:{...S,Authorization:E},body:new Uint8Array(s)});if(!f.ok){let b=await f.text();throw Error(`Upload part failed: ${f.status} ${b}`)}return{ETag:f.headers.get("etag")||""}}async completeMultipartUpload(e,t,r,n){let i=`<?xml version="1.0" encoding="UTF-8"?>
|
|
80
80
|
<CompleteMultipartUpload>${n.sort((a,o)=>a.PartNumber-o.PartNumber).map((a)=>`<Part><PartNumber>${a.PartNumber}</PartNumber><ETag>${a.ETag}</ETag></Part>`).join("")}</CompleteMultipartUpload>`;await this.client.request({service:"s3",region:this.region,method:"POST",path:`/${e}/${t}`,queryParams:{uploadId:r},headers:{"Content-Type":"application/xml"},body:i})}async abortMultipartUpload(e,t,r){await this.client.request({service:"s3",region:this.region,method:"DELETE",path:`/${e}/${t}`,queryParams:{uploadId:r}})}async listMultipartUploads(e){let r=(await this.client.request({service:"s3",region:this.region,method:"GET",path:`/${e}`,queryParams:{uploads:""}}))?.ListMultipartUploadsResult?.Upload;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({Key:s.Key,UploadId:s.UploadId,Initiated:s.Initiated}))}async restoreObject(e,t,r,n="Standard"){let s=`<?xml version="1.0" encoding="UTF-8"?>
|
|
81
81
|
<RestoreRequest>
|
|
82
82
|
<Days>${r}</Days>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/cloud",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.73.0",
|
|
6
6
|
"description": "The Stacks cloud/serverless integration & implementation.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -59,20 +59,20 @@
|
|
|
59
59
|
"prepublishOnly": "bun run build"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@stacksjs/ts-cloud": "^0.12.
|
|
62
|
+
"@stacksjs/ts-cloud": "^0.12.10",
|
|
63
63
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@stacksjs/cli": "0.
|
|
67
|
-
"@stacksjs/config": "0.
|
|
66
|
+
"@stacksjs/cli": "0.73.0",
|
|
67
|
+
"@stacksjs/config": "0.73.0",
|
|
68
68
|
"better-dx": "^0.2.24",
|
|
69
|
-
"@stacksjs/dns": "0.
|
|
70
|
-
"@stacksjs/env": "0.
|
|
71
|
-
"@stacksjs/logging": "0.
|
|
72
|
-
"@stacksjs/path": "0.
|
|
73
|
-
"@stacksjs/router": "0.
|
|
74
|
-
"@stacksjs/storage": "0.
|
|
75
|
-
"@stacksjs/utils": "0.
|
|
76
|
-
"@stacksjs/validation": "0.
|
|
69
|
+
"@stacksjs/dns": "0.73.0",
|
|
70
|
+
"@stacksjs/env": "0.73.0",
|
|
71
|
+
"@stacksjs/logging": "0.73.0",
|
|
72
|
+
"@stacksjs/path": "0.73.0",
|
|
73
|
+
"@stacksjs/router": "0.73.0",
|
|
74
|
+
"@stacksjs/storage": "0.73.0",
|
|
75
|
+
"@stacksjs/utils": "0.73.0",
|
|
76
|
+
"@stacksjs/validation": "0.73.0"
|
|
77
77
|
}
|
|
78
78
|
}
|