exlo 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,19 @@
1
- import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypto";import{mkdirSync as st,rmSync as rt,writeFileSync as nt}from"node:fs";import{readFile as ot,rm as it,stat as at}from"node:fs/promises";import D from"node:path";import{XMLBuilder as ct,XMLParser as dt}from"fast-xml-parser";import{createHash as Ye}from"node:crypto";var R=i=>Ye("md5").update(i).digest("hex");function B(i,r,e){let t=[];for(let s of e)if(s.startsWith(i)){let n=s.indexOf(r,i.length);if(n>0){let o=s.substring(0,n+r.length);t.includes(o)||t.push(o)}}return t.sort(),t}var we=({Bucket:i,RequestId:r})=>`<?xml version="1.0" encoding="UTF-8"?>
1
+ import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypto";import{mkdirSync as st,rmSync as rt,writeFileSync as nt}from"node:fs";import{readFile as ot,rm as it,stat as at}from"node:fs/promises";import O from"node:path";import{XMLBuilder as ct,XMLParser as dt}from"fast-xml-parser";import{createHash as Je}from"node:crypto";var R=i=>Je("md5").update(i).digest("hex");function j(i,r,e){let t=[];for(let s of e)if(s.startsWith(i)){let n=s.indexOf(r,i.length);if(n>0){let o=s.substring(0,n+r.length);t.includes(o)||t.push(o)}}return t.sort(),t}var we=({Bucket:i,RequestId:r})=>`<?xml version="1.0" encoding="UTF-8"?>
2
2
  <Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message><BucketName>${i}</BucketName><RequestId>${r}</RequestId><HostId>local</HostId></Error>
3
- `,k=({Key:i,RequestId:r})=>`<?xml version="1.0" encoding="UTF-8"?>
4
- <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>${i}</Key><RequestId>${r}</RequestId><HostId>local</HostId></Error>`;var I=class i extends Error{statusCode;Code;SenderFault=!0;RequestId;constructor({Code:r,Message:e,SenderFault:t,RequestId:s,statusCode:n}){super(e),this.Code=r,this.RequestId=s,this.statusCode=n,typeof t=="boolean"&&(this.SenderFault=t)}toXml(r=""){return i.genericError({Code:this.Code,Message:this.message,RequestId:this.RequestId,info:r})}static genericError({Code:r,Message:e,RequestId:t,info:s}){return`<?xml version="1.0" encoding="UTF-8"?>
5
- <Error><Code>${r}</Code><Message>${e}</Message>${s??""}<RequestId>${t}</RequestId><HostId>local</HostId></Error>`}},H=class extends I{TagKey;constructor({TagKey:r,Message:e,RequestId:t}){super({Code:"InvalidTag",Message:e,SenderFault:!0,statusCode:400,RequestId:t}),this.TagKey=r}toXml(){return super.toXml(`<TagKey>${this.TagKey}</TagKey>`)}},P=class extends I{constructor(r){super({Code:"MalformedXML",Message:"The XML you provided was not well-formed or did not validate against our published schema",RequestId:r})}},N=class extends I{constructor({Message:r,RequestId:e}){super({Code:"BadRequest",Message:r,RequestId:e})}},C=class extends I{ArgumentName;ArgumentValue;constructor({Message:r,RequestId:e,ArgumentName:t,ArgumentValue:s}){super({Code:"InvalidArgument",Message:r,RequestId:e}),this.ArgumentName=t,this.ArgumentValue=s}toXml(){let r=`<ArgumentName>${this.ArgumentName}</ArgumentName>`;return typeof this.ArgumentValue<"u"&&(r+=`<ArgumentValue>${this.ArgumentValue}</ArgumentValue>`),super.toXml(r)}},j=class extends I{PartNumberRequested;ActualPartCount;constructor({RequestId:r,PartNumberRequested:e,ActualPartCount:t}){super({Code:"InvalidPartNumber",Message:"The requested partnumber is not satisfiable",RequestId:r}),this.PartNumberRequested=e,this.ActualPartCount=t}toXml(){return super.toXml(`<PartNumberRequested>${this.PartNumberRequested}</PartNumberRequested><ActualPartCount>${this.ActualPartCount}</ActualPartCount>`)}},te=class extends I{constructor(r){super({Code:"NoSuchTagSet",Message:"The TagSet does not exist",RequestId:r,statusCode:404})}},A=class extends I{constructor(r,e){super({Code:"UnsupportedCommand",Message:`${r} is currently not supported`,RequestId:e,statusCode:500})}};var Qe={PutObject:["ObjectCreated","Put"],CopyObject:["ObjectCreated","Copy"],DeleteObject:["ObjectRemoved","Delete"]},Ze=({bucket:i,eTag:r,size:e,key:t,eventName:s,sourceIPAddress:n,requestId:o})=>({eventVersion:"2.1",eventSource:"aws:s3",awsRegion:"eu-west-3",eventTime:new Date().toUTCString(),eventName:s,userIdentity:{principalId:"AWS:AIDA6ECTW4PP5BZ6IKOGM"},requestParameters:{sourceIPAddress:n},responseElements:{"x-amz-request-id":o,"x-amz-id-2":"K9uTQdtIwO9VVKYvEk0BrLAAO9zWajA33cUGdcrZvjoLHLwBUBocXu1GU50BEcMIfNTLdt2KKmzaagHcGBWncOyUgcXx8UILLYKd26F/pf4="},s3:{s3SchemaVersion:"1.0",configurationId:"975e5867-6fe6-4b2c-925e-ef15389f6d3f",bucket:{name:i,ownerIdentity:{principalId:"A1HCF0AO1IXCSI"},arn:`arn:aws:s3:::${i}`},object:{key:t,size:e,eTag:r,sequencer:"0063E38F8ED88A5726"}}}),et=(i,r)=>{if(!i)return!0;if(Array.isArray(i))return i.map(e=>typeof e.prefix=="string"?r.startsWith(e.prefix):typeof e.suffix=="string"?r.endsWith(e.suffix):!1).every(e=>e===!0)},q=async(i,{bucket:r,eTag:e,size:t,key:s,requestCmd:n,sourceIPAddress:o,requestId:a})=>{let d=Qe[n];for(let c of i)for(let u of c.s3){if(r!=u.bucket)continue;let[l,m]=u.type;if(l==d[0]&&(m=="*"||m==d[1])&&et(u.rules,s))try{await c.invoke({Records:[Ze({bucket:r,eTag:e,size:t,key:s,sourceIPAddress:o,requestId:a,eventName:d.join(":")})]},{kind:"s3",event:u})}catch(g){console.log(g)}}};var ut=["STANDARD","REDUCED_REDUNDANCY","STANDARD_IA","ONEZONE_IA","INTELLIGENT_TIERING","GLACIER","DEEP_ARCHIVE","OUTPOSTS","GLACIER_IR","SNOW"],lt=/\.{2,}/,mt=/^(\d{1,3}\.){3}\d{1,3}$/,pt=/^[a-z0-9]+[a-z0-9.-]+[a-z0-9]$/,b=class i{constructor(r,e=!1,t){this.localStoragePath=r;this.persist=e;this.port=t}static XMLBuilder=new ct;static XMLParser=new dt;static genLocalKey(r,e,t){return R(D.posix.join(r,e,t??""))}static async getTagsFromRequest(r,e,t){let s;r.on("data",l=>{s=typeof s>"u"?l:Buffer.concat([s,l])});let n=await new Promise(l=>{r.on("end",async()=>{l(s)})}),o=new P(e);if(!n)throw new I({Code:"MissingRequestBodyError",Message:"Request Body is empty",RequestId:e});let a;try{a=i.XMLParser.parse(n)}catch{throw o}if(a.Tagging=="")return;let d=a.Tagging.TagSet.Tag;d&&!Array.isArray(d)&&(d=[d]);let c={};for(let l of d){if(l===null||typeof l!="object"||Array.isArray(l))throw o;let{Key:m,Value:g}=l;if(typeof m!="string"||typeof g!="string")throw o;if(m in c)throw new H({TagKey:m,RequestId:e,Message:"Cannot provide multiple Tags with the same key"});if(m.length>128||m.length<1)throw new H({TagKey:m,RequestId:e,Message:"The TagKey you have provided is invalid"});if(g.length>256)throw new H({TagKey:m,RequestId:e,Message:"The TagValue you have provided is invalid"});c[m]=g}let u=t=="Bucket"?50:10;if(Object.keys(c).length>u)throw new N({Message:`${t} tag count cannot be greater than ${u}`,RequestId:e});return c}persistence={version:2,buckets:{}};callableLambdas=[];accountId="123456789012";ownerId=[Ce(),Ce()].join("").replaceAll("-","");region="us-east-1";allowToDeleteNonEmptyBuckets=!1;async bootstrap(){try{let r=await ot(D.join(this.localStoragePath,"__state.json"),"utf-8"),e=JSON.parse(r);if(e.version==2){this.persistence=e;return}}catch{}}async createBucket(r,e){let t=D.join(this.localStoragePath,r);st(t,{recursive:!0}),this.persistence.buckets[r]={date:Date.now(),acl:{accessControlPolicy:`<?xml version="1.0" encoding="UTF-8"?>
6
- <AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>${this.ownerId}</ID></Owner><AccessControlList><Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>${this.ownerId}</ID></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList></AccessControlPolicy>`},...e,objects:{},multipartUploads:{}}}saveState(){this.persist?nt(D.join(this.localStoragePath,"__state.json"),JSON.stringify(this.persistence)):rt(this.localStoragePath,{force:!0,recursive:!0})}static isValidBucketName(r){let e=r.length;return e<3||e>63||lt.test(r)||mt.test(r)||r.startsWith("xn--")||r.startsWith("sthree-")||r.endsWith("-s3alias")||r.endsWith("--ol-s3")?!1:pt.test(r)}async removeObject(r,e,t,s){let n=this.persistence.buckets[r].objects[e];if(!n)return;let o=D.join(this.localStoragePath,r,n.currentKey);try{let a=await at(o);a.isFile()&&await it(o),delete this.persistence.buckets[r].objects[e],setTimeout(async()=>{try{await q(this.callableLambdas,{bucket:r,key:e,requestId:s,requestCmd:"DeleteObject",eTag:n.ETag,sourceIPAddress:t,size:a.size})}catch{}},30)}catch{}}setCorsHeaders(r,e){r.headers.origin&&(e.setHeader("access-control-allow-origin",r.headers.origin),e.setHeader("access-control-allow-credentials","true"))}getCorsHeaders(r,e=!1){if(r.headers.origin)return e?["access-control-allow-origin",r.headers.origin,"access-control-allow-credentials","true"]:{"access-control-allow-origin":r.headers.origin,"access-control-allow-credentials":"true"}}},p=class{constructor(r,e){this.localService=e;this.requestId=r["amz-sdk-invocation-id"]??Ce(),Object.keys(r).filter(s=>s.startsWith("x-amz-meta-")).forEach(s=>this.metadata[s]=r[s])}requestId;metadata={};isValidStorageClass(r,e,t){return ut.includes(r)?!0:(e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<Error><Code>InvalidStorageClass</Code><Message>The storage class you specified is not valid</Message><StorageClassRequested>${r}</StorageClassRequested><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!1)}hasNot(r,e,t){if(!b.isValidBucketName(r)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
7
- <Error><Code>InvalidBucketName</Code><Message>The specified bucket is not valid.</Message><BucketName>${r}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(!this.localService.persistence.buckets[r])return e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(we({Bucket:r,RequestId:this.requestId})),!0}};import{statSync as gt}from"node:fs";import ht from"node:path";var Te=i=>{let r=typeof i=="string"?i:".exlo/s3/";r=ht.resolve(r),r.endsWith("/")||(r+="/");try{if(gt(r).isDirectory())return r;throw new Error(`Provided localStorageDir '${i}' is not a directory`)}catch(e){if(e.code=="ENOENT")return r;throw e.code=="ENOTDIR"?new Error(`Provided localStorageDir '${i}' is not a directory`):e}};import{createServer as ss}from"node:http";import{rm as ft}from"node:fs/promises";import It from"node:path";var O=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=Object.keys(this.localService.persistence.buckets[this.bucket].objects).length>0;if(!this.localService.allowToDeleteNonEmptyBuckets&&s){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
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>`);return}delete this.localService.persistence.buckets[this.bucket];try{await ft(It.join(this.localService.localStoragePath,this.bucket),{recursive:!0,force:!0,maxRetries:1})}catch{}e.writeHead(204,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end()}};var K=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.version=e.searchParams.get("versionId")}bucket;key;version;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e);let s=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await this.localService.removeObject(this.bucket,this.key,s,this.requestId),e.end()}};var S=class extends p{constructor(e,t,s){super(t,s);this.localService=s}exec(e,t){e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>UnknownOperation</Code><Message>Your request is currently not supported.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var re=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{this.localService.persistence.buckets[this.bucket].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var ne=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/")}bucket;key;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({Key:this.key,RequestId:this.requestId}));return}try{this.localService.persistence.buckets[this.bucket].objects[this.key].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};import{unlink as bt}from"node:fs/promises";var oe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId")??"invalid"}bucket;key;uploadId;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!s){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
9
- <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}s.aborted=!0,e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(),s.completed||setTimeout(async()=>{for(let n of s.parts)try{await bt(n.filePath)}catch{}},100)}};var ie=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];s.policy=void 0,e.statusCode=204,e.end()}};var yt=new Set(["rm","rb.rm","mv","delete-object"]),Pe=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=s.pathname.split("/").filter(Boolean).length==1;if(s.searchParams.has("policy"))return n?new ie(s,t,r):new S(s,t,r);if(s.searchParams.has("tagging"))return n?new re(s,t,r):new ne(s,t,r);if(s.searchParams.has("uploadId")&&!n)return new oe(s,t,r);let o=t["user-agent"];if(o?.startsWith("aws-cli")){let[,a]=o.split("command/"),[,...d]=a.split("."),c=d.join(".");if(yt.has(c))return new K(s,t,r);if(c=="rb"||c=="delete-bucket")return new O(s,t,r)}else{let a=s.searchParams.get("x-id");if(!a)return new O(s,t,r);if(a=="DeleteObject")return new K(s,t,r)}return new S(s,t,r)};var ae=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.delimiter=e.searchParams.get("delimiter"),this.encodingType=e.searchParams.get("encoding-type");let o=e.searchParams.get("max-keys");o&&(this.maxKeys=o),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")}bucket;delimiter;encodingType;maxKeys=1e3;prefix;expectedOwner;optionalObjectAttributes;requestPayer;getKeys(){let e=Object.keys(this.localService.persistence.buckets[this.bucket].objects);return this.prefix&&(e=e.filter(t=>t.startsWith(this.prefix))),e.sort(),e}isInvalidMaxKeys(e,t){if(this.maxKeys){if(isNaN(this.maxKeys))return e.statusCode=400,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?>
3
+ `,C=({Key:i,RequestId:r})=>`<?xml version="1.0" encoding="UTF-8"?>
4
+ <Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>${i}</Key><RequestId>${r}</RequestId><HostId>local</HostId></Error>`;var b=class i extends Error{statusCode;Code;SenderFault=!0;RequestId;constructor({Code:r,Message:e,SenderFault:t,RequestId:s,statusCode:n}){super(e),this.Code=r,this.RequestId=s,this.statusCode=n,typeof t=="boolean"&&(this.SenderFault=t)}toXml(r=""){return i.genericError({Code:this.Code,Message:this.message,RequestId:this.RequestId,info:r})}static genericError({Code:r,Message:e,RequestId:t,info:s}){return`<?xml version="1.0" encoding="UTF-8"?>
5
+ <Error><Code>${r}</Code><Message>${e}</Message>${s??""}<RequestId>${t}</RequestId><HostId>local</HostId></Error>`}},H=class extends b{TagKey;constructor({TagKey:r,Message:e,RequestId:t}){super({Code:"InvalidTag",Message:e,SenderFault:!0,statusCode:400,RequestId:t}),this.TagKey=r}toXml(){return super.toXml(`<TagKey>${this.TagKey}</TagKey>`)}},N=class extends b{constructor(r){super({Code:"MalformedXML",Message:"The XML you provided was not well-formed or did not validate against our published schema",RequestId:r})}},P=class extends b{constructor({Message:r,RequestId:e}){super({Code:"BadRequest",Message:r,RequestId:e})}},v=class extends b{ArgumentName;ArgumentValue;constructor({Message:r,RequestId:e,ArgumentName:t,ArgumentValue:s}){super({Code:"InvalidArgument",Message:r,RequestId:e}),this.ArgumentName=t,this.ArgumentValue=s}toXml(){let r=`<ArgumentName>${this.ArgumentName}</ArgumentName>`;return typeof this.ArgumentValue<"u"&&(r+=`<ArgumentValue>${this.ArgumentValue}</ArgumentValue>`),super.toXml(r)}},D=class extends b{PartNumberRequested;ActualPartCount;constructor({RequestId:r,PartNumberRequested:e,ActualPartCount:t}){super({Code:"InvalidPartNumber",Message:"The requested partnumber is not satisfiable",RequestId:r}),this.PartNumberRequested=e,this.ActualPartCount=t}toXml(){return super.toXml(`<PartNumberRequested>${this.PartNumberRequested}</PartNumberRequested><ActualPartCount>${this.ActualPartCount}</ActualPartCount>`)}},re=class extends b{constructor(r){super({Code:"NoSuchTagSet",Message:"The TagSet does not exist",RequestId:r,statusCode:404})}},A=class extends b{constructor(r,e){super({Code:"UnsupportedCommand",Message:`${r} is currently not supported`,RequestId:e,statusCode:500})}};var Ye={PutObject:["ObjectCreated","Put"],CopyObject:["ObjectCreated","Copy"],DeleteObject:["ObjectRemoved","Delete"]},Qe=({bucket:i,eTag:r,size:e,key:t,eventName:s,sourceIPAddress:n,requestId:o})=>({eventVersion:"2.1",eventSource:"aws:s3",awsRegion:"eu-west-3",eventTime:new Date().toUTCString(),eventName:s,userIdentity:{principalId:"AWS:AIDA6ECTW4PP5BZ6IKOGM"},requestParameters:{sourceIPAddress:n},responseElements:{"x-amz-request-id":o,"x-amz-id-2":"K9uTQdtIwO9VVKYvEk0BrLAAO9zWajA33cUGdcrZvjoLHLwBUBocXu1GU50BEcMIfNTLdt2KKmzaagHcGBWncOyUgcXx8UILLYKd26F/pf4="},s3:{s3SchemaVersion:"1.0",configurationId:"975e5867-6fe6-4b2c-925e-ef15389f6d3f",bucket:{name:i,ownerIdentity:{principalId:"A1HCF0AO1IXCSI"},arn:`arn:aws:s3:::${i}`},object:{key:t,size:e,eTag:r,sequencer:"0063E38F8ED88A5726"}}}),Ze=(i,r)=>{if(!i)return!0;if(Array.isArray(i))return i.map(e=>{let t=e.Name,s=e.Value;return t=="prefix"?r.startsWith(s):t=="suffix"?r.endsWith(s):!1}).every(e=>e===!0)};function et(i,r){let[e,t]=r;for(let s of i){let[n,o,a]=s.split(":");if(n=="s3"&&e==o&&(t==a||a=="*"))return!0}}var q=async(i,r,{bucket:e,eTag:t,size:s,key:n,requestCmd:o,sourceIPAddress:a,requestId:d})=>{let c=Ye[o];if(r.LambdaFunctionConfigurations)for(let u of r.LambdaFunctionConfigurations){if(!et(u.Events,c))continue;let l=u.Filter?.Key?.FilterRules;if(l&&!Ze(l,n))continue;let m=u.LambdaFunctionArn;if(m?.startsWith("arn:")){let[g,f,y,k,se,$,S]=m.split(":");y=="lambda"&&$=="function"&&(m=S)}let h=i.getLambdas().find(g=>g.name==m);if(h)try{let g={Records:[Qe({bucket:e,eTag:t,size:s,key:n,sourceIPAddress:a,requestId:d,eventName:c.join(":")})]};await h.invoke(g)}catch(g){console.log(g)}}};var ut=["STANDARD","REDUCED_REDUNDANCY","STANDARD_IA","ONEZONE_IA","INTELLIGENT_TIERING","GLACIER","DEEP_ARCHIVE","OUTPOSTS","GLACIER_IR","SNOW"],lt=/\.{2,}/,mt=/^(\d{1,3}\.){3}\d{1,3}$/,pt=/^[a-z0-9]+[a-z0-9.-]+[a-z0-9]$/,I=class i{constructor(r,e=!1,t){this.localStoragePath=r;this.persist=e;this.port=t}static XMLBuilder=new ct;static XMLParser=new dt;static genLocalKey(r,e,t){return R(O.posix.join(r,e,t??""))}static async getTagsFromRequest(r,e,t){let s;r.on("data",l=>{s=typeof s>"u"?l:Buffer.concat([s,l])});let n=await new Promise(l=>{r.on("end",async()=>{l(s)})}),o=new N(e);if(!n)throw new b({Code:"MissingRequestBodyError",Message:"Request Body is empty",RequestId:e});let a;try{a=i.XMLParser.parse(n)}catch{throw o}if(a.Tagging=="")return;let d=a.Tagging.TagSet.Tag;d&&!Array.isArray(d)&&(d=[d]);let c={};for(let l of d){if(l===null||typeof l!="object"||Array.isArray(l))throw o;let{Key:m,Value:h}=l;if(typeof m!="string"||typeof h!="string")throw o;if(m in c)throw new H({TagKey:m,RequestId:e,Message:"Cannot provide multiple Tags with the same key"});if(m.length>128||m.length<1)throw new H({TagKey:m,RequestId:e,Message:"The TagKey you have provided is invalid"});if(h.length>256)throw new H({TagKey:m,RequestId:e,Message:"The TagValue you have provided is invalid"});c[m]=h}let u=t=="Bucket"?50:10;if(Object.keys(c).length>u)throw new P({Message:`${t} tag count cannot be greater than ${u}`,RequestId:e});return c}persistence={version:2,buckets:{}};getLambdas=()=>[];accountId="123456789012";ownerId=[Ce(),Ce()].join("").replaceAll("-","");region="us-east-1";allowToDeleteNonEmptyBuckets=!1;async bootstrap(){try{let r=await ot(O.join(this.localStoragePath,"__state.json"),"utf-8"),e=JSON.parse(r);if(e.version==2){this.persistence=e;return}}catch{}}async createBucket(r,e){let t=O.join(this.localStoragePath,r);st(t,{recursive:!0}),this.persistence.buckets[r]={date:Date.now(),acl:{accessControlPolicy:`<?xml version="1.0" encoding="UTF-8"?>
6
+ <AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>${this.ownerId}</ID></Owner><AccessControlList><Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>${this.ownerId}</ID></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList></AccessControlPolicy>`},...e,objects:{},multipartUploads:{}}}saveState(){this.persist?nt(O.join(this.localStoragePath,"__state.json"),JSON.stringify(this.persistence)):rt(this.localStoragePath,{force:!0,recursive:!0})}static isValidBucketName(r){let e=r.length;return e<3||e>63||lt.test(r)||mt.test(r)||r.startsWith("xn--")||r.startsWith("sthree-")||r.endsWith("-s3alias")||r.endsWith("--ol-s3")?!1:pt.test(r)}async removeObject(r,e,t,s){let n=this.persistence.buckets[r].objects[e];if(!n)return;let o=O.join(this.localStoragePath,r,n.currentKey);try{let a=await at(o);a.isFile()&&await it(o),delete this.persistence.buckets[r].objects[e];let d=this.persistence.buckets[r].notification;d&&setTimeout(async()=>{try{await q(this,d,{bucket:r,key:e,requestId:s,requestCmd:"DeleteObject",eTag:n.ETag,sourceIPAddress:t,size:a.size})}catch{}},30)}catch{}}setCorsHeaders(r,e){r.headers.origin&&(e.setHeader("access-control-allow-origin",r.headers.origin),e.setHeader("access-control-allow-credentials","true"))}getCorsHeaders(r,e=!1){if(r.headers.origin)return e?["access-control-allow-origin",r.headers.origin,"access-control-allow-credentials","true"]:{"access-control-allow-origin":r.headers.origin,"access-control-allow-credentials":"true"}}},p=class{constructor(r,e){this.localService=e;this.requestId=r["amz-sdk-invocation-id"]??Ce(),Object.keys(r).filter(s=>s.startsWith("x-amz-meta-")).forEach(s=>this.metadata[s]=r[s])}requestId;metadata={};isValidStorageClass(r,e,t){return ut.includes(r)?!0:(e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<Error><Code>InvalidStorageClass</Code><Message>The storage class you specified is not valid</Message><StorageClassRequested>${r}</StorageClassRequested><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!1)}hasNot(r,e,t){if(!I.isValidBucketName(r)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
7
+ <Error><Code>InvalidBucketName</Code><Message>The specified bucket is not valid.</Message><BucketName>${r}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(!this.localService.persistence.buckets[r])return e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(we({Bucket:r,RequestId:this.requestId})),!0}};import{statSync as gt}from"node:fs";import ht from"node:path";var Te=i=>{let r=typeof i=="string"?i:".exlo/s3/";r=ht.resolve(r),r.endsWith("/")||(r+="/");try{if(gt(r).isDirectory())return r;throw new Error(`Provided localStorageDir '${i}' is not a directory`)}catch(e){if(e.code=="ENOENT")return r;throw e.code=="ENOTDIR"?new Error(`Provided localStorageDir '${i}' is not a directory`):e}};import{createServer as ss}from"node:http";import{rm as ft}from"node:fs/promises";import bt from"node:path";var K=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=Object.keys(this.localService.persistence.buckets[this.bucket].objects).length>0;if(!this.localService.allowToDeleteNonEmptyBuckets&&s){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
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>`);return}delete this.localService.persistence.buckets[this.bucket];try{await ft(bt.join(this.localService.localStoragePath,this.bucket),{recursive:!0,force:!0,maxRetries:1})}catch{}e.writeHead(204,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end()}};var F=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.version=e.searchParams.get("versionId")}bucket;key;version;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e);let s=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await this.localService.removeObject(this.bucket,this.key,s,this.requestId),e.end()}};var x=class extends p{constructor(e,t,s){super(t,s);this.localService=s}exec(e,t){e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>UnknownOperation</Code><Message>Your request is currently not supported.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var oe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{this.localService.persistence.buckets[this.bucket].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var ie=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/")}bucket;key;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({Key:this.key,RequestId:this.requestId}));return}try{this.localService.persistence.buckets[this.bucket].objects[this.key].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};import{unlink as It}from"node:fs/promises";var ae=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId")??"invalid"}bucket;key;uploadId;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!s){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
9
+ <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}s.aborted=!0,e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(),s.completed||setTimeout(async()=>{for(let n of s.parts)try{await It(n.filePath)}catch{}},100)}};var ce=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];s.policy=void 0,e.statusCode=204,e.end()}};var yt=new Set(["rm","rb.rm","mv","delete-object"]),Ne=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=s.pathname.split("/").filter(Boolean).length==1;if(s.searchParams.has("policy"))return n?new ce(s,t,r):new x(s,t,r);if(s.searchParams.has("tagging"))return n?new oe(s,t,r):new ie(s,t,r);if(s.searchParams.has("uploadId")&&!n)return new ae(s,t,r);let o=t["user-agent"];if(o?.startsWith("aws-cli")){let[,a]=o.split("command/"),[,...d]=a.split("."),c=d.join(".");if(yt.has(c))return new F(s,t,r);if(c=="rb"||c=="delete-bucket")return new K(s,t,r)}else{let a=s.searchParams.get("x-id");if(!a)return new K(s,t,r);if(a=="DeleteObject")return new F(s,t,r)}return new x(s,t,r)};var de=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.delimiter=e.searchParams.get("delimiter"),this.encodingType=e.searchParams.get("encoding-type");let o=e.searchParams.get("max-keys");o&&(this.maxKeys=o),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")}bucket;delimiter;encodingType;maxKeys=1e3;prefix;expectedOwner;optionalObjectAttributes;requestPayer;getKeys(){let e=Object.keys(this.localService.persistence.buckets[this.bucket].objects);return this.prefix&&(e=e.filter(t=>t.startsWith(this.prefix))),e.sort(),e}isInvalidMaxKeys(e,t){if(this.maxKeys){if(isNaN(this.maxKeys))return e.statusCode=400,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?>
10
10
  <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"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?>
11
- <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}}},M=class extends ae{constructor(e,t,s){super(e,t,s);this.localService=s;this.marker=e.searchParams.get("marker")}marker;exec(e,t){if(this.hasNot(this.bucket,e,t)||this.isInvalidMaxKeys(e,t))return;let s=!1,n="",o="",a=[],d="",c=this.getKeys();if(this.marker){c=c.filter(h=>h.localeCompare(this.marker)>0);let g=c.findIndex(h=>h.startsWith(this.marker));g>-1&&(c=c.slice(g+1))}let u=Number(this.maxKeys),l=c.length;l>u&&(s=!0,c=c.slice(0,u),l>c.length&&(n=c[c.length-1])),this.delimiter&&(o=`<Delimiter>${this.delimiter}</Delimiter>`,a=B(this.prefix??"",this.delimiter,c),this.marker&&(a=a.filter(g=>g!=this.marker))),a.length&&(c=c.filter(g=>!a.some(h=>g.startsWith(h))),d=a.map(g=>`<CommonPrefixes><Prefix>${g}</Prefix></CommonPrefixes>`).join("")),this.marker&&s&&!c.length&&a.length&&(n=a[0]),e.statusCode=200,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let m=c.map(g=>{let h=this.localService.persistence.buckets[this.bucket].objects[g];return`<Contents>
12
- <Key>${g}</Key>
13
- <LastModified>${new Date(h.LastModified).toISOString()}</LastModified>
14
- <ETag>${h.ETag}</ETag>
15
- <Size>${h.size}</Size>
16
- <StorageClass>${h.StorageClass}</StorageClass>
11
+ <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}}},M=class extends de{constructor(e,t,s){super(e,t,s);this.localService=s;this.marker=e.searchParams.get("marker")}marker;exec(e,t){if(this.hasNot(this.bucket,e,t)||this.isInvalidMaxKeys(e,t))return;let s=!1,n="",o="",a=[],d="",c=this.getKeys();if(this.marker){c=c.filter(g=>g.localeCompare(this.marker)>0);let h=c.findIndex(g=>g.startsWith(this.marker));h>-1&&(c=c.slice(h+1))}let u=Number(this.maxKeys),l=c.length;l>u&&(s=!0,c=c.slice(0,u),l>c.length&&(n=c[c.length-1])),this.delimiter&&(o=`<Delimiter>${this.delimiter}</Delimiter>`,a=j(this.prefix??"",this.delimiter,c),this.marker&&(a=a.filter(h=>h!=this.marker))),a.length&&(c=c.filter(h=>!a.some(g=>h.startsWith(g))),d=a.map(h=>`<CommonPrefixes><Prefix>${h}</Prefix></CommonPrefixes>`).join("")),this.marker&&s&&!c.length&&a.length&&(n=a[0]),e.statusCode=200,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let m=c.map(h=>{let g=this.localService.persistence.buckets[this.bucket].objects[h];return`<Contents>
12
+ <Key>${h}</Key>
13
+ <LastModified>${new Date(g.LastModified).toISOString()}</LastModified>
14
+ <ETag>${g.ETag}</ETag>
15
+ <Size>${g.size}</Size>
16
+ <StorageClass>${g.StorageClass}</StorageClass>
17
17
  </Contents>`}).join("");e.end(`<?xml version="1.0" encoding="UTF-8"?>
18
18
  <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
19
19
  <Name>${this.bucket}</Name>
@@ -25,7 +25,7 @@ import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypt
25
25
  <MaxKeys>${this.maxKeys}</MaxKeys>
26
26
  <IsTruncated>${s}</IsTruncated>
27
27
  ${m}
28
- </ListBucketResult>`)}},w=class extends ae{constructor(e,t,s){super(e,t,s);this.localService=s;this.continuationToken=e.searchParams.get("continuation-token"),this.fetchOwner=e.searchParams.get("fetch-owner"),this.startAfter=e.searchParams.get("start-after")}continuationToken;fetchOwner;startAfter;exec(e,t){if(this.hasNot(this.bucket,e,t)||this.isInvalidMaxKeys(e,t))return;let s=!1,n="",o="",a=[],d="",c=this.getKeys(),u="";if(this.continuationToken?u=Buffer.from(this.continuationToken,"base64").toString():this.startAfter&&(u=this.startAfter),u){c=c.filter(y=>y.localeCompare(u)>0);let f=c.findIndex(y=>y.startsWith(u));f>-1&&(c=c.slice(f+1))}let l=Number(this.maxKeys);c.length>l&&(s=!0,c=c.slice(0,l)),this.delimiter&&(o=`<Delimiter>${this.delimiter}</Delimiter>`,a=B(this.prefix??"",this.delimiter,c),u&&(a=a.filter(f=>f!=u))),a.length&&(c=c.filter(f=>!a.some(y=>f.startsWith(y))),d=a.map(f=>`<CommonPrefixes><Prefix>${f}</Prefix></CommonPrefixes>`).join(""));let g=c.length+a.length;s&&(c.length?n=Buffer.from(c[c.length-1]).toString("base64"):a.length&&(n=Buffer.from(a[0]).toString("base64"))),e.statusCode=200,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let h=c.map(f=>{let y=this.localService.persistence.buckets[this.bucket].objects[f];return`<Contents>
28
+ </ListBucketResult>`)}},w=class extends de{constructor(e,t,s){super(e,t,s);this.localService=s;this.continuationToken=e.searchParams.get("continuation-token"),this.fetchOwner=e.searchParams.get("fetch-owner"),this.startAfter=e.searchParams.get("start-after")}continuationToken;fetchOwner;startAfter;exec(e,t){if(this.hasNot(this.bucket,e,t)||this.isInvalidMaxKeys(e,t))return;let s=!1,n="",o="",a=[],d="",c=this.getKeys(),u="";if(this.continuationToken?u=Buffer.from(this.continuationToken,"base64").toString():this.startAfter&&(u=this.startAfter),u){c=c.filter(y=>y.localeCompare(u)>0);let f=c.findIndex(y=>y.startsWith(u));f>-1&&(c=c.slice(f+1))}let l=Number(this.maxKeys);c.length>l&&(s=!0,c=c.slice(0,l)),this.delimiter&&(o=`<Delimiter>${this.delimiter}</Delimiter>`,a=j(this.prefix??"",this.delimiter,c),u&&(a=a.filter(f=>f!=u))),a.length&&(c=c.filter(f=>!a.some(y=>f.startsWith(y))),d=a.map(f=>`<CommonPrefixes><Prefix>${f}</Prefix></CommonPrefixes>`).join(""));let h=c.length+a.length;s&&(c.length?n=Buffer.from(c[c.length-1]).toString("base64"):a.length&&(n=Buffer.from(a[0]).toString("base64"))),e.statusCode=200,e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let g=c.map(f=>{let y=this.localService.persistence.buckets[this.bucket].objects[f];return`<Contents>
29
29
  <Key>${f}</Key>
30
30
  <LastModified>${new Date(y.LastModified).toISOString()}</LastModified>
31
31
  <ETag>${y.ETag}</ETag>
@@ -37,15 +37,15 @@ import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypt
37
37
  <Prefix>${this.prefix??""}</Prefix>
38
38
  ${o}
39
39
  ${d}
40
- <KeyCount>${g}</KeyCount>
40
+ <KeyCount>${h}</KeyCount>
41
41
  ${n?`<NextContinuationToken>${n}</NextContinuationToken>`:""}
42
42
  <MaxKeys>${this.maxKeys}</MaxKeys>
43
43
  <IsTruncated>${s}</IsTruncated>
44
44
  ${this.continuationToken?`<ContinuationToken>${this.continuationToken}</ContinuationToken>`:""}
45
45
  ${!this.continuationToken&&this.startAfter?`<StartAfter>${this.startAfter}</StartAfter>`:""}
46
- ${h}
47
- </ListBucketResult>`)}};import{randomUUID as St}from"node:crypto";var E=class extends p{constructor(e,t,s){super(t,s);this.localService=s;e.searchParams.has("bucket-region")&&(this.bucketRegion=e.searchParams.get("bucket-region")),e.searchParams.has("continuation-token")&&(this.continuationToken=e.searchParams.get("continuation-token")),e.searchParams.has("prefix")&&(this.prefix=e.searchParams.get("prefix")),e.searchParams.has("max-buckets")&&(this.rawMaxBuckets=e.searchParams.get("max-buckets"))}bucketRegion;continuationToken;rawMaxBuckets;prefix;isValidToken(e){return!(!e||typeof e!="object"||typeof e.id!="string"||e.port!==this.localService.port||typeof e.prefix<"u"&&typeof e.prefix!="string"||typeof e.nextStartingPosition!="number"||Number(e.nextStartingPosition)<1)}isValidRequest(e,t){let s=Number(this.rawMaxBuckets);if(this.rawMaxBuckets){if(isNaN(s)||this.rawMaxBuckets.includes(".")||s<1||s>1e4){let o=new C({ArgumentName:"max-buckets",ArgumentValue:this.rawMaxBuckets,Message:"Argument max-buckets must be an integer between 1 and 10000",RequestId:this.requestId}).toXml();e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o);return}}else s=1e4;let n;if(this.continuationToken){let o=new C({ArgumentName:"continuation-token",Message:"The continuation token provided is incorrect",RequestId:this.requestId}).toXml();try{let a=JSON.parse(Buffer.from(this.continuationToken,"base64").toString("utf-8"));this.isValidToken(a)||(e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o)),n=a}catch{e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o);return}}return{maxBuckets:s,continuationToken:n,prefix:this.prefix,bucketRegion:this.bucketRegion}}createContinuationToken(e){let t={id:St(),port:this.localService.port,prefix:this.prefix??"",nextStartingPosition:e};return Buffer.from(JSON.stringify(t)).toString("base64")}getBucketNames(e,t){let s=Object.keys(this.localService.persistence.buckets).sort((n,o)=>n.localeCompare(o));return e?(e.prefix&&(s=s.filter(n=>n.startsWith(e.prefix))),s=s.slice(e.nextStartingPosition),t&&(s=s.filter(n=>n.startsWith(t))),s):t?s.filter(n=>n.startsWith(t)):s}async exec(e,t){let s=this.isValidRequest(e,t);if(!s)return;let{maxBuckets:n,continuationToken:o,prefix:a,bucketRegion:d}=s,c=this.getBucketNames(o,a),u="",l=d;!d&&(this.rawMaxBuckets||this.prefix||this.continuationToken)&&(l=this.localService.region);let m="";l&&(m+=`<BucketRegion>${l}</BucketRegion>`);let g=[];for(let y=0;y<c.length;y++){let v=c[y],xe=this.localService.persistence.buckets[v],ke=`<Bucket>${m}<CreationDate>${new Date(xe.date).toISOString()}</CreationDate><Name>${v}</Name></Bucket>`;if(g.push(ke),g.length==n){if(c[y+1]){let x=y+1;o&&(x=x+o.nextStartingPosition),u=this.createContinuationToken(x)}break}}let h="";u&&(h=`<ContinuationToken>${u}</ContinuationToken>`);let f="";this.prefix&&(f=`<Prefix>${this.prefix}</Prefix>`),e.writeHead(200,{"x-amz-request-id":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}),e.end(`<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Buckets>${g.join("")}</Buckets>${h}${f}<Owner><ID>${this.localService.ownerId}</ID></Owner></ListAllMyBucketsResult>`)}};import{createReadStream as xt}from"node:fs";import Ne from"node:path";var V=({ifMatch:i,ifNoneMatch:r,ifModifiedSince:e,ifUnmodifiedSince:t},{ETag:s,LastModified:n})=>i&&i!==s?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Match"}:r&&r===s?{statusCode:304,Code:"PreconditionFailed",Condition:"If-None-Match"}:e&&e>=n?{statusCode:304,Code:"PreconditionFailed",Condition:"If-Modified-Since"}:t&&t<n?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Unmodified-Since"}:200,L=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.bucketPath=Ne.join(this.localService.localStoragePath,o),this.versionId=e.searchParams.get("versionId"),this.hasPartNumber=e.searchParams.has("partNumber");let d=e.searchParams.get("partNumber"),c=Number(d);if(this.partNumber=this.hasPartNumber&&!isNaN(c)?c:d,t.range){this.hasRange=!0;let[u]=t.range.split("bytes=").filter(Boolean),[l,m]=u.split("-");!isNaN(Number(l))&&!isNaN(Number(m))&&(this.range=[Number(l),Number(m)])}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())}bucketPath;bucket;key;versionId;partNumber;hasPartNumber;hasRange=!1;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({Key:this.key,RequestId:this.requestId}));return}try{let s={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},n=this.localService.persistence.buckets[this.bucket].objects[this.key],o=n.currentKey,a=V(s,n);if(this.hasRange&&this.hasPartNumber){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>InvalidRequest</Code><Message>Cannot specify both Range header and partNumber query parameter</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(a==200){let d=200,c=n.size,u,l=Ne.join(this.bucketPath,n.currentKey),m={};if(this.hasPartNumber){let h=this.partNumber;if(isNaN(h)||h<1||h>1e4){let f=new C({ArgumentName:"partNumber",ArgumentValue:h,RequestId:this.requestId,Message:"Part number must be an integer between 1 and 10000, inclusive"}).toXml();e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(f);return}if(n.versions[o].multipartUploadId){let f=this.localService.persistence.buckets[this.bucket].multipartUploads[n.versions[o].multipartUploadId];d=206;let y;m.start=0;for(let v of f.parts){if(v.partNumber==h){y=v,m.end=m.start+y.size-1;break}m.start=m.start+v.size}if(!y){let v=new j({RequestId:this.requestId,PartNumberRequested:h,ActualPartCount:f.parts.length}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(v);return}e.setHeader("x-amz-mp-parts-count",f.parts.length),c=y?.size,u=`bytes ${m.start}-${m.end}/${n.size}`}else if(this.partNumber==1)d=206,u=`bytes 0-${n.size-1}/${n.size}`;else{let f=new j({RequestId:this.requestId,PartNumberRequested:this.partNumber,ActualPartCount:1}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(f);return}}let g=n.type;if(this.range){d=206,m.start=this.range[0],m.end=this.range[1];let h=1;m.end>n.size&&(m.end=n.size,h--),c=h+m.end-m.start,u=`bytes ${m.start}-${m.end}/${n.size}`,g="application/octet-stream"}e.statusCode=d,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(n.LastModified).toUTCString()),e.setHeader("ETag",n.ETag),e.setHeader("Accept-Ranges","bytes"),u&&e.setHeader("Content-Range",u),e.setHeader("Content-Length",c),g&&e.setHeader("Content-Type",g),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),n.cacheControl&&e.setHeader("Cache-Control",n.cacheControl),n.contentDisposition&&e.setHeader("Content-Disposition",n.contentDisposition),n.contentEncoding&&e.setHeader("Content-Encoding",n.contentEncoding),n.contentLanguage&&e.setHeader("Content-Language",n.contentLanguage),n.expires&&e.setHeader("Expires",new Date(n.expires).toUTCString()),n.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",n.websiteRedirectLocation);for(let[h,f]of Object.entries(n.metadata))e.setHeader(h,f);xt(l,m).pipe(e)}else e.writeHead(a.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${a.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${a.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var F=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/"),this.versionId=e.searchParams.get("versionId")}bucket;key;versionId;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({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 s={Tagging:{TagSet:{Tag:[]}}},n=this.localService.persistence.buckets[this.bucket].objects[this.key].tags;if(n)for(let[a,d]of Object.entries(n))s.Tagging.TagSet.Tag.push({Key:a,Value:d});let o=b.XMLBuilder.build(s);e.end(`<?xml version="1.0" encoding="UTF-8"?>${o}`)}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var _=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{e.setHeader("x-amzn-requestid",this.requestId);let s=this.localService.persistence.buckets[this.bucket].tags;if(!s)throw new te(this.requestId);e.statusCode=200;let n={Tagging:{TagSet:{Tag:[]}}};for(let[a,d]of Object.entries(s))n.Tagging.TagSet.Tag.push({Key:a,Value:d});let o=b.XMLBuilder.build(n);e.setHeader("Content-Type","application/xml"),e.end(`<?xml version="1.0" encoding="UTF-8"?>${o}`)}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var ce=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];if(s.policy){e.setHeader("x-amzn-requestid",this.requestId),e.end(JSON.stringify(s.policy));return}e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
48
- <Error><Code>NoSuchBucketPolicy</Code><BucketName>${this.bucket}</BucketName><Message>The bucket policy does not exist</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var de=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId"),this.hasPartNumberMarker=e.searchParams.has("part-number-marker"),e.searchParams.has("part-number-marker")&&(this.partNumberMarker=e.searchParams.get("part-number-marker")??""),e.searchParams.has("max-parts")&&(this.maxParts=e.searchParams.get("max-parts")??"")}bucket;key;uploadId;partNumberMarker="";hasPartNumberMarker=!1;maxParts="1000";validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId??""];if(!this.uploadId||!s||s.aborted||s.completed){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
46
+ ${g}
47
+ </ListBucketResult>`)}};import{randomUUID as St}from"node:crypto";var E=class extends p{constructor(e,t,s){super(t,s);this.localService=s;e.searchParams.has("bucket-region")&&(this.bucketRegion=e.searchParams.get("bucket-region")),e.searchParams.has("continuation-token")&&(this.continuationToken=e.searchParams.get("continuation-token")),e.searchParams.has("prefix")&&(this.prefix=e.searchParams.get("prefix")),e.searchParams.has("max-buckets")&&(this.rawMaxBuckets=e.searchParams.get("max-buckets"))}bucketRegion;continuationToken;rawMaxBuckets;prefix;isValidToken(e){return!(!e||typeof e!="object"||typeof e.id!="string"||e.port!==this.localService.port||typeof e.prefix<"u"&&typeof e.prefix!="string"||typeof e.nextStartingPosition!="number"||Number(e.nextStartingPosition)<1)}isValidRequest(e,t){let s=Number(this.rawMaxBuckets);if(this.rawMaxBuckets){if(isNaN(s)||this.rawMaxBuckets.includes(".")||s<1||s>1e4){let o=new v({ArgumentName:"max-buckets",ArgumentValue:this.rawMaxBuckets,Message:"Argument max-buckets must be an integer between 1 and 10000",RequestId:this.requestId}).toXml();e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o);return}}else s=1e4;let n;if(this.continuationToken){let o=new v({ArgumentName:"continuation-token",Message:"The continuation token provided is incorrect",RequestId:this.requestId}).toXml();try{let a=JSON.parse(Buffer.from(this.continuationToken,"base64").toString("utf-8"));this.isValidToken(a)||(e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o)),n=a}catch{e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(o);return}}return{maxBuckets:s,continuationToken:n,prefix:this.prefix,bucketRegion:this.bucketRegion}}createContinuationToken(e){let t={id:St(),port:this.localService.port,prefix:this.prefix??"",nextStartingPosition:e};return Buffer.from(JSON.stringify(t)).toString("base64")}getBucketNames(e,t){let s=Object.keys(this.localService.persistence.buckets).sort((n,o)=>n.localeCompare(o));return e?(e.prefix&&(s=s.filter(n=>n.startsWith(e.prefix))),s=s.slice(e.nextStartingPosition),t&&(s=s.filter(n=>n.startsWith(t))),s):t?s.filter(n=>n.startsWith(t)):s}async exec(e,t){let s=this.isValidRequest(e,t);if(!s)return;let{maxBuckets:n,continuationToken:o,prefix:a,bucketRegion:d}=s,c=this.getBucketNames(o,a),u="",l=d;!d&&(this.rawMaxBuckets||this.prefix||this.continuationToken)&&(l=this.localService.region);let m="";l&&(m+=`<BucketRegion>${l}</BucketRegion>`);let h=[];for(let y=0;y<c.length;y++){let k=c[y],se=this.localService.persistence.buckets[k],$=`<Bucket>${m}<CreationDate>${new Date(se.date).toISOString()}</CreationDate><Name>${k}</Name></Bucket>`;if(h.push($),h.length==n){if(c[y+1]){let S=y+1;o&&(S=S+o.nextStartingPosition),u=this.createContinuationToken(S)}break}}let g="";u&&(g=`<ContinuationToken>${u}</ContinuationToken>`);let f="";this.prefix&&(f=`<Prefix>${this.prefix}</Prefix>`),e.writeHead(200,{"x-amz-request-id":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}),e.end(`<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Buckets>${h.join("")}</Buckets>${g}${f}<Owner><ID>${this.localService.ownerId}</ID></Owner></ListAllMyBucketsResult>`)}};import{createReadStream as xt}from"node:fs";import Pe from"node:path";var V=({ifMatch:i,ifNoneMatch:r,ifModifiedSince:e,ifUnmodifiedSince:t},{ETag:s,LastModified:n})=>i&&i!==s?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Match"}:r&&r===s?{statusCode:304,Code:"PreconditionFailed",Condition:"If-None-Match"}:e&&e>=n?{statusCode:304,Code:"PreconditionFailed",Condition:"If-Modified-Since"}:t&&t<n?{statusCode:412,Code:"PreconditionFailed",Condition:"If-Unmodified-Since"}:200,L=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.bucketPath=Pe.join(this.localService.localStoragePath,o),this.versionId=e.searchParams.get("versionId"),this.hasPartNumber=e.searchParams.has("partNumber");let d=e.searchParams.get("partNumber"),c=Number(d);if(this.partNumber=this.hasPartNumber&&!isNaN(c)?c:d,t.range){this.hasRange=!0;let[u]=t.range.split("bytes=").filter(Boolean),[l,m]=u.split("-");!isNaN(Number(l))&&!isNaN(Number(m))&&(this.range=[Number(l),Number(m)])}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())}bucketPath;bucket;key;versionId;partNumber;hasPartNumber;hasRange=!1;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({Key:this.key,RequestId:this.requestId}));return}try{let s={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},n=this.localService.persistence.buckets[this.bucket].objects[this.key],o=n.currentKey,a=V(s,n);if(this.hasRange&&this.hasPartNumber){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>InvalidRequest</Code><Message>Cannot specify both Range header and partNumber query parameter</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(a==200){let d=200,c=n.size,u,l=Pe.join(this.bucketPath,n.currentKey),m={};if(this.hasPartNumber){let g=this.partNumber;if(isNaN(g)||g<1||g>1e4){let f=new v({ArgumentName:"partNumber",ArgumentValue:g,RequestId:this.requestId,Message:"Part number must be an integer between 1 and 10000, inclusive"}).toXml();e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(f);return}if(n.versions[o].multipartUploadId){let f=this.localService.persistence.buckets[this.bucket].multipartUploads[n.versions[o].multipartUploadId];d=206;let y;m.start=0;for(let k of f.parts){if(k.partNumber==g){y=k,m.end=m.start+y.size-1;break}m.start=m.start+k.size}if(!y){let k=new D({RequestId:this.requestId,PartNumberRequested:g,ActualPartCount:f.parts.length}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k);return}e.setHeader("x-amz-mp-parts-count",f.parts.length),c=y?.size,u=`bytes ${m.start}-${m.end}/${n.size}`}else if(this.partNumber==1)d=206,u=`bytes 0-${n.size-1}/${n.size}`;else{let f=new D({RequestId:this.requestId,PartNumberRequested:this.partNumber,ActualPartCount:1}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(f);return}}let h=n.type;if(this.range){d=206,m.start=this.range[0],m.end=this.range[1];let g=1;m.end>n.size&&(m.end=n.size,g--),c=g+m.end-m.start,u=`bytes ${m.start}-${m.end}/${n.size}`,h="application/octet-stream"}e.statusCode=d,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(n.LastModified).toUTCString()),e.setHeader("ETag",n.ETag),e.setHeader("Accept-Ranges","bytes"),u&&e.setHeader("Content-Range",u),e.setHeader("Content-Length",c),h&&e.setHeader("Content-Type",h),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),n.cacheControl&&e.setHeader("Cache-Control",n.cacheControl),n.contentDisposition&&e.setHeader("Content-Disposition",n.contentDisposition),n.contentEncoding&&e.setHeader("Content-Encoding",n.contentEncoding),n.contentLanguage&&e.setHeader("Content-Language",n.contentLanguage),n.expires&&e.setHeader("Expires",new Date(n.expires).toUTCString()),n.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",n.websiteRedirectLocation);for(let[g,f]of Object.entries(n.metadata))e.setHeader(g,f);xt(l,m).pipe(e)}else e.writeHead(a.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${a.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${a.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var _=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/"),this.versionId=e.searchParams.get("versionId")}bucket;key;versionId;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({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 s={Tagging:{TagSet:{Tag:[]}}},n=this.localService.persistence.buckets[this.bucket].objects[this.key].tags;if(n)for(let[a,d]of Object.entries(n))s.Tagging.TagSet.Tag.push({Key:a,Value:d});let o=I.XMLBuilder.build(s);e.end(`<?xml version="1.0" encoding="UTF-8"?>${o}`)}catch(s){if(e.statusCode=400,s instanceof b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var X=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{e.setHeader("x-amzn-requestid",this.requestId);let s=this.localService.persistence.buckets[this.bucket].tags;if(!s)throw new re(this.requestId);e.statusCode=200;let n={Tagging:{TagSet:{Tag:[]}}};for(let[a,d]of Object.entries(s))n.Tagging.TagSet.Tag.push({Key:a,Value:d});let o=I.XMLBuilder.build(n);e.setHeader("Content-Type","application/xml"),e.end(`<?xml version="1.0" encoding="UTF-8"?>${o}`)}catch(s){if(e.statusCode=400,s instanceof b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var ue=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];if(s.policy){e.setHeader("x-amzn-requestid",this.requestId),e.end(JSON.stringify(s.policy));return}e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
48
+ <Error><Code>NoSuchBucketPolicy</Code><BucketName>${this.bucket}</BucketName><Message>The bucket policy does not exist</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var le=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId"),this.hasPartNumberMarker=e.searchParams.has("part-number-marker"),e.searchParams.has("part-number-marker")&&(this.partNumberMarker=e.searchParams.get("part-number-marker")??""),e.searchParams.has("max-parts")&&(this.maxParts=e.searchParams.get("max-parts")??"")}bucket;key;uploadId;partNumberMarker="";hasPartNumberMarker=!1;maxParts="1000";validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId??""];if(!this.uploadId||!s||s.aborted||s.completed){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
49
49
  <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let n=Number(this.partNumberMarker);if(this.hasPartNumberMarker&&(!this.partNumberMarker||isNaN(n)||this.partNumberMarker.includes(".")||n<0||n>2147483647)){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
50
50
  <Error><Code>InvalidArgument</Code><ArgumentName>part-number-marker</ArgumentName><ArgumentValue>${this.partNumberMarker}</ArgumentValue><Message>Argument part-number-marker must be an integer between 0 and 2147483647</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let o=Number(this.maxParts);if(!this.maxParts||isNaN(o)||this.maxParts.includes(".")||o<0||o>2147483647){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
51
51
  <Error><Code>InvalidArgument</Code><ArgumentName>max-parts</ArgumentName><ArgumentValue>${this.maxParts}</ArgumentValue><Message>Argument max-parts must be an integer between 0 and 2147483647</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return{partNumberMarker:this.hasPartNumberMarker?n:0,maxParts:o,uploadId:this.uploadId,multipartUpload:s}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{uploadId:n,partNumberMarker:o,maxParts:a,multipartUpload:d}=s,c=[],u=d.parts.sort((f,y)=>f.partNumber-y.partNumber);isNaN(o)||(u=u.filter(f=>f.partNumber>o));let l=!1;a?(l=u.length>a,u=u.slice(0,a)):u=[];let m;for(let f of u)c.push(`<Part>
@@ -53,13 +53,13 @@ import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypt
53
53
  <LastModified>${f.lastModified}</LastModified>
54
54
  <ETag>"${f.eTag}"</ETag>
55
55
  <Size>${f.size}</Size>
56
- </Part>`),m=f;let g=0;m&&(g=m.partNumber);let h=`<?xml version="1.0" encoding="UTF-8"?>
56
+ </Part>`),m=f;let h=0;m&&(h=m.partNumber);let g=`<?xml version="1.0" encoding="UTF-8"?>
57
57
  <ListPartsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
58
58
  <Bucket>${this.bucket}</Bucket>
59
59
  <Key>${this.key}</Key>
60
60
  <UploadId>${n}</UploadId>
61
61
  <PartNumberMarker>${o}</PartNumberMarker>
62
- <NextPartNumberMarker>${g}</NextPartNumberMarker>
62
+ <NextPartNumberMarker>${h}</NextPartNumberMarker>
63
63
  <MaxParts>${a}</MaxParts>
64
64
  <IsTruncated>${l}</IsTruncated>
65
65
  ${c.join("")}
@@ -70,28 +70,28 @@ import{S3 as ns}from"@aws-sdk/client-s3";import{randomUUID as Ce}from"node:crypt
70
70
  <ID>${this.localService.ownerId}</ID>
71
71
  </Owner>
72
72
  <StorageClass>${d.data.StorageClass}</StorageClass>
73
- </ListPartsResult>`;e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(h)}};var ue=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o,this.delimiter=e.searchParams.get("delimiter"),this.hasEncodingType=e.searchParams.has("encoding-type"),this.encodingType=e.searchParams.get("encoding-type"),this.prefix=e.searchParams.get("prefix"),this.keyMarker=e.searchParams.get("key-marker"),this.uploadIdMarker=e.searchParams.get("upload-id-marker"),this.hasMaxUploads=e.searchParams.has("max-uploads"),this.hasMaxUploads&&(this.maxUploads=e.searchParams.get("max-uploads"))}bucket;delimiter;encodingType;hasEncodingType;maxUploads="1000";hasMaxUploads;prefix;keyMarker;uploadIdMarker;validateRequest(e,t){if(this.hasMaxUploads){let s=Number(this.maxUploads);if(isNaN(s)||this.maxUploads.includes(".")){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
73
+ </ListPartsResult>`;e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(g)}};var me=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o,this.delimiter=e.searchParams.get("delimiter"),this.hasEncodingType=e.searchParams.has("encoding-type"),this.encodingType=e.searchParams.get("encoding-type"),this.prefix=e.searchParams.get("prefix"),this.keyMarker=e.searchParams.get("key-marker"),this.uploadIdMarker=e.searchParams.get("upload-id-marker"),this.hasMaxUploads=e.searchParams.has("max-uploads"),this.hasMaxUploads&&(this.maxUploads=e.searchParams.get("max-uploads"))}bucket;delimiter;encodingType;hasEncodingType;maxUploads="1000";hasMaxUploads;prefix;keyMarker;uploadIdMarker;validateRequest(e,t){if(this.hasMaxUploads){let s=Number(this.maxUploads);if(isNaN(s)||this.maxUploads.includes(".")){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
74
74
  <Error><Code>InvalidArgument</Code><ArgumentName>max-uploads</ArgumentName><ArgumentValue>${this.maxUploads}</ArgumentValue><Message>Provided max-uploads not an integer or within integer range</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(s<0||s>2147483647){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
75
75
  <Error><Code>InvalidArgument</Code><ArgumentName>max-uploads</ArgumentName><ArgumentValue>${this.maxUploads}</ArgumentValue><Message>Argument max-uploads must be an integer between 0 and 2147483647</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}}if(this.hasEncodingType&&this.encodingType.toLowerCase()!="url"){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
76
- <Error><Code>InvalidArgument</Code><ArgumentName>encoding-type</ArgumentName><ArgumentValue>${this.encodingType}</ArgumentValue><Message>Invalid Encoding Method specified in Request</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return!0}collectUploads(e){return e.sort((n,o)=>n.key.localeCompare(o.key)),this.keyMarker?this.uploadIdMarker?e.find(n=>n.key==this.keyMarker&&n.uploadId==this.uploadIdMarker)?e.filter(n=>n.key.localeCompare(this.keyMarker)>=0).filter(n=>n.key==this.keyMarker?n.uploadId.localeCompare(this.uploadIdMarker)>0:!0):new C({ArgumentName:"upload-id-marker",ArgumentValue:this.uploadIdMarker,Message:"Invalid uploadId marker",RequestId:this.requestId}):e.filter(n=>n.key.localeCompare(this.keyMarker)>0):e}getUploads(){let e=[],t=!1,s,n="",o="",a=this.localService.persistence.buckets[this.bucket].multipartUploads;if(a){e=Object.values(a).filter(u=>!u.aborted&&!u.completed),this.prefix&&(e=e.filter(u=>u.key.startsWith(this.prefix)));let d=this.collectUploads(e);if(d instanceof C)return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o,error:d};let c=d.length;e=d.slice(0,Number(this.maxUploads)),t=c-e.length>0,this.delimiter&&(s=B(this.prefix??"",this.delimiter,e.map(u=>u.key)),e=e.filter(u=>!s.some(l=>u.key.startsWith(l))))}if(e.length){let d=e[e.length-1];n=d.key,o=d.uploadId}return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o}}async exec(e,t){if(this.hasNot(this.bucket,e,t)||!this.validateRequest(e,t))return;let{uploads:n,isTruncated:o,commonPrefixes:a,nextKeyMarker:d,nextUploadIdMarker:c,error:u}=this.getUploads();if(u){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(u.toXml());return}let l=`<?xml version="1.0" encoding="UTF-8"?>
77
- <ListMultipartUploadsResult><Bucket>${this.bucket}</Bucket><IsTruncated>${o}</IsTruncated><KeyMarker>${this.keyMarker??""}</KeyMarker><MaxUploads>${this.maxUploads??"1000"}</MaxUploads>`;if(l+=`<UploadIdMarker>${this.uploadIdMarker??""}</UploadIdMarker><NextUploadIdMarker>${c}</NextUploadIdMarker><NextKeyMarker>${d}</NextKeyMarker>`,this.prefix&&(l+=`<Prefix>${this.prefix}</Prefix>`),this.delimiter&&(l+=`<Delimiter>${this.delimiter}</Delimiter>`),a)for(let h of a)l+=`<CommonPrefixes><Prefix>${h}</Prefix></CommonPrefixes>`;this.encodingType&&(l+=`<EncodingType>${this.encodingType}</EncodingType>`);let m=`<Owner><ID>${this.localService.ownerId}</ID></Owner>`,g=`<Initiator><ID>${this.localService.ownerId}</ID></Initiator>`;for(let h of n)l+=`<Upload><Initiated>${h.initDate}</Initiated>${g}<Key>${h.key}</Key>${m}<StorageClass>${h.data.StorageClass}</StorageClass><UploadId>${h.uploadId}</UploadId></Upload>`;l+="</ListMultipartUploadsResult>",e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(l)}};var le=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(s.acl.accessControlPolicy)}};var me=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(s.acl.accessControlPolicy)}};var Ae=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=t["user-agent"],o=s.pathname.split("/").filter(Boolean).length==1;if(n?.startsWith("aws-cli")){let[,a]=n.split("command/"),[,...d]=a.split(".");switch(d.join(".")){case"ls":return/@s3\/?$/.test(e)?new E(s,t,r):s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r);case"list-buckets":return new E(s,t,r);case"list-objects":return new M(s,t,r);case"list-objects-v2":return new w(s,t,r);case"rb.rm":return s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r);case"get-object":return new L(s,t,r);case"cp":case"mv":case"sync":return o?s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r):new L(s,t,r);case"get-bucket-tagging":return new _(s,t,r);case"get-object-tagging":return new F(s,t,r);default:break}}else return s.searchParams.has("acl")?o?new le(s,t,r):new me(s,t,r):s.searchParams.has("uploads")?o?new ue(s,t,r):new S(s,t,r):s.searchParams.has("policy")?new ce(s,t,r):s.searchParams.has("tagging")?o?new _(s,t,r):new F(s,t,r):s.searchParams.has("uploadId")?o?new S(s,t,r):new de(s,t,r):s.pathname=="/"?new E(s,t,r):o?s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r):new L(s,t,r);return new S(s,t,r)};var pe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=200,e.setHeader("x-amz-request-id",this.requestId),e.end())}};import qe from"node:path";var ge=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);if(this.bucket=o,this.key=a.join("/"),this.bucketPath=qe.join(this.localService.localStoragePath,o),this.filePath=qe.join(this.bucketPath,...a),this.versionId=e.searchParams.get("versionId"),this.partNumber=e.searchParams.has("partNumber")?Number(e.searchParams.get("partNumber")):null,t.range){let[d]=t.range.split("bytes=").filter(Boolean),[c,u]=d.split("-");!isNaN(Number(c))&&!isNaN(Number(u))&&(this.range=[Number(c),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())}filePath;bucketPath;bucket;key;versionId;partNumber;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({Key:this.key,RequestId:this.requestId}));return}try{let s={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},n=this.localService.persistence.buckets[this.bucket].objects[this.key],o=V(s,n);if(o==200){let a=200,d=n.size,c,u=n.type,l={};if(this.range){a=206,l.start=this.range[0],l.end=this.range[1];let m=1;l.end>n.size&&(l.end=n.size,m--),d=m+l.end-l.start,c=`bytes ${l.start}-${l.end}/${n.size}`,u="application/octet-stream"}e.statusCode=a,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(n.LastModified).toUTCString()),e.setHeader("ETag",n.ETag),e.setHeader("Accept-Ranges","bytes"),c&&e.setHeader("Content-Range",c),e.setHeader("Content-Length",d),u&&e.setHeader("Content-Type",u),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),n.cacheControl&&e.setHeader("Cache-Control",n.cacheControl),n.contentDisposition&&e.setHeader("Content-Disposition",n.contentDisposition),n.contentEncoding&&e.setHeader("Content-Encoding",n.contentEncoding),n.contentLanguage&&e.setHeader("Content-Language",n.contentLanguage),n.expires&&e.setHeader("Expires",new Date(n.expires).toUTCString()),n.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",n.websiteRedirectLocation);for(let[m,g]of Object.entries(n.metadata))e.setHeader(m,g);e.end()}else e.writeHead(o.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${o.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${o.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var Ee=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000");return s.pathname.split("/").filter(Boolean).length>1?new ge(s,t,r):new pe(s,t,r)};var X=class i{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=r=>r.toLowerCase().split("-").map(Le).join("-");static getMultiValueHeaders=r=>{let e={},t=r.filter((n,o)=>o%2==0).map(n=>n.toLowerCase()),s=r.filter((n,o)=>o%2!==0);return t.forEach((n,o)=>{n!="x-mock-type"&&(e[n]?e[n].push(s[o]):e[n]=[s[o]])}),e};static getIsBase64Encoded=r=>{let e=r["content-type"];return r["content-encoding"]||!e?!0:!(e.startsWith("application/json")||e.startsWith("application/xml")||e.startsWith("application/javascript")||e.startsWith("text/"))};static knownHeaders=["accept","accept-encoding","user-agent","host","via","content-length"];static getApiGV1Headers(r,e){let{rawHeaders:t}=r,s,n={"X-Forwarded-For":r.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(i.port)};for(let c=0;c<t.length;){let u=t[c],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){c=c+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let m=t[c+1];n[u]=m,l=="x-api-key"&&(s=m),c=c+2}let o={};for(let c of Object.keys(n).sort((u,l)=>u.localeCompare(l)))o[c]=n[c];let a={"X-Forwarded-For":[r.socket.remoteAddress],"X-Forwarded-Proto":["http"],"X-Forwarded-Port":[String(i.port)]};for(let c=0;c<t.length;){let u=t[c],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){c=c+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let m=t[c+1];a[u]?a[u].push(m):a[u]=[m],c=c+2}let d={};for(let c of Object.keys(a).sort((u,l)=>u.localeCompare(l)))d[c]=a[c];return{headers:o,multiValueHeaders:d,apiKey:s}}static getCustomHeaders(r,e){let{headers:t}=r;return delete t["x-mock-type"],delete t.connection,{"X-Forwarded-For":r.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(i.port),...t}}static getPathParameters(r,e){let t=r.paths[0].split("/"),s=e.pathname.split("/"),n={};return t.forEach((o,a)=>{o.startsWith("{")&&o.endsWith("}")&&!o.endsWith("+}")&&(n[o.slice(1,-1)]=s[a])}),n}static normalizeSearchParams=(r,e)=>{let t={};Array.from(r.keys()).forEach(o=>{let a=r.getAll(o).map(c=>c.toLowerCase()),d=o.toLowerCase();a?t[d]?t[d].push(...a):t[d]=a:t[d]||(t[d]=void 0)});let s="",n=e.indexOf("?");return n!=-1&&(s=e.slice(n+1)),t.toString=()=>s,t};static getMultiValueQueryStringParameters=r=>{let e={};r.delete("x_mock_type");for(let t of Array.from(new Set(r.keys())))e[t]=r.getAll(t).map(encodeURI);return e};static isEndpointTimeoutError=r=>{if(!r)return;let e=r.match(this.timeoutRegex)?.[0];if(e){let t=e.split(" ")[1];if(!isNaN(t))return Number(t)>=i.apgRequestTimeout}}};var he=!1,kt=i=>{he=i},Ct=()=>he,U=(i,r)=>{he&&console.log(`\x1B[${i}m${r}\x1B[0m`)},vt=i=>console.log(`\x1B[31m${i}\x1B[0m`),Ht=i=>U("32",i),Rt=i=>U("33",i),Mt=i=>U("36",i),wt=i=>U("90",i),Tt=i=>U("94",i),Pt=i=>U("95",i),Nt=i=>he?console.log(i):void 0,Ue={GREEN:Ht,YELLOW:Rt,CYAN:Mt,BR_BLUE:Tt,RED:vt,GREY:wt,PINK:Pt,setDebug:kt,getDebug:Ct,info:Nt};var ze="application/vnd.awslambda.http-integration-response",Me=class i{buffer;_isHttpIntegrationResponse;_metaDelimiter;_endDelimiter;_ct;_isStreamResponse=!0;#e;static codec=new TextDecoder;static splitMessage=(r,e)=>{if(!r)return;let t=Array.from(r.values()),s=null;if(e)s=e;else for(let n=0;n<t.length;n++)if(t[n]===0&&[t[n+1],t[n+2],t[n+3],t[n+4],t[n+5],t[n+6],t[n+7]].every(d=>d===0)){s=n;break}if(s)return new Uint8Array(t.slice(0,s))};constructor(r){this._isHttpIntegrationResponse=!1,this._metaDelimiter=0,this._endDelimiter=0,this.#e=r}setHeader(r,e){this._isHttpIntegrationResponse=!this.buffer&&e==ze&&(!this._ct||this._ct==ze),this._ct=e}write(r,e){!this._isHttpIntegrationResponse&&!this._metaDelimiter&&(this._metaDelimiter=r.byteLength),this.#s(r)}end(r){this.buffer&&(this._endDelimiter=this.buffer.byteLength),r&&this.#s(r)}destroy(){}#s(r){this.buffer=typeof this.buffer>"u"?r:Buffer.concat([this.buffer,r])}getParsedResponse(){if(!this.#e)return;let r=this.#e.kind;if(r=="alb")return this.#r();if(r=="url")return this.#o();if(r=="apg")return this.#n()}#r(){let r=this._isHttpIntegrationResponse?i.splitMessage(this.buffer):this.buffer,e;return r&&(e=this.#t(r)),e}#n(){if(this._isHttpIntegrationResponse)return Ue.RED("awslambda.HttpResponseStream.from() is not supported with API Gateway"),{statusCode:500,headers:{"Content-Type":X.contentType.json},body:X.httpErrMsg};if(this.buffer)return this.#t(this.buffer)}#o(){let r=i.splitMessage(this.buffer,this._isHttpIntegrationResponse?void 0:this._metaDelimiter),e;return r&&(e=this.#t(r)),e}#t(r){let e=i.codec.decode(r);if(typeof e=="string")try{e=JSON.parse(e)}catch{}return e}};var $e="<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 gn=JSON.stringify({Message:null});var Be=async(i,r)=>{let e=Buffer.alloc(0);return i.on("data",s=>{e=Buffer.concat([e,s])}),await new Promise(s=>{i.on("end",async()=>{s(e?e.toString(r?"base64":"utf-8"):void 0)})})};var hn=JSON.stringify({Type:null,message:"Client context must be a valid Base64-encoded JSON object."});var fn=new Error($e);var Le=i=>i.charAt(0).toUpperCase()+i.slice(1);var At=i=>{let r=[],e;try{i.split("<Object>").forEach(t=>{let s=t.indexOf("<Key>");if(s==-1)return;let n=t.indexOf("</Key>"),a={Key:t.slice(s+5,n)},d=t.indexOf("<VersionId>");if(d>-1){let c=t.indexOf("</VersionId>"),u=t.slice(d+11,c);a.VersionId=u}r.push(a)})}catch(t){console.error(t)}return{Objects:r,Quiet:e}},fe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=await Be(t),{Objects:n,Quiet:o}=At(s);if(!n.length){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>MalformedXML</Code><Message>The XML you provided was not well-formed or did not validate against our published schema</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let a=n.map(c=>`<Deleted><Key>${c.Key}</Key></Deleted>`).join(""),d=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";e.statusCode=200,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e);for(let c of n)await this.localService.removeObject(this.bucket,c.Key,d,this.requestId);e.end(`<?xml version="1.0" encoding="UTF-8"?><DeleteResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">${a}</DeleteResult>`)}};import{getRandomValues as $t}from"crypto";import{createWriteStream as qt,mkdirSync as Et,readFileSync as Lt,statSync as Ut}from"node:fs";import je from"node:path";var Ie=i=>`"${R(i)}"`;var T=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.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 a=t["x-amz-storage-class"];a&&(this.storageClass=a);let d=new Date(t.expires);isNaN(d)||(this.expires=d.getTime())}bucket;key;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";tagging;validateRequest(e,t){if(this.hasNot(this.bucket,e,t)||!this.isValidStorageClass(this.storageClass,e,t))return;let s={};if(this.tagging){let o=()=>{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new C({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"){o();return}if(!zt(this.tagging)){o();return}let a=new URLSearchParams(this.tagging);for(let d of a.keys()){if(d in s){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"Cannot provide multiple Tags with the same key"}).toXml());return}if(d.length>128||d.length<1){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"The TagKey you have provided is invalid"}).toXml());return}let c=a.get(d);if(c.length>256){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"The TagValue you have provided is invalid"}).toXml());return}s[d]=c}}let n=Object.keys(s).length;if(n>10){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new N({Message:`Object tag count cannot be greater than ${10}`,RequestId:this.requestId}).toXml());return}return{tagsLen:n,Tags:s}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{Tags:n,tagsLen:o}=s,a=b.genLocalKey(this.bucket,this.key),d=je.join(this.localService.localStoragePath,this.bucket,a);try{Et(je.dirname(d),{recursive:!0})}catch{}let c=qt(d,{flush:!0});c.on("finish",async()=>{try{let u=Ut(d),l=Ie(Lt(d));this.localService.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,websiteRedirectLocation:this.websiteRedirectLocation,ETag:l,size:u.size,LastModified:u.mtimeMs,StorageClass:this.storageClass,metadata:this.metadata,versions:{[a]:{}},tags:o?n:void 0};let m=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";e.end(),await q(this.localService.callableLambdas,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"PutObject",eTag:l,sourceIPAddress:m,size:u.size})}catch(u){console.log(u),e.statusCode=500,e.end()}}),e.setHeader("status",100),e.setHeader("Server","AmazonS3"),e.setHeader("x-amzn-requestid",this.requestId),this.localService.setCorsHeaders(t,e),t.pipe(c)}},zt=i=>!i.split("&").find(r=>r.split("=").length>2);var Bt="abcdefghijklmnopqrstuvwxyz0123456789_.",De=`ABCDEFGHIJKLMNOPQRSTUVWXYZ${Bt}`,be=class extends p{constructor(e,t,s){super(t,s);this.url=e;this.headers=t;this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.version=e.searchParams.get("versionId")}bucket;key;version;generateUploadId(){let e="",t=new Uint8Array(128);$t(t);for(let s=0;s<128;s++)e+=De[t[s]%De.length];return e}async exec(e,t){let s=new T(this.url,this.headers,this.localService),n=s.validateRequest(e,t);if(!n)return;let{Tags:o,tagsLen:a}=n,d=b.genLocalKey(this.bucket,this.key),c=this.generateUploadId();this.localService.persistence.buckets[this.bucket].multipartUploads[c]={uploadId:c,aborted:!1,completed:!1,key:this.key,initDate:new Date().toISOString(),data:{currentKey:d,type:s.contentType,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,websiteRedirectLocation:s.websiteRedirectLocation,metadata:s.metadata,StorageClass:s.storageClass,versions:{[d]:{multipartUploadId:c}},tags:a?o:void 0},parts:[]},e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}),e.end(`<?xml version="1.0" encoding="UTF-8"?>
76
+ <Error><Code>InvalidArgument</Code><ArgumentName>encoding-type</ArgumentName><ArgumentValue>${this.encodingType}</ArgumentValue><Message>Invalid Encoding Method specified in Request</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return!0}collectUploads(e){return e.sort((n,o)=>n.key.localeCompare(o.key)),this.keyMarker?this.uploadIdMarker?e.find(n=>n.key==this.keyMarker&&n.uploadId==this.uploadIdMarker)?e.filter(n=>n.key.localeCompare(this.keyMarker)>=0).filter(n=>n.key==this.keyMarker?n.uploadId.localeCompare(this.uploadIdMarker)>0:!0):new v({ArgumentName:"upload-id-marker",ArgumentValue:this.uploadIdMarker,Message:"Invalid uploadId marker",RequestId:this.requestId}):e.filter(n=>n.key.localeCompare(this.keyMarker)>0):e}getUploads(){let e=[],t=!1,s,n="",o="",a=this.localService.persistence.buckets[this.bucket].multipartUploads;if(a){e=Object.values(a).filter(u=>!u.aborted&&!u.completed),this.prefix&&(e=e.filter(u=>u.key.startsWith(this.prefix)));let d=this.collectUploads(e);if(d instanceof v)return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o,error:d};let c=d.length;e=d.slice(0,Number(this.maxUploads)),t=c-e.length>0,this.delimiter&&(s=j(this.prefix??"",this.delimiter,e.map(u=>u.key)),e=e.filter(u=>!s.some(l=>u.key.startsWith(l))))}if(e.length){let d=e[e.length-1];n=d.key,o=d.uploadId}return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o}}async exec(e,t){if(this.hasNot(this.bucket,e,t)||!this.validateRequest(e,t))return;let{uploads:n,isTruncated:o,commonPrefixes:a,nextKeyMarker:d,nextUploadIdMarker:c,error:u}=this.getUploads();if(u){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(u.toXml());return}let l=`<?xml version="1.0" encoding="UTF-8"?>
77
+ <ListMultipartUploadsResult><Bucket>${this.bucket}</Bucket><IsTruncated>${o}</IsTruncated><KeyMarker>${this.keyMarker??""}</KeyMarker><MaxUploads>${this.maxUploads??"1000"}</MaxUploads>`;if(l+=`<UploadIdMarker>${this.uploadIdMarker??""}</UploadIdMarker><NextUploadIdMarker>${c}</NextUploadIdMarker><NextKeyMarker>${d}</NextKeyMarker>`,this.prefix&&(l+=`<Prefix>${this.prefix}</Prefix>`),this.delimiter&&(l+=`<Delimiter>${this.delimiter}</Delimiter>`),a)for(let g of a)l+=`<CommonPrefixes><Prefix>${g}</Prefix></CommonPrefixes>`;this.encodingType&&(l+=`<EncodingType>${this.encodingType}</EncodingType>`);let m=`<Owner><ID>${this.localService.ownerId}</ID></Owner>`,h=`<Initiator><ID>${this.localService.ownerId}</ID></Initiator>`;for(let g of n)l+=`<Upload><Initiated>${g.initDate}</Initiated>${h}<Key>${g.key}</Key>${m}<StorageClass>${g.data.StorageClass}</StorageClass><UploadId>${g.uploadId}</UploadId></Upload>`;l+="</ListMultipartUploadsResult>",e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(l)}};var pe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(s.acl.accessControlPolicy)}};var ge=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(s.acl.accessControlPolicy)}};var Ae=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=t["user-agent"],o=s.pathname.split("/").filter(Boolean).length==1;if(n?.startsWith("aws-cli")){let[,a]=n.split("command/"),[,...d]=a.split(".");switch(d.join(".")){case"ls":return/@s3\/?$/.test(e)?new E(s,t,r):s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r);case"list-buckets":return new E(s,t,r);case"list-objects":return new M(s,t,r);case"list-objects-v2":return new w(s,t,r);case"rb.rm":return s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r);case"get-object":return new L(s,t,r);case"cp":case"mv":case"sync":return o?s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r):new L(s,t,r);case"get-bucket-tagging":return new X(s,t,r);case"get-object-tagging":return new _(s,t,r);default:break}}else return s.searchParams.has("acl")?o?new pe(s,t,r):new ge(s,t,r):s.searchParams.has("uploads")?o?new me(s,t,r):new x(s,t,r):s.searchParams.has("policy")?new ue(s,t,r):s.searchParams.has("tagging")?o?new X(s,t,r):new _(s,t,r):s.searchParams.has("uploadId")?o?new x(s,t,r):new le(s,t,r):s.pathname=="/"?new E(s,t,r):o?s.searchParams.get("list-type")=="2"?new w(s,t,r):new M(s,t,r):new L(s,t,r);return new x(s,t,r)};var he=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=200,e.setHeader("x-amz-request-id",this.requestId),e.end())}};import qe from"node:path";var fe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);if(this.bucket=o,this.key=a.join("/"),this.bucketPath=qe.join(this.localService.localStoragePath,o),this.filePath=qe.join(this.bucketPath,...a),this.versionId=e.searchParams.get("versionId"),this.partNumber=e.searchParams.has("partNumber")?Number(e.searchParams.get("partNumber")):null,t.range){let[d]=t.range.split("bytes=").filter(Boolean),[c,u]=d.split("-");!isNaN(Number(c))&&!isNaN(Number(u))&&(this.range=[Number(c),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())}filePath;bucketPath;bucket;key;versionId;partNumber;range;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({Key:this.key,RequestId:this.requestId}));return}try{let s={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},n=this.localService.persistence.buckets[this.bucket].objects[this.key],o=V(s,n);if(o==200){let a=200,d=n.size,c,u=n.type,l={};if(this.range){a=206,l.start=this.range[0],l.end=this.range[1];let m=1;l.end>n.size&&(l.end=n.size,m--),d=m+l.end-l.start,c=`bytes ${l.start}-${l.end}/${n.size}`,u="application/octet-stream"}e.statusCode=a,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(n.LastModified).toUTCString()),e.setHeader("ETag",n.ETag),e.setHeader("Accept-Ranges","bytes"),c&&e.setHeader("Content-Range",c),e.setHeader("Content-Length",d),u&&e.setHeader("Content-Type",u),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),n.cacheControl&&e.setHeader("Cache-Control",n.cacheControl),n.contentDisposition&&e.setHeader("Content-Disposition",n.contentDisposition),n.contentEncoding&&e.setHeader("Content-Encoding",n.contentEncoding),n.contentLanguage&&e.setHeader("Content-Language",n.contentLanguage),n.expires&&e.setHeader("Expires",new Date(n.expires).toUTCString()),n.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",n.websiteRedirectLocation);for(let[m,h]of Object.entries(n.metadata))e.setHeader(m,h);e.end()}else e.writeHead(o.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${o.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${o.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var Ee=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000");return s.pathname.split("/").filter(Boolean).length>1?new fe(s,t,r):new he(s,t,r)};var G=class i{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=r=>r.toLowerCase().split("-").map(Le).join("-");static getMultiValueHeaders=r=>{let e={},t=r.filter((n,o)=>o%2==0).map(n=>n.toLowerCase()),s=r.filter((n,o)=>o%2!==0);return t.forEach((n,o)=>{n!="x-mock-type"&&(e[n]?e[n].push(s[o]):e[n]=[s[o]])}),e};static getIsBase64Encoded=r=>{let e=r["content-type"];return r["content-encoding"]||!e?!0:!(e.startsWith("application/json")||e.startsWith("application/xml")||e.startsWith("application/javascript")||e.startsWith("text/"))};static knownHeaders=["accept","accept-encoding","user-agent","host","via","content-length"];static getApiGV1Headers(r,e){let{rawHeaders:t}=r,s,n={"X-Forwarded-For":r.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(i.port)};for(let c=0;c<t.length;){let u=t[c],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){c=c+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let m=t[c+1];n[u]=m,l=="x-api-key"&&(s=m),c=c+2}let o={};for(let c of Object.keys(n).sort((u,l)=>u.localeCompare(l)))o[c]=n[c];let a={"X-Forwarded-For":[r.socket.remoteAddress],"X-Forwarded-Proto":["http"],"X-Forwarded-Port":[String(i.port)]};for(let c=0;c<t.length;){let u=t[c],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){c=c+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let m=t[c+1];a[u]?a[u].push(m):a[u]=[m],c=c+2}let d={};for(let c of Object.keys(a).sort((u,l)=>u.localeCompare(l)))d[c]=a[c];return{headers:o,multiValueHeaders:d,apiKey:s}}static getCustomHeaders(r,e){let{headers:t}=r;return delete t["x-mock-type"],delete t.connection,{"X-Forwarded-For":r.socket.remoteAddress,"X-Forwarded-Proto":"http","X-Forwarded-Port":String(i.port),...t}}static getPathParameters(r,e){let t=r.paths[0].split("/"),s=e.pathname.split("/"),n={};return t.forEach((o,a)=>{o.startsWith("{")&&o.endsWith("}")&&!o.endsWith("+}")&&(n[o.slice(1,-1)]=s[a])}),n}static normalizeSearchParams=(r,e)=>{let t={};Array.from(r.keys()).forEach(o=>{let a=r.getAll(o).map(c=>c.toLowerCase()),d=o.toLowerCase();a?t[d]?t[d].push(...a):t[d]=a:t[d]||(t[d]=void 0)});let s="",n=e.indexOf("?");return n!=-1&&(s=e.slice(n+1)),t.toString=()=>s,t};static getMultiValueQueryStringParameters=r=>{let e={};r.delete("x_mock_type");for(let t of Array.from(new Set(r.keys())))e[t]=r.getAll(t).map(encodeURI);return e};static isEndpointTimeoutError=r=>{if(!r)return;let e=r.match(this.timeoutRegex)?.[0];if(e){let t=e.split(" ")[1];if(!isNaN(t))return Number(t)>=i.apgRequestTimeout}}};var be=!1,kt=i=>{be=i},Ct=()=>be,U=(i,r)=>{be&&console.log(`\x1B[${i}m${r}\x1B[0m`)},vt=i=>console.log(`\x1B[31m${i}\x1B[0m`),Ht=i=>U("32",i),Rt=i=>U("33",i),Mt=i=>U("36",i),wt=i=>U("90",i),Tt=i=>U("94",i),Nt=i=>U("95",i),Pt=i=>be?console.log(i):void 0,Ue={GREEN:Ht,YELLOW:Rt,CYAN:Mt,BR_BLUE:Tt,RED:vt,GREY:wt,PINK:Nt,setDebug:kt,getDebug:Ct,info:Pt};var ze="application/vnd.awslambda.http-integration-response",Me=class i{buffer;_isHttpIntegrationResponse;_metaDelimiter;_endDelimiter;_ct;_isStreamResponse=!0;#e;static codec=new TextDecoder;static splitMessage=(r,e)=>{if(!r)return;let t=Array.from(r.values()),s=null;if(e)s=e;else for(let n=0;n<t.length;n++)if(t[n]===0&&[t[n+1],t[n+2],t[n+3],t[n+4],t[n+5],t[n+6],t[n+7]].every(d=>d===0)){s=n;break}if(s)return new Uint8Array(t.slice(0,s))};constructor(r){this._isHttpIntegrationResponse=!1,this._metaDelimiter=0,this._endDelimiter=0,this.#e=r}setHeader(r,e){this._isHttpIntegrationResponse=!this.buffer&&e==ze&&(!this._ct||this._ct==ze),this._ct=e}write(r,e){!this._isHttpIntegrationResponse&&!this._metaDelimiter&&(this._metaDelimiter=r.byteLength),this.#s(r)}end(r){this.buffer&&(this._endDelimiter=this.buffer.byteLength),r&&this.#s(r)}destroy(){}#s(r){this.buffer=typeof this.buffer>"u"?r:Buffer.concat([this.buffer,r])}getParsedResponse(){if(!this.#e)return;let r=this.#e.kind;if(r=="alb")return this.#r();if(r=="url")return this.#o();if(r=="apg")return this.#n()}#r(){let r=this._isHttpIntegrationResponse?i.splitMessage(this.buffer):this.buffer,e;return r&&(e=this.#t(r)),e}#n(){if(this._isHttpIntegrationResponse)return Ue.RED("awslambda.HttpResponseStream.from() is not supported with API Gateway"),{statusCode:500,headers:{"Content-Type":G.contentType.json},body:G.httpErrMsg};if(this.buffer)return this.#t(this.buffer)}#o(){let r=i.splitMessage(this.buffer,this._isHttpIntegrationResponse?void 0:this._metaDelimiter),e;return r&&(e=this.#t(r)),e}#t(r){let e=i.codec.decode(r);if(typeof e=="string")try{e=JSON.parse(e)}catch{}return e}};var $e="<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 gn=JSON.stringify({Message:null});var Be=async(i,r)=>{let e=Buffer.alloc(0);return i.on("data",s=>{e=Buffer.concat([e,s])}),await new Promise(s=>{i.on("end",async()=>{s(e?e.toString(r?"base64":"utf-8"):void 0)})})};var hn=JSON.stringify({Type:null,message:"Client context must be a valid Base64-encoded JSON object."});var fn=new Error($e);var Le=i=>i.charAt(0).toUpperCase()+i.slice(1);var At=i=>{let r=[],e;try{i.split("<Object>").forEach(t=>{let s=t.indexOf("<Key>");if(s==-1)return;let n=t.indexOf("</Key>"),a={Key:t.slice(s+5,n)},d=t.indexOf("<VersionId>");if(d>-1){let c=t.indexOf("</VersionId>"),u=t.slice(d+11,c);a.VersionId=u}r.push(a)})}catch(t){console.error(t)}return{Objects:r,Quiet:e}},Ie=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o]=n.split("/").filter(Boolean);this.bucket=o}bucket;async exec(e,t){if(this.hasNot(this.bucket,e,t))return;let s=await Be(t),{Objects:n,Quiet:o}=At(s);if(!n.length){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<Error><Code>MalformedXML</Code><Message>The XML you provided was not well-formed or did not validate against our published schema</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let a=n.map(c=>`<Deleted><Key>${c.Key}</Key></Deleted>`).join(""),d=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";e.statusCode=200,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e);for(let c of n)await this.localService.removeObject(this.bucket,c.Key,d,this.requestId);e.end(`<?xml version="1.0" encoding="UTF-8"?><DeleteResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">${a}</DeleteResult>`)}};import{getRandomValues as $t}from"crypto";import{createWriteStream as qt,mkdirSync as Et,readFileSync as Lt,statSync as Ut}from"node:fs";import je from"node:path";var ye=i=>`"${R(i)}"`;var T=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.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 a=t["x-amz-storage-class"];a&&(this.storageClass=a);let d=new Date(t.expires);isNaN(d)||(this.expires=d.getTime())}bucket;key;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";tagging;validateRequest(e,t){if(this.hasNot(this.bucket,e,t)||!this.isValidStorageClass(this.storageClass,e,t))return;let s={};if(this.tagging){let o=()=>{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new v({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"){o();return}if(!zt(this.tagging)){o();return}let a=new URLSearchParams(this.tagging);for(let d of a.keys()){if(d in s){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"Cannot provide multiple Tags with the same key"}).toXml());return}if(d.length>128||d.length<1){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"The TagKey you have provided is invalid"}).toXml());return}let c=a.get(d);if(c.length>256){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new H({TagKey:d,RequestId:this.requestId,Message:"The TagValue you have provided is invalid"}).toXml());return}s[d]=c}}let n=Object.keys(s).length;if(n>10){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new P({Message:`Object tag count cannot be greater than ${10}`,RequestId:this.requestId}).toXml());return}return{tagsLen:n,Tags:s}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{Tags:n,tagsLen:o}=s,a=I.genLocalKey(this.bucket,this.key),d=je.join(this.localService.localStoragePath,this.bucket,a);try{Et(je.dirname(d),{recursive:!0})}catch{}let c=qt(d,{flush:!0});c.on("finish",async()=>{try{let u=Ut(d),l=ye(Lt(d));this.localService.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,websiteRedirectLocation:this.websiteRedirectLocation,ETag:l,size:u.size,LastModified:u.mtimeMs,StorageClass:this.storageClass,metadata:this.metadata,versions:{[a]:{}},tags:o?n:void 0},e.end();let m=this.localService.persistence.buckets[this.bucket].notification;if(m){let h=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";setTimeout(async()=>{await q(this.localService,m,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"PutObject",eTag:l,sourceIPAddress:h,size:u.size})},30)}}catch(u){console.log(u),e.statusCode=500,e.end()}}),e.setHeader("status",100),e.setHeader("Server","AmazonS3"),e.setHeader("x-amzn-requestid",this.requestId),this.localService.setCorsHeaders(t,e),t.pipe(c)}},zt=i=>!i.split("&").find(r=>r.split("=").length>2);var Bt="abcdefghijklmnopqrstuvwxyz0123456789_.",De=`ABCDEFGHIJKLMNOPQRSTUVWXYZ${Bt}`,Se=class extends p{constructor(e,t,s){super(t,s);this.url=e;this.headers=t;this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.version=e.searchParams.get("versionId")}bucket;key;version;generateUploadId(){let e="",t=new Uint8Array(128);$t(t);for(let s=0;s<128;s++)e+=De[t[s]%De.length];return e}async exec(e,t){let s=new T(this.url,this.headers,this.localService),n=s.validateRequest(e,t);if(!n)return;let{Tags:o,tagsLen:a}=n,d=I.genLocalKey(this.bucket,this.key),c=this.generateUploadId();this.localService.persistence.buckets[this.bucket].multipartUploads[c]={uploadId:c,aborted:!1,completed:!1,key:this.key,initDate:new Date().toISOString(),data:{currentKey:d,type:s.contentType,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,websiteRedirectLocation:s.websiteRedirectLocation,metadata:s.metadata,StorageClass:s.storageClass,versions:{[d]:{multipartUploadId:c}},tags:a?o:void 0},parts:[]},e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3",...this.localService.getCorsHeaders(t)}),e.end(`<?xml version="1.0" encoding="UTF-8"?>
78
78
  <InitiateMultipartUploadResult>
79
79
  <Bucket>${this.bucket}</Bucket>
80
80
  <Key>${this.key}</Key>
81
81
  <UploadId>${c}</UploadId>
82
- </InitiateMultipartUploadResult>`)}};import{mkdirSync as jt}from"fs";import{appendFile as Dt,readFile as Ot,rm as Kt,stat as Vt}from"fs/promises";import Oe from"path";var Ve=5242880,Ft=({uploadId:i,PartNumber:r,ETag:e,requestId:t})=>`<Error><Code>InvalidPart</Code><UploadId>${i}</UploadId><PartNumber>${r}</PartNumber><ETag>${e}</ETag><Message>One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.</Message><RequestId>${t}</RequestId><HostId>local</HostId></Error>`,Ke=i=>`<Error><Code>MalformedXML</Code><Message>The XML you provided was not well-formed or did not validate against our published schema</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,_t=(i,r)=>`<Error><Code>InvalidPartOrder</Code><UploadId>${r}</UploadId><Message>The list of parts was not in ascending order. Parts must be ordered by part number.</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,Xt=({requestId:i,ArgumentName:r,ArgumentValue:e,Message:t})=>`<Error><Code>InvalidArgument</Code><ArgumentName>${r}</ArgumentName><ArgumentValue>${e}</ArgumentValue><Message>${t}</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,Gt=({ProposedSize:i,ETag:r,PartNumber:e,requestId:t})=>`<Error><Code>EntityTooSmall</Code><ProposedSize>${i}</ProposedSize><MinSizeAllowed>${Ve}</MinSizeAllowed><PartNumber>${e}</PartNumber><ETag>${r}</ETag><Message>Your proposed upload is smaller than the minimum allowed size</Message><RequestId>${t}</RequestId><HostId>local</HostId></Error>`,ye=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId")}bucket;key;uploadId;validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;if(!this.uploadId){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
82
+ </InitiateMultipartUploadResult>`)}};import{mkdirSync as jt}from"fs";import{appendFile as Dt,readFile as Ot,rm as Kt,stat as Ft}from"fs/promises";import Oe from"path";var Fe=5242880,Vt=({uploadId:i,PartNumber:r,ETag:e,requestId:t})=>`<Error><Code>InvalidPart</Code><UploadId>${i}</UploadId><PartNumber>${r}</PartNumber><ETag>${e}</ETag><Message>One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.</Message><RequestId>${t}</RequestId><HostId>local</HostId></Error>`,Ke=i=>`<Error><Code>MalformedXML</Code><Message>The XML you provided was not well-formed or did not validate against our published schema</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,_t=(i,r)=>`<Error><Code>InvalidPartOrder</Code><UploadId>${r}</UploadId><Message>The list of parts was not in ascending order. Parts must be ordered by part number.</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,Xt=({requestId:i,ArgumentName:r,ArgumentValue:e,Message:t})=>`<Error><Code>InvalidArgument</Code><ArgumentName>${r}</ArgumentName><ArgumentValue>${e}</ArgumentValue><Message>${t}</Message><RequestId>${i}</RequestId><HostId>local</HostId></Error>`,Gt=({ProposedSize:i,ETag:r,PartNumber:e,requestId:t})=>`<Error><Code>EntityTooSmall</Code><ProposedSize>${i}</ProposedSize><MinSizeAllowed>${Fe}</MinSizeAllowed><PartNumber>${e}</PartNumber><ETag>${r}</ETag><Message>Your proposed upload is smaller than the minimum allowed size</Message><RequestId>${t}</RequestId><HostId>local</HostId></Error>`,xe=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId")}bucket;key;uploadId;validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;if(!this.uploadId){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
83
83
  <Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>partNumber</ArgumentValue><Message>This operation does not accept partNumber without uploadId</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!s||s.aborted){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
84
- <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return{uploadId:this.uploadId}}async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}async getRequestBody(e){let t=await this.collectBody(e);return b.XMLParser.parse(t)}async verifyCompleteMultiPartUploadParts(e,t,s){let n={verifiedParts:[]},o=[];if(Array.isArray(e.CompleteMultipartUpload?.Part))o=e.CompleteMultipartUpload.Part;else if(e.CompleteMultipartUpload?.Part&&typeof e.CompleteMultipartUpload.Part=="object")o=[e.CompleteMultipartUpload.Part];else return n.hasCompleteMultiPartUploadError=Ke(this.requestId),n;for(let a=0;a<o.length;a++){let d=o[a];if(typeof d.PartNumber!="number"||typeof d.ETag!="string")return n.hasCompleteMultiPartUploadError=Ke(this.requestId),n;if(d.PartNumber<1)return n.hasCompleteMultiPartUploadError=Xt({ArgumentName:"PartNumber",ArgumentValue:d.PartNumber,requestId:this.requestId,Message:"PartNumber must be >= 1"}),n;let c=d.ETag.slice(1,-1);if(n.verifiedParts.find(m=>m.partNumber>=d.PartNumber))return n.hasCompleteMultiPartUploadError=_t(this.requestId,t),n;let l=s.parts.find(m=>d?.PartNumber==m.partNumber&&c==m.eTag);if(!l)return n.hasCompleteMultiPartUploadError=Ft({uploadId:t,PartNumber:d.PartNumber,ETag:d.ETag,requestId:this.requestId}),n;if(l.size<Ve&&a!=o.length-1)return n.hasCompleteMultiPartUploadError=Gt({requestId:this.requestId,PartNumber:l.partNumber,ETag:l.eTag,ProposedSize:l.size}),n;n.verifiedParts.push(l)}return n}async safeCreateObject(e){let t=Oe.join(this.localService.localStoragePath,this.bucket,e.data.currentKey);try{jt(Oe.dirname(t),{recursive:!0})}catch{}return{filePath:t}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{uploadId:n}=s,o=this.localService.persistence.buckets[this.bucket].multipartUploads[n],a=await this.getRequestBody(t),d=["x-amzn-requestid",this.requestId,"Server","AmazonS3"],c=this.localService.getCorsHeaders(t,!0);c&&d.push(...c),e.writeHead(200,d);function u(){e.writable&&(e.write(""),setTimeout(u,1e3))}u();let{hasCompleteMultiPartUploadError:l,verifiedParts:m}=await this.verifyCompleteMultiPartUploadParts(a,n,o);if(l){e.end(l);return}let g=m.map(x=>x.eTag).join(""),{filePath:h}=await this.safeCreateObject(o);for(let x of m){let $=await Ot(x.filePath,{flag:"r"});await Dt(h,$)}let y=`"${R(Buffer.from(g,"hex"))}-${m.length}"`,v=await Vt(h),xe=m.map((x,$)=>({...x,partNumber:$+1})).sort((x,$)=>x.partNumber-$.partNumber),ke=o.parts.map(x=>x.filePath);o.parts=xe,o.completed=!0,this.localService.persistence.buckets[this.bucket].objects[this.key]={...o.data,ETag:y,size:v.size,LastModified:v.mtimeMs},e.end(`<?xml version="1.0" encoding="UTF-8"?>
84
+ <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return{uploadId:this.uploadId}}async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}async getRequestBody(e){let t=await this.collectBody(e);return I.XMLParser.parse(t)}async verifyCompleteMultiPartUploadParts(e,t,s){let n={verifiedParts:[]},o=[];if(Array.isArray(e.CompleteMultipartUpload?.Part))o=e.CompleteMultipartUpload.Part;else if(e.CompleteMultipartUpload?.Part&&typeof e.CompleteMultipartUpload.Part=="object")o=[e.CompleteMultipartUpload.Part];else return n.hasCompleteMultiPartUploadError=Ke(this.requestId),n;for(let a=0;a<o.length;a++){let d=o[a];if(typeof d.PartNumber!="number"||typeof d.ETag!="string")return n.hasCompleteMultiPartUploadError=Ke(this.requestId),n;if(d.PartNumber<1)return n.hasCompleteMultiPartUploadError=Xt({ArgumentName:"PartNumber",ArgumentValue:d.PartNumber,requestId:this.requestId,Message:"PartNumber must be >= 1"}),n;let c=d.ETag.slice(1,-1);if(n.verifiedParts.find(m=>m.partNumber>=d.PartNumber))return n.hasCompleteMultiPartUploadError=_t(this.requestId,t),n;let l=s.parts.find(m=>d?.PartNumber==m.partNumber&&c==m.eTag);if(!l)return n.hasCompleteMultiPartUploadError=Vt({uploadId:t,PartNumber:d.PartNumber,ETag:d.ETag,requestId:this.requestId}),n;if(l.size<Fe&&a!=o.length-1)return n.hasCompleteMultiPartUploadError=Gt({requestId:this.requestId,PartNumber:l.partNumber,ETag:l.eTag,ProposedSize:l.size}),n;n.verifiedParts.push(l)}return n}async safeCreateObject(e){let t=Oe.join(this.localService.localStoragePath,this.bucket,e.data.currentKey);try{jt(Oe.dirname(t),{recursive:!0})}catch{}return{filePath:t}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{uploadId:n}=s,o=this.localService.persistence.buckets[this.bucket].multipartUploads[n],a=await this.getRequestBody(t),d=["x-amzn-requestid",this.requestId,"Server","AmazonS3"],c=this.localService.getCorsHeaders(t,!0);c&&d.push(...c),e.writeHead(200,d);function u(){e.writable&&(e.write(""),setTimeout(u,1e3))}u();let{hasCompleteMultiPartUploadError:l,verifiedParts:m}=await this.verifyCompleteMultiPartUploadParts(a,n,o);if(l){e.end(l);return}let h=m.map(S=>S.eTag).join(""),{filePath:g}=await this.safeCreateObject(o);for(let S of m){let B=await Ot(S.filePath,{flag:"r"});await Dt(g,B)}let y=`"${R(Buffer.from(h,"hex"))}-${m.length}"`,k=await Ft(g),se=m.map((S,B)=>({...S,partNumber:B+1})).sort((S,B)=>S.partNumber-B.partNumber),$=o.parts.map(S=>S.filePath);o.parts=se,o.completed=!0,this.localService.persistence.buckets[this.bucket].objects[this.key]={...o.data,ETag:y,size:k.size,LastModified:k.mtimeMs},e.end(`<?xml version="1.0" encoding="UTF-8"?>
85
85
  <CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
86
86
  <Location>http://127.0.0.1:${this.localService.port}/${this.bucket}/${encodeURIComponent(this.key)}</Location>
87
87
  <Bucket>${this.bucket}</Bucket>
88
88
  <Key>${this.key}</Key>
89
89
  <ETag>${y}</ETag>
90
- </CompleteMultipartUploadResult>`),setTimeout(async()=>{for(let x of ke)try{await Kt(x,{maxRetries:5,force:!0,retryDelay:200})}catch{}},100)}};var Fe=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000");if(s.pathname.split("/").filter(Boolean).length==1){if(s.searchParams.has("delete"))return new fe(s,t,r)}else{if(s.searchParams.has("uploads"))return new be(s,t,r);if(s.searchParams.has("uploadId"))return new ye(s,t,r)}return new S(s,t,r)};var G=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!b.isValidBucketName(this.bucket)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
90
+ </CompleteMultipartUploadResult>`),setTimeout(async()=>{for(let S of $)try{await Kt(S,{maxRetries:5,force:!0,retryDelay:200})}catch{}},100)}};var Ve=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000");if(s.pathname.split("/").filter(Boolean).length==1){if(s.searchParams.has("delete"))return new Ie(s,t,r)}else{if(s.searchParams.has("uploads"))return new Se(s,t,r);if(s.searchParams.has("uploadId"))return new xe(s,t,r)}return new x(s,t,r)};var W=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!I.isValidBucketName(this.bucket)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
91
91
  <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(this.localService.persistence.buckets[this.bucket]){e.statusCode=409,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
92
- <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 this.localService.createBucket(this.bucket),e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Location",`/${this.bucket}`),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end()}};import{copyFile as Wt,readFile as Jt,stat as Yt}from"node:fs/promises";import _e from"node:path";var z=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.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 a=t["x-amz-storage-class"];a&&(this.storageClass=a);let d=new Date(t.expires);isNaN(d)||(this.expires=d.getTime()),this.metadataDirective=t["x-amz-metadata-directive"];let c=t["x-amz-copy-source"]??"",[u,...l]=decodeURIComponent(c).split("/").filter(Boolean);this.sourceBucket=u,this.sourceKey=l.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())}bucket;key;sourceBucket;sourceKey;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";metadataDirective;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;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"),this.localService.setCorsHeaders(t,e),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,t)||this.hasNot(this.sourceBucket,e,t)||!this.isValidStorageClass(this.storageClass,e,t))return;if(!this.localService.persistence.buckets[this.sourceBucket].objects[this.sourceKey]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({Key:this.sourceKey,RequestId:this.requestId}));return}let s=this.localService.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(l=>l===!0)){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),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},o=V(n,s);if(o!==200){e.writeHead(o.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${o.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${o.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let a=_e.join(this.localService.localStoragePath,this.sourceBucket,s.currentKey),d=b.genLocalKey(this.bucket,this.key),c=_e.join(this.localService.localStoragePath,this.bucket,d);try{await Wt(a,c);let u=await Yt(c),l=Ie(await Jt(c));this.metadataDirective=="COPY"?this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:d,type:s.type,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,ETag:l,StorageClass:s.StorageClass,LastModified:u.mtimeMs,size:u.size,metadata:s.metadata,versions:{[d]:{}}}:this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:d,type:this.contentType,cacheControl:this.cacheControl,contentDisposition:this.contentDisposition,contentEncoding:this.contentEncoding,contentLanguage:this.contentLanguage,expires:this.expires,ETag:l,StorageClass:this.storageClass,LastModified:u.mtimeMs,size:u.size,metadata:this.metadata,websiteRedirectLocation:this.websiteRedirectLocation,versions:{[d]:{}}};let m=new Date(u.mtimeMs).toISOString();e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
93
- <CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LastModified>${m}</LastModified><ETag>${l}</ETag></CopyObjectResult>`);let g=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await q(this.localService.callableLambdas,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"CopyObject",eTag:l,sourceIPAddress:g,size:u.size})}catch(u){console.error(u),e.statusCode=500,e.end("Internal Server Error")}}};var W=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{e.setHeader("x-amzn-requestid",this.requestId),this.localService.persistence.buckets[this.bucket].tags=await b.getTagsFromRequest(t,this.requestId,"Bucket"),e.statusCode=204,e.end()}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var J=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/")}bucket;key;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(k({Key:this.key,RequestId:this.requestId}));return}try{e.setHeader("x-amzn-requestid",this.requestId),this.localService.persistence.buckets[this.bucket].objects[this.key].tags=await b.getTagsFromRequest(t,this.requestId,"Object"),e.statusCode=200,e.end()}catch(s){if(e.statusCode=400,s instanceof I){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(I.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var Y=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{let s=await this.collectBody(t),n=JSON.parse(s),o=this.localService.persistence.buckets[this.bucket];o.policy=n,e.end()}catch{e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
94
- <Error><Code>MalformedPolicy</Code><Message>Policies must be valid JSON</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}}};var Q=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new A("PutBucketCors",this.requestId).toXml()))}};var Z=class i extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;static aclHeaders=["x-amz-acl","x-amz-grant-full-control","x-amz-grant-read","x-amz-grant-read-acp","x-amz-grant-write","x-amz-grant-write-acp"];async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}getAclHeaders(e){let t={};for(let s of i.aclHeaders){let n=e[s];n&&(t[s]=n)}return t}async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{let s=await this.collectBody(t),n=this.getAclHeaders(t.headers),o=this.localService.persistence.buckets[this.bucket];s&&(b.XMLParser.parse(s),o.acl.accessControlPolicy=s),o.acl.headers=n,e.end();return}catch{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(new P(this.requestId).toXml())}}};var ee=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new A("PutObjectAcl",this.requestId).toXml()))}};import{createWriteStream as Qt,mkdirSync as Zt,readFileSync as es,statSync as ts}from"node:fs";import Xe from"node:path";var Se=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId"),e.searchParams.has("partNumber")&&(this.partNumber=e.searchParams.get("partNumber")??"")}bucket;key;uploadId;partNumber="";validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;if(!this.uploadId){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
92
+ <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 this.localService.createBucket(this.bucket),e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Location",`/${this.bucket}`),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end()}};import{copyFile as Wt,readFile as Jt,stat as Yt}from"node:fs/promises";import _e from"node:path";var z=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.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 a=t["x-amz-storage-class"];a&&(this.storageClass=a);let d=new Date(t.expires);isNaN(d)||(this.expires=d.getTime()),this.metadataDirective=t["x-amz-metadata-directive"];let c=t["x-amz-copy-source"]??"",[u,...l]=decodeURIComponent(c).split("/").filter(Boolean);this.sourceBucket=u,this.sourceKey=l.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())}bucket;key;sourceBucket;sourceKey;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";metadataDirective;ifMatch;ifNoneMatch;ifModifiedSince;ifUnmodifiedSince;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"),this.localService.setCorsHeaders(t,e),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,t)||this.hasNot(this.sourceBucket,e,t)||!this.isValidStorageClass(this.storageClass,e,t))return;if(!this.localService.persistence.buckets[this.sourceBucket].objects[this.sourceKey]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({Key:this.sourceKey,RequestId:this.requestId}));return}let s=this.localService.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(l=>l===!0)){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),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},o=V(n,s);if(o!==200){e.writeHead(o.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${o.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${o.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let a=_e.join(this.localService.localStoragePath,this.sourceBucket,s.currentKey),d=I.genLocalKey(this.bucket,this.key),c=_e.join(this.localService.localStoragePath,this.bucket,d);try{await Wt(a,c);let u=await Yt(c),l=ye(await Jt(c));this.metadataDirective=="COPY"?this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:d,type:s.type,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,ETag:l,StorageClass:s.StorageClass,LastModified:u.mtimeMs,size:u.size,metadata:s.metadata,versions:{[d]:{}}}:this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:d,type:this.contentType,cacheControl:this.cacheControl,contentDisposition:this.contentDisposition,contentEncoding:this.contentEncoding,contentLanguage:this.contentLanguage,expires:this.expires,ETag:l,StorageClass:this.storageClass,LastModified:u.mtimeMs,size:u.size,metadata:this.metadata,websiteRedirectLocation:this.websiteRedirectLocation,versions:{[d]:{}}};let m=new Date(u.mtimeMs).toISOString();e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
93
+ <CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LastModified>${m}</LastModified><ETag>${l}</ETag></CopyObjectResult>`);let h=this.localService.persistence.buckets[this.bucket].notification;if(h){let g=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await q(this.localService,h,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"CopyObject",eTag:l,sourceIPAddress:g,size:u.size})}}catch(u){console.error(u),e.statusCode=500,e.end("Internal Server Error")}}};var J=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{e.setHeader("x-amzn-requestid",this.requestId),this.localService.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 b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};var Y=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n,...o]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n,this.key=o.join("/")}bucket;key;async exec(e,t){if(!this.hasNot(this.bucket,e,t)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(C({Key:this.key,RequestId:this.requestId}));return}try{e.setHeader("x-amzn-requestid",this.requestId),this.localService.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 b){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(b.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var Q=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{let s=await this.collectBody(t),n=JSON.parse(s),o=this.localService.persistence.buckets[this.bucket];o.policy=n,e.end()}catch{e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3",...this.localService.getCorsHeaders(t)}).end(`<?xml version="1.0" encoding="UTF-8"?>
94
+ <Error><Code>MalformedPolicy</Code><Message>Policies must be valid JSON</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}}};var Z=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new A("PutBucketCors",this.requestId).toXml()))}};var ee=class i extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;static aclHeaders=["x-amz-acl","x-amz-grant-full-control","x-amz-grant-read","x-amz-grant-read-acp","x-amz-grant-write","x-amz-grant-write-acp"];async collectBody(e){let t=Buffer.alloc(0);return e.on("data",s=>{t=Buffer.concat([t,s])}),new Promise(s=>{e.on("end",async()=>{s(t.toString("utf-8"))})})}getAclHeaders(e){let t={};for(let s of i.aclHeaders){let n=e[s];n&&(t[s]=n)}return t}async exec(e,t){if(!this.hasNot(this.bucket,e,t))try{let s=await this.collectBody(t),n=this.getAclHeaders(t.headers),o=this.localService.persistence.buckets[this.bucket];s&&(I.XMLParser.parse(s),o.acl.accessControlPolicy=s),o.acl.headers=n,e.end();return}catch{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(new N(this.requestId).toXml())}}};var te=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;async exec(e,t){this.hasNot(this.bucket,e,t)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new A("PutObjectAcl",this.requestId).toXml()))}};import{createWriteStream as Qt,mkdirSync as Zt,readFileSync as es,statSync as ts}from"node:fs";import Xe from"node:path";var ke=class extends p{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...a]=n.split("/").filter(Boolean);this.bucket=o,this.key=a.join("/"),this.uploadId=e.searchParams.get("uploadId"),e.searchParams.has("partNumber")&&(this.partNumber=e.searchParams.get("partNumber")??"")}bucket;key;uploadId;partNumber="";validateRequest(e,t){if(this.hasNot(this.bucket,e,t))return;if(!this.uploadId){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
95
95
  <Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>partNumber</ArgumentValue><Message>This operation does not accept partNumber without uploadId</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let s=Number(this.partNumber);if(!this.partNumber||isNaN(s)||this.partNumber.includes(".")||s<1||s>1e4){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
96
96
  <Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>${this.partNumber}</ArgumentValue><Message>Part number must be an integer between 1 and 10000, inclusive</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let n=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!n||n.aborted||n.completed){e.statusCode=404,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.end(`<?xml version="1.0" encoding="UTF-8"?>
97
- <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return{partNumber:s,uploadId:this.uploadId}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{partNumber:n,uploadId:o}=s,a=this.localService.persistence.buckets[this.bucket].multipartUploads[o],d=b.genLocalKey(this.bucket,this.key,`${o}-${n}`),c=Xe.join(this.localService.localStoragePath,this.bucket,d);try{Zt(Xe.dirname(c),{recursive:!0})}catch{}let u=Qt(c,{flush:!0});u.on("finish",async()=>{try{let l=R(es(c)),m=a.parts.find(h=>h.partNumber==n),g=ts(c);m?(m.eTag=l,m.size=g.size,m.lastModified=g.mtime.toISOString()):a.parts.push({filePath:c,eTag:l,partNumber:n,size:g.size,lastModified:g.mtime.toISOString()}),e.setHeader("status",200),e.setHeader("ETag",`"${l}"`),e.end()}catch(l){console.log(l),e.statusCode=500,e.end()}}),e.setHeader("status",100),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("x-amzn-requestid",this.requestId),t.pipe(u)}};var Ge=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=t["user-agent"],o=typeof t["x-amz-copy-source"]=="string";if(n?.startsWith("aws-cli")){let[,a]=n.split("command/"),[,...d]=a.split(".");switch(d.join(".")){case"cp":case"sync":case"mv":return o?new z(s,t,r):new T(s,t,r);case"mb":case"create-bucket":return new G(s,t,r);case"copy-object":return new z(s,t,r);case"put-object":return new T(s,t,r);case"put-bucket-tagging":return new W(s,t,r);case"put-object-tagging":return new J(s,t,r);case"put-bucket-policy":return new Y(s,t,r);case"put-bucket-cors":return new Q(s,t,r);case"put-bucket-acl":return new Z(s,t,r);case"put-object-acl":return new ee(s,t,r);default:break}}else{let a=s.pathname.split("/").filter(Boolean).length==1;return!a&&s.searchParams.has("partNumber")&&s.searchParams.has("uploadId")?o?new S(s,t,r):new Se(s,t,r):s.searchParams.has("policy")?a?new Y(s,t,r):new S(s,t,r):s.searchParams.has("cors")?a?new Q(s,t,r):new S(s,t,r):s.searchParams.has("acl")?a?new Z(s,t,r):new ee(s,t,r):s.searchParams.has("tagging")?a?new W(s,t,r):new J(s,t,r):o?a?new S(s,t,r):new z(s,t,r):a?new G(s,t,r):new T(s,t,r)}return new S(s,t,r)};var rs=async(i,r,e)=>{switch(i.method){case"HEAD":await Ee(i,e).exec(r,i);break;case"GET":await Ae(i,e).exec(r,i);break;case"PUT":await Ge(i,e).exec(r,i);break;case"DELETE":await Pe(i,e).exec(r,i);break;case"POST":await Fe(i,e).exec(r,i);break;case"OPTIONS":i.headers.origin&&i.headers["access-control-request-method"]&&r.writeHead(200,"OK",{"access-control-allow-origin":i.headers.origin,"access-control-allow-headers":"*","access-control-allow-methods":i.headers["access-control-request-method"],"access-control-max-age":"86400","access-control-allow-credentials":"true"}),r.end();break;default:break}},We=i=>{let r={port:0,localStorageDir:"./.exlo/s3",...i},e=new b(r.localStorageDir,r.persist,r.port);return i?.accountId&&(e.accountId=i.accountId),i?.region&&(e.region=i.region),new Promise(t=>{let s=ss((a,d)=>{rs(a,d,e)}),n=async()=>{let a=s.address();a&&typeof a=="object"&&(e.port=a.port),t({server:s,localService:e})},o=[r.port];r.hostname&&o.push(r.hostname),o.push(n),s.listen(...o)})};var Je=[],Qo=i=>{let r=Te(i?.localStorageDir),e={setEndpointEnvVar:!0,...i,localStorageDir:r},t,s;return{name:"s3-local",onInit:async function(){let{accountId:n,region:o}=this.getAwsProviderDefaults(),{localService:a,server:d}=await We({accountId:n,region:o,...e});t=a,typeof e.allowToDeleteNonEmptyBuckets=="boolean"&&(t.allowToDeleteNonEmptyBuckets=e.allowToDeleteNonEmptyBuckets),s=d,s.unref(),Je=[],t.callableLambdas=Je;let u=`http://127.0.0.1:${s.address().port}`;try{await t.bootstrap(),this.setEndpoint("s3",u,e.setEndpointEnvVar?"AWS_ENDPOINT_URL_S3":void 0)}catch{}if(!this.getServices().s3){let l=new ns({region:o,endpoint:u,forcePathStyle:!0,credentials:{accessKeyId:"test",secretAccessKey:"test"}});this.setService("s3",l)}this.log.PINK(`S3 endpoint: ${u}`)},async onKill(){try{t.saveState()}catch{}},server:{async onReady(){let n=e.buckets??{};for(let o of Object.keys(n)){if(!b.isValidBucketName(o)){console.error(`Invalid Bucket Name: "${o}"`);continue}await t.createBucket(o,n[o])}}}}};export{Qo as s3Plugin};
97
+ <Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}return{partNumber:s,uploadId:this.uploadId}}async exec(e,t){let s=this.validateRequest(e,t);if(!s)return;let{partNumber:n,uploadId:o}=s,a=this.localService.persistence.buckets[this.bucket].multipartUploads[o],d=I.genLocalKey(this.bucket,this.key,`${o}-${n}`),c=Xe.join(this.localService.localStoragePath,this.bucket,d);try{Zt(Xe.dirname(c),{recursive:!0})}catch{}let u=Qt(c,{flush:!0});u.on("finish",async()=>{try{let l=R(es(c)),m=a.parts.find(g=>g.partNumber==n),h=ts(c);m?(m.eTag=l,m.size=h.size,m.lastModified=h.mtime.toISOString()):a.parts.push({filePath:c,eTag:l,partNumber:n,size:h.size,lastModified:h.mtime.toISOString()}),e.setHeader("status",200),e.setHeader("ETag",`"${l}"`),e.end()}catch(l){console.log(l),e.statusCode=500,e.end()}}),e.setHeader("status",100),e.setHeader("Server","AmazonS3"),this.localService.setCorsHeaders(t,e),e.setHeader("x-amzn-requestid",this.requestId),t.pipe(u)}};var Ge=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000"),n=t["user-agent"],o=typeof t["x-amz-copy-source"]=="string";if(n?.startsWith("aws-cli")){let[,a]=n.split("command/"),[,...d]=a.split(".");switch(d.join(".")){case"cp":case"sync":case"mv":return o?new z(s,t,r):new T(s,t,r);case"mb":case"create-bucket":return new W(s,t,r);case"copy-object":return new z(s,t,r);case"put-object":return new T(s,t,r);case"put-bucket-tagging":return new J(s,t,r);case"put-object-tagging":return new Y(s,t,r);case"put-bucket-policy":return new Q(s,t,r);case"put-bucket-cors":return new Z(s,t,r);case"put-bucket-acl":return new ee(s,t,r);case"put-object-acl":return new te(s,t,r);default:break}}else{let a=s.pathname.split("/").filter(Boolean).length==1;return!a&&s.searchParams.has("partNumber")&&s.searchParams.has("uploadId")?o?new x(s,t,r):new ke(s,t,r):s.searchParams.has("policy")?a?new Q(s,t,r):new x(s,t,r):s.searchParams.has("cors")?a?new Z(s,t,r):new x(s,t,r):s.searchParams.has("acl")?a?new ee(s,t,r):new te(s,t,r):s.searchParams.has("tagging")?a?new J(s,t,r):new Y(s,t,r):o?a?new x(s,t,r):new z(s,t,r):a?new W(s,t,r):new T(s,t,r)}return new x(s,t,r)};var rs=async(i,r,e)=>{switch(i.method){case"HEAD":await Ee(i,e).exec(r,i);break;case"GET":await Ae(i,e).exec(r,i);break;case"PUT":await Ge(i,e).exec(r,i);break;case"DELETE":await Ne(i,e).exec(r,i);break;case"POST":await Ve(i,e).exec(r,i);break;case"OPTIONS":i.headers.origin&&i.headers["access-control-request-method"]&&r.writeHead(200,"OK",{"access-control-allow-origin":i.headers.origin,"access-control-allow-headers":"*","access-control-allow-methods":i.headers["access-control-request-method"],"access-control-max-age":"86400","access-control-allow-credentials":"true"}),r.end();break;default:break}},We=i=>{let r={port:0,localStorageDir:"./.exlo/s3",...i},e=new I(r.localStorageDir,r.persist,r.port);return i?.accountId&&(e.accountId=i.accountId),i?.region&&(e.region=i.region),new Promise(t=>{let s=ss((a,d)=>{rs(a,d,e)}),n=async()=>{let a=s.address();a&&typeof a=="object"&&(e.port=a.port),t({server:s,localService:e})},o=[r.port];r.hostname&&o.push(r.hostname),o.push(n),s.listen(...o)})};var Qo=i=>{let r=Te(i?.localStorageDir),e={setEndpointEnvVar:!0,...i,localStorageDir:r},t,s;return{name:"s3-local",onInit:async function(){let{accountId:n,region:o}=this.getAwsProviderDefaults(),{localService:a,server:d}=await We({accountId:n,region:o,...e});t=a,typeof e.allowToDeleteNonEmptyBuckets=="boolean"&&(t.allowToDeleteNonEmptyBuckets=e.allowToDeleteNonEmptyBuckets),s=d,s.unref();let c=()=>this.lambdas;t.getLambdas=c.bind(this);let l=`http://127.0.0.1:${s.address().port}`;try{await t.bootstrap(),this.setEndpoint("s3",l,e.setEndpointEnvVar?"AWS_ENDPOINT_URL_S3":void 0)}catch{}if(!this.getServices().s3){let m=new ns({region:o,endpoint:l,forcePathStyle:!0,credentials:{accessKeyId:"test",secretAccessKey:"test"}});this.setService("s3",m)}this.log.PINK(`S3 endpoint: ${l}`)},async onKill(){try{t.saveState()}catch{}},server:{async onReady(){let n=e.buckets??{};for(let o of Object.keys(n)){if(!I.isValidBucketName(o)){console.error(`Invalid Bucket Name: "${o}"`);continue}await t.createBucket(o,n[o])}}}}};export{Qo as s3Plugin};
@@ -1,4 +1,5 @@
1
- import type { ILambda } from "../../defineConfig";
1
+ import type { NotificationConfiguration } from "@aws-sdk/client-s3";
2
+ import type { S3LocalService } from "./actions/localAction";
2
3
  interface IEventInfo {
3
4
  bucket: string;
4
5
  eTag: string;
@@ -8,5 +9,5 @@ interface IEventInfo {
8
9
  sourceIPAddress: string;
9
10
  requestId: string;
10
11
  }
11
- export declare const triggerEvent: (lambdas: ILambda[], { bucket, eTag, size, key, requestCmd, sourceIPAddress, requestId }: IEventInfo) => Promise<void>;
12
+ export declare const triggerEvent: (localService: S3LocalService, notification: NotificationConfiguration, { bucket, eTag, size, key, requestCmd, sourceIPAddress, requestId }: IEventInfo) => Promise<void>;
12
13
  export {};