@nextlyhq/storage-s3 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts","../src/plugin.ts","../src/index.ts"],"names":["S3Client","Upload","DeleteObjectCommand","DeleteObjectsCommand","HeadObjectCommand","GetObjectCommand","getSignedUrl","PutObjectCommand"],"mappings":";;;;;;;AAsFO,IAAM,mBAAN,MAAkD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWvD,YAAoB,MAAA,EAAyB;AAAzB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAElB,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAAA,IAC1D;AACA,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAAA,IAC1D;AAGA,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA,CAAO,QAAA,EAAU,QAAA,CAAS,0BAA0B,CAAA,IAAK,KAAA;AAGrE,IAAA,IAAA,CAAK,cAAA,GAAiB;AAAA,MACpB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,cAAA,EAAgB,OAAO,cAAA,IAAkB,KAAA;AAAA,MACzC,GAAA,EAAK,OAAO,GAAA,IAAO,SAAA;AAAA,MACnB,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,YAAA,EAAc,OAAO,YAAA,IAAgB,0BAAA;AAAA,MACrC,oBAAoB,MAAA,CAAO,kBAAA;AAAA,MAC3B,kBAAA,EAAoB,OAAO,kBAAA,IAAsB;AAAA,KACnD;AAGA,IAAA,MAAM,WAAA,GAAc,KAAK,gBAAA,EAAiB;AAG1C,IAAA,IAAA,CAAK,MAAA,GAAS,IAAIA,iBAAA,CAAS;AAAA,MACzB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,WAAA;AAAA,MACA,cAAA,EAAgB,KAAK,cAAA,CAAe,cAAA;AAAA,MACpC,GAAG,MAAA,CAAO;AAAA,KACX,CAAA;AAAA,EACH;AAAA,EA9CQ,MAAA;AAAA,EACA,cAAA;AAAA,EACA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkDA,gBAAA,GAEM;AACZ,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,WAAA,IAAe,IAAA,CAAK,OAAO,eAAA,EAAiB;AAC1D,MAAA,OAAO;AAAA,QACL,WAAA,EAAa,KAAK,MAAA,CAAO,WAAA;AAAA,QACzB,eAAA,EAAiB,KAAK,MAAA,CAAO;AAAA,OAC/B;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,WAAA,EAAa;AACnC,MAAA,OAAO,MAAA;AAAA,IACT;AAGA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,MAAA,CAAO,MAAA,EAAgB,OAAA,EAA+C;AAC1E,IAAA,MAAM,MAAM,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,QAAA,EAAU,QAAQ,MAAM,CAAA;AAG7D,IAAA,MAAM,YAAA,GAAsC;AAAA,MAC1C,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,MAC5B,GAAA,EAAK,GAAA;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,WAAA,EAAa,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAA;AAAA,MAC5C,YAAA,EAAc,KAAK,cAAA,CAAe;AAAA,KACpC;AAGA,IAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,MAAA,YAAA,CAAa,GAAA,GAAM,KAAK,cAAA,CAAe,GAAA;AAAA,IACzC;AAGA,IAAA,MAAM,WAAA,GACJ,OAAA,CAAQ,kBAAA,IAAsB,IAAA,CAAK,cAAA,CAAe,kBAAA;AACpD,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,OAAA,CAAQ,QAAQ,CAAA;AACvD,MAAA,YAAA,CAAa,kBAAA,GACX,WAAA,KAAgB,YAAA,GACZ,CAAA,sBAAA,EAAyB,QAAQ,CAAA,CAAA,CAAA,GACjC,QAAA;AAAA,IACR;AAGA,IAAA,YAAA,CAAa,QAAA,GAAW;AAAA,MACtB,qBAAqB,OAAA,CAAQ;AAAA,KAC/B;AAGA,IAAA,MAAM,MAAA,GAAS,IAAIC,iBAAA,CAAO;AAAA,MACxB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,OAAO,IAAA,EAAK;AAElB,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,IAAA,CAAK,YAAA,CAAa,GAAG,CAAA;AAAA,MAC1B,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,QAAA,EAAiC;AAC5C,IAAA,MAAM,OAAA,GAAU,IAAIC,4BAAA,CAAoB;AAAA,MACtC,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,MAC5B,GAAA,EAAK;AAAA,KACN,CAAA;AAED,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,WAAW,SAAA,EAAgD;AAC/D,IAAA,MAAM,aAAuB,EAAC;AAC9B,IAAA,MAAM,SAAqD,EAAC;AAC5D,IAAA,MAAM,YAAA,GAAe,GAAA;AAErB,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,MAAA,EAAQ,KAAK,YAAA,EAAc;AACvD,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,IAAI,YAAY,CAAA;AACjD,MAAA,MAAM,OAAA,GAAU,IAAIC,6BAAA,CAAqB;AAAA,QACvC,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,QAC5B,MAAA,EAAQ;AAAA,UACN,SAAS,KAAA,CAAM,GAAA,CAAI,UAAQ,EAAE,GAAA,EAAK,KAAI,CAAE,CAAA;AAAA,UACxC,KAAA,EAAO;AAAA;AACT,OACD,CAAA;AAED,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,OAAO,CAAA;AAE/C,MAAA,IAAI,QAAA,CAAS,MAAA,IAAU,QAAA,CAAS,MAAA,CAAO,SAAS,CAAA,EAAG;AACjD,QAAA,KAAA,MAAW,GAAA,IAAO,SAAS,MAAA,EAAQ;AACjC,UAAA,IAAI,IAAI,GAAA,EAAK;AACX,YAAA,MAAA,CAAO,IAAA,CAAK;AAAA,cACV,UAAU,GAAA,CAAI,GAAA;AAAA,cACd,KAAA,EAAO,IAAI,OAAA,IAAW;AAAA,aACvB,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,OAAA,EAAS;AACpB,QAAA,KAAA,MAAW,GAAA,IAAO,SAAS,OAAA,EAAS;AAClC,UAAA,IAAI,IAAI,GAAA,EAAK;AACX,YAAA,UAAA,CAAW,IAAA,CAAK,IAAI,GAAG,CAAA;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,YAAY,MAAA,EAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,OAAO,QAAA,EAAoC;AAC/C,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,IAAIC,0BAAA,CAAkB;AAAA,QACpC,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,QAC5B,GAAA,EAAK;AAAA,OACN,CAAA;AAED,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAC9B,MAAA,OAAO,IAAA;AAAA,IACT,SAAS,KAAA,EAAgB;AAEvB,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,KAAK,CAAA,EAAG;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,aAAa,QAAA,EAA0B;AAErC,IAAA,IAAI,IAAA,CAAK,eAAe,SAAA,EAAW;AACjC,MAAA,MAAM,UAAU,IAAA,CAAK,cAAA,CAAe,SAAA,CAAU,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC/D,MAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAAA,IAC/B;AAGA,IAAA,IAAI,KAAK,IAAA,EAAM;AACb,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OAKF;AAAA,IACF;AAIA,IAAA,OAAO,CAAA,QAAA,EAAW,KAAK,cAAA,CAAe,MAAM,OAAO,IAAA,CAAK,cAAA,CAAe,MAAM,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA;AAAA,EACzG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAA,GAAgB;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAA,GAA8B;AAC5B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,IAAA;AAAA,MACN,IAAA,EAAM,kBAAA;AAAA,MACN,kBAAA,EAAoB,IAAA;AAAA,MACpB,qBAAA,EAAuB;AAAA,KACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,YAAY,QAAA,EAAgD;AAChE,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,IAAIA,0BAAA,CAAkB;AAAA,QACpC,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,QAC5B,GAAA,EAAK;AAAA,OACN,CAAA;AAED,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,OAAO,CAAA;AAC/C,MAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK,QAAA;AAE9C,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,QAAA;AAAA,QACJ,QAAA;AAAA,QACA,gBAAA,EAAkB,QAAA,CAAS,QAAA,GAAW,mBAAmB,CAAA,IAAK,QAAA;AAAA,QAC9D,QAAA,EAAU,SAAS,WAAA,IAAe,0BAAA;AAAA,QAClC,IAAA,EAAM,SAAS,aAAA,IAAiB,CAAA;AAAA,QAChC,GAAA,EAAK,IAAA,CAAK,YAAA,CAAa,QAAQ,CAAA;AAAA,QAC/B,SAAA,EACE,SAAS,YAAA,EAAc,WAAA,uBAAiB,IAAI,IAAA,IAAO,WAAA;AAAY,OACnE;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,KAAK,CAAA,EAAG;AAC/B,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,YAAA,CAAa,QAAA,EAAkB,SAAA,EAAqC;AACxE,IAAA,MAAM,OAAA,GAAU,IAAIC,yBAAA,CAAiB;AAAA,MACnC,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,MAC5B,GAAA,EAAK;AAAA,KACN,CAAA;AAED,IAAA,OAAOC,+BAAA,CAAa,IAAA,CAAK,MAAA,EAAQ,OAAA,EAAS;AAAA,MACxC,SAAA,EAAW,SAAA,IAAa,IAAA,CAAK,cAAA,CAAe;AAAA,KAC7C,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,qBAAA,CACJ,GAAA,EACA,QAAA,EACA,SAAA,EAC2B;AAC3B,IAAA,MAAM,UAAA,GAAa,SAAA,IAAa,IAAA,CAAK,cAAA,CAAe,kBAAA;AAGpD,IAAA,MAAM,aAAA,GAAuC;AAAA,MAC3C,MAAA,EAAQ,KAAK,cAAA,CAAe,MAAA;AAAA,MAC5B,GAAA,EAAK,GAAA;AAAA,MACL,WAAA,EAAa,QAAA;AAAA,MACb,YAAA,EAAc,KAAK,cAAA,CAAe;AAAA,KACpC;AAGA,IAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,MAAA,aAAA,CAAc,GAAA,GAAM,KAAK,cAAA,CAAe,GAAA;AAAA,IAC1C;AAEA,IAAA,MAAM,OAAA,GAAU,IAAIC,yBAAA,CAAiB,aAAa,CAAA;AAElD,IAAA,MAAM,SAAA,GAAY,MAAMD,+BAAA,CAAa,IAAA,CAAK,QAAQ,OAAA,EAAS;AAAA,MACzD,SAAA,EAAW;AAAA,KACZ,CAAA;AAED,IAAA,OAAO;AAAA,MACL,SAAA;AAAA,MACA,IAAA,EAAM,GAAA;AAAA,MACN,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,WAAW,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,aAAa,GAAI;AAAA,KACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,WAAA,CAAY,UAAkB,MAAA,EAAyB;AAC7D,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAChD,IAAA,MAAM,IAAA,GAAO,OAAO,UAAA,EAAW;AAC/B,IAAA,MAAM,IAAA,uBAAW,IAAA,EAAK;AACtB,IAAA,MAAM,IAAA,GAAO,KAAK,WAAA,EAAY;AAC9B,IAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,CAAK,QAAA,KAAa,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAEzD,IAAA,MAAM,MAAA,GAAS,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAEvE,IAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,IAAI,SAAS,CAAA,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBAAiB,QAAA,EAA0B;AACjD,IAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA,CAAE,KAAI,IAAK,QAAA;AAClD,IAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,kBAAA,EAAoB,GAAG,CAAA;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,gBAAgB,KAAA,EAAyB;AAC/C,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,MAAA,MAAM,CAAA,GAAI,KAAA;AAIV,MAAA,OAAO,CAAA,CAAE,IAAA,KAAS,UAAA,IAAc,CAAA,CAAE,WAAW,cAAA,KAAmB,GAAA;AAAA,IAClE;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAA,GAAsB;AACpB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,GAAoB;AAClB,IAAA,OAAO,KAAK,cAAA,CAAe,MAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,GAAoB;AAClB,IAAA,OAAO,KAAK,cAAA,CAAe,MAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,GAA0B;AACxB,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AACF;;;AC/dO,SAAS,UAAU,MAAA,EAAwC;AAIhE,EAAA,IAAI,MAAA,CAAO,YAAY,KAAA,EAAO;AAC5B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA;AAAA,MACN,IAAA,EAAM,IAAA;AAAA,MACN,aAAa,EAAC;AAAA,MACd,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAIA,EAAA,MAAM,OAAA,GAAU,IAAI,gBAAA,CAAiB,MAAM,CAAA;AAG3C,EAAA,MAAM,MAAA,GAAwB;AAAA,IAC5B,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM,IAAA;AAAA,IACN,aAAa,MAAA,CAAO,WAAA;AAAA,IACpB,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAaA,MAAM,kBAAA,CACJ,QAAA,EACA,QAAA,EACA,UAAA,EAC2B;AAE3B,MAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA;AACtD,MAAA,MAAM,MAAA,GACJ,OAAO,gBAAA,KAAqB,QAAA,GACxB,iBAAiB,MAAA,GACjB,MAAA;AAIN,MAAA,MAAM,GAAA,GAAM,kBAAA,CAAmB,QAAA,EAAU,MAAM,CAAA;AAG/C,MAAA,OAAO,OAAA,CAAQ,qBAAA,CAAsB,GAAA,EAAK,QAAQ,CAAA;AAAA,IACpD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYA,MAAM,oBAAA,CACJ,IAAA,EACA,SAAA,EACiB;AACjB,MAAA,OAAO,OAAA,CAAQ,YAAA;AAAA,QACb,IAAA;AAAA,QACA,SAAA,IAAa,OAAO,kBAAA,IAAsB;AAAA,OAC5C;AAAA,IACF;AAAA,GACF;AAEA,EAAA,OAAO,MAAA;AACT;AAgBA,SAAS,kBAAA,CAAmB,UAAkB,MAAA,EAAyB;AACrE,EAAA,MAAM,SAAA,GAAY,iBAAiB,QAAQ,CAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,OAAO,UAAA,EAAW;AAC/B,EAAA,MAAM,IAAA,uBAAW,IAAA,EAAK;AACtB,EAAA,MAAM,IAAA,GAAO,KAAK,WAAA,EAAY;AAC9B,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,CAAK,QAAA,KAAa,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAEzD,EAAA,MAAM,SAAA,GAAY,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAEzE,EAAA,OAAO,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,IAAI,IAAI,SAAS,CAAA,CAAA;AAC1C;AAWA,SAAS,iBAAiB,QAAA,EAA0B;AAElD,EAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA,CAAE,KAAI,IAAK,QAAA;AAElD,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,kBAAA,EAAoB,GAAG,CAAA;AACjD;;;AC7HO,IAAM,YAAA,GAAe;AACrB,IAAM,eAAA,GAAkB","file":"index.cjs","sourcesContent":["/**\n * S3 Storage Adapter\n *\n * Stores files on AWS S3 or S3-compatible services (Cloudflare R2, MinIO, DigitalOcean Spaces).\n * Uses AWS SDK v3 with automatic multipart upload for large files (>5MB).\n *\n * Features:\n * - Automatic multipart upload via @aws-sdk/lib-storage\n * - Pre-signed URL generation for client-side uploads\n * - Signed URL generation for private file access\n * - Cloudflare R2 support (S3-compatible API)\n * - Custom endpoint support (MinIO, DigitalOcean Spaces)\n * - CDN URL override support\n * - File metadata retrieval\n *\n * @example AWS S3\n * ```typescript\n * const adapter = new S3StorageAdapter({\n * bucket: 'my-media-bucket',\n * region: 'us-east-1',\n * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n * collections: { media: true }\n * });\n * ```\n *\n * @example Cloudflare R2\n * ```typescript\n * const adapter = new S3StorageAdapter({\n * bucket: 'my-media',\n * region: 'auto',\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * endpoint: `https://${accountId}.r2.cloudflarestorage.com`,\n * publicUrl: 'https://pub-abc.r2.dev',\n * collections: { media: true }\n * });\n * ```\n *\n * @example MinIO (self-hosted)\n * ```typescript\n * const adapter = new S3StorageAdapter({\n * bucket: 'my-bucket',\n * region: 'us-east-1',\n * accessKeyId: process.env.MINIO_ACCESS_KEY!,\n * secretAccessKey: process.env.MINIO_SECRET_KEY!,\n * endpoint: 'http://localhost:9000',\n * forcePathStyle: true,\n * collections: { media: true }\n * });\n * ```\n */\n\nimport {\n S3Client,\n DeleteObjectCommand,\n DeleteObjectsCommand,\n HeadObjectCommand,\n GetObjectCommand,\n PutObjectCommand,\n type PutObjectCommandInput,\n} from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport type {\n IStorageAdapter,\n UploadOptions,\n UploadResult,\n StorageAdapterInfo,\n ClientUploadData,\n FileMetadata,\n BulkDeleteResult,\n} from \"nextly/storage\";\n\nimport type { S3StorageConfig, ResolvedS3Config } from \"./types\";\n\n// ============================================================\n// S3 Storage Adapter\n// ============================================================\n\n/**\n * S3 Storage Adapter\n *\n * Implements the IStorageAdapter interface for AWS S3 and S3-compatible services.\n * Provides full support for uploads, downloads, signed URLs, and client-side uploads.\n */\nexport class S3StorageAdapter implements IStorageAdapter {\n private client: S3Client;\n private resolvedConfig: ResolvedS3Config;\n private isR2: boolean;\n\n /**\n * Create a new S3 storage adapter.\n *\n * @param config - S3 storage configuration\n * @throws Error if bucket or region is not provided\n */\n constructor(private config: S3StorageConfig) {\n // Validate required config\n if (!config.bucket) {\n throw new Error(\"@nextly/storage-s3: bucket is required\");\n }\n if (!config.region) {\n throw new Error(\"@nextly/storage-s3: region is required\");\n }\n\n // Detect if this is Cloudflare R2\n this.isR2 = config.endpoint?.includes(\"r2.cloudflarestorage.com\") ?? false;\n\n // Resolve config with defaults\n this.resolvedConfig = {\n bucket: config.bucket,\n region: config.region,\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle ?? false,\n acl: config.acl ?? \"private\",\n publicUrl: config.publicUrl,\n cacheControl: config.cacheControl ?? \"public, max-age=31536000\",\n contentDisposition: config.contentDisposition,\n signedUrlExpiresIn: config.signedUrlExpiresIn ?? 3600,\n };\n\n // Build credentials\n const credentials = this.buildCredentials();\n\n // Initialize S3 client\n this.client = new S3Client({\n region: config.region,\n endpoint: config.endpoint,\n credentials,\n forcePathStyle: this.resolvedConfig.forcePathStyle,\n ...config.config,\n });\n }\n\n /**\n * Build AWS credentials from config.\n * Supports explicit credentials or falls back to SDK default chain.\n */\n private buildCredentials():\n | { accessKeyId: string; secretAccessKey: string }\n | undefined {\n if (this.config.accessKeyId && this.config.secretAccessKey) {\n return {\n accessKeyId: this.config.accessKeyId,\n secretAccessKey: this.config.secretAccessKey,\n };\n }\n\n // Check if credentials are in the config object\n if (this.config.config?.credentials) {\n return undefined; // Let SDK use the provided config.credentials\n }\n\n // Fall back to SDK default credential chain (env vars, IAM roles, etc.)\n return undefined;\n }\n\n // ============================================================\n // Core IStorageAdapter Methods\n // ============================================================\n\n /**\n * Upload file to S3.\n *\n * Uses AWS SDK v3's Upload class from @aws-sdk/lib-storage which:\n * - Automatically handles multipart upload for large files (>5MB)\n * - Provides progress tracking capability\n * - Includes retry logic\n * - Optimizes upload performance\n *\n * @param buffer - File content as Buffer\n * @param options - Upload options (filename, mimeType, folder, collection)\n * @returns Upload result with URL and storage path\n */\n async upload(buffer: Buffer, options: UploadOptions): Promise<UploadResult> {\n const key = this.generateKey(options.filename, options.folder);\n\n // Build upload parameters\n const uploadParams: PutObjectCommandInput = {\n Bucket: this.resolvedConfig.bucket,\n Key: key,\n Body: buffer,\n ContentType: options.contentType || options.mimeType,\n CacheControl: this.resolvedConfig.cacheControl,\n };\n\n // Add ACL if not R2 (R2 ignores ACL settings)\n if (!this.isR2) {\n uploadParams.ACL = this.resolvedConfig.acl;\n }\n\n // Add Content-Disposition: per-file override takes priority, then global config\n const disposition =\n options.contentDisposition ?? this.resolvedConfig.contentDisposition;\n if (disposition) {\n const filename = this.sanitizeFilename(options.filename);\n uploadParams.ContentDisposition =\n disposition === \"attachment\"\n ? `attachment; filename=\"${filename}\"`\n : \"inline\";\n }\n\n // Store original filename in metadata for later retrieval\n uploadParams.Metadata = {\n \"original-filename\": options.filename,\n };\n\n // Use Upload for automatic multipart handling\n const upload = new Upload({\n client: this.client,\n params: uploadParams,\n });\n\n await upload.done();\n\n return {\n url: this.getPublicUrl(key),\n path: key,\n };\n }\n\n /**\n * Delete file from S3.\n *\n * @param filePath - Storage path/key to delete\n */\n async delete(filePath: string): Promise<void> {\n const command = new DeleteObjectCommand({\n Bucket: this.resolvedConfig.bucket,\n Key: filePath,\n });\n\n await this.client.send(command);\n }\n\n /**\n * Bulk delete files from S3 using a single API call per 1000 keys.\n *\n * Uses AWS SDK v3's DeleteObjectsCommand which supports up to 1000 keys per\n * request. Automatically batches larger arrays and collects per-key results.\n *\n * @param filePaths - Storage paths/keys to delete\n * @returns Object with arrays of successful and failed deletions\n */\n async bulkDelete(filePaths: string[]): Promise<BulkDeleteResult> {\n const successful: string[] = [];\n const failed: Array<{ filePath: string; error: string }> = [];\n const maxBatchSize = 1000; // AWS limit\n\n for (let i = 0; i < filePaths.length; i += maxBatchSize) {\n const batch = filePaths.slice(i, i + maxBatchSize);\n const command = new DeleteObjectsCommand({\n Bucket: this.resolvedConfig.bucket,\n Delete: {\n Objects: batch.map(key => ({ Key: key })),\n Quiet: false,\n },\n });\n\n const response = await this.client.send(command);\n\n if (response.Errors && response.Errors.length > 0) {\n for (const err of response.Errors) {\n if (err.Key) {\n failed.push({\n filePath: err.Key,\n error: err.Message ?? \"Unknown S3 delete error\",\n });\n }\n }\n }\n\n if (response.Deleted) {\n for (const del of response.Deleted) {\n if (del.Key) {\n successful.push(del.Key);\n }\n }\n }\n }\n\n return { successful, failed };\n }\n\n /**\n * Check if file exists in S3.\n *\n * Uses HeadObject command which is more efficient than GetObject\n * for existence checks (doesn't download the file).\n *\n * @param filePath - Storage path/key to check\n * @returns true if file exists, false otherwise\n */\n async exists(filePath: string): Promise<boolean> {\n try {\n const command = new HeadObjectCommand({\n Bucket: this.resolvedConfig.bucket,\n Key: filePath,\n });\n\n await this.client.send(command);\n return true;\n } catch (error: unknown) {\n // HeadObject returns 404 if object doesn't exist\n if (this.isNotFoundError(error)) {\n return false;\n }\n // Re-throw other errors (permissions, network, etc.)\n throw error;\n }\n }\n\n /**\n * Get public URL for S3 file.\n *\n * Priority order:\n * 1. Custom publicUrl (CDN or custom domain) if configured\n * 2. Standard S3 URL based on region and bucket\n *\n * For R2: Requires publicUrl configuration (R2 has no default public URLs).\n *\n * @param filePath - Storage path/key\n * @returns Public URL to access the file\n * @throws Error if R2 is used without publicUrl configuration\n */\n getPublicUrl(filePath: string): string {\n // Use custom CDN/public URL if configured\n if (this.resolvedConfig.publicUrl) {\n const baseUrl = this.resolvedConfig.publicUrl.replace(/\\/$/, \"\");\n return `${baseUrl}/${filePath}`;\n }\n\n // R2 requires custom domain or public bucket URL\n if (this.isR2) {\n throw new Error(\n \"@nextly/storage-s3: Cloudflare R2 requires publicUrl configuration.\\n\\n\" +\n \"R2 does not have default public URLs like AWS S3. Configure one of:\\n\" +\n \"1. Public bucket URL: publicUrl: 'https://pub-xxx.r2.dev'\\n\" +\n \"2. Custom domain: publicUrl: 'https://cdn.example.com'\\n\\n\" +\n \"Set up public access in the Cloudflare R2 dashboard.\"\n );\n }\n\n // Standard S3 URL format\n // https://bucket.s3.region.amazonaws.com/key\n return `https://${this.resolvedConfig.bucket}.s3.${this.resolvedConfig.region}.amazonaws.com/${filePath}`;\n }\n\n /**\n * Get storage type identifier.\n *\n * Returns \"s3\" for all S3-compatible services (AWS S3, R2, MinIO, etc.)\n * as they all use the S3 API.\n */\n getType(): \"s3\" {\n return \"s3\";\n }\n\n // ============================================================\n // Optional IStorageAdapter Methods\n // ============================================================\n\n /**\n * Get adapter info including capabilities.\n *\n * @returns Adapter info with type, name, and capability flags\n */\n getInfo(): StorageAdapterInfo {\n return {\n type: \"s3\",\n name: \"S3StorageAdapter\",\n supportsSignedUrls: true,\n supportsClientUploads: true,\n };\n }\n\n /**\n * Get file metadata from S3.\n *\n * Retrieves file information including size, content type, and timestamps\n * using the HeadObject command.\n *\n * @param filePath - Storage path/key\n * @returns File metadata or null if file not found\n */\n async getMetadata(filePath: string): Promise<FileMetadata | null> {\n try {\n const command = new HeadObjectCommand({\n Bucket: this.resolvedConfig.bucket,\n Key: filePath,\n });\n\n const response = await this.client.send(command);\n const filename = filePath.split(\"/\").pop() || filePath;\n\n return {\n id: filePath,\n filename,\n originalFilename: response.Metadata?.[\"original-filename\"] || filename,\n mimeType: response.ContentType || \"application/octet-stream\",\n size: response.ContentLength || 0,\n url: this.getPublicUrl(filePath),\n createdAt:\n response.LastModified?.toISOString() || new Date().toISOString(),\n };\n } catch (error: unknown) {\n if (this.isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Generate signed URL for temporary private file access.\n *\n * Creates a pre-signed GetObject URL that grants temporary read access\n * to private files. Useful for serving files from private buckets.\n *\n * @param filePath - Storage path/key\n * @param expiresIn - URL validity duration in seconds (default: 3600)\n * @returns Pre-signed URL for downloading the file\n */\n async getSignedUrl(filePath: string, expiresIn?: number): Promise<string> {\n const command = new GetObjectCommand({\n Bucket: this.resolvedConfig.bucket,\n Key: filePath,\n });\n\n return getSignedUrl(this.client, command, {\n expiresIn: expiresIn ?? this.resolvedConfig.signedUrlExpiresIn,\n });\n }\n\n /**\n * Generate pre-signed URL for client-side uploads.\n *\n * Creates a pre-signed PutObject URL that allows direct uploads from\n * the browser to S3, bypassing server-side upload limits (e.g., Vercel's 4.5MB).\n *\n * @param key - Storage path/key for the upload\n * @param mimeType - MIME type of the file being uploaded\n * @param expiresIn - URL validity duration in seconds (default: 3600)\n * @returns Client upload data with URL, method, and headers\n */\n async getPresignedUploadUrl(\n key: string,\n mimeType: string,\n expiresIn?: number\n ): Promise<ClientUploadData> {\n const expiration = expiresIn ?? this.resolvedConfig.signedUrlExpiresIn;\n\n // Build PutObject command parameters\n const commandParams: PutObjectCommandInput = {\n Bucket: this.resolvedConfig.bucket,\n Key: key,\n ContentType: mimeType,\n CacheControl: this.resolvedConfig.cacheControl,\n };\n\n // Add ACL if not R2\n if (!this.isR2) {\n commandParams.ACL = this.resolvedConfig.acl;\n }\n\n const command = new PutObjectCommand(commandParams);\n\n const uploadUrl = await getSignedUrl(this.client, command, {\n expiresIn: expiration,\n });\n\n return {\n uploadUrl,\n path: key,\n method: \"PUT\",\n headers: {\n \"Content-Type\": mimeType,\n },\n expiresAt: new Date(Date.now() + expiration * 1000),\n };\n }\n\n // ============================================================\n // Helper Methods\n // ============================================================\n\n /**\n * Generate a unique storage key with date-based prefix.\n *\n * Creates keys in format: {folder}/{year}/{month}/{uuid}-{sanitized-filename}\n *\n * @param filename - Original filename (will be sanitized)\n * @param folder - Optional folder/prefix for organizing uploads\n * @returns Generated storage key\n */\n private generateKey(filename: string, folder?: string): string {\n const sanitized = this.sanitizeFilename(filename);\n const uuid = crypto.randomUUID();\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n\n const prefix = folder ? `${folder}/${year}/${month}` : `${year}/${month}`;\n\n return `${prefix}/${uuid}-${sanitized}`;\n }\n\n /**\n * Sanitize filename to prevent directory traversal and S3 key issues.\n *\n * @param filename - Original filename\n * @returns Sanitized filename safe for S3 keys\n */\n private sanitizeFilename(filename: string): string {\n const basename = filename.split(/[/\\\\]/).pop() || filename;\n return basename.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n }\n\n /**\n * Check if an error is a \"not found\" error from S3.\n *\n * @param error - Error to check\n * @returns true if error indicates file not found\n */\n private isNotFoundError(error: unknown): boolean {\n if (error && typeof error === \"object\") {\n const e = error as {\n name?: string;\n $metadata?: { httpStatusCode?: number };\n };\n return e.name === \"NotFound\" || e.$metadata?.httpStatusCode === 404;\n }\n return false;\n }\n\n // ============================================================\n // Public Accessors\n // ============================================================\n\n /**\n * Get the S3 client instance.\n * Useful for advanced operations not covered by the adapter interface.\n */\n getClient(): S3Client {\n return this.client;\n }\n\n /**\n * Get the bucket name.\n */\n getBucket(): string {\n return this.resolvedConfig.bucket;\n }\n\n /**\n * Get the AWS region.\n */\n getRegion(): string {\n return this.resolvedConfig.region;\n }\n\n /**\n * Check if this adapter is configured for Cloudflare R2.\n */\n isCloudflareR2(): boolean {\n return this.isR2;\n }\n}\n","/**\n * S3 Storage Plugin\n *\n * Factory function that creates a storage plugin for AWS S3 and S3-compatible services.\n * Returns a StoragePlugin that can be registered with MediaStorage.\n *\n * @example Basic usage with AWS S3\n * ```typescript\n * import { s3Storage } from '@nextly/storage-s3'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * s3Storage({\n * bucket: process.env.S3_BUCKET!,\n * region: process.env.AWS_REGION!,\n * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With Cloudflare R2\n * ```typescript\n * s3Storage({\n * bucket: process.env.R2_BUCKET!,\n * region: 'auto',\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,\n * publicUrl: process.env.R2_PUBLIC_URL,\n * collections: { media: true }\n * })\n * ```\n *\n * @example With collection-specific configuration\n * ```typescript\n * s3Storage({\n * bucket: 'my-bucket',\n * region: 'us-east-1',\n * collections: {\n * // Simple enable with defaults\n * media: true,\n *\n * // Full configuration for private documents\n * 'private-docs': {\n * prefix: 'private/',\n * clientUploads: true,\n * signedDownloads: true,\n * signedUrlExpiresIn: 3600\n * }\n * }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { StoragePlugin, ClientUploadData } from \"nextly/storage\";\n\nimport { S3StorageAdapter } from \"./adapter\";\nimport type { S3StorageConfig } from \"./types\";\n\n// ============================================================\n// Plugin Factory Function\n// ============================================================\n\n/**\n * Create an S3 storage plugin for Nextly.\n *\n * This factory function creates a StoragePlugin that can be added to\n * the `storage` array in `nextly.config.ts`. It supports:\n *\n * - AWS S3 (standard)\n * - Cloudflare R2 (S3-compatible)\n * - MinIO (S3-compatible, self-hosted)\n * - DigitalOcean Spaces (S3-compatible)\n * - Any other S3-compatible service\n *\n * @param config - S3 storage configuration\n * @returns A StoragePlugin that MediaStorage can register\n *\n * @throws Error if bucket is not provided (via adapter)\n * @throws Error if region is not provided (via adapter)\n */\nexport function s3Storage(config: S3StorageConfig): StoragePlugin {\n // Handle disabled plugin\n // When disabled, return a plugin with no collections and null adapter\n // MediaStorage.registerPlugin() checks for null adapter and skips registration\n if (config.enabled === false) {\n return {\n name: \"s3-storage\",\n type: \"s3\",\n collections: {},\n adapter: null as unknown as StoragePlugin[\"adapter\"],\n };\n }\n\n // Create the S3 adapter\n // Adapter constructor validates required config (bucket, region)\n const adapter = new S3StorageAdapter(config);\n\n // Build and return the plugin\n const plugin: StoragePlugin = {\n name: \"s3-storage\",\n type: \"s3\",\n collections: config.collections,\n adapter,\n\n /**\n * Generate a pre-signed URL for client-side uploads.\n *\n * This allows files to be uploaded directly from the browser to S3,\n * bypassing server-side upload limits (e.g., Vercel's 4.5MB limit).\n *\n * @param filename - Original filename from the client\n * @param mimeType - MIME type of the file\n * @param collection - Collection slug this upload belongs to\n * @returns Client upload data with pre-signed URL\n */\n async getClientUploadUrl(\n filename: string,\n mimeType: string,\n collection: string\n ): Promise<ClientUploadData> {\n // Get collection-specific configuration\n const collectionConfig = config.collections[collection];\n const prefix =\n typeof collectionConfig === \"object\"\n ? collectionConfig.prefix\n : undefined;\n\n // Generate storage key matching adapter's format\n // Format: {prefix}{year}/{month}/{uuid}-{sanitized-filename}\n const key = generateStorageKey(filename, prefix);\n\n // Get pre-signed upload URL from adapter\n return adapter.getPresignedUploadUrl(key, mimeType);\n },\n\n /**\n * Generate a signed URL for private file downloads.\n *\n * Creates a time-limited URL for accessing files in private buckets.\n * Only works when collection has `signedDownloads: true`.\n *\n * @param path - Storage path/key of the file\n * @param expiresIn - URL validity duration in seconds\n * @returns Signed URL for downloading the file\n */\n async getSignedDownloadUrl(\n path: string,\n expiresIn?: number\n ): Promise<string> {\n return adapter.getSignedUrl(\n path,\n expiresIn ?? config.signedUrlExpiresIn ?? 3600\n );\n },\n };\n\n return plugin;\n}\n\n// ============================================================\n// Helper Functions\n// ============================================================\n\n/**\n * Generate a unique storage key with date-based prefix.\n *\n * Creates keys in format: {prefix}{year}/{month}/{uuid}-{sanitized-filename}\n * This matches the format used by S3StorageAdapter for consistency.\n *\n * @param filename - Original filename (will be sanitized)\n * @param prefix - Optional folder/prefix for organizing uploads\n * @returns Generated storage key\n */\nfunction generateStorageKey(filename: string, prefix?: string): string {\n const sanitized = sanitizeFilename(filename);\n const uuid = crypto.randomUUID();\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n\n const keyPrefix = prefix ? `${prefix}${year}/${month}` : `${year}/${month}`;\n\n return `${keyPrefix}/${uuid}-${sanitized}`;\n}\n\n/**\n * Sanitize filename to prevent directory traversal and S3 key issues.\n *\n * Removes path separators and replaces unsafe characters with hyphens.\n * Keeps only: a-z, A-Z, 0-9, dot, underscore, hyphen\n *\n * @param filename - Original filename\n * @returns Sanitized filename safe for S3 keys\n */\nfunction sanitizeFilename(filename: string): string {\n // Extract basename (remove any path components)\n const basename = filename.split(/[/\\\\]/).pop() || filename;\n // Replace unsafe characters with hyphens\n return basename.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n}\n","/**\n * @nextly/storage-s3\n *\n * AWS S3 storage adapter for Nextly CMS.\n * Also works with S3-compatible services like Cloudflare R2, MinIO, and DigitalOcean Spaces.\n *\n * @example Basic usage with AWS S3\n * ```typescript\n * import { s3Storage } from '@nextly/storage-s3'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * s3Storage({\n * bucket: process.env.S3_BUCKET!,\n * region: process.env.AWS_REGION!,\n * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With Cloudflare R2\n * ```typescript\n * s3Storage({\n * bucket: process.env.R2_BUCKET!,\n * region: 'auto',\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,\n * publicUrl: process.env.R2_PUBLIC_URL,\n * collections: { media: true }\n * })\n * ```\n *\n * @example With MinIO\n * ```typescript\n * s3Storage({\n * bucket: 'my-bucket',\n * region: 'us-east-1',\n * accessKeyId: process.env.MINIO_ACCESS_KEY!,\n * secretAccessKey: process.env.MINIO_SECRET_KEY!,\n * endpoint: 'http://localhost:9000',\n * forcePathStyle: true,\n * collections: { media: true }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\n// ============================================================\n// S3 Storage Plugin Export (Primary API)\n// ============================================================\n\nexport { s3Storage } from \"./plugin\";\n\n// ============================================================\n// S3 Storage Adapter Export\n// ============================================================\n\nexport { S3StorageAdapter } from \"./adapter\";\n\n// ============================================================\n// S3 Types Export\n// ============================================================\n\nexport type {\n S3StorageConfig,\n S3ObjectACL,\n S3CollectionConfig,\n S3CollectionStorageMap,\n ResolvedS3Config,\n} from \"./types\";\n\n// ============================================================\n// Package Metadata\n// ============================================================\n\nexport const PACKAGE_NAME = \"@nextly/storage-s3\";\nexport const PACKAGE_VERSION = \"0.1.0\";\n"]}