@webiny/api-file-manager-s3 0.0.0-unstable.78f581c1d2 → 0.0.0-unstable.7be00a75a9

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 (184) hide show
  1. package/README.md +11 -1
  2. package/assetDelivery/abstractions.d.ts +9 -0
  3. package/assetDelivery/abstractions.js +7 -0
  4. package/assetDelivery/abstractions.js.map +1 -0
  5. package/assetDelivery/assetDeliveryConfig.d.ts +2 -0
  6. package/assetDelivery/assetDeliveryConfig.js +15 -0
  7. package/assetDelivery/assetDeliveryConfig.js.map +1 -0
  8. package/assetDelivery/createAssetDelivery.d.ts +3 -0
  9. package/assetDelivery/createAssetDelivery.js +9 -0
  10. package/assetDelivery/createAssetDelivery.js.map +1 -0
  11. package/assetDelivery/feature.d.ts +5 -0
  12. package/assetDelivery/feature.js +37 -0
  13. package/assetDelivery/feature.js.map +1 -0
  14. package/assetDelivery/index.d.ts +8 -0
  15. package/assetDelivery/index.js +8 -0
  16. package/assetDelivery/s3/S3AssetResolver.d.ts +14 -0
  17. package/assetDelivery/s3/S3AssetResolver.js +39 -0
  18. package/assetDelivery/s3/S3AssetResolver.js.map +1 -0
  19. package/assetDelivery/s3/S3ContentsReader.d.ts +8 -0
  20. package/assetDelivery/s3/S3ContentsReader.js +17 -0
  21. package/assetDelivery/s3/S3ContentsReader.js.map +1 -0
  22. package/assetDelivery/s3/S3ErrorAssetReply.d.ts +4 -0
  23. package/assetDelivery/s3/S3ErrorAssetReply.js +14 -0
  24. package/assetDelivery/s3/S3ErrorAssetReply.js.map +1 -0
  25. package/assetDelivery/s3/S3OutputStrategy.d.ts +15 -0
  26. package/assetDelivery/s3/S3OutputStrategy.js +40 -0
  27. package/assetDelivery/s3/S3OutputStrategy.js.map +1 -0
  28. package/assetDelivery/s3/S3RedirectAssetReply.d.ts +4 -0
  29. package/assetDelivery/s3/S3RedirectAssetReply.js +17 -0
  30. package/assetDelivery/s3/S3RedirectAssetReply.js.map +1 -0
  31. package/assetDelivery/s3/S3StreamAssetReply.d.ts +5 -0
  32. package/assetDelivery/s3/S3StreamAssetReply.js +17 -0
  33. package/assetDelivery/s3/S3StreamAssetReply.js.map +1 -0
  34. package/assetDelivery/s3/SharpTransform.d.ts +18 -0
  35. package/assetDelivery/s3/SharpTransform.js +162 -0
  36. package/assetDelivery/s3/SharpTransform.js.map +1 -0
  37. package/assetDelivery/s3/transformation/AssetKeyGenerator.d.ts +8 -0
  38. package/assetDelivery/s3/transformation/AssetKeyGenerator.js +21 -0
  39. package/assetDelivery/s3/transformation/AssetKeyGenerator.js.map +1 -0
  40. package/assetDelivery/s3/transformation/CallableContentsReader.d.ts +10 -0
  41. package/assetDelivery/s3/transformation/CallableContentsReader.js +11 -0
  42. package/assetDelivery/s3/transformation/CallableContentsReader.js.map +1 -0
  43. package/assetDelivery/s3/transformation/WidthCollection.d.ts +7 -0
  44. package/assetDelivery/s3/transformation/WidthCollection.js +19 -0
  45. package/assetDelivery/s3/transformation/WidthCollection.js.map +1 -0
  46. package/assetDelivery/s3/transformation/utils.d.ts +9 -0
  47. package/assetDelivery/s3/transformation/utils.js +31 -0
  48. package/assetDelivery/s3/transformation/utils.js.map +1 -0
  49. package/assetDelivery/threatDetection/ObjectKey.d.ts +7 -0
  50. package/assetDelivery/threatDetection/ObjectKey.js +18 -0
  51. package/assetDelivery/threatDetection/ObjectKey.js.map +1 -0
  52. package/assetDelivery/threatDetection/createThreatDetectionEventHandler.d.ts +2 -0
  53. package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js +37 -0
  54. package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js.map +1 -0
  55. package/assetDelivery/threatDetection/createThreatDetectionPluginLoader.d.ts +2 -0
  56. package/assetDelivery/threatDetection/createThreatDetectionPluginLoader.js +5 -0
  57. package/assetDelivery/threatDetection/createThreatDetectionPluginLoader.js.map +1 -0
  58. package/assetDelivery/threatDetection/index.d.ts +2 -0
  59. package/assetDelivery/threatDetection/index.js +2 -0
  60. package/assetDelivery/threatDetection/processThreatScanResult.d.ts +3 -0
  61. package/assetDelivery/threatDetection/processThreatScanResult.js +59 -0
  62. package/assetDelivery/threatDetection/processThreatScanResult.js.map +1 -0
  63. package/assetDelivery/threatDetection/types.d.ts +9 -0
  64. package/assetDelivery/threatDetection/types.js +0 -0
  65. package/assetDelivery/types.d.ts +10 -0
  66. package/assetDelivery/types.js +0 -0
  67. package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.d.ts +11 -0
  68. package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js +23 -0
  69. package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js.map +1 -0
  70. package/enterprise/ApplyThreatScanning/feature.d.ts +4 -0
  71. package/enterprise/ApplyThreatScanning/feature.js +11 -0
  72. package/enterprise/ApplyThreatScanning/feature.js.map +1 -0
  73. package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.d.ts +15 -0
  74. package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.js +35 -0
  75. package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.js.map +1 -0
  76. package/features/DeleteFileFromBucket/DeleteS3FolderTask.d.ts +32 -0
  77. package/features/DeleteFileFromBucket/DeleteS3FolderTask.js +50 -0
  78. package/features/DeleteFileFromBucket/DeleteS3FolderTask.js.map +1 -0
  79. package/features/DeleteFileFromBucket/feature.d.ts +4 -0
  80. package/features/DeleteFileFromBucket/feature.js +13 -0
  81. package/features/DeleteFileFromBucket/feature.js.map +1 -0
  82. package/features/ExtractMetadata/ExtractMetadataHandler.d.ts +11 -0
  83. package/features/ExtractMetadata/ExtractMetadataHandler.js +25 -0
  84. package/features/ExtractMetadata/ExtractMetadataHandler.js.map +1 -0
  85. package/features/ExtractMetadata/ExtractMetadataTask.d.ts +24 -0
  86. package/features/ExtractMetadata/ExtractMetadataTask.js +90 -0
  87. package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -0
  88. package/features/ExtractMetadata/feature.d.ts +4 -0
  89. package/features/ExtractMetadata/feature.js +13 -0
  90. package/features/ExtractMetadata/feature.js.map +1 -0
  91. package/features/FlushCache/FlushCacheOnFileDeleteHandler.d.ts +12 -0
  92. package/features/FlushCache/FlushCacheOnFileDeleteHandler.js +28 -0
  93. package/features/FlushCache/FlushCacheOnFileDeleteHandler.js.map +1 -0
  94. package/features/FlushCache/FlushCacheOnFileUpdateHandler.d.ts +12 -0
  95. package/features/FlushCache/FlushCacheOnFileUpdateHandler.js +31 -0
  96. package/features/FlushCache/FlushCacheOnFileUpdateHandler.js.map +1 -0
  97. package/features/FlushCache/InvalidateCacheTask.d.ts +26 -0
  98. package/features/FlushCache/InvalidateCacheTask.js +75 -0
  99. package/features/FlushCache/InvalidateCacheTask.js.map +1 -0
  100. package/features/FlushCache/feature.d.ts +4 -0
  101. package/features/FlushCache/feature.js +15 -0
  102. package/features/FlushCache/feature.js.map +1 -0
  103. package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +13 -0
  104. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +40 -0
  105. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js.map +1 -0
  106. package/features/GetFileContentsById/feature.d.ts +4 -0
  107. package/features/GetFileContentsById/feature.js +11 -0
  108. package/features/GetFileContentsById/feature.js.map +1 -0
  109. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.d.ts +13 -0
  110. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +40 -0
  111. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js.map +1 -0
  112. package/features/GetFileContentsByKey/feature.d.ts +4 -0
  113. package/features/GetFileContentsByKey/feature.js +11 -0
  114. package/features/GetFileContentsByKey/feature.js.map +1 -0
  115. package/features/WriteFileMetadata/MetadataReader.d.ts +14 -0
  116. package/features/WriteFileMetadata/MetadataReader.js +13 -0
  117. package/features/WriteFileMetadata/MetadataReader.js.map +1 -0
  118. package/features/WriteFileMetadata/MetadataWriter.d.ts +10 -0
  119. package/features/WriteFileMetadata/MetadataWriter.js +26 -0
  120. package/features/WriteFileMetadata/MetadataWriter.js.map +1 -0
  121. package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.d.ts +12 -0
  122. package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.js +23 -0
  123. package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.js.map +1 -0
  124. package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.d.ts +12 -0
  125. package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.js +25 -0
  126. package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.js.map +1 -0
  127. package/features/WriteFileMetadata/feature.d.ts +4 -0
  128. package/features/WriteFileMetadata/feature.js +13 -0
  129. package/features/WriteFileMetadata/feature.js.map +1 -0
  130. package/graphql/checkPermissions.d.ts +5 -0
  131. package/graphql/checkPermissions.js +22 -0
  132. package/graphql/checkPermissions.js.map +1 -0
  133. package/graphql/schema.d.ts +1 -0
  134. package/graphql/schema.js +201 -0
  135. package/graphql/schema.js.map +1 -0
  136. package/index.d.ts +4 -2
  137. package/index.js +29 -14
  138. package/index.js.map +1 -1
  139. package/multiPartUpload/CompleteMultiPartUploadUseCase.d.ts +15 -0
  140. package/multiPartUpload/CompleteMultiPartUploadUseCase.js +55 -0
  141. package/multiPartUpload/CompleteMultiPartUploadUseCase.js.map +1 -0
  142. package/multiPartUpload/CreateMultiPartUploadUseCase.d.ts +20 -0
  143. package/multiPartUpload/CreateMultiPartUploadUseCase.js +34 -0
  144. package/multiPartUpload/CreateMultiPartUploadUseCase.js.map +1 -0
  145. package/package.json +35 -24
  146. package/types.d.ts +14 -9
  147. package/types.js +1 -5
  148. package/utils/CdnPathsGenerator.d.ts +3 -0
  149. package/utils/CdnPathsGenerator.js +11 -0
  150. package/utils/CdnPathsGenerator.js.map +1 -0
  151. package/utils/FileExtension.d.ts +6 -0
  152. package/utils/FileExtension.js +16 -0
  153. package/utils/FileExtension.js.map +1 -0
  154. package/utils/FileKey.d.ts +11 -0
  155. package/utils/FileKey.js +33 -0
  156. package/utils/FileKey.js.map +1 -0
  157. package/utils/FileKey.test.d.ts +1 -0
  158. package/utils/FileKey.test.js +59 -0
  159. package/utils/FileKey.test.js.map +1 -0
  160. package/utils/FileNormalizer.d.ts +18 -0
  161. package/utils/FileNormalizer.js +41 -0
  162. package/utils/FileNormalizer.js.map +1 -0
  163. package/utils/FileUploadModifier.d.ts +30 -0
  164. package/utils/FileUploadModifier.js +39 -0
  165. package/utils/FileUploadModifier.js.map +1 -0
  166. package/utils/createFileNormalizerFromContext.d.ts +3 -0
  167. package/utils/createFileNormalizerFromContext.js +9 -0
  168. package/utils/createFileNormalizerFromContext.js.map +1 -0
  169. package/utils/getPresignedPostPayload.d.ts +4 -4
  170. package/utils/getPresignedPostPayload.js +39 -83
  171. package/utils/getPresignedPostPayload.js.map +1 -1
  172. package/utils/mimeTypes.d.ts +5 -0
  173. package/utils/mimeTypes.js +9 -0
  174. package/utils/mimeTypes.js.map +1 -0
  175. package/utils/uploadFileToS3.d.ts +2 -4
  176. package/utils/uploadFileToS3.js +12 -27
  177. package/utils/uploadFileToS3.js.map +1 -1
  178. package/plugins/fileStorageS3.d.ts +0 -6
  179. package/plugins/fileStorageS3.js +0 -68
  180. package/plugins/fileStorageS3.js.map +0 -1
  181. package/plugins/graphqlFileStorageS3.d.ts +0 -4
  182. package/plugins/graphqlFileStorageS3.js +0 -150
  183. package/plugins/graphqlFileStorageS3.js.map +0 -1
  184. package/types.js.map +0 -1
@@ -0,0 +1,11 @@
1
+ import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ declare class ExtractMetadataHandlerImpl implements FileAfterCreateEventHandler.Interface {
4
+ private taskService;
5
+ constructor(taskService: TaskService.Interface);
6
+ handle(event: FileAfterCreateEventHandler.Event): Promise<void>;
7
+ }
8
+ export declare const ExtractMetadataHandler: typeof ExtractMetadataHandlerImpl & {
9
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher/abstractions.js").IEventHandler<import("@webiny/api-file-manager/features/file/CreateFile/events.js").FileAfterCreateEvent>>;
10
+ };
11
+ export {};
@@ -0,0 +1,25 @@
1
+ import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ class ExtractMetadataHandlerImpl {
4
+ constructor(taskService){
5
+ this.taskService = taskService;
6
+ }
7
+ async handle(event) {
8
+ const { file } = event.payload;
9
+ await this.taskService.trigger({
10
+ definition: "fileManagerExtractMetadata",
11
+ input: {
12
+ fileId: file.id
13
+ }
14
+ });
15
+ }
16
+ }
17
+ const ExtractMetadataHandler = FileAfterCreateEventHandler.createImplementation({
18
+ implementation: ExtractMetadataHandlerImpl,
19
+ dependencies: [
20
+ TaskService
21
+ ]
22
+ });
23
+ export { ExtractMetadataHandler };
24
+
25
+ //# sourceMappingURL=ExtractMetadataHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/ExtractMetadata/ExtractMetadataHandler.js","sources":["../../../src/features/ExtractMetadata/ExtractMetadataHandler.ts"],"sourcesContent":["import { FileAfterCreateEventHandler } from \"@webiny/api-file-manager/features/file/CreateFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport type { ExtractMetadataInput } from \"./ExtractMetadataTask.js\";\n\nclass ExtractMetadataHandlerImpl implements FileAfterCreateEventHandler.Interface {\n constructor(private taskService: TaskService.Interface) {}\n\n async handle(event: FileAfterCreateEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n\n // Trigger the metadata extraction task\n await this.taskService.trigger<ExtractMetadataInput>({\n definition: \"fileManagerExtractMetadata\",\n input: {\n fileId: file.id\n }\n });\n }\n}\n\nexport const ExtractMetadataHandler = FileAfterCreateEventHandler.createImplementation({\n implementation: ExtractMetadataHandlerImpl,\n dependencies: [TaskService]\n});\n"],"names":["ExtractMetadataHandlerImpl","taskService","event","file","ExtractMetadataHandler","FileAfterCreateEventHandler","TaskService"],"mappings":";;AAIA,MAAMA;IACF,YAAoBC,WAAkC,CAAE;aAApCA,WAAW,GAAXA;IAAqC;IAEzD,MAAM,OAAOC,KAAwC,EAAiB;QAClE,MAAM,EAAEC,IAAI,EAAE,GAAGD,MAAM,OAAO;QAG9B,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAuB;YACjD,YAAY;YACZ,OAAO;gBACH,QAAQC,KAAK,EAAE;YACnB;QACJ;IACJ;AACJ;AAEO,MAAMC,yBAAyBC,4BAA4B,oBAAoB,CAAC;IACnF,gBAAgBL;IAChB,cAAc;QAACM;KAAY;AAC/B"}
@@ -0,0 +1,24 @@
1
+ import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
2
+ import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
3
+ import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
4
+ export interface ExtractMetadataInput {
5
+ fileId: string;
6
+ }
7
+ declare class ExtractMetadataTask implements TaskDefinition.Interface<ExtractMetadataInput> {
8
+ private keyValueStore;
9
+ private updateFileUseCase;
10
+ id: string;
11
+ title: string;
12
+ description: string;
13
+ maxIterations: number;
14
+ isPrivate: boolean;
15
+ databaseLogs: boolean;
16
+ selfCleanup: ("onSuccess" | "onAbort")[];
17
+ constructor(keyValueStore: GlobalKeyValueStore.Interface, updateFileUseCase: UpdateFileUseCase.Interface);
18
+ run({ input, controller }: TaskDefinition.RunParams<ExtractMetadataInput>): Promise<TaskDefinition.Result<ExtractMetadataInput>>;
19
+ private cleanValues;
20
+ }
21
+ export declare const ExtractMetadataTaskDefinition: typeof ExtractMetadataTask & {
22
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskDefinition<import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskInput, import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskOutput>>;
23
+ };
24
+ export {};
@@ -0,0 +1,90 @@
1
+ import { S3 } from "@webiny/aws-sdk/client-s3/index.js";
2
+ import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
3
+ import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
4
+ import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
5
+ import { MetadataReader } from "../WriteFileMetadata/MetadataReader.js";
6
+ class ExtractMetadataTask {
7
+ constructor(keyValueStore, updateFileUseCase){
8
+ this.keyValueStore = keyValueStore;
9
+ this.updateFileUseCase = updateFileUseCase;
10
+ this.id = "fileManagerExtractMetadata";
11
+ this.title = "Extract image metadata (dimensions, EXIF, IPTC)";
12
+ this.description = "A task to extract metadata from uploaded image files";
13
+ this.maxIterations = 1;
14
+ this.isPrivate = true;
15
+ this.databaseLogs = false;
16
+ this.selfCleanup = [
17
+ "onSuccess",
18
+ "onAbort"
19
+ ];
20
+ }
21
+ async run({ input, controller }) {
22
+ if (controller.runtime.isAborted()) return controller.response.aborted();
23
+ const metadataReader = new MetadataReader(this.keyValueStore);
24
+ const fileMetadata = await metadataReader.read(input.fileId);
25
+ if (!fileMetadata) return controller.response.error({
26
+ message: `File metadata not found for file ID: ${input.fileId}`
27
+ });
28
+ if (!fileMetadata.contentType.startsWith("image/")) return controller.response.done();
29
+ const s3 = new S3();
30
+ const bucket = String(process.env.S3_BUCKET);
31
+ try {
32
+ const s3Object = await s3.getObject({
33
+ Bucket: bucket,
34
+ Key: fileMetadata.bucketKey
35
+ });
36
+ if (!s3Object.Body) return controller.response.error({
37
+ message: `S3 object body is empty for file: ${input.fileId}`
38
+ });
39
+ const sharp = await import("sharp").then((m)=>m.default);
40
+ const ExifReader = await import("exifreader").then((m)=>m.default);
41
+ const buffer = Buffer.from(await s3Object.Body.transformToByteArray());
42
+ const sharpInstance = sharp(buffer);
43
+ const sharpMetadata = await sharpInstance.metadata();
44
+ const tags = ExifReader.load(buffer, {
45
+ expanded: true
46
+ });
47
+ const metadata = {
48
+ image: {
49
+ width: sharpMetadata.width,
50
+ height: sharpMetadata.height,
51
+ format: sharpMetadata.format,
52
+ orientation: sharpMetadata.orientation ?? 1
53
+ }
54
+ };
55
+ if (tags.exif) metadata.exif = this.cleanValues(tags.exif);
56
+ if (tags.iptc) metadata.iptc = this.cleanValues(tags.iptc);
57
+ const updateResult = await this.updateFileUseCase.execute({
58
+ id: input.fileId,
59
+ metadata
60
+ });
61
+ if (updateResult.isFail()) return controller.response.error({
62
+ message: `Failed to update file with metadata: ${updateResult.error.message}`
63
+ });
64
+ return controller.response.done();
65
+ } catch (error) {
66
+ return controller.response.error({
67
+ message: `Failed to extract metadata: ${error instanceof Error ? error.message : String(error)}`
68
+ });
69
+ }
70
+ }
71
+ cleanValues(tags) {
72
+ const cleaned = {};
73
+ for (const [key, tag] of Object.entries(tags))if (tag && "object" == typeof tag) {
74
+ if (void 0 !== tag.description && null !== tag.description) cleaned[key] = tag.description;
75
+ else if (Array.isArray(tag.value) && tag.value.length > 20) ;
76
+ else if (void 0 !== tag.value) cleaned[key] = tag.value;
77
+ }
78
+ return cleaned;
79
+ }
80
+ }
81
+ const ExtractMetadataTaskDefinition = TaskDefinition.createImplementation({
82
+ implementation: ExtractMetadataTask,
83
+ dependencies: [
84
+ GlobalKeyValueStore,
85
+ UpdateFileUseCase
86
+ ]
87
+ });
88
+ export { ExtractMetadataTaskDefinition };
89
+
90
+ //# sourceMappingURL=ExtractMetadataTask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/ExtractMetadata/ExtractMetadataTask.js","sources":["../../../src/features/ExtractMetadata/ExtractMetadataTask.ts"],"sourcesContent":["import type { ExifTags } from \"exifreader\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { MetadataReader } from \"../WriteFileMetadata/MetadataReader.js\";\n\nexport interface ExtractMetadataInput {\n fileId: string;\n}\n\nclass ExtractMetadataTask implements TaskDefinition.Interface<ExtractMetadataInput> {\n id = \"fileManagerExtractMetadata\";\n title = \"Extract image metadata (dimensions, EXIF, IPTC)\";\n description = \"A task to extract metadata from uploaded image files\";\n maxIterations = 1;\n isPrivate = true;\n databaseLogs = false;\n\n selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n constructor(\n private keyValueStore: GlobalKeyValueStore.Interface,\n private updateFileUseCase: UpdateFileUseCase.Interface\n ) {}\n\n public async run({\n input,\n controller\n }: TaskDefinition.RunParams<ExtractMetadataInput>): Promise<\n TaskDefinition.Result<ExtractMetadataInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n // Load file metadata\n const metadataReader = new MetadataReader(this.keyValueStore);\n const fileMetadata = await metadataReader.read(input.fileId);\n\n if (!fileMetadata) {\n return controller.response.error({\n message: `File metadata not found for file ID: ${input.fileId}`\n });\n }\n\n // Check if it's an image file\n if (!fileMetadata.contentType.startsWith(\"image/\")) {\n return controller.response.done();\n }\n\n // Fetch the image from S3\n const s3 = new S3();\n const bucket = String(process.env.S3_BUCKET);\n\n try {\n const s3Object = await s3.getObject({\n Bucket: bucket,\n Key: fileMetadata.bucketKey\n });\n\n if (!s3Object.Body) {\n return controller.response.error({\n message: `S3 object body is empty for file: ${input.fileId}`\n });\n }\n\n const sharp = await import(/* webpackChunkName: \"sharp\" */ \"sharp\").then(\n m => m.default\n );\n\n const ExifReader = await import(/* webpackChunkName: \"exifreader\" */ \"exifreader\").then(\n m => m.default\n );\n\n // Convert S3 body to buffer\n const buffer = Buffer.from(await s3Object.Body.transformToByteArray());\n\n // Extract metadata using Sharp for image dimensions\n const sharpInstance = sharp(buffer);\n const sharpMetadata = await sharpInstance.metadata();\n\n // Use ExifReader to extract EXIF and IPTC data\n const tags = ExifReader.load(buffer, { expanded: true });\n\n // Build metadata object\n const metadata: Record<string, any> = {\n image: {\n width: sharpMetadata.width,\n height: sharpMetadata.height,\n format: sharpMetadata.format,\n orientation: sharpMetadata.orientation ?? 1\n }\n };\n\n // Extract EXIF data if available\n if (tags.exif) {\n metadata.exif = this.cleanValues(tags.exif);\n }\n\n // Extract IPTC data if available\n if (tags.iptc) {\n metadata.iptc = this.cleanValues(tags.iptc);\n }\n\n // Update the file with extracted metadata\n const updateResult = await this.updateFileUseCase.execute({\n id: input.fileId,\n metadata\n });\n\n if (updateResult.isFail()) {\n return controller.response.error({\n message: `Failed to update file with metadata: ${updateResult.error.message}`\n });\n }\n\n return controller.response.done();\n } catch (error) {\n return controller.response.error({\n message: `Failed to extract metadata: ${\n error instanceof Error ? error.message : String(error)\n }`\n });\n }\n }\n\n private cleanValues(tags: ExifTags) {\n const cleaned: Record<string, any> = {};\n\n for (const [key, tag] of Object.entries(tags)) {\n if (!tag || typeof tag !== \"object\") {\n continue;\n }\n\n // Use description if available, otherwise value\n if (tag.description !== undefined && tag.description !== null) {\n cleaned[key] = tag.description;\n } else if (Array.isArray(tag.value) && tag.value.length > 20) {\n // Skip large byte arrays\n } else if (tag.value !== undefined) {\n cleaned[key] = tag.value;\n }\n }\n\n return cleaned;\n }\n}\n\nexport const ExtractMetadataTaskDefinition = TaskDefinition.createImplementation({\n implementation: ExtractMetadataTask,\n dependencies: [GlobalKeyValueStore, UpdateFileUseCase]\n});\n"],"names":["ExtractMetadataTask","keyValueStore","updateFileUseCase","input","controller","metadataReader","MetadataReader","fileMetadata","s3","S3","bucket","String","process","s3Object","sharp","m","ExifReader","buffer","Buffer","sharpInstance","sharpMetadata","tags","metadata","updateResult","error","Error","cleaned","key","tag","Object","undefined","Array","ExtractMetadataTaskDefinition","TaskDefinition","GlobalKeyValueStore","UpdateFileUseCase"],"mappings":";;;;;AAWA,MAAMA;IAUF,YACYC,aAA4C,EAC5CC,iBAA8C,CACxD;aAFUD,aAAa,GAAbA;aACAC,iBAAiB,GAAjBA;aAXZ,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aAEf,WAAW,GAAG;YAAC;YAAsB;SAAmB;IAKrD;IAEH,MAAa,IAAI,EACbC,KAAK,EACLC,UAAU,EACmC,EAE/C;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAItC,MAAMC,iBAAiB,IAAIC,eAAe,IAAI,CAAC,aAAa;QAC5D,MAAMC,eAAe,MAAMF,eAAe,IAAI,CAACF,MAAM,MAAM;QAE3D,IAAI,CAACI,cACD,OAAOH,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS,CAAC,qCAAqC,EAAED,MAAM,MAAM,EAAE;QACnE;QAIJ,IAAI,CAACI,aAAa,WAAW,CAAC,UAAU,CAAC,WACrC,OAAOH,WAAW,QAAQ,CAAC,IAAI;QAInC,MAAMI,KAAK,IAAIC;QACf,MAAMC,SAASC,OAAOC,QAAQ,GAAG,CAAC,SAAS;QAE3C,IAAI;YACA,MAAMC,WAAW,MAAML,GAAG,SAAS,CAAC;gBAChC,QAAQE;gBACR,KAAKH,aAAa,SAAS;YAC/B;YAEA,IAAI,CAACM,SAAS,IAAI,EACd,OAAOT,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,kCAAkC,EAAED,MAAM,MAAM,EAAE;YAChE;YAGJ,MAAMW,QAAQ,MAAM,MAAM,CAAiC,SAAS,IAAI,CACpEC,CAAAA,IAAKA,EAAE,OAAO;YAGlB,MAAMC,aAAa,MAAM,MAAM,CAAsC,cAAc,IAAI,CACnFD,CAAAA,IAAKA,EAAE,OAAO;YAIlB,MAAME,SAASC,OAAO,IAAI,CAAC,MAAML,SAAS,IAAI,CAAC,oBAAoB;YAGnE,MAAMM,gBAAgBL,MAAMG;YAC5B,MAAMG,gBAAgB,MAAMD,cAAc,QAAQ;YAGlD,MAAME,OAAOL,WAAW,IAAI,CAACC,QAAQ;gBAAE,UAAU;YAAK;YAGtD,MAAMK,WAAgC;gBAClC,OAAO;oBACH,OAAOF,cAAc,KAAK;oBAC1B,QAAQA,cAAc,MAAM;oBAC5B,QAAQA,cAAc,MAAM;oBAC5B,aAAaA,cAAc,WAAW,IAAI;gBAC9C;YACJ;YAGA,IAAIC,KAAK,IAAI,EACTC,SAAS,IAAI,GAAG,IAAI,CAAC,WAAW,CAACD,KAAK,IAAI;YAI9C,IAAIA,KAAK,IAAI,EACTC,SAAS,IAAI,GAAG,IAAI,CAAC,WAAW,CAACD,KAAK,IAAI;YAI9C,MAAME,eAAe,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;gBACtD,IAAIpB,MAAM,MAAM;gBAChBmB;YACJ;YAEA,IAAIC,aAAa,MAAM,IACnB,OAAOnB,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,qCAAqC,EAAEmB,aAAa,KAAK,CAAC,OAAO,EAAE;YACjF;YAGJ,OAAOnB,WAAW,QAAQ,CAAC,IAAI;QACnC,EAAE,OAAOoB,OAAO;YACZ,OAAOpB,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,4BAA4B,EAClCoB,iBAAiBC,QAAQD,MAAM,OAAO,GAAGb,OAAOa,QAClD;YACN;QACJ;IACJ;IAEQ,YAAYH,IAAc,EAAE;QAChC,MAAMK,UAA+B,CAAC;QAEtC,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIC,OAAO,OAAO,CAACR,MACpC,IAAI,AAACO,OAAO,AAAe,YAAf,OAAOA,KAKnB;YAAA,IAAIA,AAAoBE,WAApBF,IAAI,WAAW,IAAkBA,AAAoB,SAApBA,IAAI,WAAW,EAChDF,OAAO,CAACC,IAAI,GAAGC,IAAI,WAAW;iBAC3B,IAAIG,MAAM,OAAO,CAACH,IAAI,KAAK,KAAKA,IAAI,KAAK,CAAC,MAAM,GAAG;iBAEnD,IAAIA,AAAcE,WAAdF,IAAI,KAAK,EAChBF,OAAO,CAACC,IAAI,GAAGC,IAAI,KAAK;QAC5B;QAGJ,OAAOF;IACX;AACJ;AAEO,MAAMM,gCAAgCC,eAAe,oBAAoB,CAAC;IAC7E,gBAAgBjC;IAChB,cAAc;QAACkC;QAAqBC;KAAkB;AAC1D"}
@@ -0,0 +1,4 @@
1
+ export declare const ExtractMetadataFeature: {
2
+ name: string;
3
+ register(container: import("@webiny/di").Container): void;
4
+ };
@@ -0,0 +1,13 @@
1
+ import { createFeature } from "@webiny/feature/api";
2
+ import { ExtractMetadataHandler } from "./ExtractMetadataHandler.js";
3
+ import { ExtractMetadataTaskDefinition } from "./ExtractMetadataTask.js";
4
+ const ExtractMetadataFeature = createFeature({
5
+ name: "FileManagerS3/ExtractMetadata",
6
+ register (container) {
7
+ container.register(ExtractMetadataHandler);
8
+ container.register(ExtractMetadataTaskDefinition);
9
+ }
10
+ });
11
+ export { ExtractMetadataFeature };
12
+
13
+ //# sourceMappingURL=feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/ExtractMetadata/feature.js","sources":["../../../src/features/ExtractMetadata/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { ExtractMetadataHandler } from \"./ExtractMetadataHandler.js\";\nimport { ExtractMetadataTaskDefinition } from \"./ExtractMetadataTask.js\";\n\nexport const ExtractMetadataFeature = createFeature({\n name: \"FileManagerS3/ExtractMetadata\",\n register(container) {\n container.register(ExtractMetadataHandler);\n container.register(ExtractMetadataTaskDefinition);\n }\n});\n"],"names":["ExtractMetadataFeature","createFeature","container","ExtractMetadataHandler","ExtractMetadataTaskDefinition"],"mappings":";;;AAIO,MAAMA,yBAAyBC,cAAc;IAChD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;IACvB;AACJ"}
@@ -0,0 +1,12 @@
1
+ import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ declare class FlushCacheOnFileDeleteHandlerImpl implements FileAfterDeleteEventHandler.Interface {
4
+ private taskService;
5
+ private readonly pathsGenerator;
6
+ constructor(taskService: TaskService.Interface);
7
+ handle(event: FileAfterDeleteEventHandler.Event): Promise<void>;
8
+ }
9
+ export declare const FlushCacheOnFileDeleteHandler: typeof FlushCacheOnFileDeleteHandlerImpl & {
10
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher").IEventHandler<import("@webiny/api-file-manager/features/file/DeleteFile/events.js").FileAfterDeleteEvent>>;
11
+ };
12
+ export {};
@@ -0,0 +1,28 @@
1
+ import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ import { CdnPathsGenerator } from "../../utils/CdnPathsGenerator.js";
4
+ class FlushCacheOnFileDeleteHandlerImpl {
5
+ constructor(taskService){
6
+ this.taskService = taskService;
7
+ this.pathsGenerator = new CdnPathsGenerator();
8
+ }
9
+ async handle(event) {
10
+ const { file } = event.payload;
11
+ await this.taskService.trigger({
12
+ definition: "cloudfrontInvalidateCache",
13
+ input: {
14
+ caller: "fm-before-delete",
15
+ paths: this.pathsGenerator.generate(file.id)
16
+ }
17
+ });
18
+ }
19
+ }
20
+ const FlushCacheOnFileDeleteHandler = FileAfterDeleteEventHandler.createImplementation({
21
+ implementation: FlushCacheOnFileDeleteHandlerImpl,
22
+ dependencies: [
23
+ TaskService
24
+ ]
25
+ });
26
+ export { FlushCacheOnFileDeleteHandler };
27
+
28
+ //# sourceMappingURL=FlushCacheOnFileDeleteHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/FlushCache/FlushCacheOnFileDeleteHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileDeleteHandler.ts"],"sourcesContent":["import { FileAfterDeleteEventHandler } from \"@webiny/api-file-manager/features/file/DeleteFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileDeleteHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileAfterDeleteEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n\n await this.taskService.trigger({\n definition: \"cloudfrontInvalidateCache\",\n input: {\n caller: \"fm-before-delete\",\n paths: this.pathsGenerator.generate(file.id)\n }\n });\n }\n}\n\nexport const FlushCacheOnFileDeleteHandler = FileAfterDeleteEventHandler.createImplementation({\n implementation: FlushCacheOnFileDeleteHandlerImpl,\n dependencies: [TaskService]\n});\n"],"names":["FlushCacheOnFileDeleteHandlerImpl","taskService","CdnPathsGenerator","event","file","FlushCacheOnFileDeleteHandler","FileAfterDeleteEventHandler","TaskService"],"mappings":";;;AAIA,MAAMA;IAGF,YAAoBC,WAAkC,CAAE;aAApCA,WAAW,GAAXA;QAChB,IAAI,CAAC,cAAc,GAAG,IAAIC;IAC9B;IAEA,MAAM,OAAOC,KAAwC,EAAiB;QAClE,MAAM,EAAEC,IAAI,EAAE,GAAGD,MAAM,OAAO;QAE9B,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAC3B,YAAY;YACZ,OAAO;gBACH,QAAQ;gBACR,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACC,KAAK,EAAE;YAC/C;QACJ;IACJ;AACJ;AAEO,MAAMC,gCAAgCC,4BAA4B,oBAAoB,CAAC;IAC1F,gBAAgBN;IAChB,cAAc;QAACO;KAAY;AAC/B"}
@@ -0,0 +1,12 @@
1
+ import { FileBeforeUpdateEventHandler } from "@webiny/api-file-manager/features/file/UpdateFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ declare class FlushCacheOnFileUpdateHandlerImpl implements FileBeforeUpdateEventHandler.Interface {
4
+ private taskService;
5
+ private readonly pathsGenerator;
6
+ constructor(taskService: TaskService.Interface);
7
+ handle(event: FileBeforeUpdateEventHandler.Event): Promise<void>;
8
+ }
9
+ export declare const FlushCacheOnFileUpdateHandler: typeof FlushCacheOnFileUpdateHandlerImpl & {
10
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher").IEventHandler<import("@webiny/api-file-manager/features/file/UpdateFile/events.js").FileBeforeUpdateEvent>>;
11
+ };
12
+ export {};
@@ -0,0 +1,31 @@
1
+ import { FileBeforeUpdateEventHandler } from "@webiny/api-file-manager/features/file/UpdateFile/events.js";
2
+ import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
3
+ import { CdnPathsGenerator } from "../../utils/CdnPathsGenerator.js";
4
+ class FlushCacheOnFileUpdateHandlerImpl {
5
+ constructor(taskService){
6
+ this.taskService = taskService;
7
+ this.pathsGenerator = new CdnPathsGenerator();
8
+ }
9
+ async handle(event) {
10
+ const { file, original } = event.payload;
11
+ const prevAccessControl = original.accessControl;
12
+ const newAccessControl = file.accessControl;
13
+ if (prevAccessControl?.type === newAccessControl?.type) return;
14
+ await this.taskService.trigger({
15
+ definition: "cloudfrontInvalidateCache",
16
+ input: {
17
+ caller: "fm-before-update",
18
+ paths: this.pathsGenerator.generate(file.id)
19
+ }
20
+ });
21
+ }
22
+ }
23
+ const FlushCacheOnFileUpdateHandler = FileBeforeUpdateEventHandler.createImplementation({
24
+ implementation: FlushCacheOnFileUpdateHandlerImpl,
25
+ dependencies: [
26
+ TaskService
27
+ ]
28
+ });
29
+ export { FlushCacheOnFileUpdateHandler };
30
+
31
+ //# sourceMappingURL=FlushCacheOnFileUpdateHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/FlushCache/FlushCacheOnFileUpdateHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileUpdateHandler.ts"],"sourcesContent":["import { FileBeforeUpdateEventHandler } from \"@webiny/api-file-manager/features/file/UpdateFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileUpdateHandlerImpl implements FileBeforeUpdateEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileBeforeUpdateEventHandler.Event): Promise<void> {\n const { file, original } = event.payload;\n\n const prevAccessControl = original.accessControl;\n const newAccessControl = file.accessControl;\n\n // Only trigger cache flush if access control type has changed\n if (prevAccessControl?.type === newAccessControl?.type) {\n return;\n }\n\n await this.taskService.trigger({\n definition: \"cloudfrontInvalidateCache\",\n input: {\n caller: \"fm-before-update\",\n paths: this.pathsGenerator.generate(file.id)\n }\n });\n }\n}\n\nexport const FlushCacheOnFileUpdateHandler = FileBeforeUpdateEventHandler.createImplementation({\n implementation: FlushCacheOnFileUpdateHandlerImpl,\n dependencies: [TaskService]\n});\n"],"names":["FlushCacheOnFileUpdateHandlerImpl","taskService","CdnPathsGenerator","event","file","original","prevAccessControl","newAccessControl","FlushCacheOnFileUpdateHandler","FileBeforeUpdateEventHandler","TaskService"],"mappings":";;;AAIA,MAAMA;IAGF,YAAoBC,WAAkC,CAAE;aAApCA,WAAW,GAAXA;QAChB,IAAI,CAAC,cAAc,GAAG,IAAIC;IAC9B;IAEA,MAAM,OAAOC,KAAyC,EAAiB;QACnE,MAAM,EAAEC,IAAI,EAAEC,QAAQ,EAAE,GAAGF,MAAM,OAAO;QAExC,MAAMG,oBAAoBD,SAAS,aAAa;QAChD,MAAME,mBAAmBH,KAAK,aAAa;QAG3C,IAAIE,mBAAmB,SAASC,kBAAkB,MAC9C;QAGJ,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAC3B,YAAY;YACZ,OAAO;gBACH,QAAQ;gBACR,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACH,KAAK,EAAE;YAC/C;QACJ;IACJ;AACJ;AAEO,MAAMI,gCAAgCC,6BAA6B,oBAAoB,CAAC;IAC3F,gBAAgBT;IAChB,cAAc;QAACU;KAAY;AAC/B"}
@@ -0,0 +1,26 @@
1
+ import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
2
+ export interface InvalidateCacheInput {
3
+ /**
4
+ * Caller of the task (e.g., `fm-before-update`, `fm-after-delete`).
5
+ */
6
+ caller: string;
7
+ /**
8
+ * Cache paths to invalidate.
9
+ */
10
+ paths: string[];
11
+ }
12
+ declare class InvalidateCloudfrontCacheTask implements TaskDefinition.Interface<InvalidateCacheInput> {
13
+ id: string;
14
+ title: string;
15
+ description: string;
16
+ maxIterations: number;
17
+ isPrivate: boolean;
18
+ selfCleanup: ("onSuccess" | "onAbort")[];
19
+ private continueIfCode;
20
+ run({ input, controller }: TaskDefinition.RunParams<InvalidateCacheInput>): Promise<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskResultError | import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskResultAborted | TaskDefinition.ResultDone<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskOutput> | TaskDefinition.ResultContinue<InvalidateCacheInput>>;
21
+ private invalidateCache;
22
+ }
23
+ export declare const InvalidateCloudfrontCacheTaskDefinition: typeof InvalidateCloudfrontCacheTask & {
24
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskDefinition<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskInput, import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskOutput>>;
25
+ };
26
+ export {};
@@ -0,0 +1,75 @@
1
+ import { ServiceDiscovery } from "@webiny/api";
2
+ import { CloudFront } from "@webiny/aws-sdk/client-cloudfront/index.js";
3
+ import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
4
+ import { executeWithRetry } from "@webiny/utils";
5
+ class ReturnContinue extends Error {
6
+ }
7
+ class InvalidateCloudfrontCacheTask {
8
+ async run({ input, controller }) {
9
+ if (controller.runtime.isAborted()) return controller.response.aborted();
10
+ const manifest = await ServiceDiscovery.load();
11
+ if (!manifest) return controller.response.error({
12
+ message: "Unable to invalidate cache due to a missing service manifest.",
13
+ code: "MISSING_SERVICE_MANIFEST",
14
+ data: {
15
+ manifest: "api"
16
+ }
17
+ });
18
+ const { distributionId } = manifest.api.cloudfront;
19
+ const invalidateCache = ()=>this.invalidateCache(input.caller, distributionId, input.paths);
20
+ try {
21
+ await executeWithRetry(invalidateCache, {
22
+ minTimeout: 2000,
23
+ retries: 10000,
24
+ onFailedAttempt: ({ error })=>{
25
+ if (this.continueIfCode.includes(error.name)) throw new ReturnContinue();
26
+ if (error.message.includes("not authorized to perform")) throw error;
27
+ if (controller.runtime.isCloseToTimeout()) throw new ReturnContinue();
28
+ }
29
+ });
30
+ } catch (error) {
31
+ if (error instanceof ReturnContinue) return controller.response.continue(input);
32
+ return controller.response.error({
33
+ message: error.message,
34
+ code: "EXECUTE_WITH_RETRY_FAILED",
35
+ data: input.paths
36
+ });
37
+ }
38
+ return controller.response.done();
39
+ }
40
+ async invalidateCache(caller, distributionId, paths) {
41
+ const cloudfront = new CloudFront();
42
+ await cloudfront.createInvalidation({
43
+ DistributionId: distributionId,
44
+ InvalidationBatch: {
45
+ CallerReference: `${new Date().getTime()}-${caller}`,
46
+ Paths: {
47
+ Quantity: paths.length,
48
+ Items: paths
49
+ }
50
+ }
51
+ });
52
+ }
53
+ constructor(){
54
+ this.id = "cloudfrontInvalidateCache";
55
+ this.title = "Invalidate CloudFront Cache";
56
+ this.description = "A task to invalidate Cloudfront cache by given paths.";
57
+ this.maxIterations = 100;
58
+ this.isPrivate = true;
59
+ this.selfCleanup = [
60
+ "onSuccess",
61
+ "onAbort"
62
+ ];
63
+ this.continueIfCode = [
64
+ "TooManyInvalidationsInProgress",
65
+ "Throttling"
66
+ ];
67
+ }
68
+ }
69
+ const InvalidateCloudfrontCacheTaskDefinition = TaskDefinition.createImplementation({
70
+ implementation: InvalidateCloudfrontCacheTask,
71
+ dependencies: []
72
+ });
73
+ export { InvalidateCloudfrontCacheTaskDefinition };
74
+
75
+ //# sourceMappingURL=InvalidateCacheTask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/FlushCache/InvalidateCacheTask.js","sources":["../../../src/features/FlushCache/InvalidateCacheTask.ts"],"sourcesContent":["import { ServiceDiscovery } from \"@webiny/api\";\nimport { CloudFront } from \"@webiny/aws-sdk/client-cloudfront/index.js\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { executeWithRetry } from \"@webiny/utils\";\n\nclass ReturnContinue extends Error {}\n\nexport interface InvalidateCacheInput {\n /**\n * Caller of the task (e.g., `fm-before-update`, `fm-after-delete`).\n */\n caller: string;\n /**\n * Cache paths to invalidate.\n */\n paths: string[];\n}\n\nclass InvalidateCloudfrontCacheTask implements TaskDefinition.Interface<InvalidateCacheInput> {\n id = \"cloudfrontInvalidateCache\";\n title = \"Invalidate CloudFront Cache\";\n description = \"A task to invalidate Cloudfront cache by given paths.\";\n maxIterations = 100;\n isPrivate = true;\n\n selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n private continueIfCode = [\"TooManyInvalidationsInProgress\", \"Throttling\"];\n\n public async run({ input, controller }: TaskDefinition.RunParams<InvalidateCacheInput>) {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const manifest = await ServiceDiscovery.load();\n\n if (!manifest) {\n return controller.response.error({\n message: `Unable to invalidate cache due to a missing service manifest.`,\n code: \"MISSING_SERVICE_MANIFEST\",\n data: {\n manifest: \"api\"\n }\n });\n }\n\n const { distributionId } = manifest.api.cloudfront;\n\n const invalidateCache = () => {\n return this.invalidateCache(input.caller, distributionId as string, input.paths);\n };\n\n try {\n await executeWithRetry(invalidateCache, {\n minTimeout: 2000,\n // instead of forever: true\n retries: 10000,\n onFailedAttempt: ({ error }) => {\n if (this.continueIfCode.includes(error.name)) {\n throw new ReturnContinue();\n }\n\n if (error.message.includes(\"not authorized to perform\")) {\n throw error;\n }\n\n if (controller.runtime.isCloseToTimeout()) {\n throw new ReturnContinue();\n }\n }\n });\n } catch (error) {\n if (error instanceof ReturnContinue) {\n return controller.response.continue(input);\n }\n\n return controller.response.error({\n message: error.message,\n code: \"EXECUTE_WITH_RETRY_FAILED\",\n data: input.paths\n });\n }\n\n return controller.response.done();\n }\n\n private async invalidateCache(\n caller: string,\n distributionId: string,\n paths: string[]\n ): Promise<void> {\n const cloudfront = new CloudFront();\n await cloudfront.createInvalidation({\n DistributionId: distributionId,\n InvalidationBatch: {\n CallerReference: `${new Date().getTime()}-${caller}`,\n Paths: {\n Quantity: paths.length,\n Items: paths\n }\n }\n });\n }\n}\n\nexport const InvalidateCloudfrontCacheTaskDefinition = TaskDefinition.createImplementation({\n implementation: InvalidateCloudfrontCacheTask,\n dependencies: []\n});\n"],"names":["ReturnContinue","Error","InvalidateCloudfrontCacheTask","input","controller","manifest","ServiceDiscovery","distributionId","invalidateCache","executeWithRetry","error","caller","paths","cloudfront","CloudFront","Date","InvalidateCloudfrontCacheTaskDefinition","TaskDefinition"],"mappings":";;;;AAKA,MAAMA,uBAAuBC;AAAO;AAapC,MAAMC;IAWF,MAAa,IAAI,EAAEC,KAAK,EAAEC,UAAU,EAAkD,EAAE;QACpF,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,WAAW,MAAMC,iBAAiB,IAAI;QAE5C,IAAI,CAACD,UACD,OAAOD,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS;YACT,MAAM;YACN,MAAM;gBACF,UAAU;YACd;QACJ;QAGJ,MAAM,EAAEG,cAAc,EAAE,GAAGF,SAAS,GAAG,CAAC,UAAU;QAElD,MAAMG,kBAAkB,IACb,IAAI,CAAC,eAAe,CAACL,MAAM,MAAM,EAAEI,gBAA0BJ,MAAM,KAAK;QAGnF,IAAI;YACA,MAAMM,iBAAiBD,iBAAiB;gBACpC,YAAY;gBAEZ,SAAS;gBACT,iBAAiB,CAAC,EAAEE,KAAK,EAAE;oBACvB,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACA,MAAM,IAAI,GACvC,MAAM,IAAIV;oBAGd,IAAIU,MAAM,OAAO,CAAC,QAAQ,CAAC,8BACvB,MAAMA;oBAGV,IAAIN,WAAW,OAAO,CAAC,gBAAgB,IACnC,MAAM,IAAIJ;gBAElB;YACJ;QACJ,EAAE,OAAOU,OAAO;YACZ,IAAIA,iBAAiBV,gBACjB,OAAOI,WAAW,QAAQ,CAAC,QAAQ,CAACD;YAGxC,OAAOC,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAASM,MAAM,OAAO;gBACtB,MAAM;gBACN,MAAMP,MAAM,KAAK;YACrB;QACJ;QAEA,OAAOC,WAAW,QAAQ,CAAC,IAAI;IACnC;IAEA,MAAc,gBACVO,MAAc,EACdJ,cAAsB,EACtBK,KAAe,EACF;QACb,MAAMC,aAAa,IAAIC;QACvB,MAAMD,WAAW,kBAAkB,CAAC;YAChC,gBAAgBN;YAChB,mBAAmB;gBACf,iBAAiB,GAAG,IAAIQ,OAAO,OAAO,GAAG,CAAC,EAAEJ,QAAQ;gBACpD,OAAO;oBACH,UAAUC,MAAM,MAAM;oBACtB,OAAOA;gBACX;YACJ;QACJ;IACJ;;aAnFA,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aAEZ,WAAW,GAAG;YAAC;YAAsB;SAAmB;aAEhD,cAAc,GAAG;YAAC;YAAkC;SAAa;;AA4E7E;AAEO,MAAMI,0CAA0CC,eAAe,oBAAoB,CAAC;IACvF,gBAAgBf;IAChB,cAAc,EAAE;AACpB"}
@@ -0,0 +1,4 @@
1
+ export declare const FlushCacheFeature: {
2
+ name: string;
3
+ register(container: import("@webiny/di").Container): void;
4
+ };
@@ -0,0 +1,15 @@
1
+ import { createFeature } from "@webiny/feature/api";
2
+ import { FlushCacheOnFileDeleteHandler } from "./FlushCacheOnFileDeleteHandler.js";
3
+ import { FlushCacheOnFileUpdateHandler } from "./FlushCacheOnFileUpdateHandler.js";
4
+ import { InvalidateCloudfrontCacheTaskDefinition } from "./InvalidateCacheTask.js";
5
+ const FlushCacheFeature = createFeature({
6
+ name: "FileManagerS3/FlushCache",
7
+ register (container) {
8
+ container.register(FlushCacheOnFileDeleteHandler);
9
+ container.register(FlushCacheOnFileUpdateHandler);
10
+ container.register(InvalidateCloudfrontCacheTaskDefinition);
11
+ }
12
+ });
13
+ export { FlushCacheFeature };
14
+
15
+ //# sourceMappingURL=feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/FlushCache/feature.js","sources":["../../../src/features/FlushCache/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { FlushCacheOnFileDeleteHandler } from \"./FlushCacheOnFileDeleteHandler.js\";\nimport { FlushCacheOnFileUpdateHandler } from \"./FlushCacheOnFileUpdateHandler.js\";\nimport { InvalidateCloudfrontCacheTaskDefinition } from \"./InvalidateCacheTask.js\";\n\nexport const FlushCacheFeature = createFeature({\n name: \"FileManagerS3/FlushCache\",\n register(container) {\n container.register(FlushCacheOnFileDeleteHandler);\n container.register(FlushCacheOnFileUpdateHandler);\n container.register(InvalidateCloudfrontCacheTaskDefinition);\n }\n});\n"],"names":["FlushCacheFeature","createFeature","container","FlushCacheOnFileDeleteHandler","FlushCacheOnFileUpdateHandler","InvalidateCloudfrontCacheTaskDefinition"],"mappings":";;;;AAKO,MAAMA,oBAAoBC,cAAc;IAC3C,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;QACnBF,UAAU,QAAQ,CAACG;IACvB;AACJ"}
@@ -0,0 +1,13 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
3
+ import { GetFileContentsByIdUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsById/index.js";
4
+ import type { FileContents } from "@webiny/api-file-manager/features/file/GetFileContentsById/index.js";
5
+ declare class GetFileContentsByIdUseCaseImpl implements GetFileContentsByIdUseCase.Interface {
6
+ private metadataReader;
7
+ constructor(keyValueStore: GlobalKeyValueStore.Interface);
8
+ execute(fileId: string): Promise<Result<FileContents, GetFileContentsByIdUseCase.Error>>;
9
+ }
10
+ export declare const GetFileContentsByIdUseCaseImplementation: typeof GetFileContentsByIdUseCaseImpl & {
11
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/file/GetFileContentsById/abstractions").IGetFileContentsByIdUseCase>;
12
+ };
13
+ export {};
@@ -0,0 +1,40 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { S3 } from "@webiny/aws-sdk/client-s3/index.js";
3
+ import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
4
+ import { GetFileContentsByIdUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsById/index.js";
5
+ import { FileNotFoundError, FilePersistenceError } from "@webiny/api-file-manager/domain/file/errors.js";
6
+ import { MetadataReader } from "../WriteFileMetadata/MetadataReader.js";
7
+ class GetFileContentsByIdUseCaseImpl {
8
+ constructor(keyValueStore){
9
+ this.metadataReader = new MetadataReader(keyValueStore);
10
+ }
11
+ async execute(fileId) {
12
+ const metadata = await this.metadataReader.read(fileId);
13
+ if (!metadata) return Result.fail(new FileNotFoundError(fileId));
14
+ try {
15
+ const s3 = new S3();
16
+ const bucket = String(process.env.S3_BUCKET);
17
+ const response = await s3.getObject({
18
+ Bucket: bucket,
19
+ Key: metadata.bucketKey
20
+ });
21
+ if (!response.Body) return Result.fail(new FileNotFoundError(fileId));
22
+ const buffer = Buffer.from(await response.Body.transformToByteArray());
23
+ return Result.ok({
24
+ buffer,
25
+ contentType: metadata.contentType
26
+ });
27
+ } catch (error) {
28
+ return Result.fail(new FilePersistenceError(error instanceof Error ? error : new Error(String(error))));
29
+ }
30
+ }
31
+ }
32
+ const GetFileContentsByIdUseCaseImplementation = GetFileContentsByIdUseCase.createImplementation({
33
+ implementation: GetFileContentsByIdUseCaseImpl,
34
+ dependencies: [
35
+ GlobalKeyValueStore
36
+ ]
37
+ });
38
+ export { GetFileContentsByIdUseCaseImplementation };
39
+
40
+ //# sourceMappingURL=GetFileContentsByIdUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/GetFileContentsById/GetFileContentsByIdUseCase.js","sources":["../../../src/features/GetFileContentsById/GetFileContentsByIdUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { GetFileContentsByIdUseCase } from \"@webiny/api-file-manager/features/file/GetFileContentsById/index.js\";\nimport type { FileContents } from \"@webiny/api-file-manager/features/file/GetFileContentsById/index.js\";\nimport {\n FileNotFoundError,\n FilePersistenceError\n} from \"@webiny/api-file-manager/domain/file/errors.js\";\nimport { MetadataReader } from \"~/features/WriteFileMetadata/MetadataReader.js\";\n\nclass GetFileContentsByIdUseCaseImpl implements GetFileContentsByIdUseCase.Interface {\n private metadataReader: MetadataReader;\n\n constructor(keyValueStore: GlobalKeyValueStore.Interface) {\n this.metadataReader = new MetadataReader(keyValueStore);\n }\n\n async execute(fileId: string): Promise<Result<FileContents, GetFileContentsByIdUseCase.Error>> {\n const metadata = await this.metadataReader.read(fileId);\n if (!metadata) {\n return Result.fail(new FileNotFoundError(fileId));\n }\n\n try {\n const s3 = new S3();\n const bucket = String(process.env.S3_BUCKET);\n const response = await s3.getObject({ Bucket: bucket, Key: metadata.bucketKey });\n\n if (!response.Body) {\n return Result.fail(new FileNotFoundError(fileId));\n }\n\n const buffer = Buffer.from(await response.Body.transformToByteArray());\n return Result.ok({ buffer, contentType: metadata.contentType });\n } catch (error) {\n return Result.fail(\n new FilePersistenceError(error instanceof Error ? error : new Error(String(error)))\n );\n }\n }\n}\n\nexport const GetFileContentsByIdUseCaseImplementation =\n GetFileContentsByIdUseCase.createImplementation({\n implementation: GetFileContentsByIdUseCaseImpl,\n dependencies: [GlobalKeyValueStore]\n });\n"],"names":["GetFileContentsByIdUseCaseImpl","keyValueStore","MetadataReader","fileId","metadata","Result","FileNotFoundError","s3","S3","bucket","String","process","response","buffer","Buffer","error","FilePersistenceError","Error","GetFileContentsByIdUseCaseImplementation","GetFileContentsByIdUseCase","GlobalKeyValueStore"],"mappings":";;;;;;AAWA,MAAMA;IAGF,YAAYC,aAA4C,CAAE;QACtD,IAAI,CAAC,cAAc,GAAG,IAAIC,eAAeD;IAC7C;IAEA,MAAM,QAAQE,MAAc,EAAmE;QAC3F,MAAMC,WAAW,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAACD;QAChD,IAAI,CAACC,UACD,OAAOC,OAAO,IAAI,CAAC,IAAIC,kBAAkBH;QAG7C,IAAI;YACA,MAAMI,KAAK,IAAIC;YACf,MAAMC,SAASC,OAAOC,QAAQ,GAAG,CAAC,SAAS;YAC3C,MAAMC,WAAW,MAAML,GAAG,SAAS,CAAC;gBAAE,QAAQE;gBAAQ,KAAKL,SAAS,SAAS;YAAC;YAE9E,IAAI,CAACQ,SAAS,IAAI,EACd,OAAOP,OAAO,IAAI,CAAC,IAAIC,kBAAkBH;YAG7C,MAAMU,SAASC,OAAO,IAAI,CAAC,MAAMF,SAAS,IAAI,CAAC,oBAAoB;YACnE,OAAOP,OAAO,EAAE,CAAC;gBAAEQ;gBAAQ,aAAaT,SAAS,WAAW;YAAC;QACjE,EAAE,OAAOW,OAAO;YACZ,OAAOV,OAAO,IAAI,CACd,IAAIW,qBAAqBD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMP,OAAOK;QAEnF;IACJ;AACJ;AAEO,MAAMG,2CACTC,2BAA2B,oBAAoB,CAAC;IAC5C,gBAAgBnB;IAChB,cAAc;QAACoB;KAAoB;AACvC"}
@@ -0,0 +1,4 @@
1
+ export declare const GetFileContentsByIdFeature: {
2
+ name: string;
3
+ register(container: import("@webiny/di").Container): void;
4
+ };
@@ -0,0 +1,11 @@
1
+ import { createFeature } from "@webiny/feature/api";
2
+ import { GetFileContentsByIdUseCaseImplementation } from "./GetFileContentsByIdUseCase.js";
3
+ const GetFileContentsByIdFeature = createFeature({
4
+ name: "FileManagerS3/GetFileContentsById",
5
+ register (container) {
6
+ container.register(GetFileContentsByIdUseCaseImplementation);
7
+ }
8
+ });
9
+ export { GetFileContentsByIdFeature };
10
+
11
+ //# sourceMappingURL=feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/GetFileContentsById/feature.js","sources":["../../../src/features/GetFileContentsById/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GetFileContentsByIdUseCaseImplementation } from \"./GetFileContentsByIdUseCase.js\";\n\nexport const GetFileContentsByIdFeature = createFeature({\n name: \"FileManagerS3/GetFileContentsById\",\n register(container) {\n container.register(GetFileContentsByIdUseCaseImplementation);\n }\n});\n"],"names":["GetFileContentsByIdFeature","createFeature","container","GetFileContentsByIdUseCaseImplementation"],"mappings":";;AAGO,MAAMA,6BAA6BC,cAAc;IACpD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
@@ -0,0 +1,13 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
3
+ import { GetFileContentsByKeyUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsByKey/index.js";
4
+ import type { FileContents } from "@webiny/api-file-manager/features/file/GetFileContentsById/index.js";
5
+ declare class GetFileContentsByKeyUseCaseImpl implements GetFileContentsByKeyUseCase.Interface {
6
+ private tenantContext;
7
+ constructor(tenantContext: TenantContext.Interface);
8
+ execute(key: string): Promise<Result<FileContents, GetFileContentsByKeyUseCase.Error>>;
9
+ }
10
+ export declare const GetFileContentsByKeyUseCaseImplementation: typeof GetFileContentsByKeyUseCaseImpl & {
11
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/file/GetFileContentsByKey/abstractions").IGetFileContentsByKeyUseCase>;
12
+ };
13
+ export {};
@@ -0,0 +1,40 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { S3 } from "@webiny/aws-sdk/client-s3/index.js";
3
+ import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
4
+ import { GetFileContentsByKeyUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsByKey/index.js";
5
+ import { FileNotFoundError, FilePersistenceError } from "@webiny/api-file-manager/domain/file/errors.js";
6
+ class GetFileContentsByKeyUseCaseImpl {
7
+ constructor(tenantContext){
8
+ this.tenantContext = tenantContext;
9
+ }
10
+ async execute(key) {
11
+ const tenant = this.tenantContext.getTenant();
12
+ const bucketKey = `tenants/${tenant.id}/files/${key}`;
13
+ try {
14
+ const s3 = new S3();
15
+ const bucket = String(process.env.S3_BUCKET);
16
+ const response = await s3.getObject({
17
+ Bucket: bucket,
18
+ Key: bucketKey
19
+ });
20
+ if (!response.Body) return Result.fail(new FileNotFoundError(key));
21
+ const buffer = Buffer.from(await response.Body.transformToByteArray());
22
+ const contentType = response.ContentType || "application/octet-stream";
23
+ return Result.ok({
24
+ buffer,
25
+ contentType
26
+ });
27
+ } catch (error) {
28
+ return Result.fail(new FilePersistenceError(error instanceof Error ? error : new Error(String(error))));
29
+ }
30
+ }
31
+ }
32
+ const GetFileContentsByKeyUseCaseImplementation = GetFileContentsByKeyUseCase.createImplementation({
33
+ implementation: GetFileContentsByKeyUseCaseImpl,
34
+ dependencies: [
35
+ TenantContext
36
+ ]
37
+ });
38
+ export { GetFileContentsByKeyUseCaseImplementation };
39
+
40
+ //# sourceMappingURL=GetFileContentsByKeyUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js","sources":["../../../src/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { GetFileContentsByKeyUseCase } from \"@webiny/api-file-manager/features/file/GetFileContentsByKey/index.js\";\nimport type { FileContents } from \"@webiny/api-file-manager/features/file/GetFileContentsById/index.js\";\nimport {\n FileNotFoundError,\n FilePersistenceError\n} from \"@webiny/api-file-manager/domain/file/errors.js\";\n\nclass GetFileContentsByKeyUseCaseImpl implements GetFileContentsByKeyUseCase.Interface {\n constructor(private tenantContext: TenantContext.Interface) {}\n\n async execute(key: string): Promise<Result<FileContents, GetFileContentsByKeyUseCase.Error>> {\n const tenant = this.tenantContext.getTenant();\n const bucketKey = `tenants/${tenant.id}/files/${key}`;\n\n try {\n const s3 = new S3();\n const bucket = String(process.env.S3_BUCKET);\n const response = await s3.getObject({ Bucket: bucket, Key: bucketKey });\n\n if (!response.Body) {\n return Result.fail(new FileNotFoundError(key));\n }\n\n const buffer = Buffer.from(await response.Body.transformToByteArray());\n const contentType = response.ContentType || \"application/octet-stream\";\n return Result.ok({ buffer, contentType });\n } catch (error) {\n return Result.fail(\n new FilePersistenceError(error instanceof Error ? error : new Error(String(error)))\n );\n }\n }\n}\n\nexport const GetFileContentsByKeyUseCaseImplementation =\n GetFileContentsByKeyUseCase.createImplementation({\n implementation: GetFileContentsByKeyUseCaseImpl,\n dependencies: [TenantContext]\n });\n"],"names":["GetFileContentsByKeyUseCaseImpl","tenantContext","key","tenant","bucketKey","s3","S3","bucket","String","process","response","Result","FileNotFoundError","buffer","Buffer","contentType","error","FilePersistenceError","Error","GetFileContentsByKeyUseCaseImplementation","GetFileContentsByKeyUseCase","TenantContext"],"mappings":";;;;;AAUA,MAAMA;IACF,YAAoBC,aAAsC,CAAE;aAAxCA,aAAa,GAAbA;IAAyC;IAE7D,MAAM,QAAQC,GAAW,EAAoE;QACzF,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAC3C,MAAMC,YAAY,CAAC,QAAQ,EAAED,OAAO,EAAE,CAAC,OAAO,EAAED,KAAK;QAErD,IAAI;YACA,MAAMG,KAAK,IAAIC;YACf,MAAMC,SAASC,OAAOC,QAAQ,GAAG,CAAC,SAAS;YAC3C,MAAMC,WAAW,MAAML,GAAG,SAAS,CAAC;gBAAE,QAAQE;gBAAQ,KAAKH;YAAU;YAErE,IAAI,CAACM,SAAS,IAAI,EACd,OAAOC,OAAO,IAAI,CAAC,IAAIC,kBAAkBV;YAG7C,MAAMW,SAASC,OAAO,IAAI,CAAC,MAAMJ,SAAS,IAAI,CAAC,oBAAoB;YACnE,MAAMK,cAAcL,SAAS,WAAW,IAAI;YAC5C,OAAOC,OAAO,EAAE,CAAC;gBAAEE;gBAAQE;YAAY;QAC3C,EAAE,OAAOC,OAAO;YACZ,OAAOL,OAAO,IAAI,CACd,IAAIM,qBAAqBD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMV,OAAOQ;QAEnF;IACJ;AACJ;AAEO,MAAMG,4CACTC,4BAA4B,oBAAoB,CAAC;IAC7C,gBAAgBpB;IAChB,cAAc;QAACqB;KAAc;AACjC"}
@@ -0,0 +1,4 @@
1
+ export declare const GetFileContentsByKeyFeature: {
2
+ name: string;
3
+ register(container: import("@webiny/di").Container): void;
4
+ };