exlo 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.mjs +1 -1
- package/dist/defineConfig.mjs +1 -1
- package/dist/plugins/s3/actions/AbortMultipartUploadAction.d.ts +1 -1
- package/dist/plugins/s3/actions/CompleteMultipartUploadAction.d.ts +1 -1
- package/dist/plugins/s3/actions/CreateBucketAction.d.ts +2 -2
- package/dist/plugins/s3/actions/CreateMultipartUploadAction.d.ts +1 -1
- package/dist/plugins/s3/actions/DeleteBucketAction.d.ts +2 -2
- package/dist/plugins/s3/actions/DeleteBucketPolicyAction.d.ts +2 -2
- package/dist/plugins/s3/actions/DeleteBucketTaggingAction.d.ts +2 -2
- package/dist/plugins/s3/actions/DeleteObjectAction.d.ts +1 -1
- package/dist/plugins/s3/actions/DeleteObjectTaggingAction.d.ts +2 -2
- package/dist/plugins/s3/actions/GetBucketAclAction.d.ts +2 -2
- package/dist/plugins/s3/actions/GetBucketPolicy.d.ts +2 -2
- package/dist/plugins/s3/actions/GetBucketTaggingAction.d.ts +2 -2
- package/dist/plugins/s3/actions/GetObjectAclAction.d.ts +2 -2
- package/dist/plugins/s3/actions/GetObjectAction.d.ts +3 -3
- package/dist/plugins/s3/actions/GetObjectTaggingAction.d.ts +2 -2
- package/dist/plugins/s3/actions/HeadBucketAction.d.ts +2 -2
- package/dist/plugins/s3/actions/HeadObjectAction.d.ts +2 -2
- package/dist/plugins/s3/actions/ListBucketsAction.d.ts +2 -2
- package/dist/plugins/s3/actions/ListMultipartUploadsAction.d.ts +2 -2
- package/dist/plugins/s3/actions/ListObjectsAction.d.ts +4 -4
- package/dist/plugins/s3/actions/ListPartsAction.d.ts +2 -2
- package/dist/plugins/s3/actions/PutObjectAction.d.ts +2 -2
- package/dist/plugins/s3/actions/UnknownAction.d.ts +2 -2
- package/dist/plugins/s3/actions/localAction.d.ts +7 -2
- package/dist/plugins/s3/index.mjs +63 -63
- package/dist/standalone.js +1 -1
- package/dist/standalone.mjs +1 -1
- package/package.json +1 -1
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import{S3 as
|
|
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"?>
|
|
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
|
-
`,
|
|
4
|
-
<Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>${i}</Key><RequestId>${r}</RequestId><HostId>local</HostId></Error>`;var
|
|
5
|
-
<Error><Code>${r}</Code><Message>${e}</Message>${s??""}<RequestId>${t}</RequestId><HostId>local</HostId></Error>`}},
|
|
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?
|
|
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"}).end(
|
|
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
|
|
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"),e.end(),s.completed||setTimeout(async()=>{for(let n of s.parts)try{await
|
|
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"),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}}},
|
|
12
|
-
<Key>${
|
|
13
|
-
<LastModified>${new Date(
|
|
14
|
-
<ETag>${
|
|
15
|
-
<Size>${
|
|
16
|
-
<StorageClass>${
|
|
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"?>
|
|
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>
|
|
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>
|
|
20
20
|
<Prefix>${this.prefix??""}</Prefix>
|
|
21
21
|
${this.marker?`<Marker>${this.marker}</Marker>`:""}
|
|
22
|
-
${
|
|
23
|
-
${
|
|
24
|
-
${
|
|
22
|
+
${o}
|
|
23
|
+
${d}
|
|
24
|
+
${n?`<NextMarker>${n}</NextMarker>`:""}
|
|
25
25
|
<MaxKeys>${this.maxKeys}</MaxKeys>
|
|
26
|
-
<IsTruncated>${
|
|
27
|
-
${
|
|
28
|
-
</ListBucketResult>`)}},
|
|
29
|
-
<Key>${
|
|
26
|
+
<IsTruncated>${s}</IsTruncated>
|
|
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>
|
|
29
|
+
<Key>${f}</Key>
|
|
30
30
|
<LastModified>${new Date(y.LastModified).toISOString()}</LastModified>
|
|
31
31
|
<ETag>${y.ETag}</ETag>
|
|
32
32
|
<Size>${y.size}</Size>
|
|
@@ -35,63 +35,63 @@ import{S3 as ss}from"@aws-sdk/client-s3";import{randomUUID as xe}from"node:crypt
|
|
|
35
35
|
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
36
36
|
<Name>${this.bucket}</Name>
|
|
37
37
|
<Prefix>${this.prefix??""}</Prefix>
|
|
38
|
-
${
|
|
39
|
-
${
|
|
40
|
-
<KeyCount>${
|
|
41
|
-
${
|
|
38
|
+
${o}
|
|
39
|
+
${d}
|
|
40
|
+
<KeyCount>${g}</KeyCount>
|
|
41
|
+
${n?`<NextContinuationToken>${n}</NextContinuationToken>`:""}
|
|
42
42
|
<MaxKeys>${this.maxKeys}</MaxKeys>
|
|
43
|
-
<IsTruncated>${
|
|
43
|
+
<IsTruncated>${s}</IsTruncated>
|
|
44
44
|
${this.continuationToken?`<ContinuationToken>${this.continuationToken}</ContinuationToken>`:""}
|
|
45
45
|
${!this.continuationToken&&this.startAfter?`<StartAfter>${this.startAfter}</StartAfter>`:""}
|
|
46
|
-
${
|
|
47
|
-
</ListBucketResult>`)}};import{randomUUID as yt}from"node:crypto";var E=class extends m{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){let t=Number(this.rawMaxBuckets);if(this.rawMaxBuckets){if(isNaN(t)||this.rawMaxBuckets.includes(".")||t<1||t>1e4){let n=new k({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"),e.end(n);return}}else t=1e4;let s;if(this.continuationToken){let n=new k({ArgumentName:"continuation-token",Message:"The continuation token provided is incorrect",RequestId:this.requestId}).toXml();try{let o=JSON.parse(Buffer.from(this.continuationToken,"base64").toString("utf-8"));this.isValidToken(o)||(e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(n)),s=o}catch{e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(n);return}}return{maxBuckets:t,continuationToken:s,prefix:this.prefix,bucketRegion:this.bucketRegion}}createContinuationToken(e){let t={id:yt(),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){let t=this.isValidRequest(e);if(!t)return;let{maxBuckets:s,continuationToken:n,prefix:o,bucketRegion:c}=t,a=this.getBucketNames(n,o),d="",u=c;!c&&(this.rawMaxBuckets||this.prefix||this.continuationToken)&&(u=this.localService.region);let l="";u&&(l+=`<BucketRegion>${u}</BucketRegion>`);let p=[];for(let y=0;y<a.length;y++){let C=a[y],Se=this.localService.persistence.buckets[C],S=`<Bucket>${l}<CreationDate>${new Date(Se.date).toISOString()}</CreationDate><Name>${C}</Name></Bucket>`;if(p.push(S),p.length==s){if(a[y+1]){let H=y+1;n&&(H=H+n.nextStartingPosition),d=this.createContinuationToken(H)}break}}let g="";d&&(g=`<ContinuationToken>${d}</ContinuationToken>`);let h="";this.prefix&&(h=`<Prefix>${this.prefix}</Prefix>`),e.writeHead(200,{"x-amz-request-id":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}),e.end(`<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Buckets>${p.join("")}</Buckets>${g}${h}<Owner><ID>${this.localService.ownerId}</ID></Owner></ListAllMyBucketsResult>`)}};import{createReadStream as It}from"node:fs";import we from"node:path";var O=({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 m{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...c]=n.split("/").filter(Boolean);this.bucket=o,this.key=c.join("/"),this.bucketPath=we.join(this.localService.localStoragePath,o),this.versionId=e.searchParams.get("versionId"),this.hasPartNumber=e.searchParams.has("partNumber");let a=e.searchParams.get("partNumber"),d=Number(a);if(this.partNumber=this.hasPartNumber&&!isNaN(d)?d:a,t.range){this.hasRange=!0;let[u]=t.range.split("bytes=").filter(Boolean),[l,p]=u.split("-");!isNaN(Number(l))&&!isNaN(Number(p))&&(this.range=[Number(l),Number(p)])}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){if(!this.hasNot(this.bucket,e)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(x({Key:this.key,RequestId:this.requestId}));return}try{let t={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},s=this.localService.persistence.buckets[this.bucket].objects[this.key],n=s.currentKey,o=O(t,s);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"),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(o==200){let c=200,a=s.size,d,u=we.join(this.bucketPath,s.currentKey),l={};if(this.hasPartNumber){let g=this.partNumber;if(isNaN(g)||g<1||g>1e4){let h=new k({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"}).end(h);return}if(s.versions[n].multipartUploadId){let h=this.localService.persistence.buckets[this.bucket].multipartUploads[s.versions[n].multipartUploadId];c=206;let y;l.start=0;for(let C of h.parts){if(C.partNumber==g){y=C,l.end=l.start+y.size-1;break}l.start=l.start+C.size}if(!y){let C=new B({RequestId:this.requestId,PartNumberRequested:g,ActualPartCount:h.parts.length}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(C);return}e.setHeader("x-amz-mp-parts-count",h.parts.length),a=y?.size,d=`bytes ${l.start}-${l.end}/${s.size}`}else if(this.partNumber==1)c=206,d=`bytes 0-${s.size-1}/${s.size}`;else{let h=new B({RequestId:this.requestId,PartNumberRequested:this.partNumber,ActualPartCount:1}).toXml();e.writeHead(416,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(h);return}}let p=s.type;if(this.range){c=206,l.start=this.range[0],l.end=this.range[1];let g=1;l.end>s.size&&(l.end=s.size,g--),a=g+l.end-l.start,d=`bytes ${l.start}-${l.end}/${s.size}`,p="application/octet-stream"}e.statusCode=c,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("x-amz-server-side-encryption","AES256"),e.setHeader("Date",new Date().toUTCString()),e.setHeader("Last-Modified",new Date(s.LastModified).toUTCString()),e.setHeader("ETag",s.ETag),e.setHeader("Accept-Ranges","bytes"),d&&e.setHeader("Content-Range",d),e.setHeader("Content-Length",a),p&&e.setHeader("Content-Type",p),e.setHeader("Server","AmazonS3"),s.cacheControl&&e.setHeader("Cache-Control",s.cacheControl),s.contentDisposition&&e.setHeader("Content-Disposition",s.contentDisposition),s.contentEncoding&&e.setHeader("Content-Encoding",s.contentEncoding),s.contentLanguage&&e.setHeader("Content-Language",s.contentLanguage),s.expires&&e.setHeader("Expires",new Date(s.expires).toUTCString()),s.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",s.websiteRedirectLocation);for(let[g,h]of Object.entries(s.metadata))e.setHeader(g,h);It(u,l).pipe(e)}else e.writeHead(o.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).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 V=class extends m{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){if(!this.hasNot(this.bucket,e)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(x({Key:this.key,RequestId:this.requestId}));return}try{e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.statusCode=200;let t={Tagging:{TagSet:{Tag:[]}}},s=this.localService.persistence.buckets[this.bucket].objects[this.key].tags;if(s)for(let[o,c]of Object.entries(s))t.Tagging.TagSet.Tag.push({Key:o,Value:c});let n=b.XMLBuilder.build(t);e.end(`<?xml version="1.0" encoding="UTF-8"?>${n}`)}catch(t){if(e.statusCode=400,t instanceof f){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(f.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}}};var F=class extends m{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){if(!this.hasNot(this.bucket,e))try{e.setHeader("x-amzn-requestid",this.requestId);let t=this.localService.persistence.buckets[this.bucket].tags;if(!t)throw new ee(this.requestId);e.statusCode=200;let s={Tagging:{TagSet:{Tag:[]}}};for(let[o,c]of Object.entries(t))s.Tagging.TagSet.Tag.push({Key:o,Value:c});let n=b.XMLBuilder.build(s);e.setHeader("Content-Type","application/xml"),e.end(`<?xml version="1.0" encoding="UTF-8"?>${n}`)}catch(t){if(e.statusCode=400,t instanceof f){e.setHeader("Content-Type","application/xml"),t.statusCode&&(e.statusCode=t.statusCode),e.end(t.toXml());return}if(t instanceof Error){e.setHeader("Content-Type","application/xml"),e.end(f.genericError({Code:"UnknownError",Message:t.message,RequestId:this.requestId}));return}e.end(t?.toString?.())}}};var ae=class extends m{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){if(this.hasNot(this.bucket,e))return;let t=this.localService.persistence.buckets[this.bucket];if(t.policy){e.setHeader("x-amzn-requestid",this.requestId),e.end(JSON.stringify(t.policy));return}e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).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
|
|
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
|
|
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
|
|
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?
|
|
52
|
-
<PartNumber>${
|
|
53
|
-
<LastModified>${
|
|
54
|
-
<ETag>"${
|
|
55
|
-
<Size>${
|
|
56
|
-
</Part>`),
|
|
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"?>
|
|
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
|
+
<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
|
+
<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>
|
|
52
|
+
<PartNumber>${f.partNumber}</PartNumber>
|
|
53
|
+
<LastModified>${f.lastModified}</LastModified>
|
|
54
|
+
<ETag>"${f.eTag}"</ETag>
|
|
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"?>
|
|
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
|
-
<UploadId>${
|
|
61
|
-
<PartNumberMarker>${
|
|
62
|
-
<NextPartNumberMarker>${
|
|
63
|
-
<MaxParts>${
|
|
64
|
-
<IsTruncated>${
|
|
65
|
-
${
|
|
60
|
+
<UploadId>${n}</UploadId>
|
|
61
|
+
<PartNumberMarker>${o}</PartNumberMarker>
|
|
62
|
+
<NextPartNumberMarker>${g}</NextPartNumberMarker>
|
|
63
|
+
<MaxParts>${a}</MaxParts>
|
|
64
|
+
<IsTruncated>${l}</IsTruncated>
|
|
65
|
+
${c.join("")}
|
|
66
66
|
<Initiator>
|
|
67
67
|
<ID>arn:aws:iam::${this.localService.accountId}:user/local-user</ID>
|
|
68
68
|
</Initiator>
|
|
69
69
|
<Owner>
|
|
70
70
|
<ID>${this.localService.ownerId}</ID>
|
|
71
71
|
</Owner>
|
|
72
|
-
<StorageClass>${
|
|
73
|
-
</ListPartsResult>`;e.statusCode=200,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(
|
|
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(
|
|
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"),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
|
|
77
|
-
<ListMultipartUploadsResult><Bucket>${this.bucket}</Bucket><IsTruncated>${n}</IsTruncated><KeyMarker>${this.keyMarker??""}</KeyMarker><MaxUploads>${this.maxUploads??"1000"}</MaxUploads>`;if(u+=`<UploadIdMarker>${this.uploadIdMarker??""}</UploadIdMarker><NextUploadIdMarker>${a}</NextUploadIdMarker><NextKeyMarker>${c}</NextKeyMarker>`,this.prefix&&(u+=`<Prefix>${this.prefix}</Prefix>`),this.delimiter&&(u+=`<Delimiter>${this.delimiter}</Delimiter>`),o)for(let g of o)u+=`<CommonPrefixes><Prefix>${g}</Prefix></CommonPrefixes>`;this.encodingType&&(u+=`<EncodingType>${this.encodingType}</EncodingType>`);let l=`<Owner><ID>${this.localService.ownerId}</ID></Owner>`,p=`<Initiator><ID>${this.localService.ownerId}</ID></Initiator>`;for(let g of s)u+=`<Upload><Initiated>${g.initDate}</Initiated>${p}<Key>${g.key}</Key>${l}<StorageClass>${g.data.StorageClass}</StorageClass><UploadId>${g.uploadId}</UploadId></Upload>`;u+="</ListMultipartUploadsResult>",e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3"}).end(u)}};var ue=class extends m{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){if(this.hasNot(this.bucket,e))return;let t=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(t.acl.accessControlPolicy)}};var le=class extends m{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){if(this.hasNot(this.bucket,e))return;let t=this.localService.persistence.buckets[this.bucket];e.writeHead(200,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(t.acl.accessControlPolicy)}};var Te=(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[,c]=n.split("command/"),[,...a]=c.split(".");switch(a.join(".")){case"ls":return/@s3\/?$/.test(e)?new E(s,t,r):s.searchParams.get("list-type")=="2"?new M(s,t,r):new q(s,t,r);case"list-buckets":return new E(s,t,r);case"list-objects":return new q(s,t,r);case"list-objects-v2":return new M(s,t,r);case"rb.rm":return s.searchParams.get("list-type")=="2"?new M(s,t,r):new q(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 M(s,t,r):new q(s,t,r):new L(s,t,r);case"get-bucket-tagging":return new F(s,t,r);case"get-object-tagging":return new V(s,t,r);default:break}}else return s.searchParams.has("acl")?o?new ue(s,t,r):new le(s,t,r):s.searchParams.has("uploads")?o?new de(s,t,r):new I(s,t,r):s.searchParams.has("policy")?new ae(s,t,r):s.searchParams.has("tagging")?o?new F(s,t,r):new V(s,t,r):s.searchParams.has("uploadId")?o?new I(s,t,r):new ce(s,t,r):s.pathname=="/"?new E(s,t,r):o?s.searchParams.get("list-type")=="2"?new M(s,t,r):new q(s,t,r):new L(s,t,r);return new I(s,t,r)};var pe=class extends m{constructor(e,t,s){super(t,s);this.localService=s;let[n]=decodeURIComponent(e.pathname).split("/").filter(Boolean);this.bucket=n}bucket;exec(e){this.hasNot(this.bucket,e)||(e.statusCode=200,e.setHeader("x-amz-request-id",this.requestId),e.end())}};import Pe from"node:path";var me=class extends m{constructor(e,t,s){super(t,s);this.localService=s;let n=decodeURIComponent(e.pathname),[o,...c]=n.split("/").filter(Boolean);if(this.bucket=o,this.key=c.join("/"),this.bucketPath=Pe.join(this.localService.localStoragePath,o),this.filePath=Pe.join(this.bucketPath,...c),this.versionId=e.searchParams.get("versionId"),this.partNumber=e.searchParams.has("partNumber")?Number(e.searchParams.get("partNumber")):null,t.range){let[a]=t.range.split("bytes=").filter(Boolean),[d,u]=a.split("-");!isNaN(Number(d))&&!isNaN(Number(u))&&(this.range=[Number(d),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){if(!this.hasNot(this.bucket,e)){if(!this.localService.persistence.buckets[this.bucket].objects[this.key]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(x({Key:this.key,RequestId:this.requestId}));return}try{let t={ifMatch:this.ifMatch,ifModifiedSince:this.ifModifiedSince,ifNoneMatch:this.ifNoneMatch,ifUnmodifiedSince:this.ifUnmodifiedSince},s=this.localService.persistence.buckets[this.bucket].objects[this.key],n=O(t,s);if(n==200){let o=200,c=s.size,a,d=s.type,u={};if(this.range){o=206,u.start=this.range[0],u.end=this.range[1];let l=1;u.end>s.size&&(u.end=s.size,l--),c=l+u.end-u.start,a=`bytes ${u.start}-${u.end}/${s.size}`,d="application/octet-stream"}e.statusCode=o,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("x-amz-server-side-encryption","AES256"),e.setHeader("Date",new Date().toUTCString()),e.setHeader("Last-Modified",new Date(s.LastModified).toUTCString()),e.setHeader("ETag",s.ETag),e.setHeader("Accept-Ranges","bytes"),a&&e.setHeader("Content-Range",a),e.setHeader("Content-Length",c),d&&e.setHeader("Content-Type",d),e.setHeader("Server","AmazonS3"),s.cacheControl&&e.setHeader("Cache-Control",s.cacheControl),s.contentDisposition&&e.setHeader("Content-Disposition",s.contentDisposition),s.contentEncoding&&e.setHeader("Content-Encoding",s.contentEncoding),s.contentLanguage&&e.setHeader("Content-Language",s.contentLanguage),s.expires&&e.setHeader("Expires",new Date(s.expires).toUTCString()),s.websiteRedirectLocation&&e.setHeader("x-amz-website-redirect-location",s.websiteRedirectLocation);for(let[l,p]of Object.entries(s.metadata))e.setHeader(l,p);e.end()}else e.writeHead(n.statusCode,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>${n.Code}</Code><Message>At least one of the pre-conditions you specified did not hold</Message><Condition>${n.Condition}</Condition><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}catch{e.statusCode=500,e.end("Internal Server Error")}}}};var Ne=(i,r)=>{let{url:e,headers:t}=i,s=new URL(e,"http://localhost:3000");return s.pathname.split("/").filter(Boolean).length>1?new me(s,t,r):new pe(s,t,r)};var _=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(Ae).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 d=0;d<t.length;){let u=t[d],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){d=d+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let p=t[d+1];n[u]=p,l=="x-api-key"&&(s=p),d=d+2}let o={};for(let d of Object.keys(n).sort((u,l)=>u.localeCompare(l)))o[d]=n[d];let c={"X-Forwarded-For":[r.socket.remoteAddress],"X-Forwarded-Proto":["http"],"X-Forwarded-Port":[String(i.port)]};for(let d=0;d<t.length;){let u=t[d],l=u.toLowerCase();if(["connection","x-mock-type"].includes(l)){d=d+2;continue}this.knownHeaders.includes(l)&&(u=this.normalizeHeaderKey(l));let p=t[d+1];c[u]?c[u].push(p):c[u]=[p],d=d+2}let a={};for(let d of Object.keys(c).sort((u,l)=>u.localeCompare(l)))a[d]=c[d];return{headers:o,multiValueHeaders:a,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,c)=>{o.startsWith("{")&&o.endsWith("}")&&!o.endsWith("+}")&&(n[o.slice(1,-1)]=s[c])}),n}static normalizeSearchParams=(r,e)=>{let t={};Array.from(r.keys()).forEach(o=>{let c=r.getAll(o).map(d=>d.toLowerCase()),a=o.toLowerCase();c?t[a]?t[a].push(...c):t[a]=c:t[a]||(t[a]=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 ge=!1,St=i=>{ge=i},xt=()=>ge,U=(i,r)=>{ge&&console.log(`\x1B[${i}m${r}\x1B[0m`)},kt=i=>console.log(`\x1B[31m${i}\x1B[0m`),Ct=i=>U("32",i),vt=i=>U("33",i),Ht=i=>U("36",i),Rt=i=>U("90",i),qt=i=>U("94",i),Mt=i=>U("95",i),wt=i=>ge?console.log(i):void 0,Ee={GREEN:Ct,YELLOW:vt,CYAN:Ht,BR_BLUE:qt,RED:kt,GREY:Rt,PINK:Mt,setDebug:St,getDebug:xt,info:wt};var Le="application/vnd.awslambda.http-integration-response",He=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(a=>a===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==Le&&(!this._ct||this._ct==Le),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 Ee.RED("awslambda.HttpResponseStream.from() is not supported with API Gateway"),{statusCode:500,headers:{"Content-Type":_.contentType.json},body:_.httpErrMsg};if(this.buffer)return this.#t(this.buffer)}#o(){let 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 Ue="<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 pn=JSON.stringify({Message:null});var ze=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 mn=JSON.stringify({Type:null,message:"Client context must be a valid Base64-encoded JSON object."});var gn=new Error(Ue);var Ae=i=>i.charAt(0).toUpperCase()+i.slice(1);var Tt=i=>{let r=[],e;try{i.split("<Object>").forEach(t=>{let s=t.indexOf("<Key>");if(s==-1)return;let n=t.indexOf("</Key>"),c={Key:t.slice(s+5,n)},a=t.indexOf("<VersionId>");if(a>-1){let d=t.indexOf("</VersionId>"),u=t.slice(a+11,d);c.VersionId=u}r.push(c)})}catch(t){console.error(t)}return{Objects:r,Quiet:e}},he=class extends m{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))return;let s=await ze(t),{Objects:n,Quiet:o}=Tt(s);if(!n.length){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),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 c=n.map(d=>`<Deleted><Key>${d.Key}</Key></Deleted>`).join(""),a=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");for(let d of n)await this.localService.removeObject(this.bucket,d.Key,a,this.requestId);e.end(`<?xml version="1.0" encoding="UTF-8"?><DeleteResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">${c}</DeleteResult>`)}};import{createWriteStream as Pt,mkdirSync as Nt,readFileSync as At,statSync as Et}from"node:fs";import $e from"node:path";var fe=i=>`"${R(i)}"`;var w=class extends m{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 c=t["x-amz-storage-class"];c&&(this.storageClass=c);let a=new Date(t.expires);isNaN(a)||(this.expires=a.getTime())}bucket;key;contentType;cacheControl;contentDisposition;contentEncoding;contentLanguage;websiteRedirectLocation;expires;storageClass="STANDARD";tagging;validateRequest(e){if(this.hasNot(this.bucket,e)||!this.isValidStorageClass(this.storageClass,e))return;let t={};if(this.tagging){let n=()=>{e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new k({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"){n();return}if(!Lt(this.tagging)){n();return}let o=new URLSearchParams(this.tagging);for(let c of o.keys()){if(c in t){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new v({TagKey:c,RequestId:this.requestId,Message:"Cannot provide multiple Tags with the same key"}).toXml());return}if(c.length>128||c.length<1){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new v({TagKey:c,RequestId:this.requestId,Message:"The TagKey you have provided is invalid"}).toXml());return}let a=o.get(c);if(a.length>256){e.statusCode=400,e.setHeader("Content-Type","application/xml"),e.end(new v({TagKey:c,RequestId:this.requestId,Message:"The TagValue you have provided is invalid"}).toXml());return}t[c]=a}}let s=Object.keys(t).length;if(s>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:s,Tags:t}}async exec(e,t){let s=this.validateRequest(e);if(!s)return;let{Tags:n,tagsLen:o}=s,c=b.genLocalKey(this.bucket,this.key),a=$e.join(this.localService.localStoragePath,this.bucket,c);try{Nt($e.dirname(a),{recursive:!0})}catch{}let d=Pt(a,{flush:!0});d.on("finish",async()=>{try{let u=Et(a),l=fe(At(a));this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:c,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:{[c]:{}},tags:o?n:void 0};let p=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";e.end(),await A(this.localService.callableLambdas,{bucket:this.bucket,key:this.key,requestId:this.requestId,requestCmd:"PutObject",eTag:l,sourceIPAddress:p,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),t.pipe(d)}},Lt=i=>!i.split("&").find(r=>r.split("=").length>2);import{getRandomValues as Ut}from"crypto";var zt="abcdefghijklmnopqrstuvwxyz0123456789_.",Be=`ABCDEFGHIJKLMNOPQRSTUVWXYZ${zt}`,be=class extends m{constructor(e,t,s){super(t,s);this.url=e;this.headers=t;this.localService=s;let n=decodeURIComponent(e.pathname),[o,...c]=n.split("/").filter(Boolean);this.bucket=o,this.key=c.join("/"),this.version=e.searchParams.get("versionId")}bucket;key;version;generateUploadId(){let e="",t=new Uint8Array(128);Ut(t);for(let s=0;s<128;s++)e+=Be[t[s]%Be.length];return e}async exec(e,t){let s=new w(this.url,this.headers,this.localService),n=s.validateRequest(e);if(!n)return;let{Tags:o,tagsLen:c}=n,a=b.genLocalKey(this.bucket,this.key),d=this.generateUploadId();this.localService.persistence.buckets[this.bucket].multipartUploads[d]={uploadId:d,aborted:!1,completed:!1,key:this.key,initDate:new Date().toISOString(),data:{currentKey:a,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:{[a]:{multipartUploadId:d}},tags:c?o:void 0},parts:[]},e.writeHead(200,{"x-amzn-requestid":this.requestId,Server:"AmazonS3"}),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
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"?>
|
|
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
|
+
<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"?>
|
|
78
78
|
<InitiateMultipartUploadResult>
|
|
79
79
|
<Bucket>${this.bucket}</Bucket>
|
|
80
80
|
<Key>${this.key}</Key>
|
|
81
|
-
<UploadId>${
|
|
82
|
-
</InitiateMultipartUploadResult>`)}};import
|
|
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
|
|
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=
|
|
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"?>
|
|
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"?>
|
|
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
|
-
<ETag>${
|
|
90
|
-
</CompleteMultipartUploadResult>`),setTimeout(async()=>{for(let
|
|
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"),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"),e.end()}};import{copyFile as
|
|
93
|
-
<CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LastModified>${
|
|
94
|
-
<Error><Code>MalformedPolicy</Code><Message>Policies must be valid JSON</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}}};var
|
|
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
|
|
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
|
|
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:
|
|
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"?>
|
|
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"?>
|
|
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
|
+
<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};
|