@webiny/api-file-manager-s3 5.41.0-dbt.0 → 5.41.0

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.
@@ -7,5 +7,6 @@ export type AssetDeliveryParams = Parameters<typeof createBaseAssetDelivery>[0]
7
7
  * @see https://repost.aws/knowledge-center/presigned-url-s3-bucket-expiration
8
8
  */
9
9
  presignedUrlTtl?: number;
10
+ assetStreamingMaxSize?: number;
10
11
  };
11
12
  export declare const assetDeliveryConfig: (params: AssetDeliveryParams) => (import("@webiny/api-file-manager").AssetDeliveryConfigModifierPlugin | (import("@webiny/api-file-manager").AssetDeliveryConfigModifierPlugin | import("@webiny/handler").ModifyFastifyPlugin)[])[];
@@ -16,6 +16,11 @@ const assetDeliveryConfig = params => {
16
16
  // Presigned URLs last 1 hour
17
17
  presignedUrlTtl = 3600,
18
18
  imageResizeWidths = [100, 300, 500, 750, 1000, 1500, 2500],
19
+ /**
20
+ * Even though Lambda's response payload limit is 6,291,556 bytes, we leave some room for the response envelope.
21
+ * We had situations where a 4.7MB file would cause the payload to go over the limit, so let's be on the safe side.
22
+ */
23
+ assetStreamingMaxSize = 4718592,
19
24
  ...baseParams
20
25
  } = params;
21
26
  return [
@@ -31,7 +36,7 @@ const assetDeliveryConfig = params => {
31
36
  return new _S3AssetResolver.S3AssetResolver(s3, bucket);
32
37
  });
33
38
  config.decorateAssetOutputStrategy(() => {
34
- return new _S3OutputStrategy.S3OutputStrategy(s3, bucket, presignedUrlTtl);
39
+ return new _S3OutputStrategy.S3OutputStrategy(s3, bucket, presignedUrlTtl, assetStreamingMaxSize);
35
40
  });
36
41
  config.decorateAssetTransformationStrategy(() => {
37
42
  return new _SharpTransform.SharpTransform({
@@ -1 +1 @@
1
- {"version":3,"names":["_apiFileManager","require","_clientS","_S3AssetResolver","_S3OutputStrategy","_SharpTransform","assetDeliveryConfig","params","bucket","process","env","S3_BUCKET","region","AWS_REGION","presignedUrlTtl","imageResizeWidths","baseParams","createBaseAssetDelivery","createAssetDeliveryConfig","config","s3","S3","decorateAssetResolver","S3AssetResolver","decorateAssetOutputStrategy","S3OutputStrategy","decorateAssetTransformationStrategy","SharpTransform","exports"],"sources":["assetDeliveryConfig.ts"],"sourcesContent":["import {\n createAssetDelivery as createBaseAssetDelivery,\n createAssetDeliveryConfig\n} from \"@webiny/api-file-manager\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3\";\nimport { S3AssetResolver } from \"~/assetDelivery/s3/S3AssetResolver\";\nimport { S3OutputStrategy } from \"~/assetDelivery/s3/S3OutputStrategy\";\nimport { SharpTransform } from \"~/assetDelivery/s3/SharpTransform\";\n\nexport type AssetDeliveryParams = Parameters<typeof createBaseAssetDelivery>[0] & {\n imageResizeWidths?: number[];\n /**\n * BE CAREFUL!\n * Setting this to more than 1 hour may cause your URLs to still expire before the desired expiration time.\n * @see https://repost.aws/knowledge-center/presigned-url-s3-bucket-expiration\n */\n presignedUrlTtl?: number;\n};\n\nexport const assetDeliveryConfig = (params: AssetDeliveryParams) => {\n const bucket = process.env.S3_BUCKET as string;\n const region = process.env.AWS_REGION as string;\n\n const {\n // Presigned URLs last 1 hour\n presignedUrlTtl = 3600,\n imageResizeWidths = [100, 300, 500, 750, 1000, 1500, 2500],\n ...baseParams\n } = params;\n\n return [\n // Base asset delivery\n createBaseAssetDelivery(baseParams),\n // S3 plugins\n createAssetDeliveryConfig(config => {\n const s3 = new S3({ region });\n\n config.decorateAssetResolver(() => {\n // This resolver loads file information from the `.metadata` file.\n return new S3AssetResolver(s3, bucket);\n });\n\n config.decorateAssetOutputStrategy(() => {\n return new S3OutputStrategy(s3, bucket, presignedUrlTtl);\n });\n\n config.decorateAssetTransformationStrategy(() => {\n return new SharpTransform({ s3, bucket, imageResizeWidths });\n });\n })\n ];\n};\n"],"mappings":";;;;;;AAAA,IAAAA,eAAA,GAAAC,OAAA;AAIA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,gBAAA,GAAAF,OAAA;AACA,IAAAG,iBAAA,GAAAH,OAAA;AACA,IAAAI,eAAA,GAAAJ,OAAA;AAYO,MAAMK,mBAAmB,GAAIC,MAA2B,IAAK;EAChE,MAAMC,MAAM,GAAGC,OAAO,CAACC,GAAG,CAACC,SAAmB;EAC9C,MAAMC,MAAM,GAAGH,OAAO,CAACC,GAAG,CAACG,UAAoB;EAE/C,MAAM;IACF;IACAC,eAAe,GAAG,IAAI;IACtBC,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC1D,GAAGC;EACP,CAAC,GAAGT,MAAM;EAEV,OAAO;EACH;EACA,IAAAU,mCAAuB,EAACD,UAAU,CAAC;EACnC;EACA,IAAAE,yCAAyB,EAACC,MAAM,IAAI;IAChC,MAAMC,EAAE,GAAG,IAAIC,WAAE,CAAC;MAAET;IAAO,CAAC,CAAC;IAE7BO,MAAM,CAACG,qBAAqB,CAAC,MAAM;MAC/B;MACA,OAAO,IAAIC,gCAAe,CAACH,EAAE,EAAEZ,MAAM,CAAC;IAC1C,CAAC,CAAC;IAEFW,MAAM,CAACK,2BAA2B,CAAC,MAAM;MACrC,OAAO,IAAIC,kCAAgB,CAACL,EAAE,EAAEZ,MAAM,EAAEM,eAAe,CAAC;IAC5D,CAAC,CAAC;IAEFK,MAAM,CAACO,mCAAmC,CAAC,MAAM;MAC7C,OAAO,IAAIC,8BAAc,CAAC;QAAEP,EAAE;QAAEZ,MAAM;QAAEO;MAAkB,CAAC,CAAC;IAChE,CAAC,CAAC;EACN,CAAC,CAAC,CACL;AACL,CAAC;AAACa,OAAA,CAAAtB,mBAAA,GAAAA,mBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_apiFileManager","require","_clientS","_S3AssetResolver","_S3OutputStrategy","_SharpTransform","assetDeliveryConfig","params","bucket","process","env","S3_BUCKET","region","AWS_REGION","presignedUrlTtl","imageResizeWidths","assetStreamingMaxSize","baseParams","createBaseAssetDelivery","createAssetDeliveryConfig","config","s3","S3","decorateAssetResolver","S3AssetResolver","decorateAssetOutputStrategy","S3OutputStrategy","decorateAssetTransformationStrategy","SharpTransform","exports"],"sources":["assetDeliveryConfig.ts"],"sourcesContent":["import {\n createAssetDelivery as createBaseAssetDelivery,\n createAssetDeliveryConfig\n} from \"@webiny/api-file-manager\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3\";\nimport { S3AssetResolver } from \"~/assetDelivery/s3/S3AssetResolver\";\nimport { S3OutputStrategy } from \"~/assetDelivery/s3/S3OutputStrategy\";\nimport { SharpTransform } from \"~/assetDelivery/s3/SharpTransform\";\n\nexport type AssetDeliveryParams = Parameters<typeof createBaseAssetDelivery>[0] & {\n imageResizeWidths?: number[];\n /**\n * BE CAREFUL!\n * Setting this to more than 1 hour may cause your URLs to still expire before the desired expiration time.\n * @see https://repost.aws/knowledge-center/presigned-url-s3-bucket-expiration\n */\n presignedUrlTtl?: number;\n assetStreamingMaxSize?: number;\n};\n\nexport const assetDeliveryConfig = (params: AssetDeliveryParams) => {\n const bucket = process.env.S3_BUCKET as string;\n const region = process.env.AWS_REGION as string;\n\n const {\n // Presigned URLs last 1 hour\n presignedUrlTtl = 3600,\n imageResizeWidths = [100, 300, 500, 750, 1000, 1500, 2500],\n /**\n * Even though Lambda's response payload limit is 6,291,556 bytes, we leave some room for the response envelope.\n * We had situations where a 4.7MB file would cause the payload to go over the limit, so let's be on the safe side.\n */\n assetStreamingMaxSize = 4718592,\n ...baseParams\n } = params;\n\n return [\n // Base asset delivery\n createBaseAssetDelivery(baseParams),\n // S3 plugins\n createAssetDeliveryConfig(config => {\n const s3 = new S3({ region });\n\n config.decorateAssetResolver(() => {\n // This resolver loads file information from the `.metadata` file.\n return new S3AssetResolver(s3, bucket);\n });\n\n config.decorateAssetOutputStrategy(() => {\n return new S3OutputStrategy(s3, bucket, presignedUrlTtl, assetStreamingMaxSize);\n });\n\n config.decorateAssetTransformationStrategy(() => {\n return new SharpTransform({ s3, bucket, imageResizeWidths });\n });\n })\n ];\n};\n"],"mappings":";;;;;;AAAA,IAAAA,eAAA,GAAAC,OAAA;AAIA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,gBAAA,GAAAF,OAAA;AACA,IAAAG,iBAAA,GAAAH,OAAA;AACA,IAAAI,eAAA,GAAAJ,OAAA;AAaO,MAAMK,mBAAmB,GAAIC,MAA2B,IAAK;EAChE,MAAMC,MAAM,GAAGC,OAAO,CAACC,GAAG,CAACC,SAAmB;EAC9C,MAAMC,MAAM,GAAGH,OAAO,CAACC,GAAG,CAACG,UAAoB;EAE/C,MAAM;IACF;IACAC,eAAe,GAAG,IAAI;IACtBC,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC1D;AACR;AACA;AACA;IACQC,qBAAqB,GAAG,OAAO;IAC/B,GAAGC;EACP,CAAC,GAAGV,MAAM;EAEV,OAAO;EACH;EACA,IAAAW,mCAAuB,EAACD,UAAU,CAAC;EACnC;EACA,IAAAE,yCAAyB,EAACC,MAAM,IAAI;IAChC,MAAMC,EAAE,GAAG,IAAIC,WAAE,CAAC;MAAEV;IAAO,CAAC,CAAC;IAE7BQ,MAAM,CAACG,qBAAqB,CAAC,MAAM;MAC/B;MACA,OAAO,IAAIC,gCAAe,CAACH,EAAE,EAAEb,MAAM,CAAC;IAC1C,CAAC,CAAC;IAEFY,MAAM,CAACK,2BAA2B,CAAC,MAAM;MACrC,OAAO,IAAIC,kCAAgB,CAACL,EAAE,EAAEb,MAAM,EAAEM,eAAe,EAAEE,qBAAqB,CAAC;IACnF,CAAC,CAAC;IAEFI,MAAM,CAACO,mCAAmC,CAAC,MAAM;MAC7C,OAAO,IAAIC,8BAAc,CAAC;QAAEP,EAAE;QAAEb,MAAM;QAAEO;MAAkB,CAAC,CAAC;IAChE,CAAC,CAAC;EACN,CAAC,CAAC,CACL;AACL,CAAC;AAACc,OAAA,CAAAvB,mBAAA,GAAAA,mBAAA","ignoreList":[]}
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { S3 } from "@webiny/aws-sdk/client-s3";
3
4
  import { Asset, AssetContentsReader } from "@webiny/api-file-manager";
4
5
  export declare class S3ContentsReader implements AssetContentsReader {
@@ -8,7 +8,8 @@ export declare class S3OutputStrategy implements AssetOutputStrategy {
8
8
  private readonly s3;
9
9
  private readonly bucket;
10
10
  private readonly presignedUrlTtl;
11
- constructor(s3: S3, bucket: string, presignedUrlTtl: number);
11
+ private readonly assetStreamingMaxSize;
12
+ constructor(s3: S3, bucket: string, presignedUrlTtl: number, assetStreamingMaxSize: number);
12
13
  output(asset: Asset): Promise<AssetReply>;
13
14
  protected getPresignedUrl(asset: Asset): Promise<string>;
14
15
  }
@@ -7,22 +7,23 @@ exports.S3OutputStrategy = void 0;
7
7
  var _clientS = require("@webiny/aws-sdk/client-s3");
8
8
  var _S3RedirectAssetReply = require("./S3RedirectAssetReply");
9
9
  var _S3StreamAssetReply = require("./S3StreamAssetReply");
10
- const MAX_RETURN_CONTENT_LENGTH = 4915200; // ~4.8 MB
11
-
12
10
  /**
13
11
  * This strategy outputs an asset taking into account the size of the asset contents.
14
12
  * If the asset is larger than 5MB, a presigned URL will be generated, and a redirect will happen.
15
13
  */
16
14
  class S3OutputStrategy {
17
- constructor(s3, bucket, presignedUrlTtl) {
15
+ constructor(s3, bucket, presignedUrlTtl, assetStreamingMaxSize) {
16
+ this.assetStreamingMaxSize = assetStreamingMaxSize;
18
17
  this.presignedUrlTtl = presignedUrlTtl;
19
18
  this.s3 = s3;
20
19
  this.bucket = bucket;
21
20
  }
22
21
  async output(asset) {
23
- if ((await asset.getSize()) > MAX_RETURN_CONTENT_LENGTH) {
22
+ if (asset.getSize() > this.assetStreamingMaxSize) {
23
+ console.log(`Asset size is greater than ${this.assetStreamingMaxSize}; redirecting to a presigned S3 URL.`);
24
24
  return new _S3RedirectAssetReply.S3RedirectAssetReply(await this.getPresignedUrl(asset), this.presignedUrlTtl);
25
25
  }
26
+ console.log(`Asset size is smaller than ${this.assetStreamingMaxSize}; streaming directly from Lambda function.`);
26
27
  return new _S3StreamAssetReply.S3StreamAssetReply(asset);
27
28
  }
28
29
  getPresignedUrl(asset) {
@@ -1 +1 @@
1
- {"version":3,"names":["_clientS","require","_S3RedirectAssetReply","_S3StreamAssetReply","MAX_RETURN_CONTENT_LENGTH","S3OutputStrategy","constructor","s3","bucket","presignedUrlTtl","output","asset","getSize","S3RedirectAssetReply","getPresignedUrl","S3StreamAssetReply","getSignedUrl","GetObjectCommand","Bucket","Key","getKey","expiresIn","exports"],"sources":["S3OutputStrategy.ts"],"sourcesContent":["import { Asset, AssetOutputStrategy, AssetReply } from \"@webiny/api-file-manager\";\nimport { GetObjectCommand, getSignedUrl, S3 } from \"@webiny/aws-sdk/client-s3\";\nimport { S3RedirectAssetReply } from \"~/assetDelivery/s3/S3RedirectAssetReply\";\nimport { S3StreamAssetReply } from \"~/assetDelivery/s3/S3StreamAssetReply\";\n\nconst MAX_RETURN_CONTENT_LENGTH = 4915200; // ~4.8 MB\n\n/**\n * This strategy outputs an asset taking into account the size of the asset contents.\n * If the asset is larger than 5MB, a presigned URL will be generated, and a redirect will happen.\n */\nexport class S3OutputStrategy implements AssetOutputStrategy {\n private readonly s3: S3;\n private readonly bucket: string;\n private readonly presignedUrlTtl: number;\n\n constructor(s3: S3, bucket: string, presignedUrlTtl: number) {\n this.presignedUrlTtl = presignedUrlTtl;\n this.s3 = s3;\n this.bucket = bucket;\n }\n\n async output(asset: Asset): Promise<AssetReply> {\n if ((await asset.getSize()) > MAX_RETURN_CONTENT_LENGTH) {\n return new S3RedirectAssetReply(\n await this.getPresignedUrl(asset),\n this.presignedUrlTtl\n );\n }\n\n return new S3StreamAssetReply(asset);\n }\n\n protected getPresignedUrl(asset: Asset) {\n return getSignedUrl(\n this.s3,\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: asset.getKey()\n }),\n { expiresIn: this.presignedUrlTtl }\n );\n }\n}\n"],"mappings":";;;;;;AACA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AACA,IAAAE,mBAAA,GAAAF,OAAA;AAEA,MAAMG,yBAAyB,GAAG,OAAO,CAAC,CAAC;;AAE3C;AACA;AACA;AACA;AACO,MAAMC,gBAAgB,CAAgC;EAKzDC,WAAWA,CAACC,EAAM,EAAEC,MAAc,EAAEC,eAAuB,EAAE;IACzD,IAAI,CAACA,eAAe,GAAGA,eAAe;IACtC,IAAI,CAACF,EAAE,GAAGA,EAAE;IACZ,IAAI,CAACC,MAAM,GAAGA,MAAM;EACxB;EAEA,MAAME,MAAMA,CAACC,KAAY,EAAuB;IAC5C,IAAI,CAAC,MAAMA,KAAK,CAACC,OAAO,CAAC,CAAC,IAAIR,yBAAyB,EAAE;MACrD,OAAO,IAAIS,0CAAoB,CAC3B,MAAM,IAAI,CAACC,eAAe,CAACH,KAAK,CAAC,EACjC,IAAI,CAACF,eACT,CAAC;IACL;IAEA,OAAO,IAAIM,sCAAkB,CAACJ,KAAK,CAAC;EACxC;EAEUG,eAAeA,CAACH,KAAY,EAAE;IACpC,OAAO,IAAAK,qBAAY,EACf,IAAI,CAACT,EAAE,EACP,IAAIU,yBAAgB,CAAC;MACjBC,MAAM,EAAE,IAAI,CAACV,MAAM;MACnBW,GAAG,EAAER,KAAK,CAACS,MAAM,CAAC;IACtB,CAAC,CAAC,EACF;MAAEC,SAAS,EAAE,IAAI,CAACZ;IAAgB,CACtC,CAAC;EACL;AACJ;AAACa,OAAA,CAAAjB,gBAAA,GAAAA,gBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_clientS","require","_S3RedirectAssetReply","_S3StreamAssetReply","S3OutputStrategy","constructor","s3","bucket","presignedUrlTtl","assetStreamingMaxSize","output","asset","getSize","console","log","S3RedirectAssetReply","getPresignedUrl","S3StreamAssetReply","getSignedUrl","GetObjectCommand","Bucket","Key","getKey","expiresIn","exports"],"sources":["S3OutputStrategy.ts"],"sourcesContent":["import { Asset, AssetOutputStrategy, AssetReply } from \"@webiny/api-file-manager\";\nimport { GetObjectCommand, getSignedUrl, S3 } from \"@webiny/aws-sdk/client-s3\";\nimport { S3RedirectAssetReply } from \"~/assetDelivery/s3/S3RedirectAssetReply\";\nimport { S3StreamAssetReply } from \"~/assetDelivery/s3/S3StreamAssetReply\";\n\n/**\n * This strategy outputs an asset taking into account the size of the asset contents.\n * If the asset is larger than 5MB, a presigned URL will be generated, and a redirect will happen.\n */\nexport class S3OutputStrategy implements AssetOutputStrategy {\n private readonly s3: S3;\n private readonly bucket: string;\n private readonly presignedUrlTtl: number;\n private readonly assetStreamingMaxSize: number;\n\n constructor(s3: S3, bucket: string, presignedUrlTtl: number, assetStreamingMaxSize: number) {\n this.assetStreamingMaxSize = assetStreamingMaxSize;\n this.presignedUrlTtl = presignedUrlTtl;\n this.s3 = s3;\n this.bucket = bucket;\n }\n\n async output(asset: Asset): Promise<AssetReply> {\n if (asset.getSize() > this.assetStreamingMaxSize) {\n console.log(\n `Asset size is greater than ${this.assetStreamingMaxSize}; redirecting to a presigned S3 URL.`\n );\n\n return new S3RedirectAssetReply(\n await this.getPresignedUrl(asset),\n this.presignedUrlTtl\n );\n }\n\n console.log(\n `Asset size is smaller than ${this.assetStreamingMaxSize}; streaming directly from Lambda function.`\n );\n return new S3StreamAssetReply(asset);\n }\n\n protected getPresignedUrl(asset: Asset) {\n return getSignedUrl(\n this.s3,\n new GetObjectCommand({\n Bucket: this.bucket,\n Key: asset.getKey()\n }),\n { expiresIn: this.presignedUrlTtl }\n );\n }\n}\n"],"mappings":";;;;;;AACA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AACA,IAAAE,mBAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA;AACO,MAAMG,gBAAgB,CAAgC;EAMzDC,WAAWA,CAACC,EAAM,EAAEC,MAAc,EAAEC,eAAuB,EAAEC,qBAA6B,EAAE;IACxF,IAAI,CAACA,qBAAqB,GAAGA,qBAAqB;IAClD,IAAI,CAACD,eAAe,GAAGA,eAAe;IACtC,IAAI,CAACF,EAAE,GAAGA,EAAE;IACZ,IAAI,CAACC,MAAM,GAAGA,MAAM;EACxB;EAEA,MAAMG,MAAMA,CAACC,KAAY,EAAuB;IAC5C,IAAIA,KAAK,CAACC,OAAO,CAAC,CAAC,GAAG,IAAI,CAACH,qBAAqB,EAAE;MAC9CI,OAAO,CAACC,GAAG,CACN,8BAA6B,IAAI,CAACL,qBAAsB,sCAC7D,CAAC;MAED,OAAO,IAAIM,0CAAoB,CAC3B,MAAM,IAAI,CAACC,eAAe,CAACL,KAAK,CAAC,EACjC,IAAI,CAACH,eACT,CAAC;IACL;IAEAK,OAAO,CAACC,GAAG,CACN,8BAA6B,IAAI,CAACL,qBAAsB,4CAC7D,CAAC;IACD,OAAO,IAAIQ,sCAAkB,CAACN,KAAK,CAAC;EACxC;EAEUK,eAAeA,CAACL,KAAY,EAAE;IACpC,OAAO,IAAAO,qBAAY,EACf,IAAI,CAACZ,EAAE,EACP,IAAIa,yBAAgB,CAAC;MACjBC,MAAM,EAAE,IAAI,CAACb,MAAM;MACnBc,GAAG,EAAEV,KAAK,CAACW,MAAM,CAAC;IACtB,CAAC,CAAC,EACF;MAAEC,SAAS,EAAE,IAAI,CAACf;IAAgB,CACtC,CAAC;EACL;AACJ;AAACgB,OAAA,CAAApB,gBAAA,GAAAA,gBAAA","ignoreList":[]}
@@ -17,6 +17,7 @@ class SharpTransform {
17
17
  }
18
18
  async transform(assetRequest, asset) {
19
19
  if (!utils.SUPPORTED_TRANSFORMABLE_IMAGES.includes(asset.getExtension())) {
20
+ console.log(`Transformations/optimizations of ${asset.getContentType()} assets are not supported. Skipping.`);
20
21
  return asset;
21
22
  }
22
23
 
@@ -36,6 +37,7 @@ class SharpTransform {
36
37
  return this.optimizeAsset(transformedAsset);
37
38
  }
38
39
  async transformAsset(asset, options) {
40
+ console.log("Transform asset", options);
39
41
  if (options.width) {
40
42
  const {
41
43
  s3,
@@ -54,7 +56,15 @@ class SharpTransform {
54
56
  throw new Error(`Missing image body!`);
55
57
  }
56
58
  const buffer = Buffer.from(await Body.transformToByteArray());
57
- asset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => buffer));
59
+ const newAsset = asset.withProps({
60
+ size: buffer.length
61
+ });
62
+ newAsset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => buffer));
63
+ console.log(`Return a previously transformed asset`, {
64
+ key: transformedAssetKey,
65
+ size: newAsset.getSize()
66
+ });
67
+ return newAsset;
58
68
  } catch (e) {
59
69
  const optimizedImage = await this.optimizeAsset(asset);
60
70
  const widths = new _WidthCollection.WidthCollection(this.params.imageResizeWidths);
@@ -63,8 +73,9 @@ class SharpTransform {
63
73
  /**
64
74
  * `width` is the only transformation we currently support.
65
75
  */
76
+ console.log(`Resize the asset (width: ${width})`);
66
77
  const buffer = await optimizedImage.getContents();
67
- const transformedBuffer = (0, _sharp.default)(buffer, {
78
+ const transformedBuffer = await (0, _sharp.default)(buffer, {
68
79
  animated: this.isAssetAnimated(asset)
69
80
  }).withMetadata().resize({
70
81
  width,
@@ -74,13 +85,21 @@ class SharpTransform {
74
85
  /**
75
86
  * Transformations are applied to the optimized image.
76
87
  */
77
- asset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => transformedBuffer));
88
+ const newAsset = asset.withProps({
89
+ size: transformedBuffer.length
90
+ });
91
+ newAsset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => transformedBuffer));
78
92
  await s3.putObject({
79
93
  Bucket: bucket,
80
94
  Key: transformedAssetKey,
81
- ContentType: asset.getContentType(),
82
- Body: await asset.getContents()
95
+ ContentType: newAsset.getContentType(),
96
+ Body: await newAsset.getContents()
97
+ });
98
+ console.log(`Return the resized asset`, {
99
+ key: transformedAssetKey,
100
+ size: newAsset.getSize()
83
101
  });
102
+ return newAsset;
84
103
  }
85
104
  }
86
105
  return asset;
@@ -90,6 +109,12 @@ class SharpTransform {
90
109
  s3,
91
110
  bucket
92
111
  } = this.params;
112
+ console.log("Optimize asset", {
113
+ id: asset.getId(),
114
+ key: asset.getKey(),
115
+ size: asset.getSize(),
116
+ type: asset.getContentType()
117
+ });
93
118
  const assetKey = new _AssetKeyGenerator.AssetKeyGenerator(asset);
94
119
  const optimizedAssetKey = assetKey.getOptimizedImageKey();
95
120
  try {
@@ -102,9 +127,15 @@ class SharpTransform {
102
127
  if (!Body) {
103
128
  throw new Error(`Missing image body!`);
104
129
  }
130
+ console.log("Return a previously optimized asset", optimizedAssetKey);
105
131
  const buffer = Buffer.from(await Body.transformToByteArray());
106
- asset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => buffer));
132
+ const newAsset = asset.withProps({
133
+ size: buffer.length
134
+ });
135
+ newAsset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => buffer));
136
+ return newAsset;
107
137
  } catch (e) {
138
+ console.log("Create an optimized version of the original asset", asset.getKey());
108
139
  // If not found, create an optimized version of the original asset.
109
140
  const buffer = await asset.getContents();
110
141
  const optimizationMap = {
@@ -114,19 +145,23 @@ class SharpTransform {
114
145
  };
115
146
  const optimization = optimizationMap[asset.getContentType()];
116
147
  if (!optimization) {
117
- console.log(`no optimizations defined for ${asset.getContentType()}`);
148
+ console.log(`No optimizations defined for ${asset.getContentType()}`);
118
149
  return asset;
119
150
  }
120
- const optimizedBuffer = optimization(buffer).toBuffer();
121
- asset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => optimizedBuffer));
151
+ const optimizedBuffer = await optimization(buffer).toBuffer();
152
+ console.log("Optimized asset size", optimizedBuffer.length);
153
+ const newAsset = asset.withProps({
154
+ size: optimizedBuffer.length
155
+ });
156
+ newAsset.setContentsReader(new _CallableContentsReader.CallableContentsReader(() => optimizedBuffer));
122
157
  await s3.putObject({
123
158
  Bucket: bucket,
124
159
  Key: optimizedAssetKey,
125
- ContentType: asset.getContentType(),
126
- Body: await asset.getContents()
160
+ ContentType: newAsset.getContentType(),
161
+ Body: await newAsset.getContents()
127
162
  });
163
+ return newAsset;
128
164
  }
129
- return asset;
130
165
  }
131
166
  isAssetAnimated(asset) {
132
167
  return ["gif", "webp"].includes(asset.getExtension());
@@ -1 +1 @@
1
- {"version":3,"names":["_sharp","_interopRequireDefault","require","_WidthCollection","utils","_interopRequireWildcard","_CallableContentsReader","_AssetKeyGenerator","SharpTransform","constructor","params","transform","assetRequest","asset","SUPPORTED_TRANSFORMABLE_IMAGES","includes","getExtension","original","options","getOptions","transformedAsset","clone","Object","keys","length","transformAsset","optimizeAsset","width","s3","bucket","assetKey","AssetKeyGenerator","transformedAssetKey","getTransformedImageKey","Body","getObject","Bucket","Key","Error","buffer","Buffer","from","transformToByteArray","setContentsReader","CallableContentsReader","e","optimizedImage","widths","WidthCollection","imageResizeWidths","getClosestOrMax","getContents","transformedBuffer","sharp","animated","isAssetAnimated","withMetadata","resize","withoutEnlargement","toBuffer","putObject","ContentType","getContentType","optimizedAssetKey","getOptimizedImageKey","optimizationMap","optimizePng","optimizeJpeg","optimization","console","log","optimizedBuffer","fit","png","compressionLevel","adaptiveFiltering","force","toFormat","quality","exports"],"sources":["SharpTransform.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3\";\nimport {\n Asset,\n AssetRequest,\n AssetRequestOptions,\n AssetTransformationStrategy\n} from \"@webiny/api-file-manager\";\nimport { WidthCollection } from \"./transformation/WidthCollection\";\nimport * as utils from \"./transformation/utils\";\nimport { CallableContentsReader } from \"./transformation/CallableContentsReader\";\nimport { AssetKeyGenerator } from \"./transformation/AssetKeyGenerator\";\n\ninterface SharpTransformationParams {\n s3: S3;\n bucket: string;\n imageResizeWidths: number[];\n}\n\nexport class SharpTransform implements AssetTransformationStrategy {\n private readonly params: SharpTransformationParams;\n\n constructor(params: SharpTransformationParams) {\n this.params = params;\n }\n\n async transform(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n if (!utils.SUPPORTED_TRANSFORMABLE_IMAGES.includes(asset.getExtension())) {\n return asset;\n }\n\n // `original` is part of the request, but it won't even get to this point in the execution.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { original, ...options } = assetRequest.getOptions();\n\n const transformedAsset = asset.clone();\n\n if (Object.keys(options).length > 0) {\n // Transformations were requested.\n return this.transformAsset(transformedAsset, options);\n }\n\n // Return an optimized asset.\n return this.optimizeAsset(transformedAsset);\n }\n\n private async transformAsset(asset: Asset, options: Omit<AssetRequestOptions, \"original\">) {\n if (options.width) {\n const { s3, bucket } = this.params;\n\n const assetKey = new AssetKeyGenerator(asset);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n try {\n const { Body } = await s3.getObject({\n Bucket: 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 asset.setContentsReader(new CallableContentsReader(() => buffer));\n } catch (e) {\n const optimizedImage = await this.optimizeAsset(asset);\n\n const widths = new WidthCollection(this.params.imageResizeWidths);\n const width = widths.getClosestOrMax(options.width);\n\n /**\n * `width` is the only transformation we currently support.\n */\n const buffer = await optimizedImage.getContents();\n const transformedBuffer = sharp(buffer, { animated: this.isAssetAnimated(asset) })\n .withMetadata()\n .resize({ width, withoutEnlargement: true })\n .toBuffer();\n\n /**\n * Transformations are applied to the optimized image.\n */\n asset.setContentsReader(new CallableContentsReader(() => transformedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: transformedAssetKey,\n ContentType: asset.getContentType(),\n Body: await asset.getContents()\n });\n }\n }\n\n return asset;\n }\n\n private async optimizeAsset(asset: Asset) {\n const { s3, bucket } = this.params;\n\n const assetKey = new AssetKeyGenerator(asset);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await s3.getObject({\n Bucket: bucket,\n Key: optimizedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n asset.setContentsReader(new CallableContentsReader(() => buffer));\n } catch (e) {\n // If not found, create an optimized version of the original asset.\n const buffer = await asset.getContents();\n\n const optimizationMap: Record<string, ((buffer: Buffer) => sharp.Sharp) | undefined> = {\n \"image/png\": (buffer: Buffer) => this.optimizePng(buffer),\n \"image/jpeg\": (buffer: Buffer) => this.optimizeJpeg(buffer),\n \"image/jpg\": (buffer: Buffer) => this.optimizeJpeg(buffer)\n };\n\n const optimization = optimizationMap[asset.getContentType()];\n\n if (!optimization) {\n console.log(`no optimizations defined for ${asset.getContentType()}`);\n return asset;\n }\n\n const optimizedBuffer = optimization(buffer).toBuffer();\n\n asset.setContentsReader(new CallableContentsReader(() => optimizedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: optimizedAssetKey,\n ContentType: asset.getContentType(),\n Body: await asset.getContents()\n });\n }\n\n return asset;\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n\n private optimizePng(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .png({ compressionLevel: 9, adaptiveFiltering: true, force: true })\n .withMetadata();\n }\n\n private optimizeJpeg(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .withMetadata()\n .toFormat(\"jpeg\", { quality: 90 });\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_sharp","_interopRequireDefault","require","_WidthCollection","utils","_interopRequireWildcard","_CallableContentsReader","_AssetKeyGenerator","SharpTransform","constructor","params","transform","assetRequest","asset","SUPPORTED_TRANSFORMABLE_IMAGES","includes","getExtension","console","log","getContentType","original","options","getOptions","transformedAsset","clone","Object","keys","length","transformAsset","optimizeAsset","width","s3","bucket","assetKey","AssetKeyGenerator","transformedAssetKey","getTransformedImageKey","Body","getObject","Bucket","Key","Error","buffer","Buffer","from","transformToByteArray","newAsset","withProps","size","setContentsReader","CallableContentsReader","key","getSize","e","optimizedImage","widths","WidthCollection","imageResizeWidths","getClosestOrMax","getContents","transformedBuffer","sharp","animated","isAssetAnimated","withMetadata","resize","withoutEnlargement","toBuffer","putObject","ContentType","id","getId","getKey","type","optimizedAssetKey","getOptimizedImageKey","optimizationMap","optimizePng","optimizeJpeg","optimization","optimizedBuffer","fit","png","compressionLevel","adaptiveFiltering","force","toFormat","quality","exports"],"sources":["SharpTransform.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3\";\nimport {\n Asset,\n AssetRequest,\n AssetRequestOptions,\n AssetTransformationStrategy\n} from \"@webiny/api-file-manager\";\nimport { WidthCollection } from \"./transformation/WidthCollection\";\nimport * as utils from \"./transformation/utils\";\nimport { CallableContentsReader } from \"./transformation/CallableContentsReader\";\nimport { AssetKeyGenerator } from \"./transformation/AssetKeyGenerator\";\n\ninterface SharpTransformationParams {\n s3: S3;\n bucket: string;\n imageResizeWidths: number[];\n}\n\nexport class SharpTransform implements AssetTransformationStrategy {\n private readonly params: SharpTransformationParams;\n\n constructor(params: SharpTransformationParams) {\n this.params = params;\n }\n\n async transform(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n if (!utils.SUPPORTED_TRANSFORMABLE_IMAGES.includes(asset.getExtension())) {\n console.log(\n `Transformations/optimizations of ${asset.getContentType()} assets are not supported. Skipping.`\n );\n return asset;\n }\n\n // `original` is part of the request, but it won't even get to this point in the execution.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { original, ...options } = assetRequest.getOptions();\n\n const transformedAsset = asset.clone();\n\n if (Object.keys(options).length > 0) {\n // Transformations were requested.\n return this.transformAsset(transformedAsset, options);\n }\n\n // Return an optimized asset.\n return this.optimizeAsset(transformedAsset);\n }\n\n private async transformAsset(asset: Asset, options: Omit<AssetRequestOptions, \"original\">) {\n console.log(\"Transform asset\", options);\n if (options.width) {\n const { s3, bucket } = this.params;\n\n const assetKey = new AssetKeyGenerator(asset);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n try {\n const { Body } = await s3.getObject({\n Bucket: 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 });\n newAsset.setContentsReader(new CallableContentsReader(() => buffer));\n\n console.log(`Return a previously transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n } catch (e) {\n const optimizedImage = await this.optimizeAsset(asset);\n\n const widths = new WidthCollection(this.params.imageResizeWidths);\n const width = widths.getClosestOrMax(options.width);\n\n /**\n * `width` is the only transformation we currently support.\n */\n console.log(`Resize the asset (width: ${width})`);\n const buffer = await optimizedImage.getContents();\n const transformedBuffer = await sharp(buffer, {\n animated: this.isAssetAnimated(asset)\n })\n .withMetadata()\n .resize({ width, withoutEnlargement: true })\n .toBuffer();\n\n /**\n * Transformations are applied to the optimized image.\n */\n const newAsset = asset.withProps({ size: transformedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => transformedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: transformedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n console.log(`Return the resized asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n }\n }\n\n return asset;\n }\n\n private async optimizeAsset(asset: Asset) {\n const { s3, bucket } = this.params;\n\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 = new AssetKeyGenerator(asset);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await s3.getObject({\n Bucket: 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(new CallableContentsReader(() => buffer));\n\n return newAsset;\n } catch (e) {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n // If not found, create an optimized version of the original asset.\n const buffer = await asset.getContents();\n\n const optimizationMap: Record<string, ((buffer: Buffer) => sharp.Sharp) | undefined> = {\n \"image/png\": (buffer: Buffer) => this.optimizePng(buffer),\n \"image/jpeg\": (buffer: Buffer) => this.optimizeJpeg(buffer),\n \"image/jpg\": (buffer: Buffer) => this.optimizeJpeg(buffer)\n };\n\n const optimization = optimizationMap[asset.getContentType()];\n\n if (!optimization) {\n console.log(`No optimizations defined for ${asset.getContentType()}`);\n return asset;\n }\n\n const optimizedBuffer = await optimization(buffer).toBuffer();\n\n console.log(\"Optimized asset size\", optimizedBuffer.length);\n\n const newAsset = asset.withProps({ size: optimizedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => optimizedBuffer));\n\n await s3.putObject({\n Bucket: 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 private optimizePng(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .png({ compressionLevel: 9, adaptiveFiltering: true, force: true })\n .withMetadata();\n }\n\n private optimizeJpeg(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .withMetadata()\n .toFormat(\"jpeg\", { quality: 90 });\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { AssetContentsReader } from "@webiny/api-file-manager";
3
4
  interface ContentsCallable {
4
5
  (): Promise<Buffer> | Buffer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/api-file-manager-s3",
3
- "version": "5.41.0-dbt.0",
3
+ "version": "5.41.0",
4
4
  "main": "index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,17 +10,17 @@
10
10
  "author": "Webiny Ltd",
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "@webiny/api": "5.41.0-dbt.0",
14
- "@webiny/api-file-manager": "5.41.0-dbt.0",
15
- "@webiny/api-security": "5.41.0-dbt.0",
16
- "@webiny/aws-sdk": "5.41.0-dbt.0",
17
- "@webiny/error": "5.41.0-dbt.0",
18
- "@webiny/handler": "5.41.0-dbt.0",
19
- "@webiny/handler-graphql": "5.41.0-dbt.0",
20
- "@webiny/plugins": "5.41.0-dbt.0",
21
- "@webiny/tasks": "5.41.0-dbt.0",
22
- "@webiny/utils": "5.41.0-dbt.0",
23
- "@webiny/validation": "5.41.0-dbt.0",
13
+ "@webiny/api": "5.41.0",
14
+ "@webiny/api-file-manager": "5.41.0",
15
+ "@webiny/api-security": "5.41.0",
16
+ "@webiny/aws-sdk": "5.41.0",
17
+ "@webiny/error": "5.41.0",
18
+ "@webiny/handler": "5.41.0",
19
+ "@webiny/handler-graphql": "5.41.0",
20
+ "@webiny/plugins": "5.41.0",
21
+ "@webiny/tasks": "5.41.0",
22
+ "@webiny/utils": "5.41.0",
23
+ "@webiny/validation": "5.41.0",
24
24
  "form-data": "4.0.0",
25
25
  "mime": "3.0.0",
26
26
  "node-fetch": "2.7.0",
@@ -34,8 +34,8 @@
34
34
  "@babel/cli": "7.24.1",
35
35
  "@babel/core": "7.24.3",
36
36
  "@types/node-fetch": "2.6.2",
37
- "@webiny/cli": "5.41.0-dbt.0",
38
- "@webiny/project-utils": "5.41.0-dbt.0",
37
+ "@webiny/cli": "5.41.0",
38
+ "@webiny/project-utils": "5.41.0",
39
39
  "rimraf": "5.0.5",
40
40
  "typescript": "4.9.5"
41
41
  },
@@ -47,5 +47,5 @@
47
47
  "build": "yarn webiny run build",
48
48
  "watch": "yarn webiny run watch"
49
49
  },
50
- "gitHead": "bbaec4dd1685579548c08bbde386aee5d96b80f8"
50
+ "gitHead": "a542f4d0806744c5e2333b3786478c4af3b6b750"
51
51
  }
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Response } from "node-fetch";
3
4
  import { PresignedPost } from "@webiny/aws-sdk/client-s3";
4
5
  declare const _default: (buffer: Buffer, preSignedPostPayload: PresignedPost) => Promise<Response>;