@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 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: string
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: string
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: string
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),E=this.hmac(q,O),C=`${I} Credential=${t.accessKeyId}/${D}, SignedHeaders=${w}, Signature=${E}`;return{...u,Authorization:C}}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"?>
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((C)=>`${C.toLowerCase()}:${u[C].trim()}
18
- `).join(""),S=Object.keys(u).sort().map((C)=>C.toLowerCase()).join(";"),P=["PUT",`/${e.key}`,"",h,S,l].join(`
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}`,E=await fetch(o,{method:"PUT",headers:{...u,Authorization:q},body:typeof e.body==="string"?e.body:new Uint8Array(e.body)});if(!E.ok){let C=await E.text();throw Error(`S3 PUT failed: ${E.status} ${C}`)}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"?>
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"),E=`${T} Credential=${r}/${w}, SignedHeaders=${P}, Signature=${q}`,C=`https://${i}${l}?policy=`,f=await fetch(C,{method:"PUT",headers:{...h,Authorization:E},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()}
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=`,E=await fetch(q,{method:"GET",headers:{...l,Authorization:O}});if(E.status===404)return null;if(!E.ok){let f=await E.text();throw Error(`Failed to get bucket policy: ${E.status} ${f}`)}let C=await E.text();try{return JSON.parse(C)}catch{throw Error(`Failed to parse bucket policy JSON: ${C.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"?>
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(),E=g.createHmac("sha256",q).update(I).digest("hex"),C=`${w} Credential=${i}/${v}, SignedHeaders=${A}, Signature=${E}`,f=await fetch(d,{method:"PUT",headers:{...S,Authorization:C},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"?>
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.72.102",
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.7",
62
+ "@stacksjs/ts-cloud": "^0.12.10",
63
63
  "@stacksjs/ts-xml": "^0.1.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@stacksjs/cli": "0.72.102",
67
- "@stacksjs/config": "0.72.102",
66
+ "@stacksjs/cli": "0.73.0",
67
+ "@stacksjs/config": "0.73.0",
68
68
  "better-dx": "^0.2.24",
69
- "@stacksjs/dns": "0.72.102",
70
- "@stacksjs/env": "0.72.102",
71
- "@stacksjs/logging": "0.72.102",
72
- "@stacksjs/path": "0.72.102",
73
- "@stacksjs/router": "0.72.102",
74
- "@stacksjs/storage": "0.72.102",
75
- "@stacksjs/utils": "0.72.102",
76
- "@stacksjs/validation": "0.72.102"
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
  }