@webiny/api-file-manager-server 0.0.0-unstable.0d717d18dd → 0.0.0-unstable.a4f3e4ea8b

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 (86) hide show
  1. package/assetDelivery/LocalAssetResolver.d.ts +4 -6
  2. package/assetDelivery/LocalAssetResolver.js +9 -9
  3. package/assetDelivery/LocalAssetResolver.js.map +1 -1
  4. package/assetDelivery/LocalOutputStrategy.d.ts +2 -3
  5. package/assetDelivery/LocalOutputStrategy.js +4 -4
  6. package/assetDelivery/LocalOutputStrategy.js.map +1 -1
  7. package/assetDelivery/LocalSharpTransform.d.ts +2 -2
  8. package/assetDelivery/LocalSharpTransform.js +34 -21
  9. package/assetDelivery/LocalSharpTransform.js.map +1 -1
  10. package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
  11. package/assetDelivery/feature.js +6 -11
  12. package/assetDelivery/feature.js.map +1 -1
  13. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.d.ts +0 -3
  14. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js +14 -18
  15. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js.map +1 -1
  16. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.d.ts +5 -7
  17. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js +5 -8
  18. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js.map +1 -1
  19. package/features/CompleteMultiPartUpload/feature.js +2 -2
  20. package/features/CompleteMultiPartUpload/feature.js.map +1 -1
  21. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.d.ts +7 -7
  22. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js +10 -9
  23. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js.map +1 -1
  24. package/features/CreateMultiPartUpload/feature.js +2 -2
  25. package/features/CreateMultiPartUpload/feature.js.map +1 -1
  26. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.d.ts +1 -3
  27. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js +3 -6
  28. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js.map +1 -1
  29. package/features/ExtractMetadata/ExtractMetadataTask.d.ts +1 -3
  30. package/features/ExtractMetadata/ExtractMetadataTask.js +3 -6
  31. package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -1
  32. package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +5 -7
  33. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +5 -8
  34. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js.map +1 -1
  35. package/features/GetFileContentsById/feature.js +2 -2
  36. package/features/GetFileContentsById/feature.js.map +1 -1
  37. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.d.ts +5 -7
  38. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +5 -8
  39. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js.map +1 -1
  40. package/features/GetFileContentsByKey/feature.js +2 -2
  41. package/features/GetFileContentsByKey/feature.js.map +1 -1
  42. package/features/GetUploadPayload/GetUploadPayloadUseCase.d.ts +6 -6
  43. package/features/GetUploadPayload/GetUploadPayloadUseCase.js +9 -8
  44. package/features/GetUploadPayload/GetUploadPayloadUseCase.js.map +1 -1
  45. package/features/GetUploadPayload/feature.js +2 -2
  46. package/features/GetUploadPayload/feature.js.map +1 -1
  47. package/index.d.ts +2 -1
  48. package/index.js +40 -1
  49. package/index.js.map +1 -0
  50. package/package.json +13 -13
  51. package/routes/uploadRoutes.d.ts +4 -0
  52. package/routes/uploadRoutes.js +130 -0
  53. package/routes/uploadRoutes.js.map +1 -0
  54. package/utils/resolveServerUrl.d.ts +2 -0
  55. package/utils/resolveServerUrl.js +10 -0
  56. package/utils/resolveServerUrl.js.map +1 -0
  57. package/FileManagerServerFeature.d.ts +0 -5
  58. package/FileManagerServerFeature.js +0 -41
  59. package/FileManagerServerFeature.js.map +0 -1
  60. package/features/FileManagerServerConfig/FileManagerServerConfig.d.ts +0 -12
  61. package/features/FileManagerServerConfig/FileManagerServerConfig.js +0 -28
  62. package/features/FileManagerServerConfig/FileManagerServerConfig.js.map +0 -1
  63. package/features/FileManagerServerConfig/abstractions.d.ts +0 -10
  64. package/features/FileManagerServerConfig/abstractions.js +0 -5
  65. package/features/FileManagerServerConfig/abstractions.js.map +0 -1
  66. package/features/FileManagerServerConfig/feature.d.ts +0 -4
  67. package/features/FileManagerServerConfig/feature.js +0 -11
  68. package/features/FileManagerServerConfig/feature.js.map +0 -1
  69. package/graphql/ServerGraphQLSchema.d.ts +0 -15
  70. package/graphql/ServerGraphQLSchema.js +0 -221
  71. package/graphql/ServerGraphQLSchema.js.map +0 -1
  72. package/routes/UploadPartRoute/UploadPartRoute.d.ts +0 -14
  73. package/routes/UploadPartRoute/UploadPartRoute.js +0 -66
  74. package/routes/UploadPartRoute/UploadPartRoute.js.map +0 -1
  75. package/routes/UploadPartRoute/feature.d.ts +0 -4
  76. package/routes/UploadPartRoute/feature.js +0 -11
  77. package/routes/UploadPartRoute/feature.js.map +0 -1
  78. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.d.ts +0 -14
  79. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js +0 -70
  80. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js.map +0 -1
  81. package/routes/UploadSingleFileRoute/feature.d.ts +0 -4
  82. package/routes/UploadSingleFileRoute/feature.js +0 -11
  83. package/routes/UploadSingleFileRoute/feature.js.map +0 -1
  84. package/routes/utils.d.ts +0 -20
  85. package/routes/utils.js +0 -62
  86. package/routes/utils.js.map +0 -1
@@ -1,15 +1,13 @@
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
- import { FileManagerServerConfig } from "../features/FileManagerServerConfig/abstractions.js";
4
- declare class AssetResolverImpl implements AssetResolverAbstraction.Interface {
3
+ export declare class LocalAssetResolver implements AssetResolverAbstraction.Interface {
5
4
  private readonly keyValueStore;
6
- private readonly config;
5
+ private readonly storagePath;
7
6
  private readonly objectKey;
8
7
  private readonly assetFactory;
9
- constructor(keyValueStore: GlobalKeyValueStore.Interface, config: FileManagerServerConfig.Interface, objectKey: ObjectKey.Interface, assetFactory: AssetFactory.Interface);
8
+ constructor(keyValueStore: GlobalKeyValueStore.Interface, storagePath: string, objectKey: ObjectKey.Interface, assetFactory: AssetFactory.Interface);
10
9
  resolve(request: AssetResolverAbstraction.Request): Promise<AssetFactory.Asset | undefined>;
11
10
  }
12
- export declare const LocalAssetResolver: typeof AssetResolverImpl & {
11
+ export declare const LocalAssetResolverImpl: typeof LocalAssetResolver & {
13
12
  __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/delivery").AssetResolver>;
14
13
  };
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 { FileManagerServerConfig } from "../features/FileManagerServerConfig/abstractions.js";
5
- class AssetResolverImpl {
6
- constructor(keyValueStore, config, objectKey, assetFactory){
4
+ import { LocalStoragePath } from "./abstractions.js";
5
+ class LocalAssetResolver {
6
+ constructor(keyValueStore, storagePath, objectKey, assetFactory){
7
7
  this.keyValueStore = keyValueStore;
8
- this.config = config;
8
+ this.storagePath = storagePath;
9
9
  this.objectKey = objectKey;
10
10
  this.assetFactory = assetFactory;
11
11
  }
@@ -22,19 +22,19 @@ class AssetResolverImpl {
22
22
  contentType: metadata.contentType,
23
23
  key: metadata.bucketKey
24
24
  });
25
- asset.setContentsReader(LocalContentsReader.create(this.config.storagePath));
25
+ asset.setContentsReader(LocalContentsReader.create(this.storagePath));
26
26
  return asset;
27
27
  }
28
28
  }
29
- const LocalAssetResolver = AssetResolver.createImplementation({
30
- implementation: AssetResolverImpl,
29
+ const LocalAssetResolverImpl = AssetResolver.createImplementation({
30
+ implementation: LocalAssetResolver,
31
31
  dependencies: [
32
32
  GlobalKeyValueStore,
33
- FileManagerServerConfig,
33
+ LocalStoragePath,
34
34
  ObjectKey,
35
35
  AssetFactory
36
36
  ]
37
37
  });
38
- export { LocalAssetResolver };
38
+ export { LocalAssetResolver, LocalAssetResolverImpl };
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 { 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
+ {"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,12 +1,11 @@
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
- declare class AssetOutputStrategyImpl implements AssetOutputStrategyAbstraction.Interface {
3
+ export declare class LocalOutputStrategy 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 LocalOutputStrategy: typeof AssetOutputStrategyImpl & {
9
+ export declare const LocalOutputStrategyImpl: typeof LocalOutputStrategy & {
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 AssetOutputStrategyImpl {
3
+ class LocalOutputStrategy {
4
4
  constructor(config, streamAssetReply){
5
5
  this.assetStreamingMaxSize = config.assetStreamingMaxSize;
6
6
  this.streamAssetReply = streamAssetReply;
@@ -9,13 +9,13 @@ class AssetOutputStrategyImpl {
9
9
  return this.streamAssetReply.create(asset);
10
10
  }
11
11
  }
12
- const LocalOutputStrategy = AssetOutputStrategy.createImplementation({
13
- implementation: AssetOutputStrategyImpl,
12
+ const LocalOutputStrategyImpl = AssetOutputStrategy.createImplementation({
13
+ implementation: LocalOutputStrategy,
14
14
  dependencies: [
15
15
  LocalAssetDeliveryConfig,
16
16
  StreamAssetReply
17
17
  ]
18
18
  });
19
- export { LocalOutputStrategy };
19
+ export { LocalOutputStrategy, LocalOutputStrategyImpl };
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\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"}
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"}
@@ -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?;
14
13
  constructor(storagePath: string, config: ILocalAssetDeliveryConfig, identityContext: IdentityContext.Interface, getFile: GetFileUseCase.Interface);
15
- private getTransformer;
16
14
  handle(assetRequest: AssetRequest, asset: Asset): Promise<Asset>;
17
15
  private loadAssetCrop;
18
16
  private transformAsset;
19
17
  private optimizeAsset;
20
18
  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,8 +1,10 @@
1
+ import sharp from "sharp";
1
2
  import promises from "node:fs/promises";
2
3
  import node_path from "node:path";
3
4
  import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
4
5
  import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
5
6
  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";
6
8
  import { normalizeImageOptions } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/normalizeImageOptions.js";
7
9
  import { AssetKeyGenerator, ImageAssetTypeHandler } from "@webiny/api-file-manager/features/assetDelivery/assetTypes/image/index.js";
8
10
  import { LocalAssetDeliveryConfig, LocalStoragePath } from "./abstractions.js";
@@ -18,13 +20,6 @@ class LocalSharpTransform {
18
20
  this.identityContext = identityContext;
19
21
  this.getFile = getFile;
20
22
  }
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
- }
28
23
  async handle(assetRequest, asset) {
29
24
  const rawQuery = assetRequest.getOptions();
30
25
  const acceptHeader = assetRequest.getContext().accept;
@@ -42,7 +37,7 @@ class LocalSharpTransform {
42
37
  async loadAssetCrop(fileId) {
43
38
  const result = await this.identityContext.withoutAuthorization(()=>this.getFile.execute(fileId));
44
39
  if (result.isFail()) return;
45
- const imageEdit = result.value.metadata?.imageEdit;
40
+ const imageEdit = result.value.metadata?.image;
46
41
  return imageEdit?.crop;
47
42
  }
48
43
  async transformAsset(asset, options, framing) {
@@ -66,8 +61,7 @@ class LocalSharpTransform {
66
61
  const optimizedImage = await this.optimizeAsset(asset, framing);
67
62
  console.log("Transform the asset", options);
68
63
  const baseBuffer = await optimizedImage.getContents();
69
- const transformer = await this.getTransformer();
70
- const { buffer: transformedBuffer, contentType: outputContentType } = await transformer.transformBuffer({
64
+ const { buffer: transformedBuffer, contentType: outputContentType } = await transformImageBuffer({
71
65
  buffer: baseBuffer,
72
66
  animated: this.isAssetAnimated(asset),
73
67
  sourceContentType: asset.getContentType(),
@@ -113,21 +107,20 @@ class LocalSharpTransform {
113
107
  } catch {
114
108
  console.log("Create an optimized version of the original asset", asset.getKey());
115
109
  let buffer = await asset.getContents();
116
- const transformer = await this.getTransformer();
117
- const framed = await transformer.extractFramedRegion(buffer, framing);
110
+ const framed = await extractFramedRegion(buffer, framing);
118
111
  const cropped = framed !== buffer;
119
112
  buffer = framed;
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}`);
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()}`);
124
121
  return asset;
125
122
  }
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
- }
123
+ const finalBuffer = optimization ? await optimization(buffer).toBuffer() : buffer;
131
124
  console.log("Optimized asset size", finalBuffer.length);
132
125
  const newAsset = asset.withProps({
133
126
  size: finalBuffer.length
@@ -146,6 +139,26 @@ class LocalSharpTransform {
146
139
  "webp"
147
140
  ].includes(asset.getExtension());
148
141
  }
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
+ }
149
162
  }
150
163
  const LocalSharpTransformImpl = ImageAssetTypeHandler.createImplementation({
151
164
  implementation: LocalSharpTransform,
@@ -1 +1 @@
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
+ {"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?.image as AssetImageEdit | undefined;\n return imageEdit?.crop;\n }\n\n private async transformAsset(asset: Asset, options: TransformOptions, framing: Framing) {\n const assetKey = AssetKeyGenerator.create(asset, framing);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n 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":"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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").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").ModifyFastifyPlugin | 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
- import { RequestContextInitializer } from "@webiny/event-handler-core";
3
2
  import { LocalAssetDeliveryConfig, LocalStoragePath } from "./abstractions.js";
4
- import { LocalAssetResolver } from "./LocalAssetResolver.js";
5
- import { LocalOutputStrategy } from "./LocalOutputStrategy.js";
3
+ import { LocalAssetResolverImpl } from "./LocalAssetResolver.js";
4
+ import { LocalOutputStrategyImpl } from "./LocalOutputStrategy.js";
5
+ import { LocalSharpTransformImpl } from "./LocalSharpTransform.js";
6
6
  const createLocalAssetDeliveryFeature = (params = {})=>createFeature({
7
7
  name: "AssetDelivery/Local",
8
8
  register (container) {
@@ -23,14 +23,9 @@ const createLocalAssetDeliveryFeature = (params = {})=>createFeature({
23
23
  imageQuality: params.imageQuality ?? {},
24
24
  assetStreamingMaxSize: params.assetStreamingMaxSize ?? 4718592
25
25
  });
26
- container.register(LocalAssetResolver);
27
- container.register(LocalOutputStrategy);
28
- if ("asset-delivery" === process.env.WEBINY_FUNCTION_TYPE) container.registerInstance(RequestContextInitializer, {
29
- async init (ctx) {
30
- const { LocalSharpTransformImpl } = await import("./LocalSharpTransform.js");
31
- ctx.container.register(LocalSharpTransformImpl).inSingletonScope();
32
- }
33
- });
26
+ container.register(LocalAssetResolverImpl);
27
+ container.register(LocalOutputStrategyImpl);
28
+ container.register(LocalSharpTransformImpl).inSingletonScope();
34
29
  }
35
30
  });
36
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 { RequestContextInitializer } from \"@webiny/event-handler-core\";\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\";\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 container.registerInstance(RequestContextInitializer, {\n async init(ctx) {\n const { LocalSharpTransformImpl } = await import(\n /* webpackChunkName: \"localAssetDelivery\" */ \"./LocalSharpTransform.js\"\n );\n (ctx.container as typeof container)\n .register(LocalSharpTransformImpl)\n .inSingletonScope();\n }\n });\n }\n }\n });\n};\n"],"names":["createLocalAssetDeliveryFeature","params","createFeature","container","LocalStoragePath","process","LocalAssetDeliveryConfig","LocalAssetResolver","LocalOutputStrategy","RequestContextInitializer","ctx","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;YAEnB,IAAIH,AAAqC,qBAArCA,QAAQ,GAAG,CAAC,oBAAoB,EAChCF,UAAU,gBAAgB,CAACM,2BAA2B;gBAClD,MAAM,MAAKC,GAAG;oBACV,MAAM,EAAEC,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAN;oBAGzCD,IAAI,SAAS,CACT,QAAQ,CAACC,yBACT,gBAAgB;gBACzB;YACJ;QAER;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 { 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,11 +1,8 @@
1
1
  import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
2
- import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
3
2
  export interface CleanupStaleMultipartUploadsInput {
4
3
  noop?: boolean;
5
4
  }
6
5
  declare class CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {
7
- private readonly config;
8
- constructor(config: FileManagerServerConfig.Interface);
9
6
  readonly id = "fileManagerCleanupStaleMultipartUploads";
10
7
  readonly title = "Clean up stale multipart upload directories";
11
8
  readonly description = "Removes multipart upload directories that are older than 24 hours.";
@@ -1,7 +1,6 @@
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";
5
4
  const STALE_THRESHOLD_MS = 86400000;
6
5
  async function readdirSafe(dirPath) {
7
6
  try {
@@ -12,22 +11,9 @@ async function readdirSafe(dirPath) {
12
11
  }
13
12
  }
14
13
  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
- }
28
14
  async run({ controller }) {
29
15
  if (controller.runtime.isAborted()) return controller.response.aborted();
30
- const storagePath = this.config.storagePath;
16
+ const storagePath = String(process.env.WEBINY_LOCAL_STORAGE_PATH);
31
17
  const tenantsDir = node_path.join(storagePath, "tenants");
32
18
  const now = Date.now();
33
19
  const tenantDirs = await readdirSafe(tenantsDir);
@@ -50,12 +36,22 @@ class CleanupStaleMultipartUploadsTaskImpl {
50
36
  }
51
37
  return controller.response.done();
52
38
  }
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
+ }
53
51
  }
54
52
  const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({
55
53
  implementation: CleanupStaleMultipartUploadsTaskImpl,
56
- dependencies: [
57
- FileManagerServerConfig
58
- ]
54
+ dependencies: []
59
55
  });
60
56
  export { CleanupStaleMultipartUploadsTaskDefinition };
61
57
 
@@ -1 +1 @@
1
- {"version":3,"file":"features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js","sources":["../../../src/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nexport interface CleanupStaleMultipartUploadsInput {\n /* Reserved for future use. */\n noop?: boolean;\n}\n\nconst STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;\n\n/* Returns directory entries or an empty array if the path does not exist. */\nasync function readdirSafe(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\nclass CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {\n public constructor(private readonly config: FileManagerServerConfig.Interface) {}\n public readonly id = \"fileManagerCleanupStaleMultipartUploads\";\n public readonly title = \"Clean up stale multipart upload directories\";\n public readonly description =\n \"Removes multipart upload directories that are older than 24 hours.\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public async run({\n controller\n }: TaskDefinition.RunParams<CleanupStaleMultipartUploadsInput>): Promise<\n TaskDefinition.Result<CleanupStaleMultipartUploadsInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const storagePath = this.config.storagePath;\n const tenantsDir = path.join(storagePath, \"tenants\");\n const now = Date.now();\n\n const tenantDirs = await readdirSafe(tenantsDir);\n\n for (const tenantId of tenantDirs) {\n const multipartDir = path.join(tenantsDir, tenantId, \"multipart\");\n const uploadDirs = await readdirSafe(multipartDir);\n\n for (const uploadId of uploadDirs) {\n const uploadPath = path.join(multipartDir, uploadId);\n\n try {\n const stat = await fs.stat(uploadPath);\n const ageMs = now - stat.mtimeMs;\n\n if (ageMs > STALE_THRESHOLD_MS) {\n await fs.rm(uploadPath, { recursive: true, force: true });\n }\n } catch (err) {\n /* Skip entries that have already been removed or cannot be accessed. */\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n }\n }\n }\n\n return controller.response.done();\n }\n}\n\nexport const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({\n implementation: CleanupStaleMultipartUploadsTaskImpl,\n dependencies: [FileManagerServerConfig]\n});\n"],"names":["STALE_THRESHOLD_MS","readdirSafe","dirPath","fs","err","CleanupStaleMultipartUploadsTaskImpl","config","controller","storagePath","tenantsDir","path","now","Date","tenantDirs","tenantId","multipartDir","uploadDirs","uploadId","uploadPath","stat","ageMs","CleanupStaleMultipartUploadsTaskDefinition","TaskDefinition","FileManagerServerConfig"],"mappings":";;;;AAUA,MAAMA,qBAAqB;AAG3B,eAAeC,YAAYC,OAAe;IACtC,IAAI;QACA,OAAO,MAAMC,SAAAA,OAAU,CAACD;IAC5B,EAAE,OAAOE,KAAK;QACV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,OAAO,EAAE;QAEb,MAAMA;IACV;AACJ;AAEA,MAAMC;IACF,YAAoCC,MAAyC,CAAE;aAA3CA,MAAM,GAANA;aACpB,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GACvB;aACY,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aACf,WAAW,GAAG;YAAC;YAAsB;SAAmB;IARQ;IAUhF,MAAa,IAAI,EACbC,UAAU,EACgD,EAE5D;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,aAAaC,UAAAA,IAAS,CAACF,aAAa;QAC1C,MAAMG,MAAMC,KAAK,GAAG;QAEpB,MAAMC,aAAa,MAAMZ,YAAYQ;QAErC,KAAK,MAAMK,YAAYD,WAAY;YAC/B,MAAME,eAAeL,UAAAA,IAAS,CAACD,YAAYK,UAAU;YACrD,MAAME,aAAa,MAAMf,YAAYc;YAErC,KAAK,MAAME,YAAYD,WAAY;gBAC/B,MAAME,aAAaR,UAAAA,IAAS,CAACK,cAAcE;gBAE3C,IAAI;oBACA,MAAME,OAAO,MAAMhB,SAAAA,IAAO,CAACe;oBAC3B,MAAME,QAAQT,MAAMQ,KAAK,OAAO;oBAEhC,IAAIC,QAAQpB,oBACR,MAAMG,SAAAA,EAAK,CAACe,YAAY;wBAAE,WAAW;wBAAM,OAAO;oBAAK;gBAE/D,EAAE,OAAOd,KAAK;oBAEV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,MAAMA;gBAEd;YACJ;QACJ;QAEA,OAAOG,WAAW,QAAQ,CAAC,IAAI;IACnC;AACJ;AAEO,MAAMc,6CAA6CC,eAAe,oBAAoB,CAAC;IAC1F,gBAAgBjB;IAChB,cAAc;QAACkB;KAAwB;AAC3C"}
1
+ {"version":3,"file":"features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js","sources":["../../../src/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\n\nexport interface CleanupStaleMultipartUploadsInput {\n /* Reserved for future use. */\n noop?: boolean;\n}\n\nconst STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;\n\n/* Returns directory entries or an empty array if the path does not exist. */\nasync function readdirSafe(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\nclass CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {\n public readonly id = \"fileManagerCleanupStaleMultipartUploads\";\n public readonly title = \"Clean up stale multipart upload directories\";\n public readonly description =\n \"Removes multipart upload directories that are older than 24 hours.\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public async run({\n controller\n }: TaskDefinition.RunParams<CleanupStaleMultipartUploadsInput>): Promise<\n TaskDefinition.Result<CleanupStaleMultipartUploadsInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const storagePath = String(process.env.WEBINY_LOCAL_STORAGE_PATH);\n const tenantsDir = path.join(storagePath, \"tenants\");\n const now = Date.now();\n\n const tenantDirs = await readdirSafe(tenantsDir);\n\n for (const tenantId of tenantDirs) {\n const multipartDir = path.join(tenantsDir, tenantId, \"multipart\");\n const uploadDirs = await readdirSafe(multipartDir);\n\n for (const uploadId of uploadDirs) {\n const uploadPath = path.join(multipartDir, uploadId);\n\n try {\n const stat = await fs.stat(uploadPath);\n const ageMs = now - stat.mtimeMs;\n\n if (ageMs > STALE_THRESHOLD_MS) {\n await fs.rm(uploadPath, { recursive: true, force: true });\n }\n } catch (err) {\n /* Skip entries that have already been removed or cannot be accessed. */\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n }\n }\n }\n\n return controller.response.done();\n }\n}\n\nexport const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({\n implementation: CleanupStaleMultipartUploadsTaskImpl,\n dependencies: []\n});\n"],"names":["STALE_THRESHOLD_MS","readdirSafe","dirPath","fs","err","CleanupStaleMultipartUploadsTaskImpl","controller","storagePath","String","process","tenantsDir","path","now","Date","tenantDirs","tenantId","multipartDir","uploadDirs","uploadId","uploadPath","stat","ageMs","CleanupStaleMultipartUploadsTaskDefinition","TaskDefinition"],"mappings":";;;AASA,MAAMA,qBAAqB;AAG3B,eAAeC,YAAYC,OAAe;IACtC,IAAI;QACA,OAAO,MAAMC,SAAAA,OAAU,CAACD;IAC5B,EAAE,OAAOE,KAAK;QACV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,OAAO,EAAE;QAEb,MAAMA;IACV;AACJ;AAEA,MAAMC;IAUF,MAAa,IAAI,EACbC,UAAU,EACgD,EAE5D;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,cAAcC,OAAOC,QAAQ,GAAG,CAAC,yBAAyB;QAChE,MAAMC,aAAaC,UAAAA,IAAS,CAACJ,aAAa;QAC1C,MAAMK,MAAMC,KAAK,GAAG;QAEpB,MAAMC,aAAa,MAAMb,YAAYS;QAErC,KAAK,MAAMK,YAAYD,WAAY;YAC/B,MAAME,eAAeL,UAAAA,IAAS,CAACD,YAAYK,UAAU;YACrD,MAAME,aAAa,MAAMhB,YAAYe;YAErC,KAAK,MAAME,YAAYD,WAAY;gBAC/B,MAAME,aAAaR,UAAAA,IAAS,CAACK,cAAcE;gBAE3C,IAAI;oBACA,MAAME,OAAO,MAAMjB,SAAAA,IAAO,CAACgB;oBAC3B,MAAME,QAAQT,MAAMQ,KAAK,OAAO;oBAEhC,IAAIC,QAAQrB,oBACR,MAAMG,SAAAA,EAAK,CAACgB,YAAY;wBAAE,WAAW;wBAAM,OAAO;oBAAK;gBAE/D,EAAE,OAAOf,KAAK;oBAEV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,MAAMA;gBAEd;YACJ;QACJ;QAEA,OAAOE,WAAW,QAAQ,CAAC,IAAI;IACnC;;aAhDgB,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GACvB;aACY,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aACf,WAAW,GAAG;YAAC;YAAsB;SAAmB;;AA0C5E;AAEO,MAAMgB,6CAA6CC,eAAe,oBAAoB,CAAC;IAC1F,gBAAgBlB;IAChB,cAAc,EAAE;AACpB"}
@@ -1,13 +1,11 @@
1
1
  import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
2
- import { CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCaseAbstraction } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
3
- import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
4
- declare class CompleteMultiPartUploadUseCaseImpl implements CompleteMultiPartUploadUseCaseAbstraction.Interface {
2
+ import { CompleteMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
3
+ declare class CompleteMultiPartUploadUseCaseImpl implements CompleteMultiPartUploadUseCase.Interface {
5
4
  private readonly tenantContext;
6
- private readonly config;
7
- constructor(tenantContext: TenantContext.Interface, config: FileManagerServerConfig.Interface);
8
- execute(params: CompleteMultiPartUploadUseCaseAbstraction.Params): Promise<void>;
5
+ constructor(tenantContext: TenantContext.Interface);
6
+ execute(params: CompleteMultiPartUploadUseCase.Params): Promise<void>;
9
7
  }
10
- export declare const CompleteMultiPartUploadUseCase: typeof CompleteMultiPartUploadUseCaseImpl & {
8
+ export declare const CompleteMultiPartUploadUseCaseImplementation: typeof CompleteMultiPartUploadUseCaseImpl & {
11
9
  __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/abstractions").ICompleteMultiPartUploadUseCase>;
12
10
  };
13
11
  export {};
@@ -2,15 +2,13 @@ import node_path from "node:path";
2
2
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
3
3
  import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
4
4
  import { CompleteMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
5
- import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
6
5
  class CompleteMultiPartUploadUseCaseImpl {
7
- constructor(tenantContext, config){
6
+ constructor(tenantContext){
8
7
  this.tenantContext = tenantContext;
9
- this.config = config;
10
8
  }
11
9
  async execute(params) {
12
10
  const { fileKey, uploadId } = params;
13
- const storagePath = this.config.storagePath;
11
+ const storagePath = String(process.env.WEBINY_LOCAL_STORAGE_PATH);
14
12
  const tenant = this.tenantContext.getTenant();
15
13
  assertNoTraversal(uploadId);
16
14
  for (const seg of fileKey.split(/[\\/]/))assertNoTraversal(seg);
@@ -50,13 +48,12 @@ function assertPathContained(resolved, root) {
50
48
  const normalizedRoot = node_path.resolve(root);
51
49
  if (!normalized.startsWith(normalizedRoot + node_path.sep) && normalized !== normalizedRoot) throw new Error("Path escapes tenant root.");
52
50
  }
53
- const CompleteMultiPartUploadUseCase_CompleteMultiPartUploadUseCase = CompleteMultiPartUploadUseCase.createImplementation({
51
+ const CompleteMultiPartUploadUseCaseImplementation = CompleteMultiPartUploadUseCase.createImplementation({
54
52
  implementation: CompleteMultiPartUploadUseCaseImpl,
55
53
  dependencies: [
56
- TenantContext,
57
- FileManagerServerConfig
54
+ TenantContext
58
55
  ]
59
56
  });
60
- export { CompleteMultiPartUploadUseCase_CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCase };
57
+ export { CompleteMultiPartUploadUseCaseImplementation };
61
58
 
62
59
  //# sourceMappingURL=CompleteMultiPartUploadUseCase.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js","sources":["../../../src/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { readdir } from \"node:fs/promises\";\nimport { readFile } from \"node:fs/promises\";\nimport { writeFile } from \"node:fs/promises\";\nimport { rm } from \"node:fs/promises\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCaseAbstraction } from \"@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nclass CompleteMultiPartUploadUseCaseImpl\n implements CompleteMultiPartUploadUseCaseAbstraction.Interface\n{\n public constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly config: FileManagerServerConfig.Interface\n ) {}\n\n public async execute(params: CompleteMultiPartUploadUseCaseAbstraction.Params): Promise<void> {\n const { fileKey, uploadId } = params;\n const storagePath = this.config.storagePath;\n const tenant = this.tenantContext.getTenant();\n\n assertNoTraversal(uploadId);\n for (const seg of fileKey.split(/[\\\\/]/)) {\n assertNoTraversal(seg);\n }\n\n const tenantRoot = path.resolve(path.join(storagePath, \"tenants\", tenant.id, \"files\"));\n const destPath = path.resolve(path.join(tenantRoot, fileKey));\n assertPathContained(destPath, tenantRoot);\n\n const multipartDir = path.join(storagePath, \"tenants\", tenant.id, \"multipart\", uploadId);\n\n const entries = await readdir(multipartDir);\n const sorted = entries\n .filter(name => name.startsWith(\"part-\"))\n .sort((a, b) => {\n const numA = parseInt(a.replace(\"part-\", \"\"), 10);\n const numB = parseInt(b.replace(\"part-\", \"\"), 10);\n return numA - numB;\n });\n\n const destDir = path.dirname(destPath);\n await mkdir(destDir, { recursive: true });\n\n const buffers: Buffer[] = [];\n for (const partName of sorted) {\n const partPath = path.join(multipartDir, partName);\n const partData = await readFile(partPath);\n buffers.push(partData);\n }\n\n const finalBuffer = Buffer.concat(buffers);\n await writeFile(destPath, finalBuffer);\n\n await rm(multipartDir, { recursive: true, force: true });\n }\n}\n\nfunction assertNoTraversal(segment: string): void {\n if (segment.includes(\"..\") || segment.includes(\"/\") || segment.includes(\"\\\\\")) {\n throw new Error(\"Invalid path segment.\");\n }\n}\n\nfunction assertPathContained(resolved: string, root: string): void {\n const normalized = path.resolve(resolved);\n const normalizedRoot = path.resolve(root);\n if (!normalized.startsWith(normalizedRoot + path.sep) && normalized !== normalizedRoot) {\n throw new Error(\"Path escapes tenant root.\");\n }\n}\n\nexport const CompleteMultiPartUploadUseCase =\n CompleteMultiPartUploadUseCaseAbstraction.createImplementation({\n implementation: CompleteMultiPartUploadUseCaseImpl,\n dependencies: [TenantContext, FileManagerServerConfig]\n });\n"],"names":["CompleteMultiPartUploadUseCaseImpl","tenantContext","config","params","fileKey","uploadId","storagePath","tenant","assertNoTraversal","seg","tenantRoot","path","destPath","assertPathContained","multipartDir","entries","readdir","sorted","name","a","b","numA","parseInt","numB","destDir","mkdir","buffers","partName","partPath","partData","readFile","finalBuffer","Buffer","writeFile","rm","segment","Error","resolved","root","normalized","normalizedRoot","CompleteMultiPartUploadUseCase","CompleteMultiPartUploadUseCaseAbstraction","TenantContext","FileManagerServerConfig"],"mappings":";;;;;AAUA,MAAMA;IAGF,YACqBC,aAAsC,EACtCC,MAAyC,CAC5D;aAFmBD,aAAa,GAAbA;aACAC,MAAM,GAANA;IAClB;IAEH,MAAa,QAAQC,MAAwD,EAAiB;QAC1F,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGF;QAC9B,MAAMG,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAE3CC,kBAAkBH;QAClB,KAAK,MAAMI,OAAOL,QAAQ,KAAK,CAAC,SAC5BI,kBAAkBC;QAGtB,MAAMC,aAAaC,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACL,aAAa,WAAWC,OAAO,EAAE,EAAE;QAC7E,MAAMK,WAAWD,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACD,YAAYN;QACpDS,oBAAoBD,UAAUF;QAE9B,MAAMI,eAAeH,UAAAA,IAAS,CAACL,aAAa,WAAWC,OAAO,EAAE,EAAE,aAAaF;QAE/E,MAAMU,UAAU,MAAMC,QAAQF;QAC9B,MAAMG,SAASF,QACV,MAAM,CAACG,CAAAA,OAAQA,KAAK,UAAU,CAAC,UAC/B,IAAI,CAAC,CAACC,GAAGC;YACN,MAAMC,OAAOC,SAASH,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,MAAMI,OAAOD,SAASF,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,OAAOC,OAAOE;QAClB;QAEJ,MAAMC,UAAUb,UAAAA,OAAY,CAACC;QAC7B,MAAMa,MAAMD,SAAS;YAAE,WAAW;QAAK;QAEvC,MAAME,UAAoB,EAAE;QAC5B,KAAK,MAAMC,YAAYV,OAAQ;YAC3B,MAAMW,WAAWjB,UAAAA,IAAS,CAACG,cAAca;YACzC,MAAME,WAAW,MAAMC,SAASF;YAChCF,QAAQ,IAAI,CAACG;QACjB;QAEA,MAAME,cAAcC,OAAO,MAAM,CAACN;QAClC,MAAMO,UAAUrB,UAAUmB;QAE1B,MAAMG,GAAGpB,cAAc;YAAE,WAAW;YAAM,OAAO;QAAK;IAC1D;AACJ;AAEA,SAASN,kBAAkB2B,OAAe;IACtC,IAAIA,QAAQ,QAAQ,CAAC,SAASA,QAAQ,QAAQ,CAAC,QAAQA,QAAQ,QAAQ,CAAC,OACpE,MAAM,IAAIC,MAAM;AAExB;AAEA,SAASvB,oBAAoBwB,QAAgB,EAAEC,IAAY;IACvD,MAAMC,aAAa5B,UAAAA,OAAY,CAAC0B;IAChC,MAAMG,iBAAiB7B,UAAAA,OAAY,CAAC2B;IACpC,IAAI,CAACC,WAAW,UAAU,CAACC,iBAAiB7B,UAAAA,GAAQ,KAAK4B,eAAeC,gBACpE,MAAM,IAAIJ,MAAM;AAExB;AAEO,MAAMK,gEACTC,+BAAAA,oBAA8D,CAAC;IAC3D,gBAAgB1C;IAChB,cAAc;QAAC2C;QAAeC;KAAwB;AAC1D"}
1
+ {"version":3,"file":"features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js","sources":["../../../src/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { readdir } from \"node:fs/promises\";\nimport { readFile } from \"node:fs/promises\";\nimport { writeFile } from \"node:fs/promises\";\nimport { rm } from \"node:fs/promises\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { CompleteMultiPartUploadUseCase } from \"@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js\";\n\nclass CompleteMultiPartUploadUseCaseImpl implements CompleteMultiPartUploadUseCase.Interface {\n public constructor(private readonly tenantContext: TenantContext.Interface) {}\n\n public async execute(params: CompleteMultiPartUploadUseCase.Params): Promise<void> {\n const { fileKey, uploadId } = params;\n const storagePath = String(process.env.WEBINY_LOCAL_STORAGE_PATH);\n const tenant = this.tenantContext.getTenant();\n\n assertNoTraversal(uploadId);\n for (const seg of fileKey.split(/[\\\\/]/)) {\n assertNoTraversal(seg);\n }\n\n const tenantRoot = path.resolve(path.join(storagePath, \"tenants\", tenant.id, \"files\"));\n const destPath = path.resolve(path.join(tenantRoot, fileKey));\n assertPathContained(destPath, tenantRoot);\n\n const multipartDir = path.join(storagePath, \"tenants\", tenant.id, \"multipart\", uploadId);\n\n const entries = await readdir(multipartDir);\n const sorted = entries\n .filter(name => name.startsWith(\"part-\"))\n .sort((a, b) => {\n const numA = parseInt(a.replace(\"part-\", \"\"), 10);\n const numB = parseInt(b.replace(\"part-\", \"\"), 10);\n return numA - numB;\n });\n\n const destDir = path.dirname(destPath);\n await mkdir(destDir, { recursive: true });\n\n const buffers: Buffer[] = [];\n for (const partName of sorted) {\n const partPath = path.join(multipartDir, partName);\n const partData = await readFile(partPath);\n buffers.push(partData);\n }\n\n const finalBuffer = Buffer.concat(buffers);\n await writeFile(destPath, finalBuffer);\n\n await rm(multipartDir, { recursive: true, force: true });\n }\n}\n\nfunction assertNoTraversal(segment: string): void {\n if (segment.includes(\"..\") || segment.includes(\"/\") || segment.includes(\"\\\\\")) {\n throw new Error(\"Invalid path segment.\");\n }\n}\n\nfunction assertPathContained(resolved: string, root: string): void {\n const normalized = path.resolve(resolved);\n const normalizedRoot = path.resolve(root);\n if (!normalized.startsWith(normalizedRoot + path.sep) && normalized !== normalizedRoot) {\n throw new Error(\"Path escapes tenant root.\");\n }\n}\n\nexport const CompleteMultiPartUploadUseCaseImplementation =\n CompleteMultiPartUploadUseCase.createImplementation({\n implementation: CompleteMultiPartUploadUseCaseImpl,\n dependencies: [TenantContext]\n });\n"],"names":["CompleteMultiPartUploadUseCaseImpl","tenantContext","params","fileKey","uploadId","storagePath","String","process","tenant","assertNoTraversal","seg","tenantRoot","path","destPath","assertPathContained","multipartDir","entries","readdir","sorted","name","a","b","numA","parseInt","numB","destDir","mkdir","buffers","partName","partPath","partData","readFile","finalBuffer","Buffer","writeFile","rm","segment","Error","resolved","root","normalized","normalizedRoot","CompleteMultiPartUploadUseCaseImplementation","CompleteMultiPartUploadUseCase","TenantContext"],"mappings":";;;;AASA,MAAMA;IACF,YAAoCC,aAAsC,CAAE;aAAxCA,aAAa,GAAbA;IAAyC;IAE7E,MAAa,QAAQC,MAA6C,EAAiB;QAC/E,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGF;QAC9B,MAAMG,cAAcC,OAAOC,QAAQ,GAAG,CAAC,yBAAyB;QAChE,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAE3CC,kBAAkBL;QAClB,KAAK,MAAMM,OAAOP,QAAQ,KAAK,CAAC,SAC5BM,kBAAkBC;QAGtB,MAAMC,aAAaC,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACP,aAAa,WAAWG,OAAO,EAAE,EAAE;QAC7E,MAAMK,WAAWD,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACD,YAAYR;QACpDW,oBAAoBD,UAAUF;QAE9B,MAAMI,eAAeH,UAAAA,IAAS,CAACP,aAAa,WAAWG,OAAO,EAAE,EAAE,aAAaJ;QAE/E,MAAMY,UAAU,MAAMC,QAAQF;QAC9B,MAAMG,SAASF,QACV,MAAM,CAACG,CAAAA,OAAQA,KAAK,UAAU,CAAC,UAC/B,IAAI,CAAC,CAACC,GAAGC;YACN,MAAMC,OAAOC,SAASH,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,MAAMI,OAAOD,SAASF,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,OAAOC,OAAOE;QAClB;QAEJ,MAAMC,UAAUb,UAAAA,OAAY,CAACC;QAC7B,MAAMa,MAAMD,SAAS;YAAE,WAAW;QAAK;QAEvC,MAAME,UAAoB,EAAE;QAC5B,KAAK,MAAMC,YAAYV,OAAQ;YAC3B,MAAMW,WAAWjB,UAAAA,IAAS,CAACG,cAAca;YACzC,MAAME,WAAW,MAAMC,SAASF;YAChCF,QAAQ,IAAI,CAACG;QACjB;QAEA,MAAME,cAAcC,OAAO,MAAM,CAACN;QAClC,MAAMO,UAAUrB,UAAUmB;QAE1B,MAAMG,GAAGpB,cAAc;YAAE,WAAW;YAAM,OAAO;QAAK;IAC1D;AACJ;AAEA,SAASN,kBAAkB2B,OAAe;IACtC,IAAIA,QAAQ,QAAQ,CAAC,SAASA,QAAQ,QAAQ,CAAC,QAAQA,QAAQ,QAAQ,CAAC,OACpE,MAAM,IAAIC,MAAM;AAExB;AAEA,SAASvB,oBAAoBwB,QAAgB,EAAEC,IAAY;IACvD,MAAMC,aAAa5B,UAAAA,OAAY,CAAC0B;IAChC,MAAMG,iBAAiB7B,UAAAA,OAAY,CAAC2B;IACpC,IAAI,CAACC,WAAW,UAAU,CAACC,iBAAiB7B,UAAAA,GAAQ,KAAK4B,eAAeC,gBACpE,MAAM,IAAIJ,MAAM;AAExB;AAEO,MAAMK,+CACTC,+BAA+B,oBAAoB,CAAC;IAChD,gBAAgB3C;IAChB,cAAc;QAAC4C;KAAc;AACjC"}
@@ -1,9 +1,9 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
- import { CompleteMultiPartUploadUseCase } from "./CompleteMultiPartUploadUseCase.js";
2
+ import { CompleteMultiPartUploadUseCaseImplementation } from "./CompleteMultiPartUploadUseCase.js";
3
3
  const CompleteMultiPartUploadFeature = createFeature({
4
4
  name: "FileManagerServer/CompleteMultiPartUpload",
5
5
  register (container) {
6
- container.register(CompleteMultiPartUploadUseCase);
6
+ container.register(CompleteMultiPartUploadUseCaseImplementation);
7
7
  }
8
8
  });
9
9
  export { CompleteMultiPartUploadFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"features/CompleteMultiPartUpload/feature.js","sources":["../../../src/features/CompleteMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { CompleteMultiPartUploadUseCase } from \"./CompleteMultiPartUploadUseCase.js\";\n\nexport const CompleteMultiPartUploadFeature = createFeature({\n name: \"FileManagerServer/CompleteMultiPartUpload\",\n register(container) {\n container.register(CompleteMultiPartUploadUseCase);\n }\n});\n"],"names":["CompleteMultiPartUploadFeature","createFeature","container","CompleteMultiPartUploadUseCase"],"mappings":";;AAGO,MAAMA,iCAAiCC,cAAc;IACxD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
1
+ {"version":3,"file":"features/CompleteMultiPartUpload/feature.js","sources":["../../../src/features/CompleteMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { CompleteMultiPartUploadUseCaseImplementation } from \"./CompleteMultiPartUploadUseCase.js\";\n\nexport const CompleteMultiPartUploadFeature = createFeature({\n name: \"FileManagerServer/CompleteMultiPartUpload\",\n register(container) {\n container.register(CompleteMultiPartUploadUseCaseImplementation);\n }\n});\n"],"names":["CompleteMultiPartUploadFeature","createFeature","container","CompleteMultiPartUploadUseCaseImplementation"],"mappings":";;AAGO,MAAMA,iCAAiCC,cAAc;IACxD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}