@webiny/api-file-manager-server 0.0.0-unstable.b6d7105cee → 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.
Files changed (89) hide show
  1. package/FileManagerServerFeature.d.ts +5 -0
  2. package/FileManagerServerFeature.js +41 -0
  3. package/FileManagerServerFeature.js.map +1 -0
  4. package/assetDelivery/LazyLocalSharpTransform.d.ts +33 -0
  5. package/assetDelivery/LazyLocalSharpTransform.js +32 -0
  6. package/assetDelivery/LazyLocalSharpTransform.js.map +1 -0
  7. package/assetDelivery/LocalAssetResolver.d.ts +6 -4
  8. package/assetDelivery/LocalAssetResolver.js +9 -9
  9. package/assetDelivery/LocalAssetResolver.js.map +1 -1
  10. package/assetDelivery/LocalOutputStrategy.d.ts +3 -2
  11. package/assetDelivery/LocalOutputStrategy.js +4 -4
  12. package/assetDelivery/LocalOutputStrategy.js.map +1 -1
  13. package/assetDelivery/LocalSharpTransform.d.ts +2 -2
  14. package/assetDelivery/LocalSharpTransform.js +20 -33
  15. package/assetDelivery/LocalSharpTransform.js.map +1 -1
  16. package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
  17. package/assetDelivery/feature.js +6 -6
  18. package/assetDelivery/feature.js.map +1 -1
  19. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.d.ts +3 -0
  20. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js +18 -14
  21. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js.map +1 -1
  22. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.d.ts +7 -5
  23. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js +8 -5
  24. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js.map +1 -1
  25. package/features/CompleteMultiPartUpload/feature.js +2 -2
  26. package/features/CompleteMultiPartUpload/feature.js.map +1 -1
  27. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.d.ts +7 -7
  28. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js +9 -10
  29. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js.map +1 -1
  30. package/features/CreateMultiPartUpload/feature.js +2 -2
  31. package/features/CreateMultiPartUpload/feature.js.map +1 -1
  32. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.d.ts +3 -1
  33. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js +6 -3
  34. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js.map +1 -1
  35. package/features/ExtractMetadata/ExtractMetadataTask.d.ts +3 -1
  36. package/features/ExtractMetadata/ExtractMetadataTask.js +6 -3
  37. package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -1
  38. package/features/FileManagerServerConfig/FileManagerServerConfig.d.ts +12 -0
  39. package/features/FileManagerServerConfig/FileManagerServerConfig.js +28 -0
  40. package/features/FileManagerServerConfig/FileManagerServerConfig.js.map +1 -0
  41. package/features/FileManagerServerConfig/abstractions.d.ts +10 -0
  42. package/features/FileManagerServerConfig/abstractions.js +5 -0
  43. package/features/FileManagerServerConfig/abstractions.js.map +1 -0
  44. package/features/FileManagerServerConfig/feature.d.ts +4 -0
  45. package/features/FileManagerServerConfig/feature.js +11 -0
  46. package/features/FileManagerServerConfig/feature.js.map +1 -0
  47. package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +7 -5
  48. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +8 -5
  49. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js.map +1 -1
  50. package/features/GetFileContentsById/feature.js +2 -2
  51. package/features/GetFileContentsById/feature.js.map +1 -1
  52. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.d.ts +7 -5
  53. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +8 -5
  54. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js.map +1 -1
  55. package/features/GetFileContentsByKey/feature.js +2 -2
  56. package/features/GetFileContentsByKey/feature.js.map +1 -1
  57. package/features/GetUploadPayload/GetUploadPayloadUseCase.d.ts +6 -6
  58. package/features/GetUploadPayload/GetUploadPayloadUseCase.js +8 -9
  59. package/features/GetUploadPayload/GetUploadPayloadUseCase.js.map +1 -1
  60. package/features/GetUploadPayload/feature.js +2 -2
  61. package/features/GetUploadPayload/feature.js.map +1 -1
  62. package/graphql/ServerGraphQLSchema.d.ts +15 -0
  63. package/graphql/ServerGraphQLSchema.js +221 -0
  64. package/graphql/ServerGraphQLSchema.js.map +1 -0
  65. package/index.d.ts +1 -2
  66. package/index.js +1 -40
  67. package/package.json +15 -15
  68. package/routes/UploadPartRoute/UploadPartRoute.d.ts +23 -0
  69. package/routes/UploadPartRoute/UploadPartRoute.js +71 -0
  70. package/routes/UploadPartRoute/UploadPartRoute.js.map +1 -0
  71. package/routes/UploadPartRoute/feature.d.ts +4 -0
  72. package/routes/UploadPartRoute/feature.js +11 -0
  73. package/routes/UploadPartRoute/feature.js.map +1 -0
  74. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.d.ts +23 -0
  75. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js +78 -0
  76. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js.map +1 -0
  77. package/routes/UploadSingleFileRoute/feature.d.ts +4 -0
  78. package/routes/UploadSingleFileRoute/feature.js +11 -0
  79. package/routes/UploadSingleFileRoute/feature.js.map +1 -0
  80. package/routes/utils.d.ts +18 -0
  81. package/routes/utils.js +55 -0
  82. package/routes/utils.js.map +1 -0
  83. package/index.js.map +0 -1
  84. package/routes/uploadRoutes.d.ts +0 -4
  85. package/routes/uploadRoutes.js +0 -130
  86. package/routes/uploadRoutes.js.map +0 -1
  87. package/utils/resolveServerUrl.d.ts +0 -2
  88. package/utils/resolveServerUrl.js +0 -10
  89. package/utils/resolveServerUrl.js.map +0 -1
@@ -0,0 +1,5 @@
1
+ import { type Container } from "@webiny/feature/api";
2
+ export declare const FileManagerServerFeature: {
3
+ name: string;
4
+ register(container: Container): void;
5
+ };
@@ -0,0 +1,41 @@
1
+ import { createFeature } from "@webiny/feature/api";
2
+ import { ReadFileMetadataFeature } from "@webiny/api-file-manager/features/upload/ReadFileMetadata/feature.js";
3
+ import { WriteFileMetadataFeature } from "@webiny/api-file-manager/features/upload/WriteFileMetadata/feature.js";
4
+ import { createLocalAssetDeliveryFeature } from "./assetDelivery/feature.js";
5
+ import { ServerGraphQLSchema } from "./graphql/ServerGraphQLSchema.js";
6
+ import { FileManagerServerConfigFeature } from "./features/FileManagerServerConfig/feature.js";
7
+ import { UploadSingleFileRouteFeature } from "./routes/UploadSingleFileRoute/feature.js";
8
+ import { UploadPartRouteFeature } from "./routes/UploadPartRoute/feature.js";
9
+ import { CleanupStaleMultipartUploadsFeature } from "./features/CleanupStaleMultipartUploads/feature.js";
10
+ import { DeleteFileFromDiskFeature } from "./features/DeleteFileFromDisk/feature.js";
11
+ import { ExtractMetadataFeature } from "./features/ExtractMetadata/feature.js";
12
+ import { FlushCacheFeature } from "./features/FlushCache/feature.js";
13
+ import { GetFileContentsByIdFeature } from "./features/GetFileContentsById/feature.js";
14
+ import { GetFileContentsByKeyFeature } from "./features/GetFileContentsByKey/feature.js";
15
+ import { GetUploadPayloadFeature } from "./features/GetUploadPayload/feature.js";
16
+ import { CreateMultiPartUploadFeature } from "./features/CreateMultiPartUpload/feature.js";
17
+ import { CompleteMultiPartUploadFeature } from "./features/CompleteMultiPartUpload/feature.js";
18
+ const FileManagerServerFeature = createFeature({
19
+ name: "FileManagerServer",
20
+ register (container) {
21
+ FileManagerServerConfigFeature.register(container);
22
+ createLocalAssetDeliveryFeature().register(container);
23
+ ReadFileMetadataFeature.register(container);
24
+ WriteFileMetadataFeature.register(container);
25
+ FlushCacheFeature.register(container);
26
+ DeleteFileFromDiskFeature.register(container);
27
+ ExtractMetadataFeature.register(container);
28
+ GetFileContentsByIdFeature.register(container);
29
+ GetFileContentsByKeyFeature.register(container);
30
+ GetUploadPayloadFeature.register(container);
31
+ CreateMultiPartUploadFeature.register(container);
32
+ CompleteMultiPartUploadFeature.register(container);
33
+ CleanupStaleMultipartUploadsFeature.register(container);
34
+ UploadSingleFileRouteFeature.register(container);
35
+ UploadPartRouteFeature.register(container);
36
+ container.register(ServerGraphQLSchema);
37
+ }
38
+ });
39
+ export { FileManagerServerFeature };
40
+
41
+ //# sourceMappingURL=FileManagerServerFeature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileManagerServerFeature.js","sources":["../src/FileManagerServerFeature.ts"],"sourcesContent":["import { type Container, createFeature } from \"@webiny/feature/api\";\nimport { ReadFileMetadataFeature } from \"@webiny/api-file-manager/features/upload/ReadFileMetadata/feature.js\";\nimport { WriteFileMetadataFeature } from \"@webiny/api-file-manager/features/upload/WriteFileMetadata/feature.js\";\nimport { createLocalAssetDeliveryFeature } from \"~/assetDelivery/feature.js\";\nimport { ServerGraphQLSchema } from \"~/graphql/ServerGraphQLSchema.js\";\nimport { FileManagerServerConfigFeature } from \"~/features/FileManagerServerConfig/feature.js\";\nimport { UploadSingleFileRouteFeature } from \"~/routes/UploadSingleFileRoute/feature.js\";\nimport { UploadPartRouteFeature } from \"~/routes/UploadPartRoute/feature.js\";\nimport { CleanupStaleMultipartUploadsFeature } from \"~/features/CleanupStaleMultipartUploads/feature.js\";\nimport { DeleteFileFromDiskFeature } from \"~/features/DeleteFileFromDisk/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { GetFileContentsByIdFeature } from \"~/features/GetFileContentsById/feature.js\";\nimport { GetFileContentsByKeyFeature } from \"~/features/GetFileContentsByKey/feature.js\";\nimport { GetUploadPayloadFeature } from \"~/features/GetUploadPayload/feature.js\";\nimport { CreateMultiPartUploadFeature } from \"~/features/CreateMultiPartUpload/feature.js\";\nimport { CompleteMultiPartUploadFeature } from \"~/features/CompleteMultiPartUpload/feature.js\";\n\nexport const FileManagerServerFeature = createFeature({\n name: \"FileManagerServer\",\n register(container: Container) {\n // NOTE: do NOT resolve FileManagerServerConfig here. This runs at the file-manager transport\n // hook, BEFORE project extensions (which register the WEBINY_LOCAL_STORAGE_PATH /\n // WEBINY_UPLOAD_SECRET build params) are applied later in the request stack. Config is resolved\n // lazily at request time by the routes/use-cases below; it also ensures its storage dir on\n // construction. Resolving it eagerly here would read the build params before they exist.\n FileManagerServerConfigFeature.register(container);\n\n // Local (disk) asset-delivery implementations (LocalAssetResolver/OutputStrategy/SharpTransform)\n // override the null delivery registered by AssetDeliveryFeature in FileManagerAppFeature — the\n // same seam FileManagerS3Feature uses with createS3AssetDeliveryFeature. Without this the domain\n // AssetDeliveryRoute resolves the null impls and serves nothing.\n createLocalAssetDeliveryFeature().register(container);\n\n // Metadata reader (FileManager/Upload/MetadataReader) — the generic domain impl backed by the\n // GlobalKeyValueStore. Required by the server's ExtractMetadata task + GetFileContentsById use\n // cases; without it createFile fails with \"No registration found for FileManager/Upload/MetadataReader\".\n ReadFileMetadataFeature.register(container);\n\n // Metadata writer — the generic domain WriteMetadataAfterCreate/BatchCreate event handlers write\n // the asset metadata (id/tenant/size/contentType/bucketKey) to the GlobalKeyValueStore on file\n // create. Asset delivery (LocalAssetResolver) reads that metadata to locate the file on disk;\n // without it every delivered file 404s (\"asset not found\"). Mirrors S3's WriteFileMetadataFeature.\n WriteFileMetadataFeature.register(container);\n\n FlushCacheFeature.register(container);\n DeleteFileFromDiskFeature.register(container);\n ExtractMetadataFeature.register(container);\n GetFileContentsByIdFeature.register(container);\n GetFileContentsByKeyFeature.register(container);\n GetUploadPayloadFeature.register(container);\n CreateMultiPartUploadFeature.register(container);\n CompleteMultiPartUploadFeature.register(container);\n CleanupStaleMultipartUploadsFeature.register(container);\n UploadSingleFileRouteFeature.register(container);\n UploadPartRouteFeature.register(container);\n\n // Upload GraphQL (getPreSignedPostPayload/getPreSignedPostPayloads + create/completeMultiPartUpload).\n // Mirrors how FileManagerS3Feature contributes its schema — same query/mutation names so the SDK\n // works unchanged; resolvers delegate to the server upload use cases registered above.\n container.register(ServerGraphQLSchema);\n }\n});\n"],"names":["FileManagerServerFeature","createFeature","container","FileManagerServerConfigFeature","createLocalAssetDeliveryFeature","ReadFileMetadataFeature","WriteFileMetadataFeature","FlushCacheFeature","DeleteFileFromDiskFeature","ExtractMetadataFeature","GetFileContentsByIdFeature","GetFileContentsByKeyFeature","GetUploadPayloadFeature","CreateMultiPartUploadFeature","CompleteMultiPartUploadFeature","CleanupStaleMultipartUploadsFeature","UploadSingleFileRouteFeature","UploadPartRouteFeature","ServerGraphQLSchema"],"mappings":";;;;;;;;;;;;;;;;;AAkBO,MAAMA,2BAA2BC,cAAc;IAClD,MAAM;IACN,UAASC,SAAoB;QAMzBC,+BAA+B,QAAQ,CAACD;QAMxCE,kCAAkC,QAAQ,CAACF;QAK3CG,wBAAwB,QAAQ,CAACH;QAMjCI,yBAAyB,QAAQ,CAACJ;QAElCK,kBAAkB,QAAQ,CAACL;QAC3BM,0BAA0B,QAAQ,CAACN;QACnCO,uBAAuB,QAAQ,CAACP;QAChCQ,2BAA2B,QAAQ,CAACR;QACpCS,4BAA4B,QAAQ,CAACT;QACrCU,wBAAwB,QAAQ,CAACV;QACjCW,6BAA6B,QAAQ,CAACX;QACtCY,+BAA+B,QAAQ,CAACZ;QACxCa,oCAAoC,QAAQ,CAACb;QAC7Cc,6BAA6B,QAAQ,CAACd;QACtCe,uBAAuB,QAAQ,CAACf;QAKhCA,UAAU,QAAQ,CAACgB;IACvB;AACJ"}
@@ -0,0 +1,33 @@
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 type { IAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType.js";
4
+ import type { Asset } from "@webiny/api-file-manager/delivery/AssetDelivery/Asset.js";
5
+ import type { AssetRequest } from "@webiny/api-file-manager/delivery/AssetDelivery/AssetRequest.js";
6
+ import type { ILocalAssetDeliveryConfig } from "../assetDelivery/abstractions.js";
7
+ /**
8
+ * Defers loading `sharp` until an image is actually transformed. Server counterpart of
9
+ * `api-file-manager-s3`'s `LazySharpTransform`.
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 LazyLocalSharpTransform implements IAssetTypeHandler {
21
+ private readonly storagePath;
22
+ private readonly config;
23
+ private readonly identityContext;
24
+ private readonly getFile;
25
+ private handler;
26
+ constructor(storagePath: string, config: ILocalAssetDeliveryConfig, identityContext: IdentityContext.Interface, getFile: GetFileUseCase.Interface);
27
+ private resolveHandler;
28
+ handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset>;
29
+ }
30
+ export declare const LazyLocalSharpTransformImpl: typeof LazyLocalSharpTransform & {
31
+ __abstraction: import("@webiny/di").Abstraction<IAssetTypeHandler>;
32
+ };
33
+ export {};
@@ -0,0 +1,32 @@
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 { LocalAssetDeliveryConfig, LocalStoragePath } from "./abstractions.js";
5
+ class LazyLocalSharpTransform {
6
+ constructor(storagePath, config, identityContext, getFile){
7
+ this.storagePath = storagePath;
8
+ this.config = config;
9
+ this.identityContext = identityContext;
10
+ this.getFile = getFile;
11
+ this.handler = null;
12
+ }
13
+ resolveHandler() {
14
+ if (!this.handler) this.handler = import("./LocalSharpTransform.js").then(({ LocalSharpTransform })=>new LocalSharpTransform(this.storagePath, this.config, this.identityContext, this.getFile));
15
+ return this.handler;
16
+ }
17
+ async handle(assetRequest, asset) {
18
+ return (await this.resolveHandler()).handle(assetRequest, asset);
19
+ }
20
+ }
21
+ const LazyLocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({
22
+ implementation: LazyLocalSharpTransform,
23
+ dependencies: [
24
+ LocalStoragePath,
25
+ LocalAssetDeliveryConfig,
26
+ IdentityContext,
27
+ GetFileUseCase
28
+ ]
29
+ });
30
+ export { LazyLocalSharpTransformImpl };
31
+
32
+ //# sourceMappingURL=LazyLocalSharpTransform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assetDelivery/LazyLocalSharpTransform.js","sources":["../../src/assetDelivery/LazyLocalSharpTransform.ts"],"sourcesContent":["import { 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 { IAssetTypeHandler } from \"@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType.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 { LocalAssetDeliveryConfig, LocalStoragePath } from \"~/assetDelivery/abstractions.js\";\nimport type { ILocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\n/**\n * Defers loading `sharp` until an image is actually transformed. Server counterpart of\n * `api-file-manager-s3`'s `LazySharpTransform`.\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 LazyLocalSharpTransform implements IAssetTypeHandler {\n private handler: Promise<IAssetTypeHandler> | null = null;\n\n constructor(\n private readonly storagePath: string,\n private readonly config: ILocalAssetDeliveryConfig,\n private readonly identityContext: IdentityContext.Interface,\n private readonly getFile: GetFileUseCase.Interface\n ) {}\n\n private resolveHandler(): Promise<IAssetTypeHandler> {\n if (!this.handler) {\n this.handler = import(\n /* webpackChunkName: \"localAssetDelivery\" */ \"./LocalSharpTransform.js\"\n ).then(\n ({ LocalSharpTransform }) =>\n new LocalSharpTransform(\n this.storagePath,\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 LazyLocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: LazyLocalSharpTransform,\n dependencies: [LocalStoragePath, LocalAssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["LazyLocalSharpTransform","storagePath","config","identityContext","getFile","LocalSharpTransform","assetRequest","asset","LazyLocalSharpTransformImpl","ImageAssetTypeHandler","LocalStoragePath","LocalAssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":";;;;AAsBA,MAAMA;IAGF,YACqBC,WAAmB,EACnBC,MAAiC,EACjCC,eAA0C,EAC1CC,OAAiC,CACpD;aAJmBH,WAAW,GAAXA;aACAC,MAAM,GAANA;aACAC,eAAe,GAAfA;aACAC,OAAO,GAAPA;aANb,OAAO,GAAsC;IAOlD;IAEK,iBAA6C;QACjD,IAAI,CAAC,IAAI,CAAC,OAAO,EACb,IAAI,CAAC,OAAO,GAAG,MAAM,CAAN,4BAEb,IAAI,CACF,CAAC,EAAEC,mBAAmB,EAAE,GACpB,IAAIA,oBACA,IAAI,CAAC,WAAW,EAChB,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,8BAA8BC,sBAAsB,oBAAoB,CAAC;IAClF,gBAAgBT;IAChB,cAAc;QAACU;QAAkBC;QAA0BC;QAAiBC;KAAe;AAC/F"}
@@ -1,13 +1,15 @@
1
1
  import { AssetFactory, AssetResolver as AssetResolverAbstraction, ObjectKey } from "@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js";
2
2
  import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
3
- export declare class LocalAssetResolver implements AssetResolverAbstraction.Interface {
3
+ import { FileManagerServerConfig } from "../features/FileManagerServerConfig/abstractions.js";
4
+ declare class AssetResolverImpl implements AssetResolverAbstraction.Interface {
4
5
  private readonly keyValueStore;
5
- private readonly storagePath;
6
+ private readonly config;
6
7
  private readonly objectKey;
7
8
  private readonly assetFactory;
8
- constructor(keyValueStore: GlobalKeyValueStore.Interface, storagePath: string, objectKey: ObjectKey.Interface, assetFactory: AssetFactory.Interface);
9
+ constructor(keyValueStore: GlobalKeyValueStore.Interface, config: FileManagerServerConfig.Interface, objectKey: ObjectKey.Interface, assetFactory: AssetFactory.Interface);
9
10
  resolve(request: AssetResolverAbstraction.Request): Promise<AssetFactory.Asset | undefined>;
10
11
  }
11
- export declare const LocalAssetResolverImpl: typeof LocalAssetResolver & {
12
+ export declare const LocalAssetResolver: typeof AssetResolverImpl & {
12
13
  __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/delivery").AssetResolver>;
13
14
  };
15
+ export {};
@@ -1,11 +1,11 @@
1
1
  import { AssetFactory, AssetResolver, ObjectKey } from "@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js";
2
2
  import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
3
3
  import { LocalContentsReader } from "./LocalContentsReader.js";
4
- import { LocalStoragePath } from "./abstractions.js";
5
- class LocalAssetResolver {
6
- constructor(keyValueStore, storagePath, objectKey, assetFactory){
4
+ import { FileManagerServerConfig } from "../features/FileManagerServerConfig/abstractions.js";
5
+ class AssetResolverImpl {
6
+ constructor(keyValueStore, config, objectKey, assetFactory){
7
7
  this.keyValueStore = keyValueStore;
8
- this.storagePath = storagePath;
8
+ this.config = config;
9
9
  this.objectKey = objectKey;
10
10
  this.assetFactory = assetFactory;
11
11
  }
@@ -22,19 +22,19 @@ class LocalAssetResolver {
22
22
  contentType: metadata.contentType,
23
23
  key: metadata.bucketKey
24
24
  });
25
- asset.setContentsReader(LocalContentsReader.create(this.storagePath));
25
+ asset.setContentsReader(LocalContentsReader.create(this.config.storagePath));
26
26
  return asset;
27
27
  }
28
28
  }
29
- const LocalAssetResolverImpl = AssetResolver.createImplementation({
30
- implementation: LocalAssetResolver,
29
+ const LocalAssetResolver = AssetResolver.createImplementation({
30
+ implementation: AssetResolverImpl,
31
31
  dependencies: [
32
32
  GlobalKeyValueStore,
33
- LocalStoragePath,
33
+ FileManagerServerConfig,
34
34
  ObjectKey,
35
35
  AssetFactory
36
36
  ]
37
37
  });
38
- export { LocalAssetResolver, LocalAssetResolverImpl };
38
+ export { LocalAssetResolver };
39
39
 
40
40
  //# sourceMappingURL=LocalAssetResolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assetDelivery/LocalAssetResolver.js","sources":["../../src/assetDelivery/LocalAssetResolver.ts"],"sourcesContent":["import {\n AssetFactory,\n AssetResolver as AssetResolverAbstraction,\n ObjectKey\n} from \"@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { LocalContentsReader } from \"~/assetDelivery/LocalContentsReader.js\";\nimport { LocalStoragePath } from \"~/assetDelivery/abstractions.js\";\n\ninterface AssetMetadata {\n id: string;\n tenant: string;\n size: number;\n contentType: string;\n bucketKey: string;\n}\n\nexport class LocalAssetResolver implements AssetResolverAbstraction.Interface {\n constructor(\n private readonly keyValueStore: GlobalKeyValueStore.Interface,\n private readonly storagePath: string,\n private readonly objectKey: ObjectKey.Interface,\n private readonly assetFactory: AssetFactory.Interface\n ) {}\n\n async resolve(\n request: AssetResolverAbstraction.Request\n ): Promise<AssetFactory.Asset | undefined> {\n const objectKey = this.objectKey.from(request.getKey());\n const fileId = objectKey.id();\n const result = await this.keyValueStore.get<AssetMetadata>(\n `FileManager/File/${fileId}/Metadata`\n );\n\n if (result.isFail()) {\n return undefined;\n }\n\n const metadata = result.value;\n\n const asset = this.assetFactory.create({\n id: metadata.id,\n tenant: metadata.tenant,\n size: metadata.size,\n contentType: metadata.contentType,\n key: metadata.bucketKey\n });\n\n asset.setContentsReader(LocalContentsReader.create(this.storagePath));\n\n return asset;\n }\n}\n\nexport const LocalAssetResolverImpl = AssetResolverAbstraction.createImplementation({\n implementation: LocalAssetResolver,\n dependencies: [GlobalKeyValueStore, LocalStoragePath, ObjectKey, AssetFactory]\n});\n"],"names":["LocalAssetResolver","keyValueStore","storagePath","objectKey","assetFactory","request","fileId","result","metadata","asset","LocalContentsReader","LocalAssetResolverImpl","AssetResolverAbstraction","GlobalKeyValueStore","LocalStoragePath","ObjectKey","AssetFactory"],"mappings":";;;;AAiBO,MAAMA;IACT,YACqBC,aAA4C,EAC5CC,WAAmB,EACnBC,SAA8B,EAC9BC,YAAoC,CACvD;aAJmBH,aAAa,GAAbA;aACAC,WAAW,GAAXA;aACAC,SAAS,GAATA;aACAC,YAAY,GAAZA;IAClB;IAEH,MAAM,QACFC,OAAyC,EACF;QACvC,MAAMF,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAACE,QAAQ,MAAM;QACpD,MAAMC,SAASH,UAAU,EAAE;QAC3B,MAAMI,SAAS,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CACvC,CAAC,iBAAiB,EAAED,OAAO,SAAS,CAAC;QAGzC,IAAIC,OAAO,MAAM,IACb;QAGJ,MAAMC,WAAWD,OAAO,KAAK;QAE7B,MAAME,QAAQ,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YACnC,IAAID,SAAS,EAAE;YACf,QAAQA,SAAS,MAAM;YACvB,MAAMA,SAAS,IAAI;YACnB,aAAaA,SAAS,WAAW;YACjC,KAAKA,SAAS,SAAS;QAC3B;QAEAC,MAAM,iBAAiB,CAACC,oBAAoB,MAAM,CAAC,IAAI,CAAC,WAAW;QAEnE,OAAOD;IACX;AACJ;AAEO,MAAME,yBAAyBC,cAAAA,oBAA6C,CAAC;IAChF,gBAAgBZ;IAChB,cAAc;QAACa;QAAqBC;QAAkBC;QAAWC;KAAa;AAClF"}
1
+ {"version":3,"file":"assetDelivery/LocalAssetResolver.js","sources":["../../src/assetDelivery/LocalAssetResolver.ts"],"sourcesContent":["import {\n AssetFactory,\n AssetResolver as AssetResolverAbstraction,\n ObjectKey\n} from \"@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { LocalContentsReader } from \"~/assetDelivery/LocalContentsReader.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\ninterface AssetMetadata {\n id: string;\n tenant: string;\n size: number;\n contentType: string;\n bucketKey: string;\n}\n\nclass AssetResolverImpl implements AssetResolverAbstraction.Interface {\n constructor(\n private readonly keyValueStore: GlobalKeyValueStore.Interface,\n private readonly config: FileManagerServerConfig.Interface,\n private readonly objectKey: ObjectKey.Interface,\n private readonly assetFactory: AssetFactory.Interface\n ) {}\n\n async resolve(\n request: AssetResolverAbstraction.Request\n ): Promise<AssetFactory.Asset | undefined> {\n const objectKey = this.objectKey.from(request.getKey());\n const fileId = objectKey.id();\n const result = await this.keyValueStore.get<AssetMetadata>(\n `FileManager/File/${fileId}/Metadata`\n );\n\n if (result.isFail()) {\n return undefined;\n }\n\n const metadata = result.value;\n\n const asset = this.assetFactory.create({\n id: metadata.id,\n tenant: metadata.tenant,\n size: metadata.size,\n contentType: metadata.contentType,\n key: metadata.bucketKey\n });\n\n asset.setContentsReader(LocalContentsReader.create(this.config.storagePath));\n\n return asset;\n }\n}\n\nexport const LocalAssetResolver = AssetResolverAbstraction.createImplementation({\n implementation: AssetResolverImpl,\n dependencies: [GlobalKeyValueStore, FileManagerServerConfig, ObjectKey, AssetFactory]\n});\n"],"names":["AssetResolverImpl","keyValueStore","config","objectKey","assetFactory","request","fileId","result","metadata","asset","LocalContentsReader","LocalAssetResolver","AssetResolverAbstraction","GlobalKeyValueStore","FileManagerServerConfig","ObjectKey","AssetFactory"],"mappings":";;;;AAiBA,MAAMA;IACF,YACqBC,aAA4C,EAC5CC,MAAyC,EACzCC,SAA8B,EAC9BC,YAAoC,CACvD;aAJmBH,aAAa,GAAbA;aACAC,MAAM,GAANA;aACAC,SAAS,GAATA;aACAC,YAAY,GAAZA;IAClB;IAEH,MAAM,QACFC,OAAyC,EACF;QACvC,MAAMF,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAACE,QAAQ,MAAM;QACpD,MAAMC,SAASH,UAAU,EAAE;QAC3B,MAAMI,SAAS,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CACvC,CAAC,iBAAiB,EAAED,OAAO,SAAS,CAAC;QAGzC,IAAIC,OAAO,MAAM,IACb;QAGJ,MAAMC,WAAWD,OAAO,KAAK;QAE7B,MAAME,QAAQ,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YACnC,IAAID,SAAS,EAAE;YACf,QAAQA,SAAS,MAAM;YACvB,MAAMA,SAAS,IAAI;YACnB,aAAaA,SAAS,WAAW;YACjC,KAAKA,SAAS,SAAS;QAC3B;QAEAC,MAAM,iBAAiB,CAACC,oBAAoB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW;QAE1E,OAAOD;IACX;AACJ;AAEO,MAAME,qBAAqBC,cAAAA,oBAA6C,CAAC;IAC5E,gBAAgBZ;IAChB,cAAc;QAACa;QAAqBC;QAAyBC;QAAWC;KAAa;AACzF"}
@@ -1,11 +1,12 @@
1
1
  import { AssetOutputStrategy as AssetOutputStrategyAbstraction, StreamAssetReply } from "@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js";
2
2
  import type { ILocalAssetDeliveryConfig } from "../assetDelivery/abstractions.js";
3
- export declare class LocalOutputStrategy implements AssetOutputStrategyAbstraction.Interface {
3
+ declare class AssetOutputStrategyImpl implements AssetOutputStrategyAbstraction.Interface {
4
4
  private readonly assetStreamingMaxSize;
5
5
  private readonly streamAssetReply;
6
6
  constructor(config: ILocalAssetDeliveryConfig, streamAssetReply: StreamAssetReply.Interface);
7
7
  output(asset: AssetOutputStrategyAbstraction.Asset): Promise<AssetOutputStrategyAbstraction.AssetReply>;
8
8
  }
9
- export declare const LocalOutputStrategyImpl: typeof LocalOutputStrategy & {
9
+ export declare const LocalOutputStrategy: typeof AssetOutputStrategyImpl & {
10
10
  __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/delivery").AssetOutputStrategy>;
11
11
  };
12
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { AssetOutputStrategy, StreamAssetReply } from "@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js";
2
2
  import { LocalAssetDeliveryConfig } from "./abstractions.js";
3
- class LocalOutputStrategy {
3
+ class AssetOutputStrategyImpl {
4
4
  constructor(config, streamAssetReply){
5
5
  this.assetStreamingMaxSize = config.assetStreamingMaxSize;
6
6
  this.streamAssetReply = streamAssetReply;
@@ -9,13 +9,13 @@ class LocalOutputStrategy {
9
9
  return this.streamAssetReply.create(asset);
10
10
  }
11
11
  }
12
- const LocalOutputStrategyImpl = AssetOutputStrategy.createImplementation({
13
- implementation: LocalOutputStrategy,
12
+ const LocalOutputStrategy = AssetOutputStrategy.createImplementation({
13
+ implementation: AssetOutputStrategyImpl,
14
14
  dependencies: [
15
15
  LocalAssetDeliveryConfig,
16
16
  StreamAssetReply
17
17
  ]
18
18
  });
19
- export { LocalOutputStrategy, LocalOutputStrategyImpl };
19
+ export { LocalOutputStrategy };
20
20
 
21
21
  //# sourceMappingURL=LocalOutputStrategy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assetDelivery/LocalOutputStrategy.js","sources":["../../src/assetDelivery/LocalOutputStrategy.ts"],"sourcesContent":["import {\n AssetOutputStrategy as AssetOutputStrategyAbstraction,\n StreamAssetReply\n} from \"@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js\";\nimport { LocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { ILocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\nexport class LocalOutputStrategy implements AssetOutputStrategyAbstraction.Interface {\n private readonly assetStreamingMaxSize: number;\n private readonly streamAssetReply: StreamAssetReply.Interface;\n\n constructor(config: ILocalAssetDeliveryConfig, streamAssetReply: StreamAssetReply.Interface) {\n this.assetStreamingMaxSize = config.assetStreamingMaxSize;\n this.streamAssetReply = streamAssetReply;\n }\n\n async output(\n asset: AssetOutputStrategyAbstraction.Asset\n ): Promise<AssetOutputStrategyAbstraction.AssetReply> {\n return this.streamAssetReply.create(asset);\n }\n}\n\nexport const LocalOutputStrategyImpl = AssetOutputStrategyAbstraction.createImplementation({\n implementation: LocalOutputStrategy,\n dependencies: [LocalAssetDeliveryConfig, StreamAssetReply]\n});\n"],"names":["LocalOutputStrategy","config","streamAssetReply","asset","LocalOutputStrategyImpl","AssetOutputStrategyAbstraction","LocalAssetDeliveryConfig","StreamAssetReply"],"mappings":";;AAOO,MAAMA;IAIT,YAAYC,MAAiC,EAAEC,gBAA4C,CAAE;QACzF,IAAI,CAAC,qBAAqB,GAAGD,OAAO,qBAAqB;QACzD,IAAI,CAAC,gBAAgB,GAAGC;IAC5B;IAEA,MAAM,OACFC,KAA2C,EACO;QAClD,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;IACxC;AACJ;AAEO,MAAMC,0BAA0BC,oBAAAA,oBAAmD,CAAC;IACvF,gBAAgBL;IAChB,cAAc;QAACM;QAA0BC;KAAiB;AAC9D"}
1
+ {"version":3,"file":"assetDelivery/LocalOutputStrategy.js","sources":["../../src/assetDelivery/LocalOutputStrategy.ts"],"sourcesContent":["import {\n AssetOutputStrategy as AssetOutputStrategyAbstraction,\n StreamAssetReply\n} from \"@webiny/api-file-manager/exports/api/file-manager/assetDelivery.js\";\nimport { LocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { ILocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\n\nclass AssetOutputStrategyImpl implements AssetOutputStrategyAbstraction.Interface {\n private readonly assetStreamingMaxSize: number;\n private readonly streamAssetReply: StreamAssetReply.Interface;\n\n constructor(config: ILocalAssetDeliveryConfig, streamAssetReply: StreamAssetReply.Interface) {\n this.assetStreamingMaxSize = config.assetStreamingMaxSize;\n this.streamAssetReply = streamAssetReply;\n }\n\n async output(\n asset: AssetOutputStrategyAbstraction.Asset\n ): Promise<AssetOutputStrategyAbstraction.AssetReply> {\n return this.streamAssetReply.create(asset);\n }\n}\n\nexport const LocalOutputStrategy = AssetOutputStrategyAbstraction.createImplementation({\n implementation: AssetOutputStrategyImpl,\n dependencies: [LocalAssetDeliveryConfig, StreamAssetReply]\n});\n"],"names":["AssetOutputStrategyImpl","config","streamAssetReply","asset","LocalOutputStrategy","AssetOutputStrategyAbstraction","LocalAssetDeliveryConfig","StreamAssetReply"],"mappings":";;AAOA,MAAMA;IAIF,YAAYC,MAAiC,EAAEC,gBAA4C,CAAE;QACzF,IAAI,CAAC,qBAAqB,GAAGD,OAAO,qBAAqB;QACzD,IAAI,CAAC,gBAAgB,GAAGC;IAC5B;IAEA,MAAM,OACFC,KAA2C,EACO;QAClD,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAACA;IACxC;AACJ;AAEO,MAAMC,sBAAsBC,oBAAAA,oBAAmD,CAAC;IACnF,gBAAgBL;IAChB,cAAc;QAACM;QAA0BC;KAAiB;AAC9D"}
@@ -10,14 +10,14 @@ export declare class LocalSharpTransform implements IAssetTypeHandler {
10
10
  private readonly imageQuality;
11
11
  private readonly identityContext;
12
12
  private readonly getFile;
13
+ private transformer?;
13
14
  constructor(storagePath: string, config: ILocalAssetDeliveryConfig, identityContext: IdentityContext.Interface, getFile: GetFileUseCase.Interface);
15
+ private getTransformer;
14
16
  handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset>;
15
17
  private loadAssetCrop;
16
18
  private transformAsset;
17
19
  private optimizeAsset;
18
20
  private isAssetAnimated;
19
- private optimizePng;
20
- private optimizeJpeg;
21
21
  }
22
22
  export declare const LocalSharpTransformImpl: typeof LocalSharpTransform & {
23
23
  __abstraction: import("@webiny/di").Abstraction<IAssetTypeHandler>;
@@ -1,10 +1,8 @@
1
- import sharp from "sharp";
2
1
  import promises from "node:fs/promises";
3
2
  import node_path from "node:path";
4
3
  import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
5
4
  import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
6
5
  import { CallableContentsReader, DEFAULT_IMAGE_QUALITY, contentTypeForFormat } from "@webiny/api-file-manager/features/assetDelivery/transformation/index.js";
7
- import { extractFramedRegion, transformImageBuffer } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/transformImage.js";
8
6
  import { normalizeImageOptions } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/normalizeImageOptions.js";
9
7
  import { AssetKeyGenerator, ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
10
8
  import { LocalAssetDeliveryConfig, LocalStoragePath } from "./abstractions.js";
@@ -20,6 +18,13 @@ class LocalSharpTransform {
20
18
  this.identityContext = identityContext;
21
19
  this.getFile = getFile;
22
20
  }
21
+ async getTransformer() {
22
+ if (!this.transformer) {
23
+ const { SharpTransformer } = await import("@webiny/api-file-manager/features/assetDelivery/assetTypes/image/SharpTransformer.js");
24
+ this.transformer = new SharpTransformer();
25
+ }
26
+ return this.transformer;
27
+ }
23
28
  async handle(assetRequest, asset) {
24
29
  const rawQuery = assetRequest.getOptions();
25
30
  const acceptHeader = assetRequest.getContext().accept;
@@ -61,7 +66,8 @@ class LocalSharpTransform {
61
66
  const optimizedImage = await this.optimizeAsset(asset, framing);
62
67
  console.log("Transform the asset", options);
63
68
  const baseBuffer = await optimizedImage.getContents();
64
- const { buffer: transformedBuffer, contentType: outputContentType } = await transformImageBuffer({
69
+ const transformer = await this.getTransformer();
70
+ const { buffer: transformedBuffer, contentType: outputContentType } = await transformer.transformBuffer({
65
71
  buffer: baseBuffer,
66
72
  animated: this.isAssetAnimated(asset),
67
73
  sourceContentType: asset.getContentType(),
@@ -107,20 +113,21 @@ class LocalSharpTransform {
107
113
  } catch {
108
114
  console.log("Create an optimized version of the original asset", asset.getKey());
109
115
  let buffer = await asset.getContents();
110
- const framed = await extractFramedRegion(buffer, framing);
116
+ const transformer = await this.getTransformer();
117
+ const framed = await transformer.extractFramedRegion(buffer, framing);
111
118
  const cropped = framed !== buffer;
112
119
  buffer = framed;
113
- const optimizationMap = {
114
- "image/png": (buffer)=>this.optimizePng(buffer),
115
- "image/jpeg": (buffer)=>this.optimizeJpeg(buffer),
116
- "image/jpg": (buffer)=>this.optimizeJpeg(buffer)
117
- };
118
- const optimization = optimizationMap[asset.getContentType()];
119
- if (!optimization && !cropped) {
120
- console.log(`No optimizations defined for ${asset.getContentType()}`);
120
+ const contentType = asset.getContentType();
121
+ const canOptimize = "image/png" === contentType || "image/jpeg" === contentType || "image/jpg" === contentType;
122
+ if (!canOptimize && !cropped) {
123
+ console.log(`No optimizations defined for ${contentType}`);
121
124
  return asset;
122
125
  }
123
- const finalBuffer = optimization ? await optimization(buffer).toBuffer() : buffer;
126
+ let finalBuffer = buffer;
127
+ if (canOptimize) {
128
+ const pipeline = "image/png" === contentType ? await transformer.optimizePng(buffer) : await transformer.optimizeJpeg(buffer);
129
+ finalBuffer = await pipeline.toBuffer();
130
+ }
124
131
  console.log("Optimized asset size", finalBuffer.length);
125
132
  const newAsset = asset.withProps({
126
133
  size: finalBuffer.length
@@ -139,26 +146,6 @@ class LocalSharpTransform {
139
146
  "webp"
140
147
  ].includes(asset.getExtension());
141
148
  }
142
- optimizePng(buffer) {
143
- return sharp(buffer).resize({
144
- width: 2560,
145
- withoutEnlargement: true,
146
- fit: "inside"
147
- }).png({
148
- compressionLevel: 9,
149
- adaptiveFiltering: true,
150
- force: true
151
- }).withMetadata();
152
- }
153
- optimizeJpeg(buffer) {
154
- return sharp(buffer).resize({
155
- width: 2560,
156
- withoutEnlargement: true,
157
- fit: "inside"
158
- }).withMetadata().toFormat("jpeg", {
159
- quality: 90
160
- });
161
- }
162
149
  }
163
150
  const LocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({
164
151
  implementation: LocalSharpTransform,
@@ -1 +1 @@
1
- {"version":3,"file":"assetDelivery/LocalSharpTransform.js","sources":["../../src/assetDelivery/LocalSharpTransform.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport type { Sharp } from \"sharp\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\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 {\n extractFramedRegion,\n transformImageBuffer\n} from \"@webiny/api-file-manager/features/assetDelivery/assetTypes/image/transformImage.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 { IAssetTypeHandler } from \"@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType.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 { LocalStoragePath } from \"~/assetDelivery/abstractions.js\";\nimport { LocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { ILocalAssetDeliveryConfig } 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 LocalSharpTransform implements IAssetTypeHandler {\n private readonly storagePath: 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\n constructor(\n storagePath: string,\n config: ILocalAssetDeliveryConfig,\n identityContext: IdentityContext.Interface,\n getFile: GetFileUseCase.Interface\n ) {\n this.storagePath = storagePath;\n this.imageResizeWidths = config.imageResizeWidths;\n this.imageQuality = { ...DEFAULT_IMAGE_QUALITY, ...(config.imageQuality ?? {}) };\n this.identityContext = identityContext;\n this.getFile = getFile;\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 const transformedFilePath = path.join(this.storagePath, transformedAssetKey);\n\n const contentType = options.format\n ? contentTypeForFormat(options.format)\n : asset.getContentType();\n\n try {\n const buffer = await fs.readFile(transformedFilePath);\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 { buffer: transformedBuffer, contentType: outputContentType } =\n await transformImageBuffer({\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 fs.mkdir(path.dirname(transformedFilePath), { recursive: true });\n await fs.writeFile(transformedFilePath, await newAsset.getContents());\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 const optimizedFilePath = path.join(this.storagePath, optimizedAssetKey);\n\n try {\n const buffer = await fs.readFile(optimizedFilePath);\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\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 framed = await extractFramedRegion(buffer, framing);\n const cropped = framed !== buffer;\n buffer = framed;\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 && !cropped) {\n console.log(`No optimizations defined for ${asset.getContentType()}`);\n return asset;\n }\n\n const finalBuffer = optimization ? await optimization(buffer).toBuffer() : buffer;\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 fs.mkdir(path.dirname(optimizedFilePath), { recursive: true });\n await fs.writeFile(optimizedFilePath, await newAsset.getContents());\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 LocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: LocalSharpTransform,\n dependencies: [LocalStoragePath, LocalAssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["hasTransform","options","undefined","LocalSharpTransform","storagePath","config","identityContext","getFile","DEFAULT_IMAGE_QUALITY","assetRequest","asset","rawQuery","acceptHeader","original","crop","focal","aspectRatio","normalizeImageOptions","assetCrop","framing","transformedAsset","fileId","result","imageEdit","assetKey","AssetKeyGenerator","transformedAssetKey","transformedFilePath","path","contentType","contentTypeForFormat","buffer","fs","newAsset","CallableContentsReader","console","optimizedImage","baseBuffer","transformedBuffer","outputContentType","transformImageBuffer","optimizedAssetKey","optimizedFilePath","framed","extractFramedRegion","cropped","optimizationMap","optimization","finalBuffer","sharp","LocalSharpTransformImpl","ImageAssetTypeHandler","LocalStoragePath","LocalAssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":";;;;;;;;;;AAiCA,MAAMA,eAAe,CAACC,UAEdA,AAAkBC,WAAlBD,QAAQ,KAAK,IAAkBA,AAAmBC,WAAnBD,QAAQ,MAAM,IAAkBA,AAAoBC,WAApBD,QAAQ,OAAO;AAI/E,MAAME;IAOT,YACIC,WAAmB,EACnBC,MAAiC,EACjCC,eAA0C,EAC1CC,OAAiC,CACnC;QACE,IAAI,CAAC,WAAW,GAAGH;QACnB,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,MAAM,OAAOE,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,GAAGf,SAAS,GAAGgB,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,IAAIV,aAAaC,UACb,OAAO,IAAI,CAAC,cAAc,CAACmB,kBAAkBnB,SAASkB;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,EAAET,OAAyB,EAAEkB,OAAgB,EAAE;QACpF,MAAMK,WAAWC,kBAAkB,MAAM,CAACf,OAAOS;QACjD,MAAMO,sBAAsBF,SAAS,sBAAsB,CAACvB;QAC5D,MAAM0B,sBAAsBC,UAAAA,IAAS,CAAC,IAAI,CAAC,WAAW,EAAEF;QAExD,MAAMG,cAAc5B,QAAQ,MAAM,GAC5B6B,qBAAqB7B,QAAQ,MAAM,IACnCS,MAAM,cAAc;QAE1B,IAAI;YACA,MAAMqB,SAAS,MAAMC,SAAAA,QAAW,CAACL;YAEjC,MAAMM,WAAWvB,MAAM,SAAS,CAAC;gBAAE,MAAMqB,OAAO,MAAM;gBAAEF;YAAY;YACpEI,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,uBAAuBlC;YACnC,MAAMoC,aAAa,MAAMD,eAAe,WAAW;YACnD,MAAM,EAAE,QAAQE,iBAAiB,EAAE,aAAaC,iBAAiB,EAAE,GAC/D,MAAMC,qBAAqB;gBACvB,QAAQH;gBACR,UAAU,IAAI,CAAC,eAAe,CAAC3B;gBAC/B,mBAAmBA,MAAM,cAAc;gBACvC,QAAQ,IAAI,CAAC,iBAAiB;gBAC9BT;gBACA,iBAAiB,IAAI,CAAC,YAAY;YACtC;YAEJ,MAAMgC,WAAWvB,MAAM,SAAS,CAAC;gBAC7B,MAAM4B,kBAAkB,MAAM;gBAC9B,aAAaC;YACjB;YACAN,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMI;YAE/D,MAAMN,SAAAA,KAAQ,CAACJ,UAAAA,OAAY,CAACD,sBAAsB;gBAAE,WAAW;YAAK;YACpE,MAAMK,SAAAA,SAAY,CAACL,qBAAqB,MAAMM,SAAS,WAAW;YAElEE,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;QACvD,MAAMkB,oBAAoBd,UAAAA,IAAS,CAAC,IAAI,CAAC,WAAW,EAAEa;QAEtD,IAAI;YACA,MAAMV,SAAS,MAAMC,SAAAA,QAAW,CAACU;YAEjCP,QAAQ,GAAG,CAAC,uCAAuCM;YAEnD,MAAMR,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,MAAMiC,SAAS,MAAMC,oBAAoBb,QAAQZ;YACjD,MAAM0B,UAAUF,WAAWZ;YAC3BA,SAASY;YAET,MAAMG,kBAA2E;gBAC7E,aAAa,CAACf,SAAmB,IAAI,CAAC,WAAW,CAACA;gBAClD,cAAc,CAACA,SAAmB,IAAI,CAAC,YAAY,CAACA;gBACpD,aAAa,CAACA,SAAmB,IAAI,CAAC,YAAY,CAACA;YACvD;YAEA,MAAMgB,eAAeD,eAAe,CAACpC,MAAM,cAAc,GAAG;YAE5D,IAAI,CAACqC,gBAAgB,CAACF,SAAS;gBAC3BV,QAAQ,GAAG,CAAC,CAAC,6BAA6B,EAAEzB,MAAM,cAAc,IAAI;gBACpE,OAAOA;YACX;YAEA,MAAMsC,cAAcD,eAAe,MAAMA,aAAahB,QAAQ,QAAQ,KAAKA;YAE3EI,QAAQ,GAAG,CAAC,wBAAwBa,YAAY,MAAM;YAEtD,MAAMf,WAAWvB,MAAM,SAAS,CAAC;gBAAE,MAAMsC,YAAY,MAAM;YAAC;YAC5Df,SAAS,iBAAiB,CAACC,uBAAuB,MAAM,CAAC,IAAMc;YAE/D,MAAMhB,SAAAA,KAAQ,CAACJ,UAAAA,OAAY,CAACc,oBAAoB;gBAAE,WAAW;YAAK;YAClE,MAAMV,SAAAA,SAAY,CAACU,mBAAmB,MAAMT,SAAS,WAAW;YAEhE,OAAOA;QACX;IACJ;IAEQ,gBAAgBvB,KAAY,EAAE;QAClC,OAAO;YAAC;YAAO;SAAO,CAAC,QAAQ,CAACA,MAAM,YAAY;IACtD;IAEQ,YAAYqB,MAAc,EAAE;QAChC,OAAOkB,MAAMlB,QACR,MAAM,CAAC;YAAE,OAAO;YAAM,oBAAoB;YAAM,KAAK;QAAS,GAC9D,GAAG,CAAC;YAAE,kBAAkB;YAAG,mBAAmB;YAAM,OAAO;QAAK,GAChE,YAAY;IACrB;IAEQ,aAAaA,MAAc,EAAE;QACjC,OAAOkB,MAAMlB,QACR,MAAM,CAAC;YAAE,OAAO;YAAM,oBAAoB;YAAM,KAAK;QAAS,GAC9D,YAAY,GACZ,QAAQ,CAAC,QAAQ;YAAE,SAAS;QAAG;IACxC;AACJ;AAEO,MAAMmB,0BAA0BC,sBAAsB,oBAAoB,CAAC;IAC9E,gBAAgBhD;IAChB,cAAc;QAACiD;QAAkBC;QAA0BC;QAAiBC;KAAe;AAC/F"}
1
+ {"version":3,"file":"assetDelivery/LocalSharpTransform.js","sources":["../../src/assetDelivery/LocalSharpTransform.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\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 { IAssetTypeHandler } from \"@webiny/api-file-manager/features/assetDelivery/abstractions/AssetType.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 { LocalStoragePath } from \"~/assetDelivery/abstractions.js\";\nimport { LocalAssetDeliveryConfig } from \"~/assetDelivery/abstractions.js\";\nimport type { ILocalAssetDeliveryConfig } 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 LocalSharpTransform implements IAssetTypeHandler {\n private readonly storagePath: 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 storagePath: string,\n config: ILocalAssetDeliveryConfig,\n identityContext: IdentityContext.Interface,\n getFile: GetFileUseCase.Interface\n ) {\n this.storagePath = storagePath;\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 const transformedFilePath = path.join(this.storagePath, transformedAssetKey);\n\n const contentType = options.format\n ? contentTypeForFormat(options.format)\n : asset.getContentType();\n\n try {\n const buffer = await fs.readFile(transformedFilePath);\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 fs.mkdir(path.dirname(transformedFilePath), { recursive: true });\n await fs.writeFile(transformedFilePath, await newAsset.getContents());\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 const optimizedFilePath = path.join(this.storagePath, optimizedAssetKey);\n\n try {\n const buffer = await fs.readFile(optimizedFilePath);\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\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 fs.mkdir(path.dirname(optimizedFilePath), { recursive: true });\n await fs.writeFile(optimizedFilePath, await newAsset.getContents());\n\n return newAsset;\n }\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n}\n\nexport const LocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({\n implementation: LocalSharpTransform,\n dependencies: [LocalStoragePath, LocalAssetDeliveryConfig, IdentityContext, GetFileUseCase]\n});\n"],"names":["hasTransform","options","undefined","LocalSharpTransform","storagePath","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","transformedFilePath","path","contentType","contentTypeForFormat","buffer","fs","newAsset","CallableContentsReader","console","optimizedImage","baseBuffer","transformer","transformedBuffer","outputContentType","optimizedAssetKey","optimizedFilePath","framed","cropped","canOptimize","finalBuffer","pipeline","LocalSharpTransformImpl","ImageAssetTypeHandler","LocalStoragePath","LocalAssetDeliveryConfig","IdentityContext","GetFileUseCase"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import type { AssetDeliveryParams } from "../assetDelivery/types.js";
2
- export declare const assetDeliveryConfig: (params: AssetDeliveryParams) => ((import("@webiny/handler").ModifyFastifyPlugin | import("@webiny/handler").RegisterExtensionPlugin<import("@webiny/handler/types").Context>)[] | import("@webiny/handler").RegisterExtensionPlugin<import("@webiny/handler/types").Context>)[];
2
+ export declare const assetDeliveryConfig: (params: AssetDeliveryParams) => (import("@webiny/handler").RegisterExtensionPlugin<import("@webiny/handler/types").Context>[] | import("@webiny/handler").RegisterExtensionPlugin<import("@webiny/handler/types").Context>)[];
@@ -1,8 +1,8 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
2
  import { LocalAssetDeliveryConfig, LocalStoragePath } from "./abstractions.js";
3
- import { LocalAssetResolverImpl } from "./LocalAssetResolver.js";
4
- import { LocalOutputStrategyImpl } from "./LocalOutputStrategy.js";
5
- import { LocalSharpTransformImpl } from "./LocalSharpTransform.js";
3
+ import { LocalAssetResolver } from "./LocalAssetResolver.js";
4
+ import { LocalOutputStrategy } from "./LocalOutputStrategy.js";
5
+ import { LazyLocalSharpTransformImpl } from "./LazyLocalSharpTransform.js";
6
6
  const createLocalAssetDeliveryFeature = (params = {})=>createFeature({
7
7
  name: "AssetDelivery/Local",
8
8
  register (container) {
@@ -23,9 +23,9 @@ const createLocalAssetDeliveryFeature = (params = {})=>createFeature({
23
23
  imageQuality: params.imageQuality ?? {},
24
24
  assetStreamingMaxSize: params.assetStreamingMaxSize ?? 4718592
25
25
  });
26
- container.register(LocalAssetResolverImpl);
27
- container.register(LocalOutputStrategyImpl);
28
- container.register(LocalSharpTransformImpl).inSingletonScope();
26
+ container.register(LocalAssetResolver);
27
+ container.register(LocalOutputStrategy);
28
+ if ("asset-delivery" === process.env.WEBINY_FUNCTION_TYPE) container.register(LazyLocalSharpTransformImpl).inSingletonScope();
29
29
  }
30
30
  });
31
31
  export { createLocalAssetDeliveryFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"assetDelivery/feature.js","sources":["../../src/assetDelivery/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { LocalStoragePath } from \"./abstractions.js\";\nimport { LocalAssetDeliveryConfig } from \"./abstractions.js\";\nimport type { AssetDeliveryParams } from \"./types.js\";\nimport { LocalAssetResolverImpl } from \"./LocalAssetResolver.js\";\nimport { LocalOutputStrategyImpl } from \"./LocalOutputStrategy.js\";\nimport { LocalSharpTransformImpl } from \"./LocalSharpTransform.js\";\n\nexport const createLocalAssetDeliveryFeature = (params: AssetDeliveryParams = {}) => {\n return createFeature({\n name: \"AssetDelivery/Local\",\n register(container) {\n container.registerInstance(\n LocalStoragePath,\n process.env.WEBINY_LOCAL_STORAGE_PATH as string\n );\n container.registerInstance(LocalAssetDeliveryConfig, {\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(LocalAssetResolverImpl);\n container.register(LocalOutputStrategyImpl);\n container.register(LocalSharpTransformImpl).inSingletonScope();\n }\n });\n};\n"],"names":["createLocalAssetDeliveryFeature","params","createFeature","container","LocalStoragePath","process","LocalAssetDeliveryConfig","LocalAssetResolverImpl","LocalOutputStrategyImpl","LocalSharpTransformImpl"],"mappings":";;;;;AAQO,MAAMA,kCAAkC,CAACC,SAA8B,CAAC,CAAC,GACrEC,cAAc;QACjB,MAAM;QACN,UAASC,SAAS;YACdA,UAAU,gBAAgB,CACtBC,kBACAC,QAAQ,GAAG,CAAC,yBAAyB;YAEzCF,UAAU,gBAAgB,CAACG,0BAA0B;gBACjD,mBAAmBL,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,CAACI;YACnBJ,UAAU,QAAQ,CAACK;YACnBL,UAAU,QAAQ,CAACM,yBAAyB,gBAAgB;QAChE;IACJ"}
1
+ {"version":3,"file":"assetDelivery/feature.js","sources":["../../src/assetDelivery/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { LocalStoragePath } from \"./abstractions.js\";\nimport { LocalAssetDeliveryConfig } from \"./abstractions.js\";\nimport type { AssetDeliveryParams } from \"./types.js\";\nimport { LocalAssetResolver } from \"./LocalAssetResolver.js\";\nimport { LocalOutputStrategy } from \"./LocalOutputStrategy.js\";\nimport { LazyLocalSharpTransformImpl } from \"./LazyLocalSharpTransform.js\";\n\nexport const createLocalAssetDeliveryFeature = (params: AssetDeliveryParams = {}) => {\n return createFeature({\n name: \"AssetDelivery/Local\",\n register(container) {\n container.registerInstance(\n LocalStoragePath,\n process.env.WEBINY_LOCAL_STORAGE_PATH as string\n );\n container.registerInstance(LocalAssetDeliveryConfig, {\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(LocalAssetResolver);\n container.register(LocalOutputStrategy);\n\n if (process.env.WEBINY_FUNCTION_TYPE === \"asset-delivery\") {\n // Registered eagerly; `sharp` is still loaded lazily, inside the handler.\n container.register(LazyLocalSharpTransformImpl).inSingletonScope();\n }\n }\n });\n};\n"],"names":["createLocalAssetDeliveryFeature","params","createFeature","container","LocalStoragePath","process","LocalAssetDeliveryConfig","LocalAssetResolver","LocalOutputStrategy","LazyLocalSharpTransformImpl"],"mappings":";;;;;AAQO,MAAMA,kCAAkC,CAACC,SAA8B,CAAC,CAAC,GACrEC,cAAc;QACjB,MAAM;QACN,UAASC,SAAS;YACdA,UAAU,gBAAgB,CACtBC,kBACAC,QAAQ,GAAG,CAAC,yBAAyB;YAEzCF,UAAU,gBAAgB,CAACG,0BAA0B;gBACjD,mBAAmBL,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,CAACI;YACnBJ,UAAU,QAAQ,CAACK;YAEnB,IAAIH,AAAqC,qBAArCA,QAAQ,GAAG,CAAC,oBAAoB,EAEhCF,UAAU,QAAQ,CAACM,6BAA6B,gBAAgB;QAExE;IACJ"}
@@ -1,8 +1,11 @@
1
1
  import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
2
+ import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
2
3
  export interface CleanupStaleMultipartUploadsInput {
3
4
  noop?: boolean;
4
5
  }
5
6
  declare class CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {
7
+ private readonly config;
8
+ constructor(config: FileManagerServerConfig.Interface);
6
9
  readonly id = "fileManagerCleanupStaleMultipartUploads";
7
10
  readonly title = "Clean up stale multipart upload directories";
8
11
  readonly description = "Removes multipart upload directories that are older than 24 hours.";
@@ -1,6 +1,7 @@
1
1
  import { promises } from "node:fs";
2
2
  import node_path from "node:path";
3
3
  import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
4
+ import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
4
5
  const STALE_THRESHOLD_MS = 86400000;
5
6
  async function readdirSafe(dirPath) {
6
7
  try {
@@ -11,9 +12,22 @@ async function readdirSafe(dirPath) {
11
12
  }
12
13
  }
13
14
  class CleanupStaleMultipartUploadsTaskImpl {
15
+ constructor(config){
16
+ this.config = config;
17
+ this.id = "fileManagerCleanupStaleMultipartUploads";
18
+ this.title = "Clean up stale multipart upload directories";
19
+ this.description = "Removes multipart upload directories that are older than 24 hours.";
20
+ this.maxIterations = 1;
21
+ this.isPrivate = true;
22
+ this.databaseLogs = false;
23
+ this.selfCleanup = [
24
+ "onSuccess",
25
+ "onAbort"
26
+ ];
27
+ }
14
28
  async run({ controller }) {
15
29
  if (controller.runtime.isAborted()) return controller.response.aborted();
16
- const storagePath = String(process.env.WEBINY_LOCAL_STORAGE_PATH);
30
+ const storagePath = this.config.storagePath;
17
31
  const tenantsDir = node_path.join(storagePath, "tenants");
18
32
  const now = Date.now();
19
33
  const tenantDirs = await readdirSafe(tenantsDir);
@@ -36,22 +50,12 @@ class CleanupStaleMultipartUploadsTaskImpl {
36
50
  }
37
51
  return controller.response.done();
38
52
  }
39
- constructor(){
40
- this.id = "fileManagerCleanupStaleMultipartUploads";
41
- this.title = "Clean up stale multipart upload directories";
42
- this.description = "Removes multipart upload directories that are older than 24 hours.";
43
- this.maxIterations = 1;
44
- this.isPrivate = true;
45
- this.databaseLogs = false;
46
- this.selfCleanup = [
47
- "onSuccess",
48
- "onAbort"
49
- ];
50
- }
51
53
  }
52
54
  const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({
53
55
  implementation: CleanupStaleMultipartUploadsTaskImpl,
54
- dependencies: []
56
+ dependencies: [
57
+ FileManagerServerConfig
58
+ ]
55
59
  });
56
60
  export { CleanupStaleMultipartUploadsTaskDefinition };
57
61