@webiny/api-file-manager-s3 6.4.11 → 6.6.0-alpha.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.
- package/FileManagerS3Feature.d.ts +9 -0
- package/FileManagerS3Feature.js +27 -0
- package/FileManagerS3Feature.js.map +1 -0
- package/assetDelivery/abstractions.d.ts +2 -0
- package/assetDelivery/abstractions.js.map +1 -1
- package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
- package/assetDelivery/assetDeliveryConfig.js +0 -2
- package/assetDelivery/assetDeliveryConfig.js.map +1 -1
- package/assetDelivery/feature.js +3 -2
- package/assetDelivery/feature.js.map +1 -1
- package/assetDelivery/s3/LazySharpTransform.d.ts +34 -0
- package/assetDelivery/s3/LazySharpTransform.js +34 -0
- package/assetDelivery/s3/LazySharpTransform.js.map +1 -0
- package/assetDelivery/s3/SharpTransform.d.ts +15 -7
- package/assetDelivery/s3/SharpTransform.js +112 -101
- package/assetDelivery/s3/SharpTransform.js.map +1 -1
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.d.ts +21 -1
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js +43 -27
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js.map +1 -1
- package/assetDelivery/threatDetection/processThreatScanResult.js +9 -7
- package/assetDelivery/threatDetection/processThreatScanResult.js.map +1 -1
- package/assetDelivery/types.d.ts +3 -0
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.d.ts +3 -1
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js +7 -2
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js.map +1 -1
- package/features/DeleteFileFromBucket/DeleteS3FolderTask.d.ts +1 -1
- package/features/ExtractMetadata/ExtractMetadataTask.d.ts +1 -1
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js +1 -1
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js.map +1 -1
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js +1 -1
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js.map +1 -1
- package/features/FlushCache/InvalidateCacheTask.d.ts +2 -2
- package/features/FlushCache/InvalidateCacheTask.js +2 -2
- package/features/FlushCache/InvalidateCacheTask.js.map +1 -1
- package/features/WriteFileMetadata/MetadataWriter.js +3 -1
- package/features/WriteFileMetadata/MetadataWriter.js.map +1 -1
- package/graphql/S3GraphQLSchema.d.ts +9 -0
- package/graphql/S3GraphQLSchema.js +229 -0
- package/graphql/S3GraphQLSchema.js.map +1 -0
- package/index.d.ts +2 -2
- package/index.js +1 -29
- package/package.json +21 -19
- package/utils/FileUploadModifier.d.ts +8 -2
- package/utils/FileUploadModifier.js +5 -3
- package/utils/FileUploadModifier.js.map +1 -1
- package/utils/createFileNormalizerFromContext.js +2 -2
- package/utils/createFileNormalizerFromContext.js.map +1 -1
- package/utils/uploadFileToS3.d.ts +1 -1
- package/graphql/schema.d.ts +0 -1
- package/graphql/schema.js +0 -203
- package/graphql/schema.js.map +0 -1
- package/index.js.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Container } from "@webiny/feature/api";
|
|
2
|
+
import type { AssetDeliveryParams } from "./assetDelivery/types.js";
|
|
3
|
+
export interface FileManagerS3FeatureConfig {
|
|
4
|
+
assetDelivery?: AssetDeliveryParams;
|
|
5
|
+
}
|
|
6
|
+
export declare const FileManagerS3Feature: {
|
|
7
|
+
name: string;
|
|
8
|
+
register(container: Container, context?: FileManagerS3FeatureConfig | undefined): void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { S3GraphQLSchema } from "./graphql/S3GraphQLSchema.js";
|
|
3
|
+
import { DeleteFileFromBucketFeature } from "./features/DeleteFileFromBucket/feature.js";
|
|
4
|
+
import { WriteFileMetadataFeature } from "./features/WriteFileMetadata/feature.js";
|
|
5
|
+
import { ApplyThreatScanningFeature } from "./enterprise/ApplyThreatScanning/feature.js";
|
|
6
|
+
import { FlushCacheFeature } from "./features/FlushCache/feature.js";
|
|
7
|
+
import { ExtractMetadataFeature } from "./features/ExtractMetadata/feature.js";
|
|
8
|
+
import { GetFileContentsByIdFeature } from "./features/GetFileContentsById/feature.js";
|
|
9
|
+
import { GetFileContentsByKeyFeature } from "./features/GetFileContentsByKey/feature.js";
|
|
10
|
+
import { createS3AssetDeliveryFeature } from "./assetDelivery/feature.js";
|
|
11
|
+
const FileManagerS3Feature = createFeature({
|
|
12
|
+
name: "FileManagerS3",
|
|
13
|
+
register (container, config = {}) {
|
|
14
|
+
createS3AssetDeliveryFeature(config.assetDelivery).register(container);
|
|
15
|
+
FlushCacheFeature.register(container);
|
|
16
|
+
DeleteFileFromBucketFeature.register(container);
|
|
17
|
+
ExtractMetadataFeature.register(container);
|
|
18
|
+
WriteFileMetadataFeature.register(container);
|
|
19
|
+
GetFileContentsByIdFeature.register(container);
|
|
20
|
+
GetFileContentsByKeyFeature.register(container);
|
|
21
|
+
container.register(S3GraphQLSchema);
|
|
22
|
+
ApplyThreatScanningFeature.register(container);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
export { FileManagerS3Feature };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=FileManagerS3Feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileManagerS3Feature.js","sources":["../src/FileManagerS3Feature.ts"],"sourcesContent":["import { type Container, createFeature } from \"@webiny/feature/api\";\nimport { S3GraphQLSchema } from \"./graphql/S3GraphQLSchema.js\";\nimport { DeleteFileFromBucketFeature } from \"~/features/DeleteFileFromBucket/feature.js\";\nimport { WriteFileMetadataFeature } from \"~/features/WriteFileMetadata/feature.js\";\nimport { ApplyThreatScanningFeature } from \"~/enterprise/ApplyThreatScanning/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nimport { GetFileContentsByIdFeature } from \"~/features/GetFileContentsById/feature.js\";\nimport { GetFileContentsByKeyFeature } from \"~/features/GetFileContentsByKey/feature.js\";\nimport { createS3AssetDeliveryFeature } from \"./assetDelivery/feature.js\";\nimport type { AssetDeliveryParams } from \"./assetDelivery/types.js\";\n\nexport interface FileManagerS3FeatureConfig {\n assetDelivery?: AssetDeliveryParams;\n}\n\nexport const FileManagerS3Feature = createFeature({\n name: \"FileManagerS3\",\n register(container: Container, config: FileManagerS3FeatureConfig = {}) {\n // Register S3-specific asset delivery implementations (S3AssetResolver, S3OutputStrategy).\n // These replace the null implementations from AssetDeliveryFeature in FileManagerAppFeature.\n createS3AssetDeliveryFeature(config.assetDelivery).register(container);\n\n // S3 file-operation features.\n FlushCacheFeature.register(container);\n DeleteFileFromBucketFeature.register(container);\n ExtractMetadataFeature.register(container);\n WriteFileMetadataFeature.register(container);\n GetFileContentsByIdFeature.register(container);\n GetFileContentsByKeyFeature.register(container);\n\n // Static S3 GraphQL schema (extends FmQuery/FmMutation) — a DI-native\n // CoreGraphQLSchemaFactory contributor (declares its resolver dependencies).\n container.register(S3GraphQLSchema);\n\n // Threat scanning is WCP-gated, but the license is per-request (loaded post-register). Register\n // unconditionally; CreateFileWithThreatScanDecorator + the GuardDuty event handler both guard\n // on canUseFileManagerThreatDetection() at request time and no-op/pass-through when unlicensed.\n ApplyThreatScanningFeature.register(container);\n }\n});\n"],"names":["FileManagerS3Feature","createFeature","container","config","createS3AssetDeliveryFeature","FlushCacheFeature","DeleteFileFromBucketFeature","ExtractMetadataFeature","WriteFileMetadataFeature","GetFileContentsByIdFeature","GetFileContentsByKeyFeature","S3GraphQLSchema","ApplyThreatScanningFeature"],"mappings":";;;;;;;;;;AAgBO,MAAMA,uBAAuBC,cAAc;IAC9C,MAAM;IACN,UAASC,SAAoB,EAAEC,SAAqC,CAAC,CAAC;QAGlEC,6BAA6BD,OAAO,aAAa,EAAE,QAAQ,CAACD;QAG5DG,kBAAkB,QAAQ,CAACH;QAC3BI,4BAA4B,QAAQ,CAACJ;QACrCK,uBAAuB,QAAQ,CAACL;QAChCM,yBAAyB,QAAQ,CAACN;QAClCO,2BAA2B,QAAQ,CAACP;QACpCQ,4BAA4B,QAAQ,CAACR;QAIrCA,UAAU,QAAQ,CAACS;QAKnBC,2BAA2B,QAAQ,CAACV;IACxC;AACJ"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { S3 } from "@webiny/aws-sdk/client-s3/index.js";
|
|
2
|
+
import type { ImageFormat } from "@webiny/api-file-manager/features/assetDelivery/transformation/index.js";
|
|
2
3
|
export interface IS3AssetDeliveryConfig {
|
|
3
4
|
presignedUrlTtl: number;
|
|
4
5
|
imageResizeWidths: number[];
|
|
6
|
+
imageQuality?: Partial<Record<ImageFormat, number>>;
|
|
5
7
|
assetStreamingMaxSize: number;
|
|
6
8
|
}
|
|
7
9
|
export declare const S3AssetDeliveryConfig: import("@webiny/di").Abstraction<IS3AssetDeliveryConfig>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/abstractions.js","sources":["../../src/assetDelivery/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\n\nexport interface IS3AssetDeliveryConfig {\n presignedUrlTtl: number;\n imageResizeWidths: number[];\n assetStreamingMaxSize: number;\n}\n\nexport const S3AssetDeliveryConfig =\n createAbstraction<IS3AssetDeliveryConfig>(\"AssetDelivery/S3Config\");\n\nexport const S3Client = createAbstraction<S3>(\"AssetDelivery/S3Client\");\n\nexport const S3Bucket = createAbstraction<string>(\"AssetDelivery/S3Bucket\");\n"],"names":["S3AssetDeliveryConfig","createAbstraction","S3Client","S3Bucket"],"mappings":";
|
|
1
|
+
{"version":3,"file":"assetDelivery/abstractions.js","sources":["../../src/assetDelivery/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport type { ImageFormat } from \"@webiny/api-file-manager/features/assetDelivery/transformation/index.js\";\n\nexport interface IS3AssetDeliveryConfig {\n presignedUrlTtl: number;\n imageResizeWidths: number[];\n imageQuality?: Partial<Record<ImageFormat, number>>;\n assetStreamingMaxSize: number;\n}\n\nexport const S3AssetDeliveryConfig =\n createAbstraction<IS3AssetDeliveryConfig>(\"AssetDelivery/S3Config\");\n\nexport const S3Client = createAbstraction<S3>(\"AssetDelivery/S3Client\");\n\nexport const S3Bucket = createAbstraction<string>(\"AssetDelivery/S3Bucket\");\n"],"names":["S3AssetDeliveryConfig","createAbstraction","S3Client","S3Bucket"],"mappings":";AAWO,MAAMA,wBACTC,kBAA0C;AAEvC,MAAMC,WAAWD,kBAAsB;AAEvC,MAAME,WAAWF,kBAA0B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { AssetDeliveryParams } from "../assetDelivery/types.js";
|
|
2
|
-
export declare const assetDeliveryConfig: (params: AssetDeliveryParams) =>
|
|
2
|
+
export declare const assetDeliveryConfig: (params: AssetDeliveryParams) => import("@webiny/handler").RegisterExtensionPlugin<import("@webiny/handler/types").Context>[];
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { createAssetDelivery } from "@webiny/api-file-manager";
|
|
2
1
|
import { createRegisterExtensionPlugin } from "@webiny/handler";
|
|
3
2
|
import { createS3AssetDeliveryFeature } from "./feature.js";
|
|
4
3
|
const assetDeliveryConfig = (params)=>{
|
|
5
4
|
const feature = createS3AssetDeliveryFeature(params);
|
|
6
5
|
return [
|
|
7
|
-
createAssetDelivery(),
|
|
8
6
|
createRegisterExtensionPlugin((context)=>{
|
|
9
7
|
feature.register(context.container);
|
|
10
8
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/assetDeliveryConfig.js","sources":["../../src/assetDelivery/assetDeliveryConfig.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"assetDelivery/assetDeliveryConfig.js","sources":["../../src/assetDelivery/assetDeliveryConfig.ts"],"sourcesContent":["import { createRegisterExtensionPlugin } from \"@webiny/handler\";\nimport type { AssetDeliveryParams } from \"~/assetDelivery/types.js\";\nimport { createS3AssetDeliveryFeature } from \"~/assetDelivery/feature.js\";\n\nexport const assetDeliveryConfig = (params: AssetDeliveryParams) => {\n const feature = createS3AssetDeliveryFeature(params);\n\n return [\n createRegisterExtensionPlugin(context => {\n feature.register(context.container);\n })\n ];\n};\n"],"names":["assetDeliveryConfig","params","feature","createS3AssetDeliveryFeature","createRegisterExtensionPlugin","context"],"mappings":";;AAIO,MAAMA,sBAAsB,CAACC;IAChC,MAAMC,UAAUC,6BAA6BF;IAE7C,OAAO;QACHG,8BAA8BC,CAAAA;YAC1BH,QAAQ,QAAQ,CAACG,QAAQ,SAAS;QACtC;KACH;AACL"}
|
package/assetDelivery/feature.js
CHANGED
|
@@ -3,7 +3,7 @@ import { S3 } from "@webiny/aws-sdk/client-s3/index.js";
|
|
|
3
3
|
import { S3AssetDeliveryConfig, S3Bucket, S3Client } from "./abstractions.js";
|
|
4
4
|
import { S3AssetResolverImpl } from "./s3/S3AssetResolver.js";
|
|
5
5
|
import { S3OutputStrategyImpl } from "./s3/S3OutputStrategy.js";
|
|
6
|
-
import {
|
|
6
|
+
import { LazySharpTransformImpl } from "./s3/LazySharpTransform.js";
|
|
7
7
|
const createS3AssetDeliveryFeature = (params = {})=>createFeature({
|
|
8
8
|
name: "AssetDelivery/S3",
|
|
9
9
|
register (container) {
|
|
@@ -25,11 +25,12 @@ const createS3AssetDeliveryFeature = (params = {})=>createFeature({
|
|
|
25
25
|
2048,
|
|
26
26
|
3840
|
|
27
27
|
],
|
|
28
|
+
imageQuality: params.imageQuality ?? {},
|
|
28
29
|
assetStreamingMaxSize: params.assetStreamingMaxSize ?? 4718592
|
|
29
30
|
});
|
|
30
31
|
container.register(S3AssetResolverImpl);
|
|
31
32
|
container.register(S3OutputStrategyImpl);
|
|
32
|
-
container.register(
|
|
33
|
+
if ("asset-delivery" === process.env.WEBINY_FUNCTION_TYPE) container.register(LazySharpTransformImpl).inSingletonScope();
|
|
33
34
|
}
|
|
34
35
|
});
|
|
35
36
|
export { createS3AssetDeliveryFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/feature.js","sources":["../../src/assetDelivery/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { S3Client, S3Bucket, S3AssetDeliveryConfig } from \"./abstractions.js\";\nimport type { AssetDeliveryParams } from \"./types.js\";\nimport { S3AssetResolverImpl } from \"./s3/S3AssetResolver.js\";\nimport { S3OutputStrategyImpl } from \"./s3/S3OutputStrategy.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"assetDelivery/feature.js","sources":["../../src/assetDelivery/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { S3Client, S3Bucket, S3AssetDeliveryConfig } from \"./abstractions.js\";\nimport type { AssetDeliveryParams } from \"./types.js\";\nimport { S3AssetResolverImpl } from \"./s3/S3AssetResolver.js\";\nimport { S3OutputStrategyImpl } from \"./s3/S3OutputStrategy.js\";\nimport { LazySharpTransformImpl } from \"./s3/LazySharpTransform.js\";\n\nexport const createS3AssetDeliveryFeature = (params: AssetDeliveryParams = {}) => {\n return createFeature({\n name: \"AssetDelivery/S3\",\n register(container) {\n container.registerInstance(\n S3Client,\n new S3({ region: process.env.AWS_REGION as string })\n );\n container.registerInstance(S3Bucket, process.env.S3_BUCKET as string);\n container.registerInstance(S3AssetDeliveryConfig, {\n presignedUrlTtl: params.presignedUrlTtl ?? 3600,\n imageResizeWidths: params.imageResizeWidths ?? [\n 128, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840\n ],\n imageQuality: params.imageQuality ?? {},\n assetStreamingMaxSize: params.assetStreamingMaxSize ?? 4718592\n });\n\n container.register(S3AssetResolverImpl);\n container.register(S3OutputStrategyImpl);\n\n if (process.env.WEBINY_FUNCTION_TYPE === \"asset-delivery\") {\n // Registered eagerly; `sharp` is still loaded lazily, inside the handler.\n container.register(LazySharpTransformImpl).inSingletonScope();\n }\n }\n });\n};\n"],"names":["createS3AssetDeliveryFeature","params","createFeature","container","S3Client","S3","process","S3Bucket","S3AssetDeliveryConfig","S3AssetResolverImpl","S3OutputStrategyImpl","LazySharpTransformImpl"],"mappings":";;;;;;AAQO,MAAMA,+BAA+B,CAACC,SAA8B,CAAC,CAAC,GAClEC,cAAc;QACjB,MAAM;QACN,UAASC,SAAS;YACdA,UAAU,gBAAgB,CACtBC,UACA,IAAIC,GAAG;gBAAE,QAAQC,QAAQ,GAAG,CAAC,UAAU;YAAW;YAEtDH,UAAU,gBAAgB,CAACI,UAAUD,QAAQ,GAAG,CAAC,SAAS;YAC1DH,UAAU,gBAAgB,CAACK,uBAAuB;gBAC9C,iBAAiBP,OAAO,eAAe,IAAI;gBAC3C,mBAAmBA,OAAO,iBAAiB,IAAI;oBAC3C;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;oBAAM;oBAAM;oBAAM;oBAAM;iBACpD;gBACD,cAAcA,OAAO,YAAY,IAAI,CAAC;gBACtC,uBAAuBA,OAAO,qBAAqB,IAAI;YAC3D;YAEAE,UAAU,QAAQ,CAACM;YACnBN,UAAU,QAAQ,CAACO;YAEnB,IAAIJ,AAAqC,qBAArCA,QAAQ,GAAG,CAAC,oBAAoB,EAEhCH,UAAU,QAAQ,CAACQ,wBAAwB,gBAAgB;QAEnE;IACJ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { S3 } from "@webiny/aws-sdk/client-s3/index.js";
|
|
2
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
3
|
+
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
4
|
+
import { ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
|
|
5
|
+
import type { Asset } from "@webiny/api-file-manager/delivery/AssetDelivery/Asset.js";
|
|
6
|
+
import type { AssetRequest } from "@webiny/api-file-manager/delivery/AssetDelivery/AssetRequest.js";
|
|
7
|
+
import type { IS3AssetDeliveryConfig } from "../../assetDelivery/abstractions.js";
|
|
8
|
+
/**
|
|
9
|
+
* Defers loading `sharp` until an image is actually transformed.
|
|
10
|
+
*
|
|
11
|
+
* The dynamic import is deliberate — it keeps `sharp` out of the main bundle (note the
|
|
12
|
+
* `webpackChunkName`). That import is async and DI resolution is not, which is why this used to be
|
|
13
|
+
* a per-request `RequestContextInitializer` that imported the module and then registered the real
|
|
14
|
+
* handler. `IAssetTypeHandler` has a single async method, so the import can be awaited there
|
|
15
|
+
* instead.
|
|
16
|
+
*
|
|
17
|
+
* The constructed handler IS memoized: the initializer registered it `.inSingletonScope()`, and
|
|
18
|
+
* nothing below caches the instance (Node caches the module, not the object built from it).
|
|
19
|
+
*/
|
|
20
|
+
declare class LazySharpTransform implements ImageAssetTypeHandler.Interface {
|
|
21
|
+
private readonly s3;
|
|
22
|
+
private readonly bucket;
|
|
23
|
+
private readonly config;
|
|
24
|
+
private readonly identityContext;
|
|
25
|
+
private readonly getFile;
|
|
26
|
+
private handler;
|
|
27
|
+
constructor(s3: S3, bucket: string, config: IS3AssetDeliveryConfig, identityContext: IdentityContext.Interface, getFile: GetFileUseCase.Interface);
|
|
28
|
+
private resolveHandler;
|
|
29
|
+
handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset>;
|
|
30
|
+
}
|
|
31
|
+
export declare const LazySharpTransformImpl: typeof LazySharpTransform & {
|
|
32
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType.js").IAssetTypeHandler>;
|
|
33
|
+
};
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
2
|
+
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
3
|
+
import { ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
|
|
4
|
+
import { S3AssetDeliveryConfig, S3Bucket, S3Client } from "../abstractions.js";
|
|
5
|
+
class LazySharpTransform {
|
|
6
|
+
constructor(s3, bucket, config, identityContext, getFile){
|
|
7
|
+
this.s3 = s3;
|
|
8
|
+
this.bucket = bucket;
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.identityContext = identityContext;
|
|
11
|
+
this.getFile = getFile;
|
|
12
|
+
this.handler = null;
|
|
13
|
+
}
|
|
14
|
+
resolveHandler() {
|
|
15
|
+
if (!this.handler) this.handler = import("./SharpTransform.js").then(({ SharpTransform })=>new SharpTransform(this.s3, this.bucket, this.config, this.identityContext, this.getFile));
|
|
16
|
+
return this.handler;
|
|
17
|
+
}
|
|
18
|
+
async handle(assetRequest, asset) {
|
|
19
|
+
return (await this.resolveHandler()).handle(assetRequest, asset);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const LazySharpTransformImpl = ImageAssetTypeHandler.createImplementation({
|
|
23
|
+
implementation: LazySharpTransform,
|
|
24
|
+
dependencies: [
|
|
25
|
+
S3Client,
|
|
26
|
+
S3Bucket,
|
|
27
|
+
S3AssetDeliveryConfig,
|
|
28
|
+
IdentityContext,
|
|
29
|
+
GetFileUseCase
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
export { LazySharpTransformImpl };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=LazySharpTransform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetDelivery/s3/LazySharpTransform.js","sources":["../../../src/assetDelivery/s3/LazySharpTransform.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 { 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 { S3AssetDeliveryConfig, S3Bucket, S3Client } from \"~/assetDelivery/abstractions.js\";\nimport type { IS3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\n/**\n * Defers loading `sharp` until an image is actually transformed.\n *\n * The dynamic import is deliberate — it keeps `sharp` out of the main bundle (note the\n * `webpackChunkName`). That import is async and DI resolution is not, which is why this used to be\n * a per-request `RequestContextInitializer` that imported the module and then registered the real\n * handler. `IAssetTypeHandler` has a single async method, so the import can be awaited there\n * instead.\n *\n * The constructed handler IS memoized: the initializer registered it `.inSingletonScope()`, and\n * nothing below caches the instance (Node caches the module, not the object built from it).\n */\nclass LazySharpTransform implements ImageAssetTypeHandler.Interface {\n private handler: Promise<ImageAssetTypeHandler.Interface> | null = null;\n\n constructor(\n private readonly s3: S3,\n private readonly bucket: string,\n private readonly config: IS3AssetDeliveryConfig,\n private readonly identityContext: IdentityContext.Interface,\n private readonly getFile: GetFileUseCase.Interface\n ) {}\n\n private resolveHandler(): Promise<ImageAssetTypeHandler.Interface> {\n if (!this.handler) {\n this.handler = import(\n /* webpackChunkName: \"s3AssetDelivery\" */ \"./SharpTransform.js\"\n ).then(\n ({ SharpTransform }) =>\n new SharpTransform(\n this.s3,\n this.bucket,\n this.config,\n this.identityContext,\n this.getFile\n )\n );\n }\n return this.handler;\n }\n\n async handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n return (await this.resolveHandler()).handle(assetRequest, asset);\n }\n}\n\nexport const LazySharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: LazySharpTransform,\n dependencies: [S3Client, S3Bucket, S3AssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["LazySharpTransform","s3","bucket","config","identityContext","getFile","SharpTransform","assetRequest","asset","LazySharpTransformImpl","ImageAssetTypeHandler","S3Client","S3Bucket","S3AssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":";;;;AAqBA,MAAMA;IAGF,YACqBC,EAAM,EACNC,MAAc,EACdC,MAA8B,EAC9BC,eAA0C,EAC1CC,OAAiC,CACpD;aALmBJ,EAAE,GAAFA;aACAC,MAAM,GAANA;aACAC,MAAM,GAANA;aACAC,eAAe,GAAfA;aACAC,OAAO,GAAPA;aAPb,OAAO,GAAoD;IAQhE;IAEK,iBAA2D;QAC/D,IAAI,CAAC,IAAI,CAAC,OAAO,EACb,IAAI,CAAC,OAAO,GAAG,MAAM,CAAN,uBAEb,IAAI,CACF,CAAC,EAAEC,cAAc,EAAE,GACf,IAAIA,eACA,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,OAAO;QAI5B,OAAO,IAAI,CAAC,OAAO;IACvB;IAEA,MAAM,OAAOC,YAA0B,EAAEC,KAAY,EAAkB;QACnE,OAAQ,OAAM,IAAI,CAAC,cAAc,EAAC,EAAG,MAAM,CAACD,cAAcC;IAC9D;AACJ;AAEO,MAAMC,yBAAyBC,sBAAsB,oBAAoB,CAAC;IAC7E,gBAAgBV;IAChB,cAAc;QAACW;QAAUC;QAAUC;QAAuBC;QAAiBC;KAAe;AAC9F"}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import type { S3 } from "@webiny/aws-sdk/client-s3/index.js";
|
|
2
|
-
import
|
|
2
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
3
|
+
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
4
|
+
import { ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
|
|
5
|
+
import type { Asset } from "@webiny/api-file-manager/delivery/AssetDelivery/Asset.js";
|
|
6
|
+
import type { AssetRequest } from "@webiny/api-file-manager/delivery/AssetDelivery/AssetRequest.js";
|
|
3
7
|
import type { IS3AssetDeliveryConfig } from "../../assetDelivery/abstractions.js";
|
|
4
|
-
export declare class SharpTransform implements
|
|
8
|
+
export declare class SharpTransform implements ImageAssetTypeHandler.Interface {
|
|
5
9
|
private readonly s3;
|
|
6
10
|
private readonly bucket;
|
|
7
11
|
private readonly imageResizeWidths;
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
private readonly imageQuality;
|
|
13
|
+
private readonly identityContext;
|
|
14
|
+
private readonly getFile;
|
|
15
|
+
private transformer?;
|
|
16
|
+
constructor(s3: S3, bucket: string, config: IS3AssetDeliveryConfig, identityContext: IdentityContext.Interface, getFile: GetFileUseCase.Interface);
|
|
17
|
+
private getTransformer;
|
|
18
|
+
handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset>;
|
|
19
|
+
private loadAssetCrop;
|
|
10
20
|
private transformAsset;
|
|
11
21
|
private optimizeAsset;
|
|
12
22
|
private isAssetAnimated;
|
|
13
|
-
private optimizePng;
|
|
14
|
-
private optimizeJpeg;
|
|
15
23
|
}
|
|
16
24
|
export declare const SharpTransformImpl: typeof SharpTransform & {
|
|
17
|
-
__abstraction: import("@webiny/di").Abstraction<
|
|
25
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType").IAssetTypeHandler>;
|
|
18
26
|
};
|
|
@@ -1,85 +1,110 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { AssetKeyGenerator } from "
|
|
1
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
2
|
+
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
3
|
+
import { CallableContentsReader, DEFAULT_IMAGE_QUALITY, contentTypeForFormat } from "@webiny/api-file-manager/features/assetDelivery/transformation/index.js";
|
|
4
|
+
import { normalizeImageOptions } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/normalizeImageOptions.js";
|
|
5
|
+
import { AssetKeyGenerator, ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
|
|
6
6
|
import { S3AssetDeliveryConfig, S3Bucket, S3Client } from "../abstractions.js";
|
|
7
|
-
|
|
7
|
+
const hasTransform = (options)=>void 0 !== options.width || void 0 !== options.format || void 0 !== options.quality;
|
|
8
8
|
class SharpTransform {
|
|
9
|
-
constructor(s3, bucket, config){
|
|
9
|
+
constructor(s3, bucket, config, identityContext, getFile){
|
|
10
10
|
this.s3 = s3;
|
|
11
11
|
this.bucket = bucket;
|
|
12
12
|
this.imageResizeWidths = config.imageResizeWidths;
|
|
13
|
+
this.imageQuality = {
|
|
14
|
+
...DEFAULT_IMAGE_QUALITY,
|
|
15
|
+
...config.imageQuality ?? {}
|
|
16
|
+
};
|
|
17
|
+
this.identityContext = identityContext;
|
|
18
|
+
this.getFile = getFile;
|
|
13
19
|
}
|
|
14
|
-
async
|
|
15
|
-
if (!
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
async getTransformer() {
|
|
21
|
+
if (!this.transformer) {
|
|
22
|
+
const { SharpTransformer } = await import("@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js");
|
|
23
|
+
this.transformer = new SharpTransformer();
|
|
18
24
|
}
|
|
19
|
-
|
|
25
|
+
return this.transformer;
|
|
26
|
+
}
|
|
27
|
+
async handle(assetRequest, asset) {
|
|
28
|
+
const rawQuery = assetRequest.getOptions();
|
|
29
|
+
const acceptHeader = assetRequest.getContext().accept;
|
|
30
|
+
const { original, crop, focal, aspectRatio, ...options } = normalizeImageOptions(rawQuery, acceptHeader);
|
|
31
|
+
const assetCrop = await this.loadAssetCrop(asset.getId());
|
|
32
|
+
const framing = {
|
|
33
|
+
crop: crop ?? assetCrop,
|
|
34
|
+
focal,
|
|
35
|
+
aspectRatio
|
|
36
|
+
};
|
|
20
37
|
const transformedAsset = asset.clone();
|
|
21
|
-
if (
|
|
22
|
-
return this.optimizeAsset(transformedAsset);
|
|
38
|
+
if (hasTransform(options)) return this.transformAsset(transformedAsset, options, framing);
|
|
39
|
+
return this.optimizeAsset(transformedAsset, framing);
|
|
23
40
|
}
|
|
24
|
-
async
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
41
|
+
async loadAssetCrop(fileId) {
|
|
42
|
+
const result = await this.identityContext.withoutAuthorization(()=>this.getFile.execute(fileId));
|
|
43
|
+
if (result.isFail()) return;
|
|
44
|
+
const imageEdit = result.value.metadata?.imageEdit;
|
|
45
|
+
return imageEdit?.crop;
|
|
46
|
+
}
|
|
47
|
+
async transformAsset(asset, options, framing) {
|
|
48
|
+
const assetKey = AssetKeyGenerator.create(asset, framing);
|
|
49
|
+
const transformedAssetKey = assetKey.getTransformedImageKey(options);
|
|
50
|
+
const contentType = options.format ? contentTypeForFormat(options.format) : asset.getContentType();
|
|
51
|
+
try {
|
|
52
|
+
const { Body } = await this.s3.getObject({
|
|
53
|
+
Bucket: this.bucket,
|
|
54
|
+
Key: transformedAssetKey
|
|
55
|
+
});
|
|
56
|
+
if (!Body) throw new Error("Missing image body!");
|
|
57
|
+
const buffer = Buffer.from(await Body.transformToByteArray());
|
|
58
|
+
const newAsset = asset.withProps({
|
|
59
|
+
size: buffer.length,
|
|
60
|
+
contentType
|
|
61
|
+
});
|
|
62
|
+
newAsset.setContentsReader(CallableContentsReader.create(()=>buffer));
|
|
63
|
+
console.log("Return a previously transformed asset", {
|
|
64
|
+
key: transformedAssetKey,
|
|
65
|
+
size: newAsset.getSize()
|
|
66
|
+
});
|
|
67
|
+
return newAsset;
|
|
68
|
+
} catch {
|
|
69
|
+
const optimizedImage = await this.optimizeAsset(asset, framing);
|
|
70
|
+
console.log("Transform the asset", options);
|
|
71
|
+
const baseBuffer = await optimizedImage.getContents();
|
|
72
|
+
const transformer = await this.getTransformer();
|
|
73
|
+
const { buffer: transformedBuffer, contentType: outputContentType } = await transformer.transformBuffer({
|
|
74
|
+
buffer: baseBuffer,
|
|
75
|
+
animated: this.isAssetAnimated(asset),
|
|
76
|
+
sourceContentType: asset.getContentType(),
|
|
77
|
+
widths: this.imageResizeWidths,
|
|
78
|
+
options,
|
|
79
|
+
qualityDefaults: this.imageQuality
|
|
80
|
+
});
|
|
81
|
+
const newAsset = asset.withProps({
|
|
82
|
+
size: transformedBuffer.length,
|
|
83
|
+
contentType: outputContentType
|
|
84
|
+
});
|
|
85
|
+
newAsset.setContentsReader(CallableContentsReader.create(()=>transformedBuffer));
|
|
86
|
+
await this.s3.putObject({
|
|
87
|
+
Bucket: this.bucket,
|
|
88
|
+
Key: transformedAssetKey,
|
|
89
|
+
ContentType: newAsset.getContentType(),
|
|
90
|
+
Body: await newAsset.getContents()
|
|
91
|
+
});
|
|
92
|
+
console.log("Return the transformed asset", {
|
|
93
|
+
key: transformedAssetKey,
|
|
94
|
+
size: newAsset.getSize(),
|
|
95
|
+
contentType: newAsset.getContentType()
|
|
96
|
+
});
|
|
97
|
+
return newAsset;
|
|
72
98
|
}
|
|
73
|
-
return asset;
|
|
74
99
|
}
|
|
75
|
-
async optimizeAsset(asset) {
|
|
100
|
+
async optimizeAsset(asset, framing) {
|
|
76
101
|
console.log("Optimize asset", {
|
|
77
102
|
id: asset.getId(),
|
|
78
103
|
key: asset.getKey(),
|
|
79
104
|
size: asset.getSize(),
|
|
80
105
|
type: asset.getContentType()
|
|
81
106
|
});
|
|
82
|
-
const assetKey =
|
|
107
|
+
const assetKey = AssetKeyGenerator.create(asset, framing);
|
|
83
108
|
const optimizedAssetKey = assetKey.getOptimizedImageKey();
|
|
84
109
|
try {
|
|
85
110
|
const { Body } = await this.s3.getObject({
|
|
@@ -92,27 +117,31 @@ class SharpTransform {
|
|
|
92
117
|
const newAsset = asset.withProps({
|
|
93
118
|
size: buffer.length
|
|
94
119
|
});
|
|
95
|
-
newAsset.setContentsReader(
|
|
120
|
+
newAsset.setContentsReader(CallableContentsReader.create(()=>buffer));
|
|
96
121
|
return newAsset;
|
|
97
122
|
} catch {
|
|
98
123
|
console.log("Create an optimized version of the original asset", asset.getKey());
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
if (!
|
|
107
|
-
console.log(`No optimizations defined for ${
|
|
124
|
+
let buffer = await asset.getContents();
|
|
125
|
+
const transformer = await this.getTransformer();
|
|
126
|
+
const framed = await transformer.extractFramedRegion(buffer, framing);
|
|
127
|
+
const cropped = framed !== buffer;
|
|
128
|
+
buffer = framed;
|
|
129
|
+
const contentType = asset.getContentType();
|
|
130
|
+
const canOptimize = "image/png" === contentType || "image/jpeg" === contentType || "image/jpg" === contentType;
|
|
131
|
+
if (!canOptimize && !cropped) {
|
|
132
|
+
console.log(`No optimizations defined for ${contentType}`);
|
|
108
133
|
return asset;
|
|
109
134
|
}
|
|
110
|
-
|
|
111
|
-
|
|
135
|
+
let finalBuffer = buffer;
|
|
136
|
+
if (canOptimize) {
|
|
137
|
+
const pipeline = "image/png" === contentType ? await transformer.optimizePng(buffer) : await transformer.optimizeJpeg(buffer);
|
|
138
|
+
finalBuffer = await pipeline.toBuffer();
|
|
139
|
+
}
|
|
140
|
+
console.log("Optimized asset size", finalBuffer.length);
|
|
112
141
|
const newAsset = asset.withProps({
|
|
113
|
-
size:
|
|
142
|
+
size: finalBuffer.length
|
|
114
143
|
});
|
|
115
|
-
newAsset.setContentsReader(
|
|
144
|
+
newAsset.setContentsReader(CallableContentsReader.create(()=>finalBuffer));
|
|
116
145
|
await this.s3.putObject({
|
|
117
146
|
Bucket: this.bucket,
|
|
118
147
|
Key: optimizedAssetKey,
|
|
@@ -128,33 +157,15 @@ class SharpTransform {
|
|
|
128
157
|
"webp"
|
|
129
158
|
].includes(asset.getExtension());
|
|
130
159
|
}
|
|
131
|
-
optimizePng(buffer) {
|
|
132
|
-
return sharp(buffer).resize({
|
|
133
|
-
width: 2560,
|
|
134
|
-
withoutEnlargement: true,
|
|
135
|
-
fit: "inside"
|
|
136
|
-
}).png({
|
|
137
|
-
compressionLevel: 9,
|
|
138
|
-
adaptiveFiltering: true,
|
|
139
|
-
force: true
|
|
140
|
-
}).withMetadata();
|
|
141
|
-
}
|
|
142
|
-
optimizeJpeg(buffer) {
|
|
143
|
-
return sharp(buffer).resize({
|
|
144
|
-
width: 2560,
|
|
145
|
-
withoutEnlargement: true,
|
|
146
|
-
fit: "inside"
|
|
147
|
-
}).withMetadata().toFormat("jpeg", {
|
|
148
|
-
quality: 90
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
160
|
}
|
|
152
|
-
const SharpTransformImpl =
|
|
161
|
+
const SharpTransformImpl = ImageAssetTypeHandler.createImplementation({
|
|
153
162
|
implementation: SharpTransform,
|
|
154
163
|
dependencies: [
|
|
155
164
|
S3Client,
|
|
156
165
|
S3Bucket,
|
|
157
|
-
S3AssetDeliveryConfig
|
|
166
|
+
S3AssetDeliveryConfig,
|
|
167
|
+
IdentityContext,
|
|
168
|
+
GetFileUseCase
|
|
158
169
|
]
|
|
159
170
|
});
|
|
160
171
|
export { SharpTransform, SharpTransformImpl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/s3/SharpTransform.js","sources":["../../../src/assetDelivery/s3/SharpTransform.ts"],"sourcesContent":["import sharp, { type Sharp } from \"sharp\";\nimport type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport type {\n Asset,\n AssetRequest,\n AssetRequestOptions,\n AssetTransformationStrategy\n} from \"@webiny/api-file-manager\";\nimport { AssetTransformationStrategy as AssetTransformationStrategyAbstraction } from \"@webiny/api-file-manager/features/assetDelivery/abstractions.js\";\nimport { WidthCollection } from \"./transformation/WidthCollection.js\";\nimport * as utils from \"./transformation/utils.js\";\nimport { CallableContentsReader } from \"./transformation/CallableContentsReader.js\";\nimport { AssetKeyGenerator } from \"./transformation/AssetKeyGenerator.js\";\nimport { S3Client, S3Bucket, S3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { IS3AssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\nexport class SharpTransform implements AssetTransformationStrategy {\n private readonly s3: S3;\n private readonly bucket: string;\n private readonly imageResizeWidths: number[];\n\n constructor(s3: S3, bucket: string, config: IS3AssetDeliveryConfig) {\n this.s3 = s3;\n this.bucket = bucket;\n this.imageResizeWidths = config.imageResizeWidths;\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 // oxlint-disable-next-line typescript/no-unused-vars\n const { original, ...options } = assetRequest.getOptions();\n\n const transformedAsset = asset.clone();\n\n if (Object.keys(options).length > 0) {\n return this.transformAsset(transformedAsset, options);\n }\n\n return this.optimizeAsset(transformedAsset);\n }\n\n private async transformAsset(asset: Asset, options: Omit<AssetRequestOptions, \"original\">) {\n if (options.width) {\n const assetKey = new AssetKeyGenerator(asset);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\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 });\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 {\n const optimizedImage = await this.optimizeAsset(asset);\n\n const widths = new WidthCollection(this.imageResizeWidths);\n const width = widths.getClosestOrMax(options.width);\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 const newAsset = asset.withProps({ size: transformedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => 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 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 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 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(new CallableContentsReader(() => buffer));\n\n return newAsset;\n } catch {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n const buffer = await asset.getContents();\n\n const optimizationMap: Record<string, ((buffer: Buffer) => 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 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 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\nexport const SharpTransformImpl = AssetTransformationStrategyAbstraction.createImplementation({\n implementation: SharpTransform,\n dependencies: [S3Client, S3Bucket, S3AssetDeliveryConfig]\n});\n"],"names":["SharpTransform","s3","bucket","config","assetRequest","asset","utils","console","original","options","transformedAsset","Object","assetKey","AssetKeyGenerator","transformedAssetKey","Body","Error","buffer","Buffer","newAsset","CallableContentsReader","optimizedImage","widths","WidthCollection","width","transformedBuffer","sharp","optimizedAssetKey","optimizationMap","optimization","optimizedBuffer","SharpTransformImpl","AssetTransformationStrategyAbstraction","S3Client","S3Bucket","S3AssetDeliveryConfig"],"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?.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":";;;;;;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"}
|
|
@@ -1,2 +1,22 @@
|
|
|
1
|
+
import type { Container } from "@webiny/feature/api";
|
|
2
|
+
import type { EventBridgeEvent } from "@webiny/aws-sdk/types/index.js";
|
|
3
|
+
import { EventBridgeEventHandler, type EventBridgeResult } from "@webiny/event-handler-aws/abstractions/handlers/EventBridgeEventHandler.js";
|
|
4
|
+
import type { ITenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
5
|
+
import type { IGetTenantByIdUseCase } from "@webiny/api-core/features/tenancy/GetTenantById/abstractions.js";
|
|
6
|
+
import type { EventContext, NextFunction } from "@webiny/event-handler-core";
|
|
1
7
|
import type { GuardDutyEvent } from "./types.js";
|
|
2
|
-
|
|
8
|
+
declare class ThreatDetectionEventBridgeLambdaHandlerImpl implements EventBridgeEventHandler.Interface {
|
|
9
|
+
private container;
|
|
10
|
+
private tenantCtx;
|
|
11
|
+
private getTenantById;
|
|
12
|
+
constructor(container: Container, tenantCtx: ITenantContext, getTenantById: IGetTenantByIdUseCase);
|
|
13
|
+
execute(eventCtx: EventContext<EventBridgeEvent<string, GuardDutyEvent>>, _next: NextFunction): Promise<EventBridgeResult>;
|
|
14
|
+
}
|
|
15
|
+
export declare const ThreatDetectionEventBridgeLambdaHandler: typeof ThreatDetectionEventBridgeLambdaHandlerImpl & {
|
|
16
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-aws/abstractions/handlers/EventBridgeEventHandler.js").IEventBridgeEventHandler>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Use ThreatDetectionEventBridgeLambdaHandler instead.
|
|
20
|
+
*/
|
|
21
|
+
export declare const createThreatDetectionEventHandler: () => never[];
|
|
22
|
+
export {};
|