exlo 0.0.12 → 0.0.14
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/index.mjs +9 -9
- package/dist/standalone.js +7 -7
- package/dist/standalone.mjs +5 -5
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFile as I}from"node:fs/promises";import p from"node:path";import{pathToFileURL as O}from"node:url";import{parseArgs as Y}from"node:util";var j="exlo",b="0.0.
|
|
2
|
+
import{readFile as I}from"node:fs/promises";import p from"node:path";import{pathToFileURL as O}from"node:url";import{parseArgs as Y}from"node:util";var j="exlo",b="0.0.14";var g=!1,R=e=>{g=e},A=()=>g,l=(e,t)=>{g&&console.log(`\x1B[${e}m${t}\x1B[0m`)},C=e=>console.log(`\x1B[31m${e}\x1B[0m`),$=e=>l("32",e),q=e=>l("33",e),L=e=>l("36",e),S=e=>l("90",e),F=e=>l("94",e),_=e=>l("95",e),D=e=>g?console.log(e):void 0,n={GREEN:$,YELLOW:q,CYAN:L,BR_BLUE:F,RED:C,GREY:S,PINK:_,setDebug:R,getDebug:A,info:D};var y={config:{type:"string",short:"c",default:"exlo.config.ts",description:"Path to exlo 'defineConfig' file."},debug:{type:"boolean",default:!1,description:"Enable debug mode. When enabled exlo will print usefull informations."},create:{type:"boolean",default:!1,description:"Create exlo 'defineConfig' file based on passed options."},runtime:{type:"string",short:"r",description:"Lambda default runtime (ex: nodejs22.x, python3.7, ruby2.7 etc.)."},timeout:{type:"string",short:"t",default:"3",description:"Lambda default timeout."},port:{type:"string",short:"p",default:"0",description:"Lambda server port."},definitions:{type:"string",short:"d",description:"Path to .json, .mjs, .cjs file with Lambda function definitions."},functions:{type:"string",short:"f",multiple:!0,description:"Glob pattern to automatically find and define Lambda handlers."},exclude:{type:"string",short:"X",multiple:!0,default:[".(test|spec)."],description:"RegExp string to exclude found enteries from --functions."},"handler-name":{type:"string",default:"handler",description:"Handler function name. To be used with --functions."},env:{type:"string",short:"e",multiple:!0,default:[],description:"Environment variables to be injected into Lambdas. All existing AWS_* are automatically injected.",example:"-e API_KEY=supersecret -e API_URL=https://website.com"},"optimize-build":{type:"boolean",default:!1,description:"externalize dependencies and other stuff"},"shim-require":{type:"boolean",default:!1,description:"shim 'require()', '__dirname' and '__filename' when bundeling Lambdas with ESM format"},help:{type:"boolean",short:"h",skipFullPrint:!0},version:{type:"boolean",short:"v",skipFullPrint:!0},"esbuild-external":{type:"string",multiple:!0,skip:!0},"esbuild-resolveExtensions":{type:"string",multiple:!0,skip:!0},"esbuild-mainFields":{type:"string",multiple:!0,skip:!0},"esbuild-conditions":{type:"string",multiple:!0,skip:!0},"esbuild-entryPoints":{type:"string",multiple:!0,skip:!0},"esbuild-inject":{type:"string",multiple:!0,skip:!0},"esbuild-nodePaths":{type:"string",multiple:!0,skip:!0}};function M(){n.setDebug(!0),n.GREY("Usage examples:"),console.log("exlo -c exlo.config.ts"),console.log(`exlo -p 3000 --debug --functions "src/lambdas/**/*.ts"
|
|
3
3
|
`),n.BR_BLUE("Options:");for(let[e,t]of Object.entries(y)){let i=e;if(t.skip)continue;if(t.short&&(i+=`, -${t.short}`),t.skipFullPrint){n.CYAN(` --${i}
|
|
4
4
|
`);continue}let s=` type: ${t.type}`;t.description&&(s+=`
|
|
5
5
|
description: ${t.description}`),"default"in t&&(s+=`
|
package/dist/defineConfig.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var h="0.0.
|
|
1
|
+
var h="0.0.14";function k(e){let c=new Set;e.plugins&&(e.plugins=e.plugins.filter((i,a)=>typeof i!="object"||!i||!("name"in i)?!1:((!i.name||!i.name.length||typeof i.name!="string")&&(i.name=`plugin-${a}`,console.warn(`No Plugin name provided at index ${a}`)),c.has(i.name)?i.name=i.name+a:c.add(i.name),!0)));async function f({stop:i,lambdas:a,region:g,esbuild:v,getServices:y,setService:d,addLambda:p,log:l,setEndpoint:b,getEndpoint:x,getAwsProviderDefaults:C,setAwsProviderDefaults:S}){let r={build:{esbuild:e?.build?.esbuild??{},shimRequire:e?.build?.shimRequire,optimizeBuild:e?.build?.optimizeBuild},server:{port:e.server?.port,setEndpointEnvVar:e.server?.setEndpointEnvVar},onKill:[]};if(e.defaults&&typeof e.defaults=="object"&&!Array.isArray(e.defaults)&&S(e.defaults),e.functions&&typeof e.functions=="object"&&!Array.isArray(e.functions))for(let[m,s]of Object.entries(e.functions))p(m,s);e.services&&(e.services.sqs&&d("sqs",e.services.sqs),e.services.sns&&d("sns",e.services.sns),e.services.dynamodb&&d("dynamodb",e.services.dynamodb));let o={stop:i,lambdas:a,region:g,esbuild:v,options:e,config:r,getServices:y,setService:d,addLambda:p,log:l,setEndpoint:b,getEndpoint:x,getAwsProviderDefaults:C};if(e.plugins){r.server.onReady=async(s,n)=>{for(let t of e.plugins)if(t.server?.onReady)try{await t.server.onReady.call(o,s,n)}catch(u){l.RED(t.name),console.error(u)}},r.buildCallback=async(s,n)=>{for(let t of e.plugins)if(t.buildCallback)try{await t.buildCallback.call(o,s,n)}catch(u){l.RED(t.name),console.error(u),n||process.exit(1)}};let m=e.plugins.reduce((s,n)=>(n.server?.request?.length&&s.push(...n.server.request),s),[]);m?.length&&(r.server.request=m.map(s=>(s.callback=s.callback.bind(o),s)));for(let s of e.plugins)if(s.onKill&&r.onKill.push(s.onKill.bind(o)),s.onInit)try{await s.onInit.call(o)}catch(n){throw l.RED(s.name),n}}return r}return f.plugins=e.plugins??[],f}export{k as defineConfig,h as exloVersion};
|
|
@@ -5,8 +5,8 @@ import{S3 as ss}from"@aws-sdk/client-s3";import{randomUUID as xe}from"node:crypt
|
|
|
5
5
|
<Error><Code>${r}</Code><Message>${e}</Message>${s??""}<RequestId>${t}</RequestId><HostId>local</HostId></Error>`}},v=class extends f{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>`)}},T=class extends f{constructor(r){super({Code:"MalformedXML",Message:"The XML you provided was not well-formed or did not validate against our published schema",RequestId:r})}},P=class extends f{constructor({Message:r,RequestId:e}){super({Code:"BadRequest",Message:r,RequestId:e})}},k=class extends f{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)}},B=class extends f{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>`)}},ee=class extends f{constructor(r){super({Code:"NoSuchTagSet",Message:"The TagSet does not exist",RequestId:r,statusCode:404})}},N=class extends f{constructor(r,e){super({Code:"UnsupportedCommand",Message:`${r} is currently not supported`,RequestId:e,statusCode:500})}};var Je={PutObject:["ObjectCreated","Put"],CopyObject:["ObjectCreated","Copy"],DeleteObject:["ObjectRemoved","Delete"]},Ye=({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"}}}),Qe=(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)},A=async(i,{bucket:r,eTag:e,size:t,key:s,requestCmd:n,sourceIPAddress:o,requestId:c})=>{let a=Je[n];for(let d of i)for(let u of d.s3){if(r!=u.bucket)continue;let[l,p]=u.type;if(l==a[0]&&(p=="*"||p==a[1])&&Qe(u.rules,s))try{await d.invoke({Records:[Ye({bucket:r,eTag:e,size:t,key:s,sourceIPAddress:o,requestId:c,eventName:a.join(":")})]},{kind:"s3",event:u})}catch(g){console.log(g)}}};var ct=["STANDARD","REDUCED_REDUNDANCY","STANDARD_IA","ONEZONE_IA","INTELLIGENT_TIERING","GLACIER","DEEP_ARCHIVE","OUTPOSTS","GLACIER_IR","SNOW"],dt=/\.{2,}/,ut=/^(\d{1,3}\.){3}\d{1,3}$/,lt=/^[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 it;static XMLParser=new at;static genLocalKey(r,e,t){return R(j.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 T(e);if(!n)throw new f({Code:"MissingRequestBodyError",Message:"Request Body is empty",RequestId:e});let c;try{c=i.XMLParser.parse(n)}catch{throw o}if(c.Tagging=="")return;let a=c.Tagging.TagSet.Tag;a&&!Array.isArray(a)&&(a=[a]);let d={};for(let l of a){if(l===null||typeof l!="object"||Array.isArray(l))throw o;let{Key:p,Value:g}=l;if(typeof p!="string"||typeof g!="string")throw o;if(p in d)throw new v({TagKey:p,RequestId:e,Message:"Cannot provide multiple Tags with the same key"});if(p.length>128||p.length<1)throw new v({TagKey:p,RequestId:e,Message:"The TagKey you have provided is invalid"});if(g.length>256)throw new v({TagKey:p,RequestId:e,Message:"The TagValue you have provided is invalid"});d[p]=g}let u=t=="Bucket"?50:10;if(Object.keys(d).length>u)throw new P({Message:`${t} tag count cannot be greater than ${u}`,RequestId:e});return d}persistence={version:2,buckets:{}};callableLambdas=[];accountId="123456789012";ownerId=[xe(),xe()].join("").replaceAll("-","");region="us-east-1";allowToDeleteNonEmptyBuckets=!1;async bootstrap(){try{let r=await rt(j.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=j.join(this.localStoragePath,r);et(t,{recursive:!0}),this.persistence.buckets[r]={date:Date.now(),acl:{accessControlPolicy:`<?xml version="1.0" encoding="UTF-8"?>
|
|
6
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?st(j.join(this.localStoragePath,"__state.json"),JSON.stringify(this.persistence)):tt(this.localStoragePath,{force:!0,recursive:!0})}static isValidBucketName(r){let e=r.length;return e<3||e>63||dt.test(r)||ut.test(r)||r.startsWith("xn--")||r.startsWith("sthree-")||r.endsWith("-s3alias")||r.endsWith("--ol-s3")?!1:lt.test(r)}async removeObject(r,e,t,s){let n=this.persistence.buckets[r].objects[e];if(!n)return;let o=j.join(this.localStoragePath,r,n.currentKey);try{let c=await ot(o);c.isFile()&&await nt(o),delete this.persistence.buckets[r].objects[e],setTimeout(async()=>{try{await A(this.callableLambdas,{bucket:r,key:e,requestId:s,requestCmd:"DeleteObject",eTag:n.ETag,sourceIPAddress:t,size:c.size})}catch{}},30)}catch{}}},m=class{constructor(r,e){this.localService=e;this.requestId=r["amz-sdk-invocation-id"]??xe(),Object.keys(r).filter(s=>s.startsWith("x-amz-meta-")).forEach(s=>this.metadata[s]=r[s])}requestId;metadata={};isValidStorageClass(r,e){return ct.includes(r)?!0:(e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<Error><Code>InvalidStorageClass</Code><Message>The storage class you specified is not valid</Message><StorageClassRequested>${r}</StorageClassRequested><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!1)}hasNot(r,e){if(!b.isValidBucketName(r)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
7
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(Re({Bucket:r,RequestId:this.requestId})),!0}};import{statSync as pt}from"node:fs";import mt from"node:path";var qe=i=>{let r=typeof i=="string"?i:".exlo/s3/";r=mt.resolve(r),r.endsWith("/")||(r+="/");try{if(pt(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 es}from"node:http";import{rm as gt}from"node:fs/promises";import ht from"node:path";var D=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){if(this.hasNot(this.bucket,e))return;let t=Object.keys(this.localService.persistence.buckets[this.bucket].objects).length>0;if(!this.localService.allowToDeleteNonEmptyBuckets&&t){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).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 gt(ht.join(this.localService.localStoragePath,this.bucket),{recursive:!0,force:!0,maxRetries:1})}catch{}e.writeHead(204,{"x-amzn-requestid":this.requestId,Server:"AmazonS3"}).end()}};var
|
|
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 ft(n.filePath)}catch{}},100)}};var oe=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];t.policy=void 0,e.statusCode=204,e.end()}};var bt=new Set(["rm","rb.rm","mv","delete-object"]),Me=(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 oe(s,t,r):new I(s,t,r);if(s.searchParams.has("tagging"))return n?new se(s,t,r):new re(s,t,r);if(s.searchParams.has("uploadId")&&!n)return new ne(s,t,r);let o=t["user-agent"];if(o?.startsWith("aws-cli")){let[,c]=o.split("command/"),[,...a]=c.split("."),d=a.join(".");if(bt.has(d))return new
|
|
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 gt(ht.join(this.localService.localStoragePath,this.bucket),{recursive:!0,force:!0,maxRetries:1})}catch{}e.writeHead(204,{"x-amzn-requestid":this.requestId,Server:"AmazonS3"}).end()}};var O=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.version=e.searchParams.get("versionId")}bucket;key;version;async exec(e,t){if(this.hasNot(this.bucket,e))return;e.statusCode=204,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3");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 I=class extends m{constructor(e,t,s){super(t,s);this.localService=s}exec(e){e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<Error><Code>UnknownOperation</Code><Message>Your request is currently not supported.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}};var se=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{this.localService.persistence.buckets[this.bucket].tags=void 0,e.setHeader("x-amzn-requestid",this.requestId),e.statusCode=204,e.end()}catch(t){if(e.statusCode=400,t instanceof 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 re=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("/")}bucket;key;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{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(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?.())}}}};import{unlink as ft}from"node:fs/promises";var ne=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.uploadId=e.searchParams.get("uploadId")??"invalid"}bucket;key;uploadId;async exec(e,t){if(this.hasNot(this.bucket,e))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"),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"),e.end(),s.completed||setTimeout(async()=>{for(let n of s.parts)try{await ft(n.filePath)}catch{}},100)}};var oe=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];t.policy=void 0,e.statusCode=204,e.end()}};var bt=new Set(["rm","rb.rm","mv","delete-object"]),Me=(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 oe(s,t,r):new I(s,t,r);if(s.searchParams.has("tagging"))return n?new se(s,t,r):new re(s,t,r);if(s.searchParams.has("uploadId")&&!n)return new ne(s,t,r);let o=t["user-agent"];if(o?.startsWith("aws-cli")){let[,c]=o.split("command/"),[,...a]=c.split("."),d=a.join(".");if(bt.has(d))return new O(s,t,r);if(d=="rb"||d=="delete-bucket")return new D(s,t,r)}else{let c=s.searchParams.get("x-id");if(!c)return new D(s,t,r);if(c=="DeleteObject")return new O(s,t,r)}return new I(s,t,r)};var ie=class extends m{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){if(this.maxKeys){if(isNaN(this.maxKeys))return e.statusCode=400,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
10
10
|
<Error><Code>InvalidArgument</Code><Message>Provided max-keys not an integer or within integer range</Message><ArgumentName>max-keys</ArgumentName><ArgumentValue>${this.maxKeys}</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`),!0;if(this.maxKeys=Number(this.maxKeys),this.maxKeys<0||this.maxKeys>2147483647)return e.statusCode=400,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
11
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}}},q=class extends ie{constructor(e,t,s){super(e,t,s);this.localService=s;this.marker=e.searchParams.get("marker")}marker;exec(e){if(this.hasNot(this.bucket,e)||this.isInvalidMaxKeys(e))return;let t=!1,s="",n="",o=[],c="",a=this.getKeys();if(this.marker){a=a.filter(g=>g.localeCompare(this.marker)>0);let p=a.findIndex(g=>g.startsWith(this.marker));p>-1&&(a=a.slice(p+1))}let d=Number(this.maxKeys),u=a.length;u>d&&(t=!0,a=a.slice(0,d),u>a.length&&(s=a[a.length-1])),this.delimiter&&(n=`<Delimiter>${this.delimiter}</Delimiter>`,o=$(this.prefix??"",this.delimiter,a),this.marker&&(o=o.filter(p=>p!=this.marker))),o.length&&(a=a.filter(p=>!o.some(g=>p.startsWith(g))),c=o.map(p=>`<CommonPrefixes><Prefix>${p}</Prefix></CommonPrefixes>`).join("")),this.marker&&t&&!a.length&&o.length&&(s=o[0]),e.statusCode=200,e.setHeader("Server","AmazonS3"),e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId);let l=a.map(p=>{let g=this.localService.persistence.buckets[this.bucket].objects[p];return`<Contents>
|
|
12
12
|
<Key>${p}</Key>
|
|
@@ -44,7 +44,7 @@ import{S3 as ss}from"@aws-sdk/client-s3";import{randomUUID as xe}from"node:crypt
|
|
|
44
44
|
${this.continuationToken?`<ContinuationToken>${this.continuationToken}</ContinuationToken>`:""}
|
|
45
45
|
${!this.continuationToken&&this.startAfter?`<StartAfter>${this.startAfter}</StartAfter>`:""}
|
|
46
46
|
${g}
|
|
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"?>
|
|
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 K=({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=K(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
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 ce=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.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){if(this.hasNot(this.bucket,e))return;let t=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId??""];if(!this.uploadId||!t||t.aborted||t.completed){e.statusCode=404,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"?>
|
|
49
49
|
<Error><Code>NoSuchUpload</Code><UploadId>${this.uploadId}</UploadId><Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let s=Number(this.partNumberMarker);if(this.hasPartNumberMarker&&(!this.partNumberMarker||isNaN(s)||this.partNumberMarker.includes(".")||s<0||s>2147483647)){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"?>
|
|
50
50
|
<Error><Code>InvalidArgument</Code><ArgumentName>part-number-marker</ArgumentName><ArgumentValue>${this.partNumberMarker}</ArgumentValue><Message>Argument part-number-marker must be an integer between 0 and 2147483647</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let n=Number(this.maxParts);if(!this.maxParts||isNaN(n)||this.maxParts.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"),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -74,24 +74,24 @@ import{S3 as ss}from"@aws-sdk/client-s3";import{randomUUID as xe}from"node:crypt
|
|
|
74
74
|
<Error><Code>InvalidArgument</Code><ArgumentName>max-uploads</ArgumentName><ArgumentValue>${this.maxUploads}</ArgumentValue><Message>Provided max-uploads not an integer or within integer range</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(t<0||t>2147483647){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"?>
|
|
75
75
|
<Error><Code>InvalidArgument</Code><ArgumentName>max-uploads</ArgumentName><ArgumentValue>${this.maxUploads}</ArgumentValue><Message>Argument max-uploads must be an integer between 0 and 2147483647</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}}if(this.hasEncodingType&&this.encodingType.toLowerCase()!="url"){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
76
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 k({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="",c=this.localService.persistence.buckets[this.bucket].multipartUploads;if(c){e=Object.values(c).filter(u=>!u.aborted&&!u.completed),this.prefix&&(e=e.filter(u=>u.key.startsWith(this.prefix)));let a=this.collectUploads(e);if(a instanceof k)return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o,error:a};let d=a.length;e=a.slice(0,Number(this.maxUploads)),t=d-e.length>0,this.delimiter&&(s=$(this.prefix??"",this.delimiter,e.map(u=>u.key)),e=e.filter(u=>!s.some(l=>u.key.startsWith(l))))}if(e.length){let a=e[e.length-1];n=a.key,o=a.uploadId}return{uploads:e,isTruncated:t,commonPrefixes:s,nextKeyMarker:n,nextUploadIdMarker:o}}async exec(e){if(this.hasNot(this.bucket,e)||!this.validateRequest(e))return;let{uploads:s,isTruncated:n,commonPrefixes:o,nextKeyMarker:c,nextUploadIdMarker:a,error:d}=this.getUploads();if(d){e.statusCode=400,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.setHeader("Server","AmazonS3"),e.end(d.toXml());return}let u=`<?xml version="1.0" encoding="UTF-8"?>
|
|
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"?>
|
|
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=K(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"?>
|
|
78
78
|
<InitiateMultipartUploadResult>
|
|
79
79
|
<Bucket>${this.bucket}</Bucket>
|
|
80
80
|
<Key>${this.key}</Key>
|
|
81
81
|
<UploadId>${d}</UploadId>
|
|
82
|
-
</InitiateMultipartUploadResult>`)}};import je from"path";import{readFile as $t,appendFile as Bt,stat as jt,rm as Dt}from"fs/promises";import{mkdirSync as
|
|
82
|
+
</InitiateMultipartUploadResult>`)}};import je from"path";import{readFile as $t,appendFile as Bt,stat as jt,rm as Dt}from"fs/promises";import{mkdirSync as Ot}from"fs";var Oe=5242880,Kt=({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>`,De=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>`,Vt=(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>`,Ft=({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>`,_t=({ProposedSize:i,ETag:r,PartNumber:e,requestId:t})=>`<Error><Code>EntityTooSmall</Code><ProposedSize>${i}</ProposedSize><MinSizeAllowed>${Oe}</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 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.uploadId=e.searchParams.get("uploadId")}bucket;key;uploadId;validateRequest(e){if(this.hasNot(this.bucket,e))return;if(!this.uploadId){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"?>
|
|
83
83
|
<Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>partNumber</ArgumentValue><Message>This operation does not accept partNumber without uploadId</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let t=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!t||t.aborted){e.statusCode=404,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"?>
|
|
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=De(this.requestId),n;for(let c=0;c<o.length;c++){let a=o[c];if(typeof a.PartNumber!="number"||typeof a.ETag!="string")return n.hasCompleteMultiPartUploadError=De(this.requestId),n;if(a.PartNumber<1)return n.hasCompleteMultiPartUploadError=Ft({ArgumentName:"PartNumber",ArgumentValue:a.PartNumber,requestId:this.requestId,Message:"PartNumber must be >= 1"}),n;let d=a.ETag.slice(1,-1);if(n.verifiedParts.find(p=>p.partNumber>=a.PartNumber))return n.hasCompleteMultiPartUploadError=Vt(this.requestId,t),n;let l=s.parts.find(p=>a?.PartNumber==p.partNumber&&d==p.eTag);if(!l)return n.hasCompleteMultiPartUploadError=
|
|
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=De(this.requestId),n;for(let c=0;c<o.length;c++){let a=o[c];if(typeof a.PartNumber!="number"||typeof a.ETag!="string")return n.hasCompleteMultiPartUploadError=De(this.requestId),n;if(a.PartNumber<1)return n.hasCompleteMultiPartUploadError=Ft({ArgumentName:"PartNumber",ArgumentValue:a.PartNumber,requestId:this.requestId,Message:"PartNumber must be >= 1"}),n;let d=a.ETag.slice(1,-1);if(n.verifiedParts.find(p=>p.partNumber>=a.PartNumber))return n.hasCompleteMultiPartUploadError=Vt(this.requestId,t),n;let l=s.parts.find(p=>a?.PartNumber==p.partNumber&&d==p.eTag);if(!l)return n.hasCompleteMultiPartUploadError=Kt({uploadId:t,PartNumber:a.PartNumber,ETag:a.ETag,requestId:this.requestId}),n;if(l.size<Oe&&c!=o.length-1)return n.hasCompleteMultiPartUploadError=_t({requestId:this.requestId,PartNumber:l.partNumber,ETag:l.eTag,ProposedSize:l.size}),n;n.verifiedParts.push(l)}return n}async safeCreateObject(e){let t=je.join(this.localService.localStoragePath,this.bucket,e.data.currentKey);try{Ot(je.dirname(t),{recursive:!0})}catch{}return{filePath:t}}async exec(e,t){let s=this.validateRequest(e);if(!s)return;let{uploadId:n}=s,o=this.localService.persistence.buckets[this.bucket].multipartUploads[n],c=await this.getRequestBody(t);e.writeHead(200,["x-amzn-requestid",this.requestId,"Server","AmazonS3"]);function a(){e.writable&&(e.write(""),setTimeout(a,1e3))}a();let{hasCompleteMultiPartUploadError:d,verifiedParts:u}=await this.verifyCompleteMultiPartUploadParts(c,n,o);if(d){e.end(d);return}let l=u.map(S=>S.eTag).join(""),{filePath:p}=await this.safeCreateObject(o);for(let S of u){let H=await $t(S.filePath,{flag:"r"});await Bt(p,H)}let h=`"${R(Buffer.from(l,"hex"))}-${u.length}"`,y=await jt(p),C=u.map((S,H)=>({...S,partNumber:H+1})).sort((S,H)=>S.partNumber-H.partNumber),Se=o.parts.map(S=>S.filePath);o.parts=C,o.completed=!0,this.localService.persistence.buckets[this.bucket].objects[this.key]={...o.data,ETag:h,size:y.size,LastModified:y.mtimeMs},e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
85
85
|
<CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
86
86
|
<Location>http://127.0.0.1:${this.localService.port}/${this.bucket}/${encodeURIComponent(this.key)}</Location>
|
|
87
87
|
<Bucket>${this.bucket}</Bucket>
|
|
88
88
|
<Key>${this.key}</Key>
|
|
89
89
|
<ETag>${h}</ETag>
|
|
90
|
-
</CompleteMultipartUploadResult>`),setTimeout(async()=>{for(let S of Se)try{await Dt(S,{maxRetries:5,force:!0,retryDelay:200})}catch{}},100)}};var
|
|
90
|
+
</CompleteMultipartUploadResult>`),setTimeout(async()=>{for(let S of Se)try{await Dt(S,{maxRetries:5,force:!0,retryDelay:200})}catch{}},100)}};var Ke=(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 he(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 I(s,t,r)};var X=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(!b.isValidBucketName(this.bucket)){e.writeHead(400,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
91
91
|
<Error><Code>InvalidBucketName</Code><Message>The specified bucket is not valid.</Message><BucketName>${this.bucket}</BucketName><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(this.localService.persistence.buckets[this.bucket]){e.statusCode=409,e.setHeader("Content-Type","application/xml"),e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Server","AmazonS3"),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 Xt,readFile as Gt,stat as Wt}from"node:fs/promises";import Ve from"node:path";var z=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"];let c=t["x-amz-storage-class"];c&&(this.storageClass=c);let a=new Date(t.expires);isNaN(a)||(this.expires=a.getTime()),this.metadataDirective=t["x-amz-metadata-directive"];let d=t["x-amz-copy-source"]??"",[u,...l]=decodeURIComponent(d).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"),e.end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>InvalidArgument</Code><Message>Invalid copy source object key</Message><ArgumentName>x-amz-copy-source</ArgumentName><ArgumentValue>x-amz-copy-source</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(this.hasNot(this.bucket,e)||this.hasNot(this.sourceBucket,e)||!this.isValidStorageClass(this.storageClass,e))return;if(!this.localService.persistence.buckets[this.sourceBucket].objects[this.sourceKey]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(x({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"),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=
|
|
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 Xt,readFile as Gt,stat as Wt}from"node:fs/promises";import Ve from"node:path";var z=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"];let c=t["x-amz-storage-class"];c&&(this.storageClass=c);let a=new Date(t.expires);isNaN(a)||(this.expires=a.getTime()),this.metadataDirective=t["x-amz-metadata-directive"];let d=t["x-amz-copy-source"]??"",[u,...l]=decodeURIComponent(d).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"),e.end(`<?xml version="1.0" encoding="UTF-8"?><Error><Code>InvalidArgument</Code><Message>Invalid copy source object key</Message><ArgumentName>x-amz-copy-source</ArgumentName><ArgumentValue>x-amz-copy-source</ArgumentValue><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}if(this.hasNot(this.bucket,e)||this.hasNot(this.sourceBucket,e)||!this.isValidStorageClass(this.storageClass,e))return;if(!this.localService.persistence.buckets[this.sourceBucket].objects[this.sourceKey]){e.writeHead(404,{"x-amzn-requestid":this.requestId,"Content-Type":"application/xml",Server:"AmazonS3"}).end(x({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"),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=K(n,s);if(o!==200){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>`);return}let c=Ve.join(this.localService.localStoragePath,this.sourceBucket,s.currentKey),a=b.genLocalKey(this.bucket,this.key),d=Ve.join(this.localService.localStoragePath,this.bucket,a);try{await Xt(c,d);let u=await Wt(d),l=fe(await Gt(d));this.metadataDirective=="COPY"?this.localService.persistence.buckets[this.bucket].objects[this.key]={currentKey:a,type:s.type,cacheControl:s.cacheControl,contentDisposition:s.contentDisposition,contentEncoding:s.contentEncoding,contentLanguage:s.contentLanguage,expires:s.expires,ETag:l,StorageClass:s.StorageClass,LastModified:u.mtimeMs,size:u.size,metadata:s.metadata,versions:{[a]:{}}}: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,ETag:l,StorageClass:this.storageClass,LastModified:u.mtimeMs,size:u.size,metadata:this.metadata,websiteRedirectLocation:this.websiteRedirectLocation,versions:{[a]:{}}};let p=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"),e.end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
93
93
|
<CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LastModified>${p}</LastModified><ETag>${l}</ETag></CopyObjectResult>`);let g=t.socket.remoteAddress?.split(":")?.[3]??"127.0.0.1";await A(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 G=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,t){if(!this.hasNot(this.bucket,e))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 f){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(f.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}};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("/")}bucket;key;async exec(e,t){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),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 f){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(f.genericError({Code:"UnknownError",Message:s.message,RequestId:this.requestId}));return}e.end(s?.toString?.())}}}};var J=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 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))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"}).end(`<?xml version="1.0" encoding="UTF-8"?>
|
|
94
94
|
<Error><Code>MalformedPolicy</Code><Message>Policies must be valid JSON</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`)}}};var Y=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,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new N("PutBucketCors",this.requestId).toXml()))}};var Q=class i extends m{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))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"),e.end(new T(this.requestId).toXml())}}};var Z=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,t){this.hasNot(this.bucket,e)||(e.statusCode=500,e.setHeader("x-amzn-requestid",this.requestId),e.setHeader("Content-Type","application/xml"),e.end(new N("PutObjectAcl",this.requestId).toXml()))}};import{createWriteStream as Jt,mkdirSync as Yt,readFileSync as Qt,statSync as Zt}from"node:fs";import Fe from"node:path";var Ie=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.uploadId=e.searchParams.get("uploadId"),e.searchParams.has("partNumber")&&(this.partNumber=e.searchParams.get("partNumber")??"")}bucket;key;uploadId;partNumber="";validateRequest(e){if(this.hasNot(this.bucket,e))return;if(!this.uploadId){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"?>
|
|
95
95
|
<Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>partNumber</ArgumentValue><Message>This operation does not accept partNumber without uploadId</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let t=Number(this.partNumber);if(!this.partNumber||isNaN(t)||this.partNumber.includes(".")||t<1||t>1e4){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"?>
|
|
96
96
|
<Error><Code>InvalidArgument</Code><ArgumentName>partNumber</ArgumentName><ArgumentValue>${this.partNumber}</ArgumentValue><Message>Part number must be an integer between 1 and 10000, inclusive</Message><RequestId>${this.requestId}</RequestId><HostId>local</HostId></Error>`);return}let s=this.localService.persistence.buckets[this.bucket].multipartUploads[this.uploadId];if(!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"),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:t,uploadId:this.uploadId}}async exec(e,t){let s=this.validateRequest(e);if(!s)return;let{partNumber:n,uploadId:o}=s,c=this.localService.persistence.buckets[this.bucket].multipartUploads[o],a=b.genLocalKey(this.bucket,this.key,`${o}-${n}`),d=Fe.join(this.localService.localStoragePath,this.bucket,a);try{Yt(Fe.dirname(d),{recursive:!0})}catch{}let u=Jt(d,{flush:!0});u.on("finish",async()=>{try{let l=R(Qt(d)),p=c.parts.find(h=>h.partNumber==n),g=Zt(d);p?(p.eTag=l,p.size=g.size,p.lastModified=g.mtime.toISOString()):c.parts.push({filePath:d,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"),e.setHeader("x-amzn-requestid",this.requestId),t.pipe(u)}};var _e=(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[,c]=n.split("command/"),[,...a]=c.split(".");switch(a.join(".")){case"cp":case"sync":case"mv":return o?new z(s,t,r):new w(s,t,r);case"mb":case"create-bucket":return new X(s,t,r);case"copy-object":return new z(s,t,r);case"put-object":return new w(s,t,r);case"put-bucket-tagging":return new G(s,t,r);case"put-object-tagging":return new W(s,t,r);case"put-bucket-policy":return new J(s,t,r);case"put-bucket-cors":return new Y(s,t,r);case"put-bucket-acl":return new Q(s,t,r);case"put-object-acl":return new Z(s,t,r);default:break}}else{let c=s.pathname.split("/").filter(Boolean).length==1;return!c&&s.searchParams.has("partNumber")&&s.searchParams.has("uploadId")?o?new I(s,t,r):new Ie(s,t,r):s.searchParams.has("policy")?c?new J(s,t,r):new I(s,t,r):s.searchParams.has("cors")?c?new Y(s,t,r):new I(s,t,r):s.searchParams.has("acl")?c?new Q(s,t,r):new Z(s,t,r):s.searchParams.has("tagging")?c?new G(s,t,r):new W(s,t,r):o?c?new I(s,t,r):new z(s,t,r):c?new X(s,t,r):new w(s,t,r)}return new I(s,t,r)};var ts=async(i,r,e)=>{switch(i.method){case"HEAD":await Ne(i,e).exec(r);break;case"GET":await Te(i,e).exec(r);break;case"PUT":await _e(i,e).exec(r,i);break;case"DELETE":await Me(i,e).exec(r,i);break;case"POST":await
|
|
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:t,uploadId:this.uploadId}}async exec(e,t){let s=this.validateRequest(e);if(!s)return;let{partNumber:n,uploadId:o}=s,c=this.localService.persistence.buckets[this.bucket].multipartUploads[o],a=b.genLocalKey(this.bucket,this.key,`${o}-${n}`),d=Fe.join(this.localService.localStoragePath,this.bucket,a);try{Yt(Fe.dirname(d),{recursive:!0})}catch{}let u=Jt(d,{flush:!0});u.on("finish",async()=>{try{let l=R(Qt(d)),p=c.parts.find(h=>h.partNumber==n),g=Zt(d);p?(p.eTag=l,p.size=g.size,p.lastModified=g.mtime.toISOString()):c.parts.push({filePath:d,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"),e.setHeader("x-amzn-requestid",this.requestId),t.pipe(u)}};var _e=(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[,c]=n.split("command/"),[,...a]=c.split(".");switch(a.join(".")){case"cp":case"sync":case"mv":return o?new z(s,t,r):new w(s,t,r);case"mb":case"create-bucket":return new X(s,t,r);case"copy-object":return new z(s,t,r);case"put-object":return new w(s,t,r);case"put-bucket-tagging":return new G(s,t,r);case"put-object-tagging":return new W(s,t,r);case"put-bucket-policy":return new J(s,t,r);case"put-bucket-cors":return new Y(s,t,r);case"put-bucket-acl":return new Q(s,t,r);case"put-object-acl":return new Z(s,t,r);default:break}}else{let c=s.pathname.split("/").filter(Boolean).length==1;return!c&&s.searchParams.has("partNumber")&&s.searchParams.has("uploadId")?o?new I(s,t,r):new Ie(s,t,r):s.searchParams.has("policy")?c?new J(s,t,r):new I(s,t,r):s.searchParams.has("cors")?c?new Y(s,t,r):new I(s,t,r):s.searchParams.has("acl")?c?new Q(s,t,r):new Z(s,t,r):s.searchParams.has("tagging")?c?new G(s,t,r):new W(s,t,r):o?c?new I(s,t,r):new z(s,t,r):c?new X(s,t,r):new w(s,t,r)}return new I(s,t,r)};var ts=async(i,r,e)=>{switch(i.method){case"HEAD":await Ne(i,e).exec(r);break;case"GET":await Te(i,e).exec(r);break;case"PUT":await _e(i,e).exec(r,i);break;case"DELETE":await Me(i,e).exec(r,i);break;case"POST":await Ke(i,e).exec(r,i);break;case"OPTIONS":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"}),r.end();break;default:break}},Xe=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=es((c,a)=>{ts(c,a,e)}),n=async()=>{let c=s.address();c&&typeof c=="object"&&(e.port=c.port),t({server:s,localService:e})},o=[r.port];r.hostname&&o.push(r.hostname),o.push(n),s.listen(...o)})};var Ge=[],Jo=i=>{let r=qe(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:c,server:a}=await Xe({accountId:n,region:o,...e});t=c,typeof e.allowToDeleteNonEmptyBuckets=="boolean"&&(t.allowToDeleteNonEmptyBuckets=e.allowToDeleteNonEmptyBuckets),s=a,s.unref(),Ge=[],t.callableLambdas=Ge;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 ss({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{Jo as s3Plugin};
|