UNPKG

serverless-aws-lambda

Version:

AWS Application Load Balancer and API Gateway - Lambda dev tool for Serverless. Allows Express synthax in handlers. Supports packaging, local invoking and offline ALB, APG, S3, SNS, SQS, DynamoDB Stream server mocking.

61 lines 53.6 kB
import{statSync as qe}from"fs";import Ee from"path";var de=o=>{let e=typeof o=="string"?o:"localS3/";e=Ee.resolve(e),e.endsWith("/")||(e+="/");try{if(qe(e).isDirectory())return e;throw new Error(`Provided localStorageDir '${o}' is not a directory`)}catch(t){if(t.code=="ENOENT")return e;throw t.code=="ENOTDIR"?new Error(`Provided localStorageDir '${o}' is not a directory`):t}};import{randomUUID as ze}from"crypto";import{readFile as me,stat as re,mkdir as Be,rm as pe}from"fs/promises";import{writeFileSync as je,rmSync as Ue}from"fs";import E from"path";var ue=({Bucket:o,RequestId:e})=>`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message><BucketName>${o}</BucketName><RequestId>${e}</RequestId><HostId>local</HostId></Error> `,f=({Key:o,RequestId:e})=>`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>${o}</Key><RequestId>${e}</RequestId><HostId>local</HostId></Error>`;var Le={PutObject:["ObjectCreated","Put"],CopyObject:["ObjectCreated","Copy"],DeleteObject:["ObjectRemoved","Delete"]},Me=({bucket:o,eTag:e,size:t,key:s,eventName:n,sourceIPAddress:r,requestId:c})=>({eventVersion:"2.1",eventSource:"aws:s3",awsRegion:"eu-west-3",eventTime:new Date().toUTCString(),eventName:n,userIdentity:{principalId:"AWS:AIDA6ECTW4PP5BZ6IKOGM"},requestParameters:{sourceIPAddress:r},responseElements:{"x-amz-request-id":c,"x-amz-id-2":"K9uTQdtIwO9VVKYvEk0BrLAAO9zWajA33cUGdcrZvjoLHLwBUBocXu1GU50BEcMIfNTLdt2KKmzaagHcGBWncOyUgcXx8UILLYKd26F/pf4="},s3:{s3SchemaVersion:"1.0",configurationId:"975e5867-6fe6-4b2c-925e-ef15389f6d3f",bucket:{name:o,ownerIdentity:{principalId:"A1HCF0AO1IXCSI"},arn:`arn:aws:s3:::${o}`},object:{key:s,size:t,eTag:e,sequencer:"0063E38F8ED88A5726"}}}),Ae=(o,e)=>{if(o){if(Array.isArray(o))return o.map(t=>typeof t.prefix=="string"?e.startsWith(t.prefix):typeof t.suffix=="string"?e.endsWith(t.suffix):!1).every(t=>t===!0)}else return!0},C=async(o,{bucket:e,eTag:t,size:s,key:n,requestCmd:r,sourceIPAddress:c,requestId:a})=>{let u=Le[r];for(let d of o)for(let m of d.s3){if(e!=m.bucket)continue;let[p,l]=m.type;if(p==u[0]&&(l=="*"||l==u[1])&&Ae(m.rules,n))try{await d.invoke({Records:[Me({bucket:e,eTag:t,size:s,key:n,sourceIPAddress:c,requestId:a,eventName:u.join(":")})]},{kind:"s3",event:m})}catch(h){console.log(h)}}};import{createHash as Pe}from"crypto";var X=o=>Pe("md5").update(o).digest("hex");var Rt=5*1024*1024;var R=o=>`"${X(o)}"`;var g=class o extends Error{statusCode;Code;SenderFault=!0;RequestId;constructor({Code:e,Message:t,SenderFault:s,RequestId:n,statusCode:r}){super(t),this.Code=e,this.RequestId=n,this.statusCode=r,typeof s=="boolean"&&(this.SenderFault=s)}toXml(e=""){return o.genericError({Code:this.Code,Message:this.message,RequestId:this.RequestId,info:e})}static genericError({Code:e,Message:t,RequestId:s,info:n}){return`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>${e}</Code><Message>${t}</Message>${n??""}<RequestId>${s}</RequestId><HostId>local</HostId></Error>`}},b=class extends g{TagKey;constructor({TagKey:e,Message:t,RequestId:s}){super({Code:"InvalidTag",Message:t,SenderFault:!0,statusCode:400,RequestId:s}),this.TagKey=e}toXml(){return super.toXml(`<TagKey>${this.TagKey}</TagKey>`)}},G=class extends g{constructor(e){super({Code:"MalformedXML",Message:"The XML you provided was not well-formed or did not validate against our published schema",RequestId:e})}},H=class extends g{constructor({Message:e,RequestId:t}){super({Code:"BadRequest",Message:e,RequestId:t})}},W=class extends g{ArgumentName;ArgumentValue;constructor({Message:e,RequestId:t,ArgumentName:s,ArgumentValue:n}){super({Code:"InvalidArgument",Message:e,RequestId:t}),this.ArgumentName=s,this.ArgumentValue=n}toXml(){return super.toXml(`<ArgumentName>${this.ArgumentName}</ArgumentName><ArgumentValue>${this.ArgumentValue}</ArgumentValue>`)}},J=class extends g{constructor(e){super({Code:"NoSuchTagSet",Message:"The TagSet does not exist",RequestId:e,statusCode:404})}},I=class extends g{constructor(e,t){super({Code:"UnsupportedCommand",Message:`${e} is currently not supported`,RequestId:t,statusCode:500})}};import{XMLParser as De,XMLBuilder as Ke}from"fast-xml-parser";var Oe=new De,$e=["STANDARD","REDUCED_REDUNDANCY","STANDARD_IA","ONEZONE_IA","INTELLIGENT_TIERING","GLACIER","DEEP_ARCHIVE","OUTPOSTS","GLACIER_IR","SNOW"],_e=/\.{2,}/,Fe=/^(\d{1,3}\.){3}\d{1,3}$/,Ve=/^[a-z0-9]+[a-z0-9.-]+[a-z0-9]$/,i=class o{static localStoragePath;static persist=!0;static persistence={version:2,buckets:{}};static XMLBuilder=new Ke;static genLocalKey(e,t,s){return X(E.posix.join(e,t,s??""))}static#e=async e=>{let t={version:2,buckets:{}};for(let[s,n]of Object.entries(e.files))try{let[r,...c]=s.replace(this.localStoragePath,"").split("/").filter(Boolean),a=await re(s),u=c.join("/"),d=this.genLocalKey(r,u),m={currentKey:d,type:n.type,cacheControl:n.cacheControl,StorageClass:"STANDARD",size:a.size,LastModified:a.mtimeMs,ETag:R(await me(s)),metadata:{},versions:{[d]:{}}};t.buckets[r]?t.buckets[r].objects[u]=m:t.buckets[r]={date:Date.now(),deletionPolicy:"Retain",objects:{[u]:m}}}catch{}return t};static async bootstrap(){try{let e=await me(E.join(this.localStoragePath,"__items.json"),"utf-8"),t=JSON.parse(e);if(t.version==2){this.persistence=t;return}this.persistence=await this.#e(t)}catch{}}static async createBucketDir(e,t){let s=E.join(this.localStoragePath,e);try{if(!(await re(s)).isDirectory())throw await pe(s),new Error}catch{try{await Be(s,{recursive:!0}),this.persistence.buckets[e]={date:Date.now(),...t,objects:{}}}catch(r){console.error(r)}}}static saveState(){o.persist?je(E.join(this.localStoragePath,"__items.json"),JSON.stringify(this.persistence)):Ue(this.localStoragePath,{force:!0,recursive:!0})}static isValidBucketName(e){let t=e.length;return t<3||t>63||_e.test(e)||Fe.test(e)||e.startsWith("xn--")||e.startsWith("sthree-")||e.endsWith("-s3alias")||e.endsWith("--ol-s3")?!1:Ve.test(e)}isValidStorageClass(e,t){return $e.includes(e)?!0:(t.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<Error><Code>InvalidStorageClass</Code><Message>The storage class you specified is not valid</Message><StorageClassRequested>${e}</StorageClassRequested><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!1)}static callableLambdas=[];requestId;metadata={};constructor(e){this.requestId=e["amz-sdk-invocation-id"]??ze(),Object.keys(e).filter(s=>s.startsWith("x-amz-meta-")).forEach(s=>this.metadata[s]=e[s])}hasNot(e,t){if(!o.isValidBucketName(e)){t.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>InvalidBucketName</Code><Message>The specified bucket is not valid.</Message><BucketName>${e}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(!o.persistence.buckets[e])return t.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(ue({Bucket:e,RequestId:this.requestId})),!0}static async removeObject(e,t,s,n){let r=this.persistence.buckets[e].objects[t];if(!r)return;let c=E.join(this.localStoragePath,e,r.currentKey);try{let a=await re(c);a.isFile()&&await pe(c),await C(this.callableLambdas,{bucket:e,key:t,requestId:n,requestCmd:"DeleteObject",eTag:r.ETag,sourceIPAddress:s,size:a.size}),delete this.persistence.buckets[e].objects[t]}catch{}}static async getTagsFromRequest(e,t,s){let n;e.on("data",p=>{n=typeof n>"u"?p:Buffer.concat([n,p])});let r=await new Promise(p=>{e.on("end",async()=>{p(n)})}),c=new G(t);if(!r)throw new g({Code:"MissingRequestBodyError",Message:"Request Body is empty",RequestId:t});let a;try{a=Oe.parse(r)}catch{throw c}if(a.Tagging=="")return;let u=a.Tagging.TagSet.Tag;u&&!Array.isArray(u)&&(u=[u]);let d={};for(let p of u){if(p===null||typeof p!="object"||Array.isArray(p))throw c;let{Key:l,Value:h}=p;if(typeof l!="string"||typeof h!="string")throw c;if(l in d)throw new b({TagKey:l,RequestId:t,Message:"Cannot provide multiple Tags with the same key"});if(l.length>128||l.length<1)throw new b({TagKey:l,RequestId:t,Message:"The TagKey you have provided is invalid"});if(h.length>256)throw new b({TagKey:l,RequestId:t,Message:"The TagValue you have provided is invalid"});d[l]=h}let m=s=="Bucket"?50:10;if(Object.keys(d).length>m)throw new H({Message:`${s} tag count cannot be greater than ${m}`,RequestId:t});return d}};var Q=class extends i{bucket;delimiter;encodingType;maxKeys=1e3;prefix;expectedOwner;optionalObjectAttributes;requestPayer;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.delimiter=e.searchParams.get("delimiter"),this.encodingType=e.searchParams.get("encoding-type");let n=e.searchParams.get("max-keys");n&&(this.maxKeys=n),this.prefix=e.searchParams.get("prefix"),this.expectedOwner=e.searchParams.get("x-amz-expected-bucket-owner"),this.optionalObjectAttributes=e.searchParams.get("x-amz-optional-object-attributes"),this.requestPayer=e.searchParams.get("x-amz-request-payer")}getKeys(){let e=Object.keys(i.persistence.buckets[this.bucket].objects);return this.prefix&&(e=e.filter(t=>t.startsWith(this.prefix))),e.sort(),e}isInvalidMaxKeys(e){if(this.maxKeys){if(isNaN(this.maxKeys))return e.statusCode=400,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>InvalidArgument</Code><Message>Provided max-keys not an integer or within integer range</Message><ArgumentName>max-keys</ArgumentName><ArgumentValue>${this.maxKeys}</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!0;if(this.maxKeys=Number(this.maxKeys),this.maxKeys<0||this.maxKeys>2147483647)return e.statusCode=400,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>InvalidArgument</Code><Message>Argument maxKeys must be an integer between 0 and 2147483647</Message><ArgumentName>maxKeys</ArgumentName><ArgumentValue>${this.maxKeys}</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!0}}};function le(o,e,t){let s=[];for(let n of t)if(n.startsWith(o)){let r=n.indexOf(e,o.length);if(r>0){let c=n.substring(0,r+e.length);s.includes(c)||s.push(c)}}return s}var S=class extends Q{marker;constructor(e,t){super(e,t),this.marker=e.searchParams.get("marker")}exec(e){if(this.hasNot(this.bucket,e)||this.isInvalidMaxKeys(e))return;let t=!1,s="",n="",r=[],c="",a=this.getKeys();if(this.marker){a=a.filter(l=>l.localeCompare(this.marker)>0);let p=a.findIndex(l=>l.startsWith(this.marker));p>-1&&(a=a.slice(p+1))}let u=Number(this.maxKeys),d=a.length;d>u&&(t=!0,a=a.slice(0,u),d>a.length&&(s=a[a.length-1])),this.delimiter&&(n=`<Delimiter>${this.delimiter}</Delimiter>`,r=le(this.prefix??"",this.delimiter,a),this.marker&&(r=r.filter(p=>p!=this.marker))),r.length&&(a=a.filter(p=>!r.some(l=>p.startsWith(l))),c=r.map(p=>`<CommonPrefixes><Prefix>${p}</Prefix></CommonPrefixes>`).join("")),this.marker&&t&&!a.length&&r.length&&(s=r[0]),e.statusCode=200,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let m=a.map(p=>{let l=i.persistence.buckets[this.bucket].objects[p];return`<Contents> <Key>${p}</Key> <LastModified>${new Date(l.LastModified).toISOString()}</LastModified> <ETag>${l.ETag}</ETag> <Size>${l.size}</Size> <StorageClass>${l.StorageClass}</StorageClass> </Contents>`}).join("");e.end(`<?xml version="1.0" encoding="UTF-8"?> <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Name>${this.bucket}</Name> <Prefix>${this.prefix??""}</Prefix> ${this.marker?`<Marker>${this.marker}</Marker>`:""} ${n} ${c} ${s?`<NextMarker>${s}</NextMarker>`:""} <MaxKeys>${this.maxKeys}</MaxKeys> <IsTruncated>${t}</IsTruncated> ${m} </ListBucketResult>`)}},x=class extends Q{continuationToken;fetchOwner;startAfter;constructor(e,t){super(e,t),this.continuationToken=e.searchParams.get("continuation-token"),this.fetchOwner=e.searchParams.get("fetch-owner"),this.startAfter=e.searchParams.get("start-after")}exec(e){if(this.hasNot(this.bucket,e)||this.isInvalidMaxKeys(e))return;let t=!1,s="",n="",r=[],c="",a=this.getKeys(),u="";if(this.continuationToken?u=Buffer.from(this.continuationToken,"base64").toString():this.startAfter&&(u=this.startAfter),u){a=a.filter(y=>y.localeCompare(u)>0);let h=a.findIndex(y=>y.startsWith(u));h>-1&&(a=a.slice(h+1))}let d=Number(this.maxKeys);a.length>d&&(t=!0,a=a.slice(0,d)),this.delimiter&&(n=`<Delimiter>${this.delimiter}</Delimiter>`,r=le(this.prefix??"",this.delimiter,a),u&&(r=r.filter(h=>h!=u))),r.length&&(a=a.filter(h=>!r.some(y=>h.startsWith(y))),c=r.map(h=>`<CommonPrefixes><Prefix>${h}</Prefix></CommonPrefixes>`).join(""));let p=a.length+r.length;t&&(a.length?s=Buffer.from(a[a.length-1]).toString("base64"):r.length&&(s=Buffer.from(r[0]).toString("base64"))),e.statusCode=200,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let l=a.map(h=>{let y=i.persistence.buckets[this.bucket].objects[h];return`<Contents> <Key>${h}</Key> <LastModified>${new Date(y.LastModified).toISOString()}</LastModified> <ETag>${y.ETag}</ETag> <Size>${y.size}</Size> <StorageClass>${y.StorageClass}</StorageClass> </Contents>`}).join("");e.end(`<?xml version="1.0" encoding="UTF-8"?> <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Name>${this.bucket}</Name> <Prefix>${this.prefix??""}</Prefix> ${n} ${c} <KeyCount>${p}</KeyCount> ${s?`<NextContinuationToken>${s}</NextContinuationToken>`:""} <MaxKeys>${this.maxKeys}</MaxKeys> <IsTruncated>${t}</IsTruncated> ${this.continuationToken?`<ContinuationToken>${this.continuationToken}</ContinuationToken>`:""} ${!this.continuationToken&&this.startAfter?`<StartAfter>${this.startAfter}</StartAfter>`:""} ${l} </ListBucketResult>`)}};var w=class extends i{constructor(e,t){super(t)}async exec(e){let t=[];Object.entries(i.persistence.buckets).forEach(([s,n])=>{t.push({name:s,date:new Date(n.date).toISOString()})}),e.writeHead(200,{"x-amz-request-id":this.requestId,"Content-Type":"application/xml","transfer-encoding":"chunked",Server:"AmazonS3"}),e.end(`<?xml version="1.0" encoding="UTF-8"?> <ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <Owner> <DisplayName>local-User</DisplayName> <ID>1234567890123456789</ID> </Owner> <Buckets> ${t.map(s=>`<Bucket> <CreationDate>${s.date}</CreationDate> <Name>${s.name}</Name> </Bucket>`).join(` `)} </Buckets> </ListAllMyBucketsResult>`)}};import{createReadStream as Xe}from"fs";import ge from"path";var L=({ifMatch:o,ifNoneMatch:e,ifModifiedSince:t,ifUnmodifiedSince:s},{ETag:n,LastModified:r})=>o&&o!==n?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Match"}:e&&e===n?{statusCode:304,Code:"PreconditionFailed",Condition:"If-None-Match"}:t&&t>=r?{statusCode:304,Code:"PreconditionFailed",Condition:"If-Modified-Since"}:s&&s<r?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Unmodified-Since"}:200,v=class o extends i{bucketPath;bucket;key;versionId;partNumber;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;constructor(e,t){super(t);let s=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")),[n,...r]=s.split("/").filter(Boolean);if(this.bucket=n,this.key=r.join("/"),this.bucketPath=ge.join(o.localStoragePath,n),this.versionId=e.searchParams.get("versionId"),this.partNumber=e.searchParams.has("partNumber")?Number(e.searchParams.get("partNumber")):null,t.range){let[c]=t.range.split("bytes=").filter(Boolean),[a,u]=c.split("-");!isNaN(Number(a))&&!isNaN(Number(u))&&(this.range=[Number(a),Number(u)])}this.ifMatch=t["if-match"],this.ifNoneMatch=t["if-none-match"],t["if-modified-since"]&&(this.ifModifiedSince=new Date(t["if-modified-since"]).getTime()),t["if-unmodified-since"]&&(this.ifUnmodifiedSince=new Date(t["if-unmodified-since"]).getTime())}async exec(e){if(!this.hasNot(this.bucket,e)){if(!i.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.key,RequestId:this.requestId}));return}try{let t={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},s=i.persistence.buckets[this.bucket].objects[this.key],n=L(t,s);if(n==200){let r=200,c=s.size,a,u=s.type,d={};if(this.range){r=206,d.start=this.range[0],d.end=this.range[1];let m=1;d.end>s.size&&(d.end=s.size,m--),c=m+d.end-d.start,a=`bytes ${d.start}-${d.end}/${s.size}`,u="application/octet-stream"}e.statusCode=r,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("x-amz-server-side-encryption","AES256"),e.setHeader("Date",new Date().toUTCString()),e.setHeader("Last-Modified",new Date(s.LastModified).toUTCString()),e.setHeader("ETag",s.ETag),e.setHeader("Accept-Ranges","bytes"),a&&e.setHeader("Content-Range",a),e.setHeader("Content-Length",c),u&&e.setHeader("Content-Type",u),e.setHeader("Server","AmazonS3"),s.cacheControl&&e.setHeader("Cache-Control",s.cacheControl),s.contentDisposition&&e.setHeader("Content-Disposition",s.contentDisposition),s.contentEncoding&&e.setHeader("Content-Encoding",s.contentEncoding),s.contentLanguage&&e.setHeader("Content-Language",s.contentLanguage),s.expires&&e.setHeader("Expires",new Date(s.expires).toUTCString()),s.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",s.websiteRedirectLocation),Object.entries(s.metadata).forEach(([m,p])=>{e.setHeader(m,p)}),Xe(ge.join(this.bucketPath,s.currentKey),d).pipe(e)}else e.writeHead(n.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${n.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${n.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var k=class extends i{constructor(e,t){super(t)}exec(e){e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<Error><Code>UnknownOperation</Code><Message>Your request is currently not supported.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var M=class extends i{bucket;key;versionId;constructor(e,t){super(t);let[s,...n]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.key=n.join("/"),this.versionId=e.searchParams.get("versionId")}async exec(e){if(!this.hasNot(this.bucket,e)){if(!i.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.key,RequestId:this.requestId}));return}try{e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.statusCode=200;let t={Tagging:{TagSet:{Tag:[]}}},s=i.persistence.buckets[this.bucket].objects[this.key].tags;if(s)for(let[r,c]of Object.entries(s))t.Tagging.TagSet.Tag.push({Key:r,Value:c});let n=i.XMLBuilder.build(t);e.end(`<?xml version="1.0" encoding="UTF-8"?>${n}`)}catch(t){if(e.statusCode=400,t instanceof g){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}}};var A=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e){if(!this.hasNot(this.bucket,e))try{e.setHeader("x-amzn-requestid",this.requestId);let t=i.persistence.buckets[this.bucket].tags;if(!t)throw new J(this.requestId);e.statusCode=200;let s={Tagging:{TagSet:{Tag:[]}}};for(let[r,c]of Object.entries(t))s.Tagging.TagSet.Tag.push({Key:r,Value:c});let n=i.XMLBuilder.build(s);e.setHeader("Content-Type","application/xml"),e.end(`<?xml version="1.0" encoding="UTF-8"?>${n}`)}catch(t){if(e.statusCode=400,t instanceof g){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}};var he=o=>{let{url:e,headers:t}=o,s=new URL(e,"http://localhost:3000"),n=s.searchParams.get("x-id"),r=t["user-agent"],c=s.pathname.replace("/%40s3/","").replace("/@s3/","").split("/").filter(Boolean).length==1;if(r&&r.startsWith("aws-cli")){let[,a]=r.split("command/"),[,...u]=a.split(".");switch(u.join(".")){case"ls":return/@s3\/?$/.test(e)?new w(s,t):s.searchParams.get("list-type")=="2"?new x(s,t):new S(s,t);case"list-buckets":return new w(s,t);case"list-objects":return new S(s,t);case"list-objects-v2":return new x(s,t);case"rb.rm":return s.searchParams.get("list-type")=="2"?new x(s,t):new S(s,t);case"get-object":return new v(s,t);case"cp":case"mv":case"sync":return c?s.searchParams.get("list-type")=="2"?new x(s,t):new S(s,t):new v(s,t);case"get-bucket-tagging":return new A(s,t);case"get-object-tagging":return new M(s,t);default:break}}else{if(!n)return s.searchParams.has("tagging")?c?new A(s,t):new M(s,t):e.endsWith("@s3/")?new w(s,t):s.searchParams.get("list-type")=="2"?new x(s,t):new S(s,t);if(n=="GetObject")return new v(s,t)}return new k(s,t)};import{createWriteStream as Ge}from"fs";import fe from"path";import{mkdir as We,readFile as Je,stat as Ye}from"fs/promises";var T=class extends i{bucket;key;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";tagging;constructor(e,t){super(t);let[s,...n]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.key=n.join("/"),this.contentType=t["content-type"]??"application/octet-stream",this.cacheControl=t["cache-control"],this.contentDisposition=t["content-disposition"],this.contentEncoding=t["content-encoding"],this.contentLanguage=t["content-language"],this.websiteRedirectLocation=t["x-amz-website-redirect-location"],t["x-amz-tagging"]&&(this.tagging=t["x-amz-tagging"]);let r=t["x-amz-storage-class"];r&&(this.storageClass=r);let c=new Date(t.expires);isNaN(c)||(this.expires=c.getTime())}async exec(e,t){if(this.hasNot(this.bucket,e)||!this.isValidStorageClass(this.storageClass,e))return;let s={};if(this.tagging){let u=()=>{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new W({ArgumentName:"x-amz-tagging",ArgumentValue:this.tagging,Message:"The header 'x-amz-tagging' shall be encoded as UTF-8 then URLEncoded URL query parameters without tag name duplicates.",RequestId:this.requestId}).toXml())};if(typeof this.tagging!="string"||!Qe(this.tagging))return u();let d=new URLSearchParams(this.tagging);for(let m of d.keys()){if(m in s){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new b({TagKey:m,RequestId:this.requestId,Message:"Cannot provide multiple Tags with the same key"}).toXml());return}if(m.length>128||m.length<1){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new b({TagKey:m,RequestId:this.requestId,Message:"The TagKey you have provided is invalid"}).toXml());return}let p=d.get(m);if(p.length>256){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new b({TagKey:m,RequestId:this.requestId,Message:"The TagValue you have provided is invalid"}).toXml());return}s[m]=p}}let n=Object.keys(s).length;if(n>10){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({Message:`Object tag count cannot be greater than ${10}`,RequestId:this.requestId}).toXml());return}let r=i.genLocalKey(this.bucket,this.key),c=fe.join(i.localStoragePath,this.bucket,r);try{await We(fe.dirname(c),{recursive:!0})}catch{}let a=Ge(c);a.on("close",async()=>{try{let u=await Ye(c),d=R(await Je(c));i.persistence.buckets[this.bucket].objects[this.key]={currentKey:r,type:this.contentType,cacheControl:this.cacheControl,contentDisposition:this.contentDisposition,contentEncoding:this.contentEncoding,contentLanguage:this.contentLanguage,expires:this.expires,websiteRedirectLocation:this.websiteRedirectLocation,ETag:d,size:u.size,LastModified:u.mtimeMs,StorageClass:this.storageClass,metadata:this.metadata,versions:{[r]:{}},tags:n?s:void 0};let m=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";e.end(),await C(i.callableLambdas,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"PutObject",eTag:d,sourceIPAddress:m,size:u.size})}catch(u){console.log(u)}}),e.setHeader("status",100),e.setHeader("Server","AmazonS3"),e.setHeader("x-amzn-requestid",this.requestId),t.pipe(a)}},Qe=o=>!o.split("&").find(e=>e.split("=").length>2);var P=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e){if(!i.isValidBucketName(this.bucket)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>InvalidBucketName</Code><Message>The specified bucket is not valid.</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(i.persistence.buckets[this.bucket]){e.statusCode=409,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),e.end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>BucketAlreadyOwnedByYou</Code><Message>Your previous request to create the named bucket succeeded and you already own it.</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}await i.createBucketDir(this.bucket,{deletionPolicy:"Retain"}),e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Location",`/${this.bucket}`),e.setHeader("Server","AmazonS3"),e.end()}};import ye from"path";import{copyFile as Ze,readFile as et,stat as tt}from"fs/promises";var q=class extends i{bucket;key;sourceBucket;sourceKey;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";metadataDirective;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;constructor(e,t){super(t);let[s,...n]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.key=n.join("/"),this.contentType=t["content-type"]??"application/octet-stream",this.cacheControl=t["cache-control"],this.contentDisposition=t["content-disposition"],this.contentEncoding=t["content-encoding"],this.contentLanguage=t["content-language"],this.websiteRedirectLocation=t["x-amz-website-redirect-location"];let r=t["x-amz-storage-class"];r&&(this.storageClass=r);let c=new Date(t.expires);isNaN(c)||(this.expires=c.getTime()),this.metadataDirective=t["x-amz-metadata-directive"];let a=t["x-amz-copy-source"]??"",[u,...d]=decodeURIComponent(a.replace("/@s3/","")).split("/").filter(Boolean);this.sourceBucket=u,this.sourceKey=d.join("/"),this.ifMatch=t["x-amz-copy-source-if-match"],this.ifNoneMatch=t["x-amz-copy-source-if-none-match"],t["x-amz-copy-source-if-modified-since"]&&(this.ifModifiedSince=new Date(t["x-amz-copy-source-if-modified-since"]).getTime()),t["x-amz-copy-source-if-unmodified-since"]&&(this.ifUnmodifiedSince=new Date(t["x-amz-copy-source-if-unmodified-since"]).getTime())}async exec(e,t){if(this.sourceKey==""){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>InvalidArgument</Code><Message>Invalid copy source object key</Message><ArgumentName>x-amz-copy-source</ArgumentName><ArgumentValue>x-amz-copy-source</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(this.hasNot(this.bucket,e)||this.hasNot(this.sourceBucket,e)||!this.isValidStorageClass(this.storageClass,e))return;if(!i.persistence.buckets[this.sourceBucket].objects[this.sourceKey]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.sourceKey,RequestId:this.requestId}));return}let s=i.persistence.buckets[this.sourceBucket].objects[this.sourceKey];if([this.bucket,this.key].join("/")==[this.sourceBucket,this.sourceKey].join("/")&&[this.storageClass==s.StorageClass,this.websiteRedirectLocation==s.websiteRedirectLocation].every(m=>m===!0)){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<Error><Code>InvalidRequest</Code><Message>This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let n={ifMatch:this.ifMatch,ifNoneMatch:this.ifNoneMatch,ifModifiedSince:this.ifModifiedSince,ifUnmodifiedSince:this.ifUnmodifiedSince},r=L(n,s);if(r!==200){e.writeHead(r.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${r.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${r.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let c=ye.join(i.localStoragePath,this.sourceBucket,s.currentKey),a=i.genLocalKey(this.bucket,this.key),u=ye.join(i.localStoragePath,this.bucket,a);try{await Ze(c,u);let d=await tt(u),m=R(await et(u));this.metadataDirective=="COPY"?i.persistence.buckets[this.bucket].objects[this.key]={currentKey:a,type:s.type,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,ETag:m,StorageClass:s.StorageClass,LastModified:d.mtimeMs,size:d.size,metadata:s.metadata,versions:{[a]:{}}}:i.persistence.buckets[this.bucket].objects[this.key]={currentKey:a,type:this.contentType,cacheControl:this.cacheControl,contentDisposition:this.contentDisposition,contentEncoding:this.contentEncoding,contentLanguage:this.contentLanguage,expires:this.expires,ETag:m,StorageClass:this.storageClass,LastModified:d.mtimeMs,size:d.size,metadata:this.metadata,websiteRedirectLocation:this.websiteRedirectLocation,versions:{[a]:{}}};let p=new Date(d.mtimeMs).toISOString();e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<?xml version="1.0" encoding="UTF-8"?> <CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LastModified>${p}</LastModified><ETag>${m}</ETag></CopyObjectResult>`);let l=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await C(i.callableLambdas,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"CopyObject",eTag:m,sourceIPAddress:l,size:d.size})}catch(d){console.error(d),e.statusCode=500,e.end("Internal Server Error")}}};var N=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e,t){if(!this.hasNot(this.bucket,e))try{e.setHeader("x-amzn-requestid",this.requestId),i.persistence.buckets[this.bucket].tags=await i.getTagsFromRequest(t,this.requestId,"Bucket"),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof g){e.setHeader("Content-Type","application/xml"),s.statusCode&&(e.statusCode=s.statusCode),e.end(s.toXml());return}if(s instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var z=class extends i{bucket;key;constructor(e,t){super(t);let[s,...n]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.key=n.join("/")}async exec(e,t){if(!this.hasNot(this.bucket,e)){if(!i.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.key,RequestId:this.requestId}));return}try{e.setHeader("x-amzn-requestid",this.requestId),i.persistence.buckets[this.bucket].objects[this.key].tags=await i.getTagsFromRequest(t,this.requestId,"Object"),e.statusCode=200,e.end()}catch(s){if(e.statusCode=400,s instanceof g){e.setHeader("Content-Type","application/xml"),s.statusCode&&(e.statusCode=s.statusCode),e.end(s.toXml());return}if(s instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var B=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new I("PutBucketPolicy",this.requestId).toXml()))}};var j=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new I("PutBucketCors",this.requestId).toXml()))}};var U=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new I("PutBucketAcl",this.requestId).toXml()))}};var D=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new I("PutObjectAcl",this.requestId).toXml()))}};var be=o=>{let{url:e,headers:t}=o,s=new URL(e,"http://localhost:3000"),n=s.searchParams.get("x-id"),r=t["user-agent"];if(r&&r.startsWith("aws-cli")){let[,c]=r.split("command/"),[,...a]=c.split("."),u=a.join("."),d=typeof t["x-amz-copy-source"]=="string";switch(u){case"cp":case"sync":case"mv":return d?new q(s,t):new T(s,t);case"mb":case"create-bucket":return new P(s,t);case"copy-object":return new q(s,t);case"put-object":return new T(s,t);case"put-bucket-tagging":return new N(s,t);case"put-object-tagging":return new z(s,t);case"put-bucket-policy":return new B(s,t);case"put-bucket-cors":return new j(s,t);case"put-bucket-acl":return new U(s,t);case"put-object-acl":return new D(s,t);default:break}}else{if(!n){let c=s.pathname.replace("/%40s3/","").replace("/@s3/","").split("/").filter(Boolean).length==1;return s.searchParams.has("policy")?new B(s,t):s.searchParams.has("cors")?new j(s,t):s.searchParams.has("acl")?c?new U(s,t):new D(s,t):s.searchParams.has("tagging")?c?new N(s,t):new z(s,t):new P(s,t)}if(n=="PutObject")return new T(s,t);if(n=="CopyObject")return new q(s,t)}return new k(s,t)};var Z=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}exec(e){this.hasNot(this.bucket,e)||(e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.end())}};import Ie from"path";var ee=class extends i{filePath;bucketPath;bucket;key;versionId;partNumber;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;constructor(e,t){super(t);let s=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")),[n,...r]=s.split("/").filter(Boolean);if(this.bucket=n,this.key=r.join("/"),this.bucketPath=Ie.join(i.localStoragePath,n),this.filePath=Ie.join(this.bucketPath,...r),this.versionId=e.searchParams.get("versionId"),this.partNumber=e.searchParams.has("partNumber")?Number(e.searchParams.get("partNumber")):null,t.range){let[c]=t.range.split("bytes=").filter(Boolean),[a,u]=c.split("-");!isNaN(Number(a))&&!isNaN(Number(u))&&(this.range=[Number(a),Number(u)])}this.ifMatch=t["if-match"],this.ifNoneMatch=t["if-none-match"],t["if-modified-since"]&&(this.ifModifiedSince=new Date(t["if-modified-since"]).getTime()),t["if-unmodified-since"]&&(this.ifUnmodifiedSince=new Date(t["if-unmodified-since"]).getTime())}async exec(e){if(!this.hasNot(this.bucket,e)){if(!i.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.key,RequestId:this.requestId}));return}try{let t={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},s=i.persistence.buckets[this.bucket].objects[this.key],n=L(t,s);if(n==200){let r=200,c=s.size,a,u=s.type,d={};if(this.range){r=206,d.start=this.range[0],d.end=this.range[1];let m=1;d.end>s.size&&(d.end=s.size,m--),c=m+d.end-d.start,a=`bytes ${d.start}-${d.end}/${s.size}`,u="application/octet-stream"}e.statusCode=r,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("x-amz-server-side-encryption","AES256"),e.setHeader("Date",new Date().toUTCString()),e.setHeader("Last-Modified",new Date(s.LastModified).toUTCString()),e.setHeader("ETag",s.ETag),e.setHeader("Accept-Ranges","bytes"),a&&e.setHeader("Content-Range",a),e.setHeader("Content-Length",c),u&&e.setHeader("Content-Type",u),e.setHeader("Server","AmazonS3"),s.cacheControl&&e.setHeader("Cache-Control",s.cacheControl),s.contentDisposition&&e.setHeader("Content-Disposition",s.contentDisposition),s.contentEncoding&&e.setHeader("Content-Encoding",s.contentEncoding),s.contentLanguage&&e.setHeader("Content-Language",s.contentLanguage),s.expires&&e.setHeader("Expires",new Date(s.expires).toUTCString()),s.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",s.websiteRedirectLocation),Object.entries(s.metadata).forEach(([m,p])=>{e.setHeader(m,p)}),e.end()}else e.writeHead(n.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${n.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${n.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var ke=o=>{let{url:e,headers:t}=o,s=new URL(e,"http://localhost:3000");return s.pathname.replace("/%40s3/","").replace("/@s3/","").split("/").filter(Boolean).length>1?new ee(s,t):new Z(s,t)};import{rm as st}from"fs/promises";import nt from"path";var K=class extends i{bucket;constructor(e,t){super(t);let s=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")),[n]=s.split("/").filter(Boolean);this.bucket=n}async exec(e,...t){if(!this.hasNot(this.bucket,e))try{let n=!(Object.keys(i.persistence.buckets[this.bucket].objects).length>0&&i.persistence.buckets[this.bucket].deletionPolicy=="Retain");await st(nt.join(i.localStoragePath,this.bucket),{recursive:n,force:!0}),delete i.persistence.buckets[this.bucket],e.writeHead(204,{"x-amzn-requestid":this.requestId,Server:"AmazonS3"}).end()}catch{e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?> <Error><Code>BucketNotEmpty</Code><Message>The bucket you tried to delete is not empty</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}}};var O=class extends i{bucket;key;version;constructor(e,t){super(t);let s=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")),[n,...r]=s.split("/").filter(Boolean);this.bucket=n,this.key=r.join("/"),this.version=e.searchParams.get("versionId")}async exec(e,t){if(this.hasNot(this.bucket,e))return;e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),e.end();let s=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await i.removeObject(this.bucket,this.key,s,this.requestId)}};var te=class extends i{bucket;constructor(e,t){super(t);let[s]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s}async exec(e){if(!this.hasNot(this.bucket,e))try{i.persistence.buckets[this.bucket].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(t){if(e.statusCode=400,t instanceof g){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}};var se=class extends i{bucket;key;constructor(e,t){super(t);let[s,...n]=decodeURIComponent(e.pathname.replace("/%40s3/","").replace("/@s3/","")).split("/").filter(Boolean);this.bucket=s,this.key=n.join("/")}async exec(e){if(!this.hasNot(this.bucket,e)){if(!i.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(f({Key:this.key,RequestId:this.requestId}));return}try{i.persistence.buckets[this.bucket].objects[this.key].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(t){if(e.statusCode=400,t instanceof g){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(g.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}}};var rt=new Set(["rm","rb.rm","mv","delete-object"]),Se=o=>{let{url:e,headers:t}=o,s=new URL(e,"http://localhost:3000"),n=s.pathname.replace("/%40s3/","").replace("/@s3/","").split("/").filter(Boolean).length==1;if(s.searchParams.has("tagging"))return n?new te(s,t):new se(s,t);let r=t["user-agent"];if(r&&r.startsWith("aws-cli")){let[,c]=r.split("command/"),[,...a]=c.split("."),u=a.join(".");if(rt.has(u))return new O(s,t);if(u=="rb"||u=="delete-bucket")return new K(s,t)}else{let c=s.searchParams.get("x-id");if(!c)return new K(s,t);if(c=="DeleteObject")return new O(s,t)}return new k(s,t)};var $=class o{static apiId="";static accountId="";static port=3e3;static serve;static contentType={json:"application/json",text:"text/plain; charset=utf-8",octet:"application/octet-stream"};static keepAlive=["Connection","keep-alive"];static dummyHost="http://localhost:3003";static httpErrMsg='{"message":"Internal Server Error"}';static apigJsonParseErrMsg='{"message":"[Unknown error parsing request body]"}';static apigForbiddenErrMsg='{"message":"Forbidden"}';static amzMsgNull='{"message":null}';static apgTimeoutMsg='{"message": "Endpoint request timed out"}';static unavailable='{"message":"Service Unavailable"}';static timeoutRegex=/after.\d+.*seconds/;static apgRequestTimeout=30;static normalizeHeaderKey=e=>e.toLowerCase().split("-").map(xe).join("-");static getMultiValueHeaders=e=>{let t={},s=e.filter((r,c)=>c%2==0).map(r=>r.toLowerCase()),n=e.filter((r,c)=>c%2!==0);return s.forEach((r,c)=>{r!="x-mock-type"&&(t[r]?t[r].push(n[c]):t[r]=[n[c]])}),t};static getIsBase64Encoded=e=>{let t=e["content-type"];return e["content-encoding"]||!t?!0:!(t.startsWith("application/json")||t.startsWith("application/xml")||t.startsWith("application/javascript")||t.startsWith("text/"))};static knownHeaders=["accept","accept-encoding","user-agent","host","via","content-length"];static getApiGV1Headers(e,t){let{rawHeaders:s}=e,n,r={"X-Forwarded-For":e.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(o.port)};for(let d=0;d<s.length;){let m=s[d],p=m.toLowerCase();if(["connection","x-mock-type"].includes(p)){d=d+2;continue}this.knownHeaders.includes(p)&&(m=this.normalizeHeaderKey(p));let l=s[d+1];r[m]=l,p=="x-api-key"&&(n=l),d=d+2}let c={};for(let d of Object.keys(r).sort((m,p)=>m.localeCompare(p)))c[d]=r[d];let a={"X-Forwarded-For":[e.socket.remoteAddress],"X-Forwarded-Proto":["http"],"X-Forwarded-Port":[String(o.port)]};for(let d=0;d<s.length;){let m=s[d],p=m.toLowerCase();if(["connection","x-mock-type"].includes(p)){d=d+2;continue}this.knownHeaders.includes(p)&&(m=this.normalizeHeaderKey(p));let l=s[d+1];a[m]?a[m].push(l):a[m]=[l],d=d+2}let u={};for(let d of Object.keys(a).sort((m,p)=>m.localeCompare(p)))u[d]=a[d];return{headers:c,multiValueHeaders:u,apiKey:n}}static getCustomHeaders(e,t){let{headers:s}=e;return delete s["x-mock-type"],delete s.connection,{"X-Forwarded-For":e.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(o.port),...s}}static getPathParameters(e,t){let s=e.paths[0].split("/"),n=t.pathname.split("/"),r={};return s.forEach((c,a)=>{c.startsWith("{")&&c.endsWith("}")&&!c.endsWith("+}")&&(r[c.slice(1,-1)]=n[a])}),r}static normalizeSearchParams=(e,t)=>{let s={};Array.from(e.keys()).forEach(c=>{let a=e.getAll(c).map(d=>d.toLowerCase()),u=c.toLowerCase();a?s[u]?s[u].push(...a):s[u]=a:s[u]||(s[u]=void 0)});let n="",r=t.indexOf("?");return r!=-1&&(n=t.slice(r+1)),s.toString=()=>n,s};static getMultiValueQueryStringParameters=e=>{let t={};e.delete("x_mock_type");for(let s of Array.from(new Set(e.keys())))t[s]=e.getAll(s).map(encodeURI);return t};static isEndpointTimeoutError=e=>{if(!e)return;let t=e.match(this.timeoutRegex)?.[0];if(t){let s=t.split(" ")[1];if(!isNaN(s))return Number(s)>=o.apgRequestTimeout}}};var ne=!1,ot=o=>{ne=o},it=()=>ne,_=(o,e)=>{ne&&console.log(`\x1B[${o}m${e}\x1B[0m`)},at=o=>console.log(`\x1B[31m${o}\x1B[0m`),ct=o=>_("32",o),dt=o=>_("33",o),ut=o=>_("36",o),mt=o=>_("90",o),pt=o=>_("94",o),lt=o=>ne?console.log(o):void 0,Ce={GREEN:ct,YELLOW:dt,CYAN:ut,BR_BLUE:pt,RED:at,GREY:mt,setDebug:ot,getDebug:it,info:lt};var Re="application/vnd.awslambda.http-integration-response",ce=class o{buffer;_isHttpIntegrationResponse;_metaDelimiter;_endDelimiter;_ct;_isStreamResponse=!0;#e;static codec=new TextDecoder;static splitMessage=(e,t)=>{if(!e)return;let s=Array.from(e.values()),n=null;if(t)n=t;else for(let r=0;r<s.length;r++)if(s[r]===0&&[s[r+1],s[r+2],s[r+3],s[r+4],s[r+5],s[r+6],s[r+7]].every(u=>u===0)){n=r;break}if(n)return new Uint8Array(s.slice(0,n))};constructor(e){this._isHttpIntegrationResponse=!1,this._metaDelimiter=0,this._endDelimiter=0,this.#e=e}setHeader(e,t){this._isHttpIntegrationResponse=!this.buffer&&t==Re&&(!this._ct||this._ct==Re),this._ct=t}write(e,t){!this._isHttpIntegrationResponse&&!this._metaDelimiter&&(this._metaDelimiter=e.byteLength),this.#s(e)}end(e){this.buffer&&(this._endDelimiter=this.buffer.byteLength),e&&this.#s(e)}destroy(){}#s(e){this.buffer=typeof this.buffer>"u"?e:Buffer.concat([this.buffer,e])}getParsedResponse(){if(!this.#e)return;let e=this.#e.kind;if(e=="alb")return this.#n();if(e=="url")return this.#o();if(e=="apg")return this.#r()}#n(){let e=this._isHttpIntegrationResponse?o.splitMessage(this.buffer):this.buffer,t;return e&&(t=this.#t(e)),t}#r(){if(this._isHttpIntegrationResponse)return Ce.RED("awslambda.HttpResponseStream.from() is not supported with API Gateway"),{statusCode:500,headers:{"Content-Type":$.contentType.json},body:$.httpErrMsg};if(this.buffer)return this.#t(this.buffer)}#o(){let e=o.splitMessage(this.buffer,this._isHttpIntegrationResponse?void 0:this._metaDelimiter),t;return e&&(t=this.#t(e)),t}#t(e){let t=o.codec.decode(e);if(typeof t=="string")try{t=JSON.parse(t)}catch{}return t}};var He="<html><head><title>400 Request Header Or Cookie Too Large</title></head><body><center><h1>400 Bad Request</h1></center><center>Request Header Or Cookie Too Large</center></body></html>";var Xn=JSON.stringify({Message:null});var we=async(o,e)=>{let t;return o.on("data",n=>{t=typeof t>"u"?n:Buffer.concat([t,n])}),await new Promise(n=>{o.on("end",async()=>{n(t?t.toString(e?"base64":"utf-8"):void 0)})})};var Gn=JSON.stringify({Type:null,message:"Client context must be a valid Base64-encoded JSON object."});var Wn=new Error(He);var xe=o=>o.charAt(0).toUpperCase()+o.slice(1);var gt=o=>{let e=[],t;try{o.split("<Object>").forEach(s=>{let n=s.indexOf("<Key>");if(n==-1)return;let r=s.indexOf("</Key>"),a={Key:s.slice(n+5,r)},u=s.indexOf("<VersionId>");if(u>-1){let d=s.indexOf("</VersionId>"),m=s.slice(u+11,d);a.VersionId=m}e.push(a)})}catch(s){console.error(s)}return{Objects:e,