@webiny/api-file-manager-s3 6.6.0-alpha.7 → 6.6.0-alpha.9

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.
@@ -41,7 +41,7 @@ class SharpTransform {
41
41
  async loadAssetCrop(fileId) {
42
42
  const result = await this.identityContext.withoutAuthorization(()=>this.getFile.execute(fileId));
43
43
  if (result.isFail()) return;
44
- const imageEdit = result.value.metadata?.imageEdit;
44
+ const imageEdit = result.value.metadata?.image;
45
45
  return imageEdit?.crop;
46
46
  }
47
47
  async transformAsset(asset, options, framing) {
@@ -1 +1 @@
1
- {"version":3,"file":"assetDelivery/s3/SharpTransform.js","sources":["../../../src/assetDelivery/s3/SharpTransform.ts"],"sourcesContent":["import type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { GetFileUseCase } from \"@webiny/api-file-manager/features/file/GetFile/index.js\";\nimport {\n contentTypeForFormat,\n DEFAULT_IMAGE_QUALITY,\n type ImageFormat\n} from \"@webiny/api-file-manager/features/assetDelivery/transformation/index.js\";\nimport type {\n AssetImageEdit,\n Framing,\n ImageRequestOptions\n} from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/imageTypes.js\";\nimport { normalizeImageOptions } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/normalizeImageOptions.js\";\nimport { CallableContentsReader } from \"@webiny/api-file-manager/features/assetDelivery/transformation/index.js\";\nimport { AssetKeyGenerator } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js\";\nimport { ImageAssetTypeHandler } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js\";\nimport type { Asset } from \"@webiny/api-file-manager/delivery/AssetDelivery/Asset.js\";\nimport type { AssetRequest } from \"@webiny/api-file-manager/delivery/AssetDelivery/AssetRequest.js\";\nimport type { SharpTransformer } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js\";\nimport { S3Client, S3Bucket, S3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { IS3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\ntype TransformOptions = Omit<ImageRequestOptions, \"original\" | \"crop\" | \"focal\" | \"aspectRatio\">;\n\nconst hasTransform = (options: TransformOptions): boolean => {\n return (\n options.width !== undefined || options.format !== undefined || options.quality !== undefined\n );\n};\n\nexport class SharpTransform implements ImageAssetTypeHandler.Interface {\n private readonly s3: S3;\n private readonly bucket: string;\n private readonly imageResizeWidths: number[];\n private readonly imageQuality: Record<ImageFormat, number>;\n private readonly identityContext: IdentityContext.Interface;\n private readonly getFile: GetFileUseCase.Interface;\n private transformer?: SharpTransformer;\n\n constructor(\n s3: S3,\n bucket: string,\n config: IS3AssetDeliveryConfig,\n identityContext: IdentityContext.Interface,\n getFile: GetFileUseCase.Interface\n ) {\n this.s3 = s3;\n this.bucket = bucket;\n this.imageResizeWidths = config.imageResizeWidths;\n this.imageQuality = { ...DEFAULT_IMAGE_QUALITY, ...(config.imageQuality ?? {}) };\n this.identityContext = identityContext;\n this.getFile = getFile;\n }\n\n private async getTransformer(): Promise<SharpTransformer> {\n if (!this.transformer) {\n const { SharpTransformer } =\n await import(\"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js\");\n this.transformer = new SharpTransformer();\n }\n return this.transformer;\n }\n\n async handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n const rawQuery = assetRequest.getOptions() as Record<string, any>;\n const acceptHeader = assetRequest.getContext<{ accept?: string }>().accept;\n // oxlint-disable-next-line typescript/no-unused-vars\n const { original, crop, focal, aspectRatio, ...options } = normalizeImageOptions(\n rawQuery,\n acceptHeader\n );\n\n const assetCrop = await this.loadAssetCrop(asset.getId());\n const framing: Framing = {\n crop: crop ?? assetCrop,\n focal,\n aspectRatio\n };\n\n const transformedAsset = asset.clone();\n\n if (hasTransform(options)) {\n return this.transformAsset(transformedAsset, options, framing);\n }\n\n return this.optimizeAsset(transformedAsset, framing);\n }\n\n private async loadAssetCrop(fileId: string) {\n const result = await this.identityContext.withoutAuthorization(() =>\n this.getFile.execute(fileId)\n );\n\n if (result.isFail()) {\n return undefined;\n }\n\n const imageEdit = result.value.metadata?.imageEdit as AssetImageEdit | undefined;\n return imageEdit?.crop;\n }\n\n private async transformAsset(asset: Asset, options: TransformOptions, framing: Framing) {\n const assetKey = AssetKeyGenerator.create(asset, framing);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n const contentType = options.format\n ? contentTypeForFormat(options.format)\n : asset.getContentType();\n\n try {\n const { Body } = await this.s3.getObject({\n Bucket: this.bucket,\n Key: transformedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length, contentType });\n newAsset.setContentsReader(CallableContentsReader.create(() => buffer));\n\n console.log(`Return a previously transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n } catch {\n const optimizedImage = await this.optimizeAsset(asset, framing);\n\n console.log(`Transform the asset`, options);\n const baseBuffer = await optimizedImage.getContents();\n const transformer = await this.getTransformer();\n const { buffer: transformedBuffer, contentType: outputContentType } =\n await transformer.transformBuffer({\n buffer: baseBuffer,\n animated: this.isAssetAnimated(asset),\n sourceContentType: asset.getContentType(),\n widths: this.imageResizeWidths,\n options,\n qualityDefaults: this.imageQuality\n });\n\n const newAsset = asset.withProps({\n size: transformedBuffer.length,\n contentType: outputContentType\n });\n newAsset.setContentsReader(CallableContentsReader.create(() => transformedBuffer));\n\n await this.s3.putObject({\n Bucket: this.bucket,\n Key: transformedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n console.log(`Return the transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize(),\n contentType: newAsset.getContentType()\n });\n\n return newAsset;\n }\n }\n\n private async optimizeAsset(asset: Asset, framing: Framing) {\n console.log(\"Optimize asset\", {\n id: asset.getId(),\n key: asset.getKey(),\n size: asset.getSize(),\n type: asset.getContentType()\n });\n\n const assetKey = AssetKeyGenerator.create(asset, framing);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await this.s3.getObject({\n Bucket: this.bucket,\n Key: optimizedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(CallableContentsReader.create(() => buffer));\n\n return newAsset;\n } catch {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n let buffer = await asset.getContents();\n\n const transformer = await this.getTransformer();\n const framed = await transformer.extractFramedRegion(buffer, framing);\n const cropped = framed !== buffer;\n buffer = framed;\n\n const contentType = asset.getContentType();\n const canOptimize =\n contentType === \"image/png\" ||\n contentType === \"image/jpeg\" ||\n contentType === \"image/jpg\";\n\n if (!canOptimize && !cropped) {\n console.log(`No optimizations defined for ${contentType}`);\n return asset;\n }\n\n let finalBuffer = buffer;\n if (canOptimize) {\n const pipeline =\n contentType === \"image/png\"\n ? await transformer.optimizePng(buffer)\n : await transformer.optimizeJpeg(buffer);\n finalBuffer = await pipeline.toBuffer();\n }\n\n console.log(\"Optimized asset size\", finalBuffer.length);\n\n const newAsset = asset.withProps({ size: finalBuffer.length });\n newAsset.setContentsReader(CallableContentsReader.create(() => finalBuffer));\n\n await this.s3.putObject({\n Bucket: this.bucket,\n Key: optimizedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n return newAsset;\n }\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n}\n\nexport const SharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: SharpTransform,\n dependencies: [S3Client, S3Bucket, S3AssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["hasTransform","options","undefined","SharpTransform","s3","bucket","config","identityContext","getFile","DEFAULT_IMAGE_QUALITY","SharpTransformer","assetRequest","asset","rawQuery","acceptHeader","original","crop","focal","aspectRatio","normalizeImageOptions","assetCrop","framing","transformedAsset","fileId","result","imageEdit","assetKey","AssetKeyGenerator","transformedAssetKey","contentType","contentTypeForFormat","Body","Error","buffer","Buffer","newAsset","CallableContentsReader","console","optimizedImage","baseBuffer","transformer","transformedBuffer","outputContentType","optimizedAssetKey","framed","cropped","canOptimize","finalBuffer","pipeline","SharpTransformImpl","ImageAssetTypeHandler","S3Client","S3Bucket","S3AssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":"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"}
1
+ {"version":3,"file":"assetDelivery/s3/SharpTransform.js","sources":["../../../src/assetDelivery/s3/SharpTransform.ts"],"sourcesContent":["import type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { GetFileUseCase } from \"@webiny/api-file-manager/features/file/GetFile/index.js\";\nimport {\n contentTypeForFormat,\n DEFAULT_IMAGE_QUALITY,\n type ImageFormat\n} from \"@webiny/api-file-manager/features/assetDelivery/transformation/index.js\";\nimport type {\n AssetImageEdit,\n Framing,\n ImageRequestOptions\n} from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/imageTypes.js\";\nimport { normalizeImageOptions } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/normalizeImageOptions.js\";\nimport { CallableContentsReader } from \"@webiny/api-file-manager/features/assetDelivery/transformation/index.js\";\nimport { AssetKeyGenerator } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js\";\nimport { ImageAssetTypeHandler } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js\";\nimport type { Asset } from \"@webiny/api-file-manager/delivery/AssetDelivery/Asset.js\";\nimport type { AssetRequest } from \"@webiny/api-file-manager/delivery/AssetDelivery/AssetRequest.js\";\nimport type { SharpTransformer } from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js\";\nimport { S3Client, S3Bucket, S3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { IS3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\ntype TransformOptions = Omit<ImageRequestOptions, \"original\" | \"crop\" | \"focal\" | \"aspectRatio\">;\n\nconst hasTransform = (options: TransformOptions): boolean => {\n return (\n options.width !== undefined || options.format !== undefined || options.quality !== undefined\n );\n};\n\nexport class SharpTransform implements ImageAssetTypeHandler.Interface {\n private readonly s3: S3;\n private readonly bucket: string;\n private readonly imageResizeWidths: number[];\n private readonly imageQuality: Record<ImageFormat, number>;\n private readonly identityContext: IdentityContext.Interface;\n private readonly getFile: GetFileUseCase.Interface;\n private transformer?: SharpTransformer;\n\n constructor(\n s3: S3,\n bucket: string,\n config: IS3AssetDeliveryConfig,\n identityContext: IdentityContext.Interface,\n getFile: GetFileUseCase.Interface\n ) {\n this.s3 = s3;\n this.bucket = bucket;\n this.imageResizeWidths = config.imageResizeWidths;\n this.imageQuality = { ...DEFAULT_IMAGE_QUALITY, ...(config.imageQuality ?? {}) };\n this.identityContext = identityContext;\n this.getFile = getFile;\n }\n\n private async getTransformer(): Promise<SharpTransformer> {\n if (!this.transformer) {\n const { SharpTransformer } =\n await import(\"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js\");\n this.transformer = new SharpTransformer();\n }\n return this.transformer;\n }\n\n async handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n const rawQuery = assetRequest.getOptions() as Record<string, any>;\n const acceptHeader = assetRequest.getContext<{ accept?: string }>().accept;\n // oxlint-disable-next-line typescript/no-unused-vars\n const { original, crop, focal, aspectRatio, ...options } = normalizeImageOptions(\n rawQuery,\n acceptHeader\n );\n\n const assetCrop = await this.loadAssetCrop(asset.getId());\n const framing: Framing = {\n crop: crop ?? assetCrop,\n focal,\n aspectRatio\n };\n\n const transformedAsset = asset.clone();\n\n if (hasTransform(options)) {\n return this.transformAsset(transformedAsset, options, framing);\n }\n\n return this.optimizeAsset(transformedAsset, framing);\n }\n\n private async loadAssetCrop(fileId: string) {\n const result = await this.identityContext.withoutAuthorization(() =>\n this.getFile.execute(fileId)\n );\n\n if (result.isFail()) {\n return undefined;\n }\n\n const imageEdit = result.value.metadata?.image as AssetImageEdit | undefined;\n return imageEdit?.crop;\n }\n\n private async transformAsset(asset: Asset, options: TransformOptions, framing: Framing) {\n const assetKey = AssetKeyGenerator.create(asset, framing);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n const contentType = options.format\n ? contentTypeForFormat(options.format)\n : asset.getContentType();\n\n try {\n const { Body } = await this.s3.getObject({\n Bucket: this.bucket,\n Key: transformedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length, contentType });\n newAsset.setContentsReader(CallableContentsReader.create(() => buffer));\n\n console.log(`Return a previously transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n } catch {\n const optimizedImage = await this.optimizeAsset(asset, framing);\n\n console.log(`Transform the asset`, options);\n const baseBuffer = await optimizedImage.getContents();\n const transformer = await this.getTransformer();\n const { buffer: transformedBuffer, contentType: outputContentType } =\n await transformer.transformBuffer({\n buffer: baseBuffer,\n animated: this.isAssetAnimated(asset),\n sourceContentType: asset.getContentType(),\n widths: this.imageResizeWidths,\n options,\n qualityDefaults: this.imageQuality\n });\n\n const newAsset = asset.withProps({\n size: transformedBuffer.length,\n contentType: outputContentType\n });\n newAsset.setContentsReader(CallableContentsReader.create(() => transformedBuffer));\n\n await this.s3.putObject({\n Bucket: this.bucket,\n Key: transformedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n console.log(`Return the transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize(),\n contentType: newAsset.getContentType()\n });\n\n return newAsset;\n }\n }\n\n private async optimizeAsset(asset: Asset, framing: Framing) {\n console.log(\"Optimize asset\", {\n id: asset.getId(),\n key: asset.getKey(),\n size: asset.getSize(),\n type: asset.getContentType()\n });\n\n const assetKey = AssetKeyGenerator.create(asset, framing);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await this.s3.getObject({\n Bucket: this.bucket,\n Key: optimizedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(CallableContentsReader.create(() => buffer));\n\n return newAsset;\n } catch {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n let buffer = await asset.getContents();\n\n const transformer = await this.getTransformer();\n const framed = await transformer.extractFramedRegion(buffer, framing);\n const cropped = framed !== buffer;\n buffer = framed;\n\n const contentType = asset.getContentType();\n const canOptimize =\n contentType === \"image/png\" ||\n contentType === \"image/jpeg\" ||\n contentType === \"image/jpg\";\n\n if (!canOptimize && !cropped) {\n console.log(`No optimizations defined for ${contentType}`);\n return asset;\n }\n\n let finalBuffer = buffer;\n if (canOptimize) {\n const pipeline =\n contentType === \"image/png\"\n ? await transformer.optimizePng(buffer)\n : await transformer.optimizeJpeg(buffer);\n finalBuffer = await pipeline.toBuffer();\n }\n\n console.log(\"Optimized asset size\", finalBuffer.length);\n\n const newAsset = asset.withProps({ size: finalBuffer.length });\n newAsset.setContentsReader(CallableContentsReader.create(() => finalBuffer));\n\n await this.s3.putObject({\n Bucket: this.bucket,\n Key: optimizedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n return newAsset;\n }\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n}\n\nexport const SharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: SharpTransform,\n dependencies: [S3Client, S3Bucket, S3AssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["hasTransform","options","undefined","SharpTransform","s3","bucket","config","identityContext","getFile","DEFAULT_IMAGE_QUALITY","SharpTransformer","assetRequest","asset","rawQuery","acceptHeader","original","crop","focal","aspectRatio","normalizeImageOptions","assetCrop","framing","transformedAsset","fileId","result","imageEdit","assetKey","AssetKeyGenerator","transformedAssetKey","contentType","contentTypeForFormat","Body","Error","buffer","Buffer","newAsset","CallableContentsReader","console","optimizedImage","baseBuffer","transformer","transformedBuffer","outputContentType","optimizedAssetKey","framed","cropped","canOptimize","finalBuffer","pipeline","SharpTransformImpl","ImageAssetTypeHandler","S3Client","S3Bucket","S3AssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":";;;;;;AAyBA,MAAMA,eAAe,CAACC,UAEdA,AAAkBC,WAAlBD,QAAQ,KAAK,IAAkBA,AAAmBC,WAAnBD,QAAQ,MAAM,IAAkBA,AAAoBC,WAApBD,QAAQ,OAAO;AAI/E,MAAME;IAST,YACIC,EAAM,EACNC,MAAc,EACdC,MAA8B,EAC9BC,eAA0C,EAC1CC,OAAiC,CACnC;QACE,IAAI,CAAC,EAAE,GAAGJ;QACV,IAAI,CAAC,MAAM,GAAGC;QACd,IAAI,CAAC,iBAAiB,GAAGC,OAAO,iBAAiB;QACjD,IAAI,CAAC,YAAY,GAAG;YAAE,GAAGG,qBAAqB;YAAE,GAAIH,OAAO,YAAY,IAAI,CAAC,CAAC;QAAE;QAC/E,IAAI,CAAC,eAAe,GAAGC;QACvB,IAAI,CAAC,OAAO,GAAGC;IACnB;IAEA,MAAc,iBAA4C;QACtD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YACnB,MAAM,EAAEE,gBAAgB,EAAE,GACtB,MAAM,MAAM,CAAC;YACjB,IAAI,CAAC,WAAW,GAAG,IAAIA;QAC3B;QACA,OAAO,IAAI,CAAC,WAAW;IAC3B;IAEA,MAAM,OAAOC,YAA0B,EAAEC,KAAY,EAAkB;QACnE,MAAMC,WAAWF,aAAa,UAAU;QACxC,MAAMG,eAAeH,aAAa,UAAU,GAAwB,MAAM;QAE1E,MAAM,EAAEI,QAAQ,EAAEC,IAAI,EAAEC,KAAK,EAAEC,WAAW,EAAE,GAAGjB,SAAS,GAAGkB,sBACvDN,UACAC;QAGJ,MAAMM,YAAY,MAAM,IAAI,CAAC,aAAa,CAACR,MAAM,KAAK;QACtD,MAAMS,UAAmB;YACrB,MAAML,QAAQI;YACdH;YACAC;QACJ;QAEA,MAAMI,mBAAmBV,MAAM,KAAK;QAEpC,IAAIZ,aAAaC,UACb,OAAO,IAAI,CAAC,cAAc,CAACqB,kBAAkBrB,SAASoB;QAG1D,OAAO,IAAI,CAAC,aAAa,CAACC,kBAAkBD;IAChD;IAEA,MAAc,cAAcE,MAAc,EAAE;QACxC,MAAMC,SAAS,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,IAC3D,IAAI,CAAC,OAAO,CAAC,OAAO,CAACD;QAGzB,IAAIC,OAAO,MAAM,IACb;QAGJ,MAAMC,YAAYD,OAAO,KAAK,CAAC,QAAQ,EAAE;QACzC,OAAOC,WAAW;IACtB;IAEA,MAAc,eAAeb,KAAY,EAAEX,OAAyB,EAAEoB,OAAgB,EAAE;QACpF,MAAMK,WAAWC,kBAAkB,MAAM,CAACf,OAAOS;QACjD,MAAMO,sBAAsBF,SAAS,sBAAsB,CAACzB;QAE5D,MAAM4B,cAAc5B,QAAQ,MAAM,GAC5B6B,qBAAqB7B,QAAQ,MAAM,IACnCW,MAAM,cAAc;QAE1B,IAAI;YACA,MAAM,EAAEmB,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;gBACrC,QAAQ,IAAI,CAAC,MAAM;gBACnB,KAAKH;YACT;YAEA,IAAI,CAACG,MACD,MAAM,IAAIC,MAAM;YAGpB,MAAMC,SAASC,OAAO,IAAI,CAAC,MAAMH,KAAK,oBAAoB;YAE1D,MAAMI,WAAWvB,MAAM,SAAS,CAAC;gBAAE,MAAMqB,OAAO,MAAM;gBAAEJ;YAAY;YACpEM,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMH;YAE/DI,QAAQ,GAAG,CAAC,yCAAyC;gBACjD,KAAKT;gBACL,MAAMO,SAAS,OAAO;YAC1B;YAEA,OAAOA;QACX,EAAE,OAAM;YACJ,MAAMG,iBAAiB,MAAM,IAAI,CAAC,aAAa,CAAC1B,OAAOS;YAEvDgB,QAAQ,GAAG,CAAC,uBAAuBpC;YACnC,MAAMsC,aAAa,MAAMD,eAAe,WAAW;YACnD,MAAME,cAAc,MAAM,IAAI,CAAC,cAAc;YAC7C,MAAM,EAAE,QAAQC,iBAAiB,EAAE,aAAaC,iBAAiB,EAAE,GAC/D,MAAMF,YAAY,eAAe,CAAC;gBAC9B,QAAQD;gBACR,UAAU,IAAI,CAAC,eAAe,CAAC3B;gBAC/B,mBAAmBA,MAAM,cAAc;gBACvC,QAAQ,IAAI,CAAC,iBAAiB;gBAC9BX;gBACA,iBAAiB,IAAI,CAAC,YAAY;YACtC;YAEJ,MAAMkC,WAAWvB,MAAM,SAAS,CAAC;gBAC7B,MAAM6B,kBAAkB,MAAM;gBAC9B,aAAaC;YACjB;YACAP,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMK;YAE/D,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;gBACpB,QAAQ,IAAI,CAAC,MAAM;gBACnB,KAAKb;gBACL,aAAaO,SAAS,cAAc;gBACpC,MAAM,MAAMA,SAAS,WAAW;YACpC;YAEAE,QAAQ,GAAG,CAAC,gCAAgC;gBACxC,KAAKT;gBACL,MAAMO,SAAS,OAAO;gBACtB,aAAaA,SAAS,cAAc;YACxC;YAEA,OAAOA;QACX;IACJ;IAEA,MAAc,cAAcvB,KAAY,EAAES,OAAgB,EAAE;QACxDgB,QAAQ,GAAG,CAAC,kBAAkB;YAC1B,IAAIzB,MAAM,KAAK;YACf,KAAKA,MAAM,MAAM;YACjB,MAAMA,MAAM,OAAO;YACnB,MAAMA,MAAM,cAAc;QAC9B;QAEA,MAAMc,WAAWC,kBAAkB,MAAM,CAACf,OAAOS;QACjD,MAAMsB,oBAAoBjB,SAAS,oBAAoB;QAEvD,IAAI;YACA,MAAM,EAAEK,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;gBACrC,QAAQ,IAAI,CAAC,MAAM;gBACnB,KAAKY;YACT;YAEA,IAAI,CAACZ,MACD,MAAM,IAAIC,MAAM;YAGpBK,QAAQ,GAAG,CAAC,uCAAuCM;YAEnD,MAAMV,SAASC,OAAO,IAAI,CAAC,MAAMH,KAAK,oBAAoB;YAE1D,MAAMI,WAAWvB,MAAM,SAAS,CAAC;gBAAE,MAAMqB,OAAO,MAAM;YAAC;YACvDE,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMH;YAE/D,OAAOE;QACX,EAAE,OAAM;YACJE,QAAQ,GAAG,CAAC,qDAAqDzB,MAAM,MAAM;YAC7E,IAAIqB,SAAS,MAAMrB,MAAM,WAAW;YAEpC,MAAM4B,cAAc,MAAM,IAAI,CAAC,cAAc;YAC7C,MAAMI,SAAS,MAAMJ,YAAY,mBAAmB,CAACP,QAAQZ;YAC7D,MAAMwB,UAAUD,WAAWX;YAC3BA,SAASW;YAET,MAAMf,cAAcjB,MAAM,cAAc;YACxC,MAAMkC,cACFjB,AAAgB,gBAAhBA,eACAA,AAAgB,iBAAhBA,eACAA,AAAgB,gBAAhBA;YAEJ,IAAI,CAACiB,eAAe,CAACD,SAAS;gBAC1BR,QAAQ,GAAG,CAAC,CAAC,6BAA6B,EAAER,aAAa;gBACzD,OAAOjB;YACX;YAEA,IAAImC,cAAcd;YAClB,IAAIa,aAAa;gBACb,MAAME,WACFnB,AAAgB,gBAAhBA,cACM,MAAMW,YAAY,WAAW,CAACP,UAC9B,MAAMO,YAAY,YAAY,CAACP;gBACzCc,cAAc,MAAMC,SAAS,QAAQ;YACzC;YAEAX,QAAQ,GAAG,CAAC,wBAAwBU,YAAY,MAAM;YAEtD,MAAMZ,WAAWvB,MAAM,SAAS,CAAC;gBAAE,MAAMmC,YAAY,MAAM;YAAC;YAC5DZ,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMW;YAE/D,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;gBACpB,QAAQ,IAAI,CAAC,MAAM;gBACnB,KAAKJ;gBACL,aAAaR,SAAS,cAAc;gBACpC,MAAM,MAAMA,SAAS,WAAW;YACpC;YAEA,OAAOA;QACX;IACJ;IAEQ,gBAAgBvB,KAAY,EAAE;QAClC,OAAO;YAAC;YAAO;SAAO,CAAC,QAAQ,CAACA,MAAM,YAAY;IACtD;AACJ;AAEO,MAAMqC,qBAAqBC,sBAAsB,oBAAoB,CAAC;IACzE,gBAAgB/C;IAChB,cAAc;QAACgD;QAAUC;QAAUC;QAAuBC;QAAiBC;KAAe;AAC9F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/api-file-manager-s3",
3
- "version": "6.6.0-alpha.7",
3
+ "version": "6.6.0-alpha.9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -14,21 +14,21 @@
14
14
  "author": "Webiny Ltd",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@webiny/api": "6.6.0-alpha.7",
18
- "@webiny/api-core": "6.6.0-alpha.7",
19
- "@webiny/api-file-manager": "6.6.0-alpha.7",
20
- "@webiny/api-graphql": "6.6.0-alpha.7",
21
- "@webiny/api-websockets": "6.6.0-alpha.7",
22
- "@webiny/aws-sdk": "6.6.0-alpha.7",
23
- "@webiny/background-tasks": "6.6.0-alpha.7",
17
+ "@webiny/api": "6.6.0-alpha.9",
18
+ "@webiny/api-core": "6.6.0-alpha.9",
19
+ "@webiny/api-file-manager": "6.6.0-alpha.9",
20
+ "@webiny/api-graphql": "6.6.0-alpha.9",
21
+ "@webiny/api-websockets": "6.6.0-alpha.9",
22
+ "@webiny/aws-sdk": "6.6.0-alpha.9",
23
+ "@webiny/background-tasks": "6.6.0-alpha.9",
24
24
  "@webiny/di": "1.1.0",
25
- "@webiny/event-handler-aws": "6.6.0-alpha.7",
26
- "@webiny/event-handler-core": "6.6.0-alpha.7",
27
- "@webiny/feature": "6.6.0-alpha.7",
28
- "@webiny/handler": "6.6.0-alpha.7",
29
- "@webiny/plugins": "6.6.0-alpha.7",
30
- "@webiny/utils": "6.6.0-alpha.7",
31
- "@webiny/validation": "6.6.0-alpha.7",
25
+ "@webiny/event-handler-aws": "6.6.0-alpha.9",
26
+ "@webiny/event-handler-core": "6.6.0-alpha.9",
27
+ "@webiny/feature": "6.6.0-alpha.9",
28
+ "@webiny/handler": "6.6.0-alpha.9",
29
+ "@webiny/plugins": "6.6.0-alpha.9",
30
+ "@webiny/utils": "6.6.0-alpha.9",
31
+ "@webiny/validation": "6.6.0-alpha.9",
32
32
  "exifreader": "4.43.0",
33
33
  "mime": "4.1.0",
34
34
  "object-hash": "3.0.0",
@@ -38,7 +38,7 @@
38
38
  "sharp": "0.35.3"
39
39
  },
40
40
  "devDependencies": {
41
- "@webiny/build-tools": "6.6.0-alpha.7",
41
+ "@webiny/build-tools": "6.6.0-alpha.9",
42
42
  "rimraf": "6.1.3",
43
43
  "typescript": "7.0.2",
44
44
  "vitest": "4.1.11"